เทคนิคที่ 073 · PYTHON / JAVASCRIPT

แผนภาพต้นไม้Node-link Tree

เห็นว่าอะไรอยู่ใต้อะไร และลึกแค่ไหน

2
ต่อยอดโดยตรงควรรู้ก่อน · ไม่ต้องมีพื้นฐานมาก่อน
ลองเล่น

01ภาพรวมของกราฟนี้

Node-link tree แสดงลำดับชั้นด้วยการวางโหนดเป็นชั้นตามความลึกและลากเส้นเชื่อมความสัมพันธ์พ่อแม่กับลูก ต่างจาก treemap ที่เน้นขนาด กราฟนี้เน้นโครงสร้างล้วน ๆ จึงตอบคำถามว่า "อะไรอยู่ใต้อะไร" ได้ตรงที่สุด

เปรียบเทียบให้เห็นภาพ

เหมือนผังองค์กรที่หัวหน้าอยู่บนและลูกน้องอยู่ล่าง เส้นบอกว่าใครรายงานตรงกับใคร

ใช้ที่ไหนบ้าง — ผังองค์กร โครงสร้างหมวดหมู่สินค้า โครงสร้างไฟล์และโฟลเดอร์ หรือแผนผังการตัดสินใจ

สร้างอย่างไร

  1. ขั้นที่ 1จัดข้อมูลเป็นความสัมพันธ์พ่อแม่กับลูก
  2. ขั้นที่ 2คำนวณความลึกของแต่ละโหนด
  3. ขั้นที่ 3กระจายใบให้ห่างเท่ากันแล้ววางพ่อแม่ไว้กึ่งกลางลูก
  4. ขั้นที่ 4ลากเส้นเชื่อมและติดชื่อโหนด

ตัวอย่างคลาสสิก · ผังองค์กรที่ใช้กันมาตั้งแต่ศตวรรษที่ 19

Daniel McCallum วาดผังองค์กรของบริษัทรถไฟนิวยอร์กแอนด์อีรีในปี 1855 ซึ่งถือเป็นผังองค์กรสมัยใหม่ชิ้นแรก เขาต้องการให้เห็นสายการบังคับบัญชาที่ชัดเจนเพื่อแก้ปัญหาการสื่อสารในองค์กรขนาดใหญ่ รูปแบบนี้แทบไม่เปลี่ยนเลยจนถึงวันนี้

Wikipedia · Organizational chart

02อธิบายภาษาคนเข้าใจง่าย ๆ

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

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

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

สิ่งที่อ่านได้ทันทีคือรูปร่างของโครงสร้าง ต้นไม้ที่กว้างและตื้นแปลว่ามีหลายสาขาแต่ไม่ลึก ส่วนต้นไม้ที่แคบและลึกแปลว่ามีสายบังคับบัญชายาว

ข้อจำกัดคือพื้นที่ จำนวนใบกำหนดความกว้างของภาพโดยตรง เมื่อมีใบเกินประมาณ 40 ใบ ชื่อจะชนกันจนอ่านไม่ได้ ทางแก้คือยุบสาขาที่ไม่ได้ดูอยู่ หรือเปลี่ยนไปใช้ radial tree

03ข้อมูลที่ต้องใช้

รูปทรงของข้อมูลลำดับชั้น parent–child
จำนวนมิติที่เข้ารหัสได้2 มิติ
จำนวนแถวที่เหมาะ10–40 โหนด และลึกไม่เกิน 5 ชั้นขั้นต่ำ 4 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องไม่มีแกนค่า ตำแหน่งสื่อความสัมพันธ์ไม่ใช่ปริมาณ

คอลัมน์ที่ต้องเตรียม

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
idชื่อโหนดโหนดy5–60 โหนดต้องไม่ซ้ำกันทั้งชุด
parentโหนดแม่โหนดpathอ้างถึง id ที่มีจริงรากใช้ค่าว่าง และห้ามมีวงจร
value
ไม่บังคับ
ขนาดตัวเลขต่อเนื่องsizeบวกเท่านั้นไม่บังคับ ใช้กำหนดขนาดของจุดถ้าต้องการ

