การแสดงกราฟด้วยภาษา DOT

การแสดงกราฟด้วยภาษา DOT

29 January 2021

หากเรามีข้อมูลที่มีความเชื่อมโยงกัน ยกตัวอย่างเช่น ผังองค์กร ผังงาน หรือ แผนที่ความคิด (Mind map) เราสามารถแสดงผลข้อมูลเป็นภาพเพื่อให้คนได้อ่านง่ายโดยใช้กราฟ การแสดงผลเป็นกราฟยังสามารถทำให้เห็นลำดับขั้นตอน ความหนาแน่นของความสัมพันธ์ สามารถเข้าใจและจดจำได้ง่ายขึ้น

เนื่องจากภาษา DOT นั้นมีความง่ายไม่ซับซ้อน ดังนั้นไม่ว่าข้อมูลตั้งต้นเราจะเป็นแบบใด การเขียนโปรแกรมเพื่อแปลงให้ออกมาเป็นผลลัพธ์ภาษา DOT นั้นก็สามารถทำได้ไม่ซับซ้อนจนเกินไปนักตามความคิดของผู้เขียน อีกทั้งภาษา DOT ยังสามารถจัด Layout ของกราฟให้โดยอัตโนมัติอีกด้วย

ไวยากรณ์ภาษา DOT

ไวยากรณ์หลักของภาษา DOT คือ

  • กราฟไม่ระบุทิศทาง (Undirected Graph) 
graph [ชื่อกราฟ] {
    [กำหนดค่าทั่วไป]
    [รายการโหนด]
    รายการความสัมพันธ์กราฟไม่ระบุทิศทาง
}

ผังงานแบบกราฟอวัฏจักรระบุทิศทาง

  • กราฟระบุทิศทาง (Directed Graph) 
digraph [ชื่อกราฟ] {
    [กำหนดค่าทั่วไป]
    [รายการโหนด]
    รายการความสัมพันธ์กราฟระบุทิศทาง
}

สิ่งที่อยู่ในวงเล็บก้ามปู [] เราจะใส่ค่าหรือไม่ก็ได้ หรือเป็น Optional นั่นเองส่วน รายการความสัมพันธ์กราฟไม่ระบุทิศทางนั้น ให้ผู้อ่านคิดเสมือนว่าเป็นการลากเส้นเชื่อมระหว่างโหนดหนึ่งกับอีกโหนดหนึ่ง เช่น

Undirected Graph

graph UndirectedGraph {
    a -- b
    b -- c
}

เป็นการลากเส้นระหว่างจุด a และจุด b และระหว่างจุด b และจุด cเราสามารถเขียนให้สั้นลงอีกเป็นบรรทัดเดียวได้เช่นกันเป็น

graph {
    a -- b -- c
}

ส่วนรายการความสัมพันธ์กราฟระบุทิศทางนั้นให้ผู้อ่านคิดเหมือนว่าเป็นการลากเส้นจากโหนดหนึ่งไปยังโหนดหนึ่ง ข้อแตกต่างกับกราฟไม่ระบุทิศทางที่เห็นได้ชัดคือ หัวลูกศรที่ปลายเส้นเชื่อม เช่น

Directed Graph

digraph DirectedGraph {
    a -> b
    b -> c
}

เป็นการลากเส้นจากจุด a ไปยังจุด b และจากจุด b ไปยังจุด cเราสามารถเขียนให้สั้นลงอีกเป็นบรรทัดเดียวได้เช่นกันเป็น

digraph {
    a -> b -> c
}

นิยามศัพท์ในภาษา DOT

นิยามส่วนต่าง ๆ ในกราฟ
  • โหนด (Node) คือจุดในกราฟ เช่นจากตัวอย่างด้านบนคือ โหนด a, โหนด b และ โหนด c
  • เส้นเชื่อม (Edge) คือเส้นที่ลากต่อระหว่างโหนดเพื่อเชื่อมความสัมพันธ์ ตามภาพด้านซ้ายมือ

สำหรับความแตกต่างระหว่างกราฟไม่ระบุทิศทางและกราฟระบุทิศทางนั้น ผู้เขียนจะบอกต่อไปด้านล่างบทความ

การใส่หมายเหตุ (Comment)

