01ภาพรวมของกราฟนี้
Force-directed graph วางโหนดด้วยการจำลองแรงทางฟิสิกส์ ทำให้กลุ่มที่เชื่อมกันหนาแน่นรวมตัวกันโดยอัตโนมัติ เหมาะกับการเห็นโครงสร้างภาพรวมและหาโหนดศูนย์กลาง แต่ตำแหน่งที่ได้ไม่มีความหมายในตัวเองและเปลี่ยนทุกครั้งที่รันใหม่
เปรียบเทียบให้เห็นภาพ
เหมือนโยนลูกปัดที่ผูกด้วยยางลงบนโต๊ะแล้วปล่อยให้มันจัดตัวเอง ลูกที่ผูกกันหลายเส้นจะถูกดึงมาอยู่ใกล้กัน
ใช้ที่ไหนบ้าง — เครือข่ายสังคม การอ้างอิงระหว่างงานวิจัย ความสัมพันธ์ระหว่างบริการในระบบซอฟต์แวร์ หรือเครือข่ายการติดต่อในการสอบสวน
สร้างอย่างไร
- ขั้นที่ 1เตรียมรายการเส้นเชื่อมแบบ source–target
- ขั้นที่ 2ตั้งแรงดึงตามเส้นเชื่อมและแรงผลักระหว่างโหนด
- ขั้นที่ 3ปล่อยให้ระบบเข้าสู่สมดุล
- ขั้นที่ 4ใช้ขนาดโหนดบอกจำนวนเส้นเชื่อม
ตัวอย่างคลาสสิก · เครือข่ายการติดต่อในการสอบสวนโรคระบาด
นักระบาดวิทยาวาดเครือข่ายผู้ติดเชื้อโดยให้เส้นแทนการติดต่อกัน ภาพที่ได้เผยให้เห็นเหตุการณ์แพร่กระจายวงกว้างเป็นกระจุกใหญ่ และเผยโหนดสะพานที่พาเชื้อข้ามจากกลุ่มหนึ่งไปอีกกลุ่ม ซึ่งเป็นข้อมูลที่ตารางรายชื่อบอกไม่ได้
02อธิบายภาษาคนเข้าใจง่าย ๆ
ข้อมูลเครือข่ายไม่ใช่ต้นไม้ เพราะโหนดหนึ่งมีพ่อแม่ได้หลายตัวและอาจมีวงจร จึงวางเป็นชั้น ๆ แบบต้นไม้ไม่ได้
วิธีแก้คือไม่กำหนดตำแหน่งเอง แต่ให้ระบบหาเอง โดยสมมติว่าเส้นเชื่อมเป็นสปริงที่ดึงโหนดเข้าหากันและโหนดทุกตัวผลักกันเหมือนประจุไฟฟ้า
เมื่อปล่อยให้ระบบเข้าสู่สมดุล โหนดที่เชื่อมกันหนาแน่นจะถูกดึงมาอยู่ใกล้กันเป็นกระจุก ทำให้เห็นกลุ่มย่อยได้โดยไม่ต้องคำนวณอะไรเพิ่ม
ราคาที่จ่ายอย่างแรกคือตำแหน่งไม่มีความหมายในตัวเอง โหนดที่อยู่บนขวาไม่ได้แปลว่าอะไรทั้งนั้น และระยะบนภาพไม่ใช่ระยะจริงในเครือข่าย
อย่างที่สองคือผลลัพธ์ไม่เสถียร รันใหม่ด้วยค่าเริ่มต้นสุ่มต่างกันก็ได้ภาพคนละแบบ ซึ่งแปลว่าผู้อ่านสองคนที่ดูภาพคนละครั้งอาจเล่าเรื่องต่างกัน ต้องล็อกค่าเริ่มต้นไว้เสมอ
อย่างที่สามคือเมื่อเส้นเชื่อมเยอะเกินราวสองร้อยเส้น ภาพจะกลายเป็นก้อนขนแมวที่อ่านอะไรไม่ได้เลย ซึ่งตอนนั้นต้องเปลี่ยนไปใช้ adjacency matrix แทน
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
source | โหนดต้นทาง | โหนด | path | 10–150 โหนด | เป็นข้อความชื่อโหนด |
target | โหนดปลายทาง | โหนด | path | ชุดเดียวกับ source | โหนดเดียวกันปรากฏได้ทั้งสองฝั่ง |
valueไม่บังคับ | น้ำหนักความสัมพันธ์ | ตัวเลขต่อเนื่อง | size | บวกเท่านั้น | ใช้ควบคุมความหนาของเส้น |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- รวมเส้นซ้ำและตัดเส้นที่เชื่อมตัวเอง
- ตัดโหนดที่ไม่เชื่อมกับใครออกหรือแยกแสดง
- ล็อกค่าเริ่มต้นของการสุ่มเพื่อให้ผลซ้ำได้
ค่าที่หายไป — เส้นที่อ้างโหนดไม่ครบจะถูกตัดทิ้ง ต้องรายงานจำนวนที่ตัด
สเกลของแกน — ขนาดโหนดควรแปรตามรากที่สองของจำนวนเส้นเชื่อม เพราะเข้ารหัสด้วยพื้นที่
กราฟจะเริ่มพังเมื่อไร
เกิน 200 เส้นเชื่อม ภาพกลายเป็นก้อนขนแมวที่อ่านไม่ได้
หน้าตาไฟล์ที่ต้องเตรียม
source,target,value
เข้าชมเว็บ,ดูสินค้า,7975
เข้าชมเว็บ,ออกทันที,4078
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- กลุ่มย่อยที่เชื่อมกันหนาแน่น
- โหนดศูนย์กลางที่มีเส้นเชื่อมมากที่สุด
- โหนดสะพานที่เชื่อมสองกลุ่มเข้าด้วยกัน
- โหนดโดดเดี่ยวที่ไม่เชื่อมกับใคร
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ ตำแหน่งบนภาพไม่มีความหมาย โหนดที่อยู่ใกล้กันบนภาพอาจไม่ได้เชื่อมกันเลย
- ★ รันใหม่ได้ภาพต่างกันถ้าไม่ล็อกค่าเริ่มต้นของการสุ่ม
- นับเส้นเชื่อมที่แม่นยำเมื่อเส้นทับกัน
อ่านตามลำดับนี้
- มองหากระจุกของโหนดก่อนเพื่อรู้ว่ามีกี่กลุ่ม
- ดูโหนดที่ใหญ่ที่สุดซึ่งมีเส้นเชื่อมมากสุด
- มองหาโหนดที่อยู่ระหว่างกระจุกซึ่งทำหน้าที่สะพาน
คำถามที่ตอบได้
- เครือข่ายนี้แบ่งเป็นกี่กลุ่ม
- ใครเป็นศูนย์กลาง
- มีใครทำหน้าที่เป็นสะพานระหว่างกลุ่ม
สัญญาณว่ามีอะไรผิด
- ภาพเป็นก้อนขนแมวไม่มีโครงสร้างให้เห็น
- ไม่ล็อกค่าเริ่มต้นของการสุ่ม ทำให้ภาพเปลี่ยนทุกครั้ง
- ตีความระยะห่างบนภาพว่าเป็นความห่างจริงในเครือข่าย
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เขียนกำกับเสมอว่าตำแหน่งไม่มีความหมาย
- ติดชื่อเฉพาะโหนดศูนย์กลางและโหนดสะพาน
- ใช้สีบอกกลุ่มย่อยที่คำนวณมาก่อน ไม่ใช่สีตามตำแหน่ง
รูปแบบชื่อกราฟที่ควรใช้
เครือข่าย <จำนวน> โหนด แบ่งเป็น <จำนวน> กลุ่ม โดยมี <โหนด> เป็นศูนย์กลาง
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ force-directed-graph-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด force-directed-graph-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import networkx as nx
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("force-directed-graph-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "position" # ← ค่าจาก 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")
pos = nx.spring_layout(G, seed=42) # seed ล็อกไว้เพื่อให้ผลซ้ำได้
deg = dict(G.degree())
nx.draw_networkx_edges(G, pos, ax=ax, edge_color="#c9c6bd",
width=[0.6 + d["value"] / df["value"].max() * 3 for *_, d in G.edges(data=True)])
nx.draw_networkx_nodes(G, pos, ax=ax, node_color=C1,
node_size=[120 + deg[n] ** 0.5 * 180 for n in G])
nx.draw_networkx_labels(G, pos, ax=ax, font_size=8)
ax.set_axis_off()
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("force-directed-graph.png", dpi=160)
print("เขียน force-directed-graph.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ตำแหน่งของโหนดไม่มีความหมายในตัวเอง ระยะห่างบนภาพไม่ใช่ระยะจริงในเครือข่าย
ดูข้อมูลเป็นตาราง (9 แถว)
| โหนด | จำนวนเส้นเชื่อม |
|---|---|
| ดูสินค้า | 3 |
| ใส่ตะกร้า | 3 |
| กรอกที่อยู่ | 3 |
| เข้าชมเว็บ | 2 |
| ออกทันที | 1 |
| ออกกลางทาง | 1 |
| ทิ้งตะกร้า | 1 |
| ชำระเงินสำเร็จ | 1 |
| ชำระไม่สำเร็จ | 1 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ลองถามตัวเองว่าโหนดที่อยู่มุมขวาบนแปลว่าอะไร — คำตอบคือไม่แปลว่าอะไรเลย นี่คือกับดักที่ผู้อ่านมักตกเสมอ
ข้อควรระวัง
- ตีความตำแหน่งของโหนดว่ามีความหมาย ทั้งที่มาจากการจำลองแรงล้วน ๆ
- ไม่ล็อกค่าเริ่มต้นของการสุ่ม ทำให้ภาพเปลี่ยนทุกครั้งที่รัน
- ใส่เส้นเชื่อมมากเกินไปจนภาพกลายเป็นก้อนขนแมว
- ใช้ในแดชบอร์ดที่ข้อมูลอัปเดตบ่อย ทำให้ผู้ใช้ตามโหนดเดิมไม่เจอ
เมื่อไหร่ไม่ควรใช้กราฟนี้
- เครือข่ายหนาแน่นเกิน 200 เส้นเชื่อม→ใช้แทน: adjacency-matrix
- โครงสร้างเป็นต้นไม้จริง ๆ ไม่มีวงจร→ใช้แทน: node-link-tree
- สนใจปริมาณที่ไหลระหว่างโหนด→ใช้แทน: sankey-diagram