ต้องเตรียมข้อมูลอย่างไรก่อนวาด

  1. ตรวจว่าโครงสร้างไม่มีวงจรและมีรากเดียว
  2. ตรวจว่าทุก parent อ้างถึง id ที่มีจริง
  3. ตัดสินใจว่าจะวางต้นไม้แนวตั้งหรือแนวนอน

ค่าที่หายไป — โหนดที่อ้างถึงพ่อแม่ที่ไม่มีอยู่จริงจะหลุดออกจากต้นไม้เงียบ ๆ ต้องตรวจจำนวนโหนดที่วาดได้เทียบกับจำนวนแถวก่อนเสมอ

สเกลของแกน — ไม่มีสเกลค่า ตำแหน่งกำหนดจากโครงสร้างล้วน ๆ

กราฟจะเริ่มพังเมื่อไร

เกิน 60 โหนด ชื่อจะชนกันจนอ่านไม่ได้ — ยุบสาขาที่ไม่ได้ดู หรือใช้ radial-tree

หน้าตาไฟล์ที่ต้องเตรียม

id,parent,value
บริษัท,,0
สินค้าอุปโภค,บริษัท,0

04อ่านแล้วเห็นอะไร

สิ่งที่เห็นได้จากภาพ

  • ความลึกของโครงสร้าง
  • สาขาที่แตกกว้างกับสาขาที่แคบ
  • โหนดที่ไม่มีลูกซึ่งคือปลายสาย
  • ความไม่สมดุลของโครงสร้าง

สิ่งที่กราฟนี้ตอบไม่ได้

  • ไม่บอกขนาดหรือความสำคัญของแต่ละโหนด เว้นแต่จะเพิ่ม channel ขนาด
  • ไม่บอกความสัมพันธ์ข้ามสาขาที่ไม่ใช่พ่อแม่ลูก

อ่านตามลำดับนี้

  1. หารากแล้วไล่ลงตามเส้น
  2. นับจำนวนชั้นเพื่อรู้ความลึก
  3. ดูว่าสาขาไหนมีลูกมากที่สุด

คำถามที่ตอบได้

  • โหนดนี้อยู่ใต้ใคร
  • โครงสร้างลึกกี่ชั้น
  • สาขาไหนแตกย่อยมากที่สุด

สัญญาณว่ามีอะไรผิด

  • จำนวนโหนดที่วาดได้น้อยกว่าจำนวนแถวในข้อมูล ซึ่งแปลว่ามีโหนดหลุด
  • ชื่อโหนดชนกันจนอ่านไม่ได้

05เหมาะกับการนำเสนอแบบไหน

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

ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย

  1. ติดชื่อโหนดทุกโหนด เพราะชื่อคือข้อมูลหลัก
  2. ใช้สีบอกประเภทของโหนดถ้ามีความหมาย
  3. ยุบสาขาที่ไม่เกี่ยวกับประเด็นให้เหลือจุดเดียว

รูปแบบชื่อกราฟที่ควรใช้

โครงสร้างลึก <จำนวน> ชั้น โดย <สาขา> แตกย่อยมากที่สุดที่ <จำนวน> รายการ

06เอาไปใช้ต่อ

โค้ดทุกชิ้นอ่านไฟล์ node-link-tree-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง

# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด node-link-tree-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg")   # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import networkx as nx  # pip install networkx

C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a"   # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"

df = pd.read_csv("node-link-tree-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "shape"   # ← ค่าจาก Playground

fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)

G = nx.DiGraph()
for _, r in df.iterrows():
    if r["parent"] and isinstance(r["parent"], str):
        G.add_edge(r["parent"], r["id"])