ในภาษา DOT นั้นการใส่หมายเหตุใช้เครื่องหมาย // นำหน้าประโยคที่ต้องการจะเขียนเป็นหมายเหตุ ลักษณะเหมือนตระกูลภาษา C เช่น

ผลลัพธ์การใส่หมายเหตุใน Code
digraph {
    // หมายเหตุ: เป็นการลากเส้นจากจุด a ไปยังจุด b และจากจุด b ไปยังจุด c
    a -> b -> c
}

โดยหมายเหตุจะไม่ถูกแสดงผลในผลลัพธ์ ดังภาพด้านซ้ายมือ

เครื่องมือเครื่องไม้ที่เราจะใช้

สำหรับเครื่องมือที่เราจะใช้เขียนภาษา DOT นั้นมีสองอย่างด้วยกันคือ

โดยหลังจากที่เราติดตั้ง Visual Studio Code และ Plugins ที่ระบุแล้วเราสามารถเขียนภาษา DOT ได้โดยสองวิธี

การใช้ไฟล์นามสกุล .gv

ไฟล์นามสกุล .gv เป็นไฟล์ของภาษา DOT เอง ดังนั้น Code ที่อยู่ในไฟล์นี้จะเป็นภาษา DOT ล้วน การเขียนภาษา DOT โดยใช้วิธีนี้มีขั้นตอนคือ

  1. สร้างไฟล์ใหม่
  1. เลือกประเภทไฟล์เป็น Graphviz (DOT)
  1. Render กราฟโดยใช้ Key ลัด ctrl+kv

การใช้ไฟล์นามสกุล .md

ไฟล์นามสกุล .md นั้นเป็นไฟล์ของภาษา Markdown ดังนั้นตัว Code ส่วนใหญ่ในไฟล์นี้ จึงเป็นภาษา Markdown ซึ่งแนบส่วนของ Code ภาษา DOT เข้าไป การเขียนภาษา DOT โดยใช้วิธีนี้สามารถทำได้โดย

  1. สร้างไฟล์ใหม่ และเลือกประเภทไฟล์เป็น Markdown
  2. Render ไฟล์ Markdown โดยใช้วิธีปกติ ctrl+shift+v ผลลัพธ์จะมีภาพของ Graph แทรกอยู่

ตัวอย่างภาษา DOT

ลักษณะข้อมูลที่ผู้เขียนพบเห็นบ่อย ๆ จะมีดังต่อไปนี้

โครงสร้างแบบต้นไม้

โครงสร้างแบบต้นไม้

ข้อมูลที่มีลักษณะเป็นโครงสร้างต้นไม้นั้น เราสามารถแสดงผลเป็นกราฟไม่ระบุทิศทาง (Undirected Graph) ตัวอย่างเช่นกราฟด้านซ้ายมือ สามารถเขียนออกมาเป็น DOT Language ได้สองแบบดังนี้

เขียนแบบปกติ

graph g {
    a -- b;
    a -- c;
    a -- d;
    a -- e;
    b -- h;
    b -- i;
    i -- f;
    e -- g;
}

เขียนแบบใช้ subgraph ช่วย

graph h {
    a -- { b c d e }; // subgraph
    b -- { h i }; // subgraph
    i -- f;
    e -- g;
}

ตัวอย่างต้นไม้ในโลกจริง ๆ ที่คุ้นเคยกันคือผังองค์กร

ผังองค์กร

จากภาพตัวอย่างด้านซ้ายมือ เราสามารถเขียนเป็น DOT Language ได้ดังนี้

graph g {
    // กำหนดค่าทั่วไป
    node [shape=box];

    // รายการโหนด
    CEO [label=
    <<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
        <tr><td border="0">Mr. Jirapant Peerapant</td></tr>
        <tr><td border="0"><b>CEO</b></td></tr>
        <tr><td border="0"><i>Company President</i></td></tr>
    </table>>
    ];
    FINANCE_VP [label=
    <<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
        <tr><td border="0">Ms. Roonnee Mitaowan</td></tr>
        <tr><td border="0"><b>Vice President</b></td></tr>
        <tr><td border="0"><i>Finance</i></td></tr>
    </table>>
    ]
    HR_VP [label=
    <<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
        <tr><td border="0">Mr. Charkrich Nuurekha</td></tr>
        <tr><td border="0"><b>Vice President</b></td></tr>
        <tr><td border="0"><i>HR</i></td></tr>
    </table>>
    ]
    ACCOUNTS [label=
    <<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
        <tr><td border="0">Mr. Karnjana Deelee</td></tr>
        <tr><td border="0"><b>Accounts</b></td></tr>
    </table>>
    ]

    BILLING [label=
    <<table border="0" cellborder="1" cellspacing="0" cellpadding="4">
        <tr><td border="0">Ms. Suyupajitr Kamruengsri</td></tr>
        <tr><td border="0"><b>Billing</b></td></tr>
    </table>>
    ]

    // รายการความสัมพันธ์
    CEO -- { FINANCE_VP HR_VP };
    FINANCE_VP -- { ACCOUNTS BILLING };
}

