01ภาพรวมของกราฟนี้
Hierarchical edge bundling วางโหนดรอบวงตามลำดับชั้น แล้วดัดเส้นให้ลู่ตามโครงสร้างจนเส้นที่ไปทางเดียวกันรวมเป็นมัด ทำให้เห็นรูปแบบการเชื่อมระหว่างสาขาได้จากภาพรวม แลกกับการที่ตามเส้นทีละเส้นแทบไม่ได้เลย
เปรียบเทียบให้เห็นภาพ
เหมือนสายไฟในตู้ที่รัดเป็นมัด ซึ่งดูเป็นระเบียบและเห็นทิศทางรวม แต่ตามสายเส้นเดียวจากปลายหนึ่งไปอีกปลายได้ยากขึ้น
ใช้ที่ไหนบ้าง — การเรียกใช้ระหว่างโมดูลในโค้ดขนาดใหญ่ การอ้างอิงข้ามแผนก หรือความสัมพันธ์ข้ามหมวดหมู่ในโครงสร้างที่มีลำดับชั้นอยู่แล้ว
สร้างอย่างไร
- ขั้นที่ 1จัดโหนดเข้าโครงสร้างลำดับชั้นและวางรอบวง
- ขั้นที่ 2หาเส้นทางผ่านโครงสร้างสำหรับแต่ละเส้นเชื่อม
- ขั้นที่ 3ดัดเส้นให้ลู่เข้าหาเส้นทางนั้นตามความแรงที่กำหนด
- ขั้นที่ 4ใช้สีบอกทิศทางเข้าออก
ตัวอย่างคลาสสิก · Edge bundling ในการแสดงการพึ่งพากันของโค้ด
Danny Holten เสนอวิธีนี้ในปี 2006 เพื่อแสดงการพึ่งพากันของคลาสในซอฟต์แวร์ขนาดใหญ่ ซึ่งวาดด้วยเส้นตรงแล้วภาพเต็มไปด้วยเส้นตัดกัน เมื่อบังคับให้เส้นลู่ตามโครงสร้างแพ็กเกจ รูปแบบการพึ่งพาข้ามแพ็กเกจก็ปรากฏขึ้นชัดเจน
02อธิบายภาษาคนเข้าใจง่าย ๆ
เมื่อเครือข่ายมีเส้นหลายร้อยเส้น การวาดเส้นตรงทุกเส้นทำให้ภาพเต็มไปด้วยเส้นตัดกันจนไม่เห็นรูปแบบอะไรเลย
Edge bundling อาศัยข้อเท็จจริงว่าโหนดมักมีโครงสร้างลำดับชั้นอยู่แล้ว เช่น ไฟล์อยู่ในโฟลเดอร์ พนักงานอยู่ในแผนก แล้วบังคับให้เส้นเดินทางผ่านโครงสร้างนั้นแทนที่จะพุ่งตรง
ผลคือเส้นที่ไปทางเดียวกันจะทับกันเป็นมัดหนา ทำให้เห็นทันทีว่ามีการเชื่อมระหว่างสาขาไหนกับสาขาไหนมากผิดปกติ
ราคาที่จ่ายอย่างแรกคือตามเส้นทีละเส้นแทบไม่ได้ เพราะเมื่อเส้นทับกันแล้วก็แยกไม่ออกว่าเส้นไหนไปไหน กราฟนี้จึงตอบคำถามภาพรวมเท่านั้น
อย่างที่สองคือความแรงของการมัดเป็นค่าที่คนตั้ง มัดแรงไปภาพจะสวยแต่บิดเบือนความจริงมาก มัดเบาไปก็ไม่ต่างจากเส้นตรง ซึ่งแปลว่าภาพเดียวกันปรับให้เล่าเรื่องต่างกันได้
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
source | โหนดต้นทาง | โหนด | angle | 20–300 โหนด | ควรมีโครงสร้างลำดับชั้นกำกับ |
target | โหนดปลายทาง | โหนด | angle | ชุดเดียวกับ source | เส้นเชื่อมลู่ตามโครงสร้าง |
valueไม่บังคับ | น้ำหนัก | ตัวเลขต่อเนื่อง | size | บวกเท่านั้น | ควบคุมความหนาของเส้น |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- จัดโหนดเข้าโครงสร้างลำดับชั้นให้ครบ
- เรียงโหนดรอบวงให้สาขาเดียวกันอยู่ติดกัน
- ตั้งค่าความแรงของการมัดและระบุไว้ในคำอธิบาย
ค่าที่หายไป — โหนดที่ไม่มีที่ในโครงสร้างลำดับชั้นต้องแยกเป็นกลุ่มอื่น ไม่ยัดเข้าสาขาใดสาขาหนึ่ง
สเกลของแกน — ความหนาของเส้นควรแปรตรงกับน้ำหนัก และใช้ความโปร่งใสเพื่อให้เห็นความหนาแน่นของมัด
กราฟจะเริ่มพังเมื่อไร
เกิน 800 เส้นเชื่อม มัดกลางภาพทึบจนไม่เห็นโครงสร้าง
หน้าตาไฟล์ที่ต้องเตรียม
source,target,value
เข้าชมเว็บ,ดูสินค้า,7975
เข้าชมเว็บ,ออกทันที,4078
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- คู่สาขาที่เชื่อมกันหนาแน่นผิดปกติ
- โหนดที่มีเส้นออกไปทุกสาขา
- สาขาที่แทบไม่เชื่อมกับใครเลย
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ ตามเส้นทีละเส้นแทบไม่ได้เมื่อเส้นถูกมัดรวม
- นับจำนวนเส้นที่แน่นอนในมัดไม่ได้
- ความแรงของการมัดเป็นค่าที่คนตั้ง จึงเทียบภาพสองภาพที่ตั้งต่างกันไม่ได้
อ่านตามลำดับนี้
- ดูมัดที่หนาที่สุดก่อนว่าเชื่อมสาขาไหนกับสาขาไหน
- ดูว่าเส้นส่วนใหญ่อยู่ภายในสาขาหรือข้ามสาขา
- ใช้การชี้เพื่อไฮไลต์เส้นของโหนดเดียวเมื่อต้องการดูรายตัว
คำถามที่ตอบได้
- สาขาไหนเชื่อมกับสาขาไหนมากที่สุด
- มีการเชื่อมข้ามสาขามากแค่ไหนเทียบกับภายในสาขา
- โหนดไหนเป็นจุดเชื่อมหลัก
สัญญาณว่ามีอะไรผิด
- มัดกลางภาพทึบจนไม่เห็นอะไร
- ไม่ระบุความแรงของการมัด
- สาขาเดียวกันกระจายอยู่คนละมุมของวง
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ตีกรอบสีของแต่ละสาขารอบวงเพื่อให้แยกกลุ่มได้
- ใช้สีต่างกันสำหรับเส้นเข้าและเส้นออกเมื่อชี้ที่โหนด
- ระบุความแรงของการมัดในคำอธิบาย
รูปแบบชื่อกราฟที่ควรใช้
การเชื่อมข้ามสาขาใน <ระบบ> โดย <สาขา> กับ <สาขา> เชื่อมกันมากที่สุด
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ edge-bundling-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด edge-bundling-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import networkx as nx
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("edge-bundling-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "bundle" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
G = nx.from_pandas_edgelist(df, "source", "target", edge_attr="value")
nodes = sorted(G) # เรียงให้สาขาเดียวกันติดกัน
ang = {n: 2 * np.pi * i / len(nodes) - np.pi / 2 for i, n in enumerate(nodes)}
pt = {n: (np.cos(a), np.sin(a)) for n, a in ang.items()}
beta = 0.85 # ความแรงของการมัด 0 = เส้นตรง
for a_, b_ in G.edges():
t = np.linspace(0, 1, 60)[:, None]
straight = (1 - t) * np.array(pt[a_]) + t * np.array(pt[b_])
curve = (1 - t) ** 2 * np.array(pt[a_]) + 2 * (1 - t) * t * np.zeros(2) + t ** 2 * np.array(pt[b_])
path = beta * curve + (1 - beta) * straight
ax.plot(path[:, 0], path[:, 1], color=C1, linewidth=1.2, alpha=0.55)
for n in nodes:
ax.plot(*pt[n], "o", markersize=5, color=C1)
ax.text(pt[n][0] * 1.08, pt[n][1] * 1.08, n, ha="center", va="center", fontsize=7.5)
ax.set_aspect("equal"); ax.axis("off")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("edge-bundling.png", dpi=160)
print("เขียน edge-bundling.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
การมัดเส้นทำให้เส้นแต่ละเส้นตามรอยยาก — ใช้เพื่อดูภาพรวมของทิศทาง ไม่ใช่เพื่อตามเส้นทีละเส้น
ดูข้อมูลเป็นตาราง (8 แถว)
| จาก | ไป | น้ำหนัก |
|---|---|---|
| เข้าชมเว็บ | ดูสินค้า | 7,975 |
| เข้าชมเว็บ | ออกทันที | 4,078 |
| ดูสินค้า | ใส่ตะกร้า | 3,083 |
| ดูสินค้า | ออกกลางทาง | 5,112 |
| ใส่ตะกร้า | กรอกที่อยู่ | 1,952 |
| ใส่ตะกร้า | ทิ้งตะกร้า | 1,166 |
| กรอกที่อยู่ | ชำระเงินสำเร็จ | 1,418 |
| กรอกที่อยู่ | ชำระไม่สำเร็จ | 457 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ลองเลือกเส้นหนึ่งเส้นแล้วตามจากต้นทางไปปลายทาง จะพบว่าทำได้ยากมาก — นี่คือราคาที่แลกมากับความเป็นระเบียบของภาพ
ข้อควรระวัง
- พยายามตามเส้นทีละเส้น ทั้งที่กราฟนี้ออกแบบมาให้ดูภาพรวม
- ไม่ระบุความแรงของการมัด ทำให้เทียบสองภาพไม่ได้
- เรียงโหนดรอบวงไม่ตามโครงสร้าง ทำให้การมัดไม่มีความหมาย
- ใช้กับเครือข่ายที่ไม่มีโครงสร้างลำดับชั้นซึ่งไม่มีอะไรให้เส้นลู่ตาม
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ต้องตามเส้นทีละเส้นให้ได้→ใช้แทน: adjacency-matrix หรือ arc-diagram
- โหนดไม่มีโครงสร้างลำดับชั้น→ใช้แทน: force-directed-graph
- เส้นเชื่อมน้อยกว่า 30 เส้น→ใช้แทน: chord-diagram