שפה, טכנולוגיה ושאר עניינים

עשות ספרים הרבה אין קץ, ולהג הרבה יגיעת בשר. (קהלת יב יב)

  • קטגוריות

  • ארכיון. וואו, כמה אבק.

  • כלים

דיאגרמת ישויות וקשרים בעזרת Graphviz dot

מאת יחזקאל ב. בתאריך ב׳ באלול תשע״א (1 בספטמבר 2011)

משהו חשוב שלמדתי בעבודה: אם לא תכתוב את זה, בעוד חודש (ולפעמים הרבה יותר מהר) תצטרך שוב ללמוד מחדש או למצוא איך עושים את זה, והפעם עם בונוס של עצבים על עצמך למה אתה לא זוכר ולמה לא כתבת את זה מיד. אז הנה, אני כותב כמה דברים שלמדתי בימים האחרונים.

בקורס במסדי נתונים, משתמשים בדיאגרמות "ישויות וקשרים", אקא ER או Entity-relationship. כלי שימושי ליצירה נוחה ומהירה של דיאגרמות כאלה, כמו עוד הרבה גרפים, הוא מנוע Graphviz (ספציפית עם תוכנת dot).

את הבסיס של Graphviz אפשר ללמוד די בקלות, יש להם מדריך נחמד (זהירות, פדף). אני אציין רק מספר טיפים ספציפיים עבור דיאגרמות ER.

  1. כדי לסמן תכונה כמפתח, אנחנו צריכים לשים קו תחתי מתחת לשם. Graphviz במתכונתה הנוכחית לא תומכת בהוספת קו תחתי, ובכלל נושא העיצוב של הטקסט די מוגבל. גם אם משתמשים בתכונות HTML שניתן להוסיף לתוויות, זה כולל רק תת־קבוצה קטנה מאוד של תכונות HTML (בעיקר עיצובי טבלאות), ושוב, זה לא כולל קו תחתי.
    המעקף: נשתמש בתו Unicode מספר 332 (COMBINING LOW LINE הוא שמו). שמרתי לי בצד העתק שלו מ"מפת תווים", ואני מעתיק אותו כשאני הולך לכתוב תווית שתכלול אותו. התו הזה, למרות שב־gedit, למשל, לא מוצג נכון, אמור להופיע מתחת לאות שאחריו שמתם אותו, בדיוק כמו תווי ניקוד ודברים דומים. (כאן למטה הוא מוצג בלי בעיה, אחרי שעטפתי את כל הקוד בתגית pre.)
    המעקף הזה לא מושלם, הקווים לא יוצאים בדיוק במקום, ועד כמה שזה נראה זה לא תלוי בעורך אלא זו אשמת dot עצמה.
  2. כדי לסמן קשר שמהווה קשר בין טיפוס ישות חלשה לטיפוס ישות חזקה, אנחנו צריכים לשים מעוין עם קו גבול כפול. כדי לסמן תכונה מרובת ערכים אנחנו צריכים לשים אליפסה עם קו גבול כפול. ברשימת הצורות האפשריות מופיעים רק מעגל ומתומן עם אפשרות של קו גבול כפול (או גם משולש, במקרה של המתומן).
    פתרון: התכונה peripheries מאפשרת לשלוט על מספר קווי הגבול שיופיעו, ולא משנה איזו צורה בחרתם. תמיד יש את האפשרות לבחור shape=polygon ולקבל הרבה יותר מאפיינים שניתן לשלוט עליהם, אבל למקרה שלנו אין בזה צורך.
  3. כדי לסמן קשר "יחיד לרבים", את צד ה"יחיד" צריך לסמן עם חץ. אם אתם עובדים עם graph (גרף לא מכוון) במקום digraph (גרף מכוון), הצלעות נטולות חיצים כברירת המחדל, ושימוש ב־‎->‎ במקום — ייכשל.
    כדי להוסיף את ראש החץ לא מספיק להוסיף את התכונה arrowhead=normal, אלא חייבים להוסיף גם dir=forward כדי ש־dot תדע איפה הראש ואיפה הזנב. כצפוי, "קדימה" אומר משמאל לימין, כלומר, אם כתבנו A — B, אז קדימה זה אומר מ־A אל B, והחץ יופיע בצד של B.
    אפשר תמיד להגדיר arrowtail ואת הכיוון back, אבל בואו נישאר עם הדברים הפשוטים.לחלופין, אם החלטתם לעבוד עם digraph, ואז ברירת המחדל של הצלעות היא עם חץ, תוכלו להוסיף את השורה edge [arrowhead=none];‎ כדי שזו תהיה ברירת המחדל לכל הצלעות מכאן ועד להודעה חדשה.
    אני לא ממליץ לעבוד עם digraph בדיאגרמות כאלה אם אין סיבה מיוחדת (קשר IS A יכול להיות סיבה טובה), מכיוון שזה אומר שהצורה שבה הגרף "יונח" על הדף בתוצאה תהיה כך שהכיוון הכללי יהיה ממעלה למטה, כשאולי בכלל לא רציתם לתת משמעות של מעלה ומטה לצלעות אלא לאפשר הרבה יותר חופש לפריסת הגרף.
  4. זה החלק הכי יפה, לטעמי, אולי כי הסתבכתי עם זה הרבה עד שקיבלתי את השכל לגגל את זה ולמצוא.
    כדי לסמן "אילוץ השתתפות מלאה", אנחנו צריכים שהצלע המחבר את טיפוס הישות לטיפוס הקשרים תופיע בקו כפול. אין לזה מאפיין ישיר, אבל ב־Stack Overflow, מקור החוכמה והידע האנושי (טוב, בתחום התכנות), מצאתי את התשובה:
    מוסיפים לצלע את המאפיין color="black:white:black"‎. אפשר לוותר על הלבן שבאמצע, אבל אז הקווים יוצאים צמודים למדי לטעמי, אבל כמו תמיד, YMMV.

דוגמה קטנה:

graph ER {
id [label="̲ת̲ע̲ו̲ד̲ת̲ ̲ז̲ה̲ו̲ת̲"];
address [label="̲כ̲ת̲ו̲ב̲ת̲"];
area [label="שטח הבית במ\"ר"];
node [shape=rectangle];
man [label="תושב"];
house [label="בית מגורים"];
live [shape=diamond,label="מתגורר ב"];
man -- id;
man -- live[color="black:white:black"];
live -- house [dir=forward,arrowhead=normal];
house -- address;
house -- area;
{rank=same; man; live; house;}
}

והתוצאה (יצוא ל־png. זו תמונה מוקטנת, קליק להצגת המקור):

השארת תגובה

XHTML: ניתן להשתמש בתגיות : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>