สังเกตได้ว่าเราสามารถใช้โครงสร้าง HTML table มาช่วยในการจัดรูปแบบของ label ภายใน node และอีกประเด็นหนึ่งก็คือ กราฟไม่ระบุทิศทางนั้น จะไม่มีลูกศรที่ปลายเส้นเชื่อมระหว่างโหนด ดังนั้นถือว่าผู้อ่านกราฟสามารถท่องไปตามเส้นที่เชื่อมต่อจากโหนดไปยังทิศทางใดก็ได้ ไม่ว่าจะเป็น จากล่างขึ้นบนหรือจากบนลงล่าง จากซ้ายไปขวาหรือขวาไปซ้าย สามารถเป็นไปได้ทั้งสิ้น

ผังงาน (Flowchart)

ในทางกลับกัน มีกราฟอีกรูปแบบหนึ่งที่ผู้อ่านกราฟสามารถท่องไปตามเส้นที่เชื่อมต่อจากโหนดไปยังทิศทางที่กำหนดโดยหัวลูกศรเท่านั้น กราฟที่มีลักษณะแบบนี้เรียกว่า กราฟระบุทิศทาง (Directed Graph) ตัวอย่างลักษณะข้อมูลที่สามารถแสดงผลออกมาเป็นกราฟระบุทิศทางได้คือผังงาน ไม่ว่าจะเป็นผังงานไม่ว่าจะเป็นผังงานแบบ กราฟอวัฏจักรระบุทิศทาง (Directed Acyclic Graph: DAG) หรือ ผังงานแบบกราฟวัฏจักรระบุทิศทาง (Directed Cyclic Graph: DCG)

ตัวอย่างผังงานแบบกราฟอวัฏจักรระบุทิศทาง จากบนลงล่าง

ผังงานแบบกราฟอวัฏจักรระบุทิศทาง
digraph {
    // รายการความสัมพันธ์
    a -> {
        rank = same;
        b -> c
    } [color=blue] // สีของเส้นเชื่อม
    c -> d;
}

ตัวอย่างผังงานแบบกราฟอวัฏจักรระบุทิศทางจากซ้ายไปขวา

ผังงานแบบกราฟอวัฏจักรระบุทิศทางจากซ้ายไปขวา

digraph {
    // กำหนดค่าทั่วไป
    rankdir=LR // กำหนดทิศทางกราฟจากซ้ายไปขวา
    node [shape=square] // วาดโหนดเป็นสี่เหลี่ยมจตุรัส

    // รายการความสัมพันธ์
    a -> b -> c
    b -> d -> e
}

ตัวอย่างผังงานแบบกราฟวัฏจักรระบุทิศทาง จากบนลงล่าง

ผังงานแบบกราฟวัฏจักรระบุทิศทาง จากบนลงล่าง

digraph {
    // กำหนดค่าทั่วไป    
    node [shape=square]
    // รายการโหนด
    a;
    b [label="b?" shape=diamond];
    c; d;
    e [label="counter > 10?" shape=parallelogram];    
    f;

    // รายการความสัมพันธ์
    a -> b
    b:w -> a:w [label="false"]
    b -> c [label="true"]
    c -> d
    d -> e
    e:w -> c:w [label="false;ncounter++"]
    e -> f [label="true;nexit loop"]
}

ผังงานในบริษัท