root = df[df["parent"].isna() | (df["parent"] == "")]["id"].iloc[0]
pos = nx.nx_agraph.graphviz_layout(G, prog="dot") if False else nx.spring_layout(G, seed=42)
nx.draw_networkx_edges(G, pos, ax=ax, edge_color="#c9c6bd", width=1.6)
nx.draw_networkx_nodes(G, pos, ax=ax, node_color=C1, node_size=320)
nx.draw_networkx_labels(G, pos, ax=ax, font_size=8, font_color="white")
ax.axis("off")
print("ความลึกสูงสุด:", nx.dag_longest_path_length(G) + 1)

ax.spines[["top", "right"]].set_visible(False)   # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("node-link-tree.png", dpi=160)
print("เขียน node-link-tree.png แล้ว ·", len(df), "แถว")

ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*" · ทดสอบกับเวอร์ชัน 3.10

07ลองเล่นเพื่อเข้าใจ

ข้อมูลตัวอย่าง · 11 แถว · seed 211● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
กว้างและตื้น หรือแคบและลึก
บริษัทบริษัท · ชั้นที่ 1สินค้าอุปโภคสินค้าอุปโภค · ชั้นที่ 2อาหารอาหาร · ชั้นที่ 2บริการบริการ · ชั้นที่ 2ของใช้ในบ้านของใช้ในบ้าน · 91.0 · ชั้นที่ 3ของใช้ส่วนตัวของใช้ส่วนตัว · 107 · ชั้นที่ 3เครื่องดื่มเครื่องดื่ม · 87.0 · ชั้นที่ 3ขนมขนม · 117 · ชั้นที่ 3อาหารแช่แข็งอาหารแช่แข็ง · 41.0 · ชั้นที่ 3ซ่อมบำรุงซ่อมบำรุง · 102 · ชั้นที่ 3จัดส่งจัดส่ง · 87.0 · ชั้นที่ 3
จำนวนโหนด11
ความลึกสูงสุด3
จำนวนใบ7
ดูข้อมูลเป็นตาราง (11 แถว)
แผนภาพต้นไม้ 11 โหนด ลึก 3 ชั้น
โหนดพ่อแม่ค่า
บริษัท(ราก)
สินค้าอุปโภคบริษัท
อาหารบริษัท
บริการบริษัท
ของใช้ในบ้านสินค้าอุปโภค91.0
ของใช้ส่วนตัวสินค้าอุปโภค107
เครื่องดื่มอาหาร87.0
ขนมอาหาร117
อาหารแช่แข็งอาหาร41.0
ซ่อมบำรุงบริการ102
จัดส่งบริการ87.0

ลองแล้วจะเห็นอะไร

  • สังเกตอะไร: เทียบกับหน้า treemap ที่ใช้ข้อมูลชุดเดียวกัน จะเห็นว่า treemap บอกขนาดได้ดีแต่โครงสร้างต้องเดา ส่วนต้นไม้บอกโครงสร้างชัดแต่ไม่บอกขนาด

ข้อควรระวัง

  1. ไม่ตรวจว่ามีโหนดหลุดออกจากต้นไม้ เพราะโหนดที่อ้างพ่อแม่ผิดจะหายไปเงียบ ๆ
  2. ใส่โหนดมากเกินไปจนชื่อชนกัน
  3. ใช้ต้นไม้ทั้งที่ข้อมูลไม่ใช่ลำดับชั้นจริง เช่น มีโหนดที่มีพ่อแม่หลายคน
  4. เรียงลูกไม่คงที่ ทำให้ภาพเปลี่ยนทุกครั้งที่วาดใหม่

เมื่อไหร่ไม่ควรใช้กราฟนี้

  • ขนาดของแต่ละโหนดสำคัญกว่าโครงสร้างใช้แทน: treemap หรือ icicle-chart
  • มีโหนดเกิน 60 โหนดใช้แทน: radial-tree หรือยุบสาขา
  • โหนดมีพ่อแม่ได้หลายคนใช้แทน: force-directed-graph หรือ flow-diagram

กราฟที่เกี่ยวข้อง

เทคนิคถัดไป · กราฟการจัดกลุ่ม