digraph {
    node [shape=box]

    drafter [label="ผู้ร่างเอกสาร"]
    supervisor [label="หัวหน้า"]
    department_manager [label="ผู้จัดการแผนก"]
    management_director [label="ผู้อำนวยการฝ่ายบริหาร"]
    ceo [label="ประธานกรรมการบริหาร"]
    end_process [label="จบกระบวนการ"]

    drafter -> supervisor [label="submit"]
    drafter -> end_process [label="cancel"]

    supervisor -> drafter [label="revise"]
    supervisor -> end_process [label="approven(low budget)"]
    supervisor -> department_manager [label="approven(medium budget)"]

    department_manager -> supervisor [label="revise"]
    department_manager -> end_process [label="approve"]
    department_manager -> management_director [label="approven(high budget)"]

    management_director -> department_manager [label="revise"]
    management_director -> end_process [label="approve"]
    management_director -> ceo [label="approven(high budget with high credit risk)"]

    ceo -> management_director [label="revise"]
    ceo -> end_process [label="approve"]
}

ตัวอย่างผังงานแบบกราฟวัฏจักรระบุทิศทาง จากซ้ายไปขวา

ผังงานแบบกราฟวัฏจักรระบุทิศทาง จากซ้ายไปขวา
digraph {
    rankdir=LR

    node [shape=box]

    client [label="User PC"]
    firewall [label="Firewall"]
    proxy [label="Proxy Server"]
    web_server [label="Web Server"]
    
    client -> firewall [label="(1) HTTP Request" color="blue" fontcolor="blue"]

    firewall -> client [label="(6)HTTP Response" color="green" fontcolor="green"]
    firewall -> client [label="(2) Reject" color="red" fontcolor="red"]
    
    firewall -> proxy [label="(2) Forward Request" color="blue" fontcolor="blue"]

    proxy -> web_server [label="(3) Forward Request" color="blue" fontcolor="blue"]
    proxy -> firewall [label="(5) Forward Response" color="green" fontcolor="green"]

    web_server -> proxy [label="(4) HTTP Response" color="green" fontcolor="green"]

}

ตัวอย่างการแปลงข้อมูลจากแหล่งอื่นเป็นภาษา DOT

SQL

ในฐานข้อมูลประเภท RDBMS นั้น เราสามารถจัดเก็บข้อมูลประเภทกราฟ และแปลงเป็นภาษา DOT ได้ด้วยการใช้ Table ประเภท linked-list ตัวอย่างเช่น หากเรามีข้อมูลตัวอย่างดังต่อไปนี้

-- สร้าง Table เพื่อเก็บข้อมูล
CREATE TABLE "orgchart" (
"node_id" VARCHAR NULL DEFAULT NULL,
"node_label" VARCHAR NULL DEFAULT NULL,
"parent_node_id" VARCHAR NULL DEFAULT NULL
);

-- ตัวอย่างข้อมูล
INSERT INTO "orgchart" VALUES
('CEO', 'Mr. Jirapant Peerapant', NULL),
('FINANCE_VP', 'Ms. Roonnee Mitaowan', 'CEO'),
('HR_VP', 'Mr. Charkrich Nuurekha', 'CEO'),
('ACCOUNTS', 'Mr. Karnjana Deelee', 'FINANCE_VP'),
('BILLING', 'Ms. Suyupajitr Kamruengsri', 'FINANCE_VP');

เราก็สามารถเขียนประโยค Select เพื่อสร้างเป็นคำสั่งภาษา DOT ได้ ตัวอย่างเช่น

SELECT *
FROM (
SELECT 0 AS ORD, 'graph {'
UNION

-- สร้าง Node
SELECT 1 AS ORD, o.node_id || ' [label="' || o.node_label || '"]' FROM "orgchart" o
UNION

-- สร้างความสัมพันธ์
SELECT 2 AS ORD, o.parent_node_id || '--' || o.node_id 
FROM "orgchart" o
WHERE parent_node_id IS NOT NULL
UNION

SELECT 3 AS ORD, '}'
) D
ORDER BY ORD;

ซึ่งจะให้ผลลัพธ์ดังนี้

ผลลัพธ์จากคำสั่ง SQL

graph {
    CEO [label="Mr. Jirapant Peerapant"]
    HR_VP [label="Mr. Charkrich Nuurekha"]
    FINANCE_VP [label="Ms. Roonnee Mitaowan"]
    ACCOUNTS [label="Mr. Karnjana Deelee"]
    BILLING [label="Ms. Suyupajitr Kamruengsri"]
    CEO--FINANCE_VP
    CEO--HR_VP
    FINANCE_VP--ACCOUNTS
    FINANCE_VP--BILLING
}

Python

ผลลัพธ์จากการรันทดสอบ Code Python ของผู้เขียน

สำหรับตัวอย่างการใช้ภาษา Python เพื่อใช้งานกับภาษา DOT นั้น ผู้อ่านสามารถดูรหัสต้นฉบับเต็มที่สามารถรันทดสอบได้จาก Repository นี้ของผู้เขียน โดยผู้เขียนขอแสดงเฉพาะผลลัพธ์ซึ่งเป็น .gif เนื่องจากรหัสต้นนั้นค่อนข้างยาวครับ

สรุป

จากทั้งหมดที่ผู้เขียนพยายามสื่อก็คือ DOT Language เป็นภาษาที่ค่อนข้างง่าย เพียงคำสั่งไม่กี่ชุดก็สามารถสร้างกราฟได้แล้ว ดังนั้นผู้เขียนหวังว่าผู้อ่านจะสามารถเก็บเกี่ยว แนวคิดที่อยู่ในบทความนี้รวมถึงจุดประกายแนวคิดใหม่ ๆ โดยใช้ DOT Language เพื่อสร้างสรรค์เป็นภาพกราฟ และสามารถสื่อให้บุคคลอื่นเข้าใจในข้อมูลของผู้อ่านโดยใช้กราฟ ในมิติที่ลึกซึ้งยิ่งขึ้น อย่างน้อยผู้เขียนหวังว่าผู้อ่านจะสามารถทำตามตัวอย่างที่ผู้เขียนได้พยายามเขียนให้สามารถอ่านได้ง่ายที่สุด หากผู้เขียนมีข้อเสนอแนะผู้เขียนขอน้อมรับมาปรับปรุงให้ดีขึ้น แล้วพบกันในบทความต่อไปครับ

Reference

Developer and Data Engineer
Government Big Data Institute (GBDi)

แบ่งปันบทความ

กลุ่มเนื้อหา

แท็กยอดนิยม

แจ้งเรื่องที่อยากอ่าน

คุณสามารถแจ้งเรื่องที่อยากอ่านให้เราทราบได้ !
และเราจะนำไปพัฒนาบทความให้มีเนื้อหาที่น่าสนใจมากขึ้น

PDPA Icon

We use cookies to optimize your browsing experience and improve our website’s performance. Learn more at our Privacy Policy and adjust your cookie settings at Settings

Privacy Preferences

You can choose your cookie settings by turning on/off each type of cookie as needed, except for necessary cookies.

Accept all
Manage Consent Preferences
  • Strictly Necessary Cookies
    Always Active

    This type of cookie is essential for providing services on the website of the Personal Data Protection Committee Office, allowing you to access various parts of the site. It also helps remember information you have previously provided through the website. Disabling this type of cookie will result in your inability to use key services of the Personal Data Protection Committee Office that require cookies to function.
    Cookies Details

  • Performance Cookies

    This type of cookie helps the Big Data Institute (Public Organization) understand user interactions with its website services, including which pages or areas of the site are most popular, as well as analyze other related data. The Big Data Institute (Public Organization) also uses this information to improve website performance and gain a better understanding of user behavior. Although the data collected by these cookies is non-identifiable and used solely for statistical analysis, disabling them will prevent the Big Data Institute (Public Organization) from knowing the number of website visitors and from evaluating the quality of its services.

  • Functional Cookies

    This type of cookie enables the Big Data Institute (Public Organization)’s website to remember the choices you have made and deliver enhanced features and content tailored to your usage. For example, it can remember your username or changes you have made to font sizes or other customizable settings on the page. Disabling these cookies may result in the website not functioning properly.

  • Targeting Cookies

    "This type of cookie helps the Big Data Institute (Public Organization) understand user interactions with its website services, including which pages or areas of the site are most popular, as well as analyze other related data. The Big Data Institute (Public Organization) also uses this information to improve website performance and gain a better understanding of user behavior. Although the data collected by these cookies is non-identifiable and used solely for statistical analysis, disabling them will prevent the Big Data Institute (Public Organization) from knowing the number of website visitors and from evaluating the quality of its services.

Save settings
This site is registered on wpml.org as a development site. Switch to a production site key to remove this banner.