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

แผนภาพคอร์ดChord Diagram

ใช้เมื่อของไหลไปกลับ ไม่ใช่ไหลทางเดียว

5
เฉพาะทางควรรู้ก่อน · อ่าน sankey diagram เป็น
ลองเล่น

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

Chord diagram จัดกลุ่มไว้รอบวงกลมแล้วลากริบบิ้นเชื่อมระหว่างกลุ่มที่มีการไหลถึงกัน จุดแข็งคือรองรับการไหลสองทางและวงจร ซึ่ง sankey ทำไม่ได้เพราะมันบังคับให้ไหลไปข้างหน้าทางเดียว

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

เหมือนแผนที่เส้นทางบินที่วาดสนามบินไว้รอบวงแล้วลากเส้นเชื่อมคู่ที่มีเที่ยวบินถึงกัน โดยเส้นหนาคือเส้นทางที่มีผู้โดยสารมาก

ใช้ที่ไหนบ้าง — การย้ายถิ่นระหว่างภูมิภาค การค้าระหว่างประเทศ การส่งต่อผู้ป่วยระหว่างโรงพยาบาล หรือการโอนเงินระหว่างบัญชี

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

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

ตัวอย่างคลาสสิก · Circos plot ในงานพันธุศาสตร์

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

Wikipedia · Chord diagram

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

Sankey ใช้ได้ดีเมื่อของไหลไปข้างหน้าทางเดียว แต่ข้อมูลหลายอย่างไม่เป็นแบบนั้น เช่น คนย้ายถิ่นระหว่างภาคที่ไหลไปกลับทั้งสองทาง

Chord diagram แก้ด้วยการเลิกใช้แกนซ้ายขวา แล้วจัดกลุ่มไว้รอบวงกลมแทน ทีนี้การไหลจากใครไปใครก็แค่ลากริบบิ้นข้ามวง ไม่มีข้อจำกัดเรื่องทิศทาง

ความยาวของส่วนโค้งที่แต่ละกลุ่มครองบอกปริมาณรวมที่ไหลผ่านกลุ่มนั้น ส่วนความหนาของริบบิ้นบอกปริมาณของคู่นั้น ๆ

ทิศทางบอกได้ด้วยสีหรือด้วยการทำให้ปลายริบบิ้นสองข้างหนาไม่เท่ากัน ซึ่งเป็นเทคนิคที่ใช้กันเมื่อการไหลสองทางไม่เท่ากัน

ข้อจำกัดที่หนักคือจำนวนเส้น เมื่อเกินประมาณ 20 ริบบิ้น เส้นที่พาดกลางวงจะทับกันจนอ่านไม่ได้ กรณีนั้นต้องเปลี่ยนไปใช้ adjacency matrix ที่ไม่มีปัญหาเส้นทับ

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

รูปทรงของข้อมูลรายการเส้นเชื่อม source–target–value
จำนวนมิติที่เข้ารหัสได้3 มิติ
จำนวนแถวที่เหมาะ5–10 กลุ่ม และไม่เกิน 20 ริบบิ้นขั้นต่ำ 4 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องไม่มีแกนค่า

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
sourceต้นทางโหนดangle4–12 กลุ่มชุดเดียวกับปลายทาง
targetปลายทางโหนดangle4–12 กลุ่มอาจไหลกลับไปยังต้นทางได้
valueปริมาณตัวเลขต่อเนื่องsizeบวกเท่านั้นความหนาของริบบิ้นแปรตามค่า

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

  1. รวมปริมาณของคู่เดียวกันให้เป็นแถวเดียว
  2. ตัดสินใจว่าจะรวมสองทิศทางเป็นเส้นเดียวหรือแยก
  3. รวมกลุ่มเล็กเป็น "อื่น ๆ"

ค่าที่หายไป — คู่ที่ไม่มีการไหลไม่ต้องวาดริบบิ้น แต่ต้องแยกให้ชัดจากคู่ที่ไม่มีข้อมูล ซึ่งควรระบุในคำอธิบาย

สเกลของแกน — ความหนาแปรตรงกับปริมาณ และความยาวส่วนโค้งแปรตามปริมาณรวมของกลุ่ม

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

เกิน 20 ริบบิ้น เส้นที่พาดกลางวงทับกันจนอ่านไม่ได้ — ใช้ adjacency-matrix

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

source,target,value
เข้าชมเว็บ,ดูสินค้า,7975
เข้าชมเว็บ,ออกทันที,4078

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

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

  • กลุ่มที่มีปริมาณไหลผ่านมากที่สุดจากความยาวส่วนโค้ง
  • คู่ที่มีการไหลมากที่สุดจากความหนาของริบบิ้น
  • กลุ่มที่เชื่อมกับทุกกลุ่มกับกลุ่มที่เชื่อมกับไม่กี่กลุ่ม

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

  • อ่านค่าที่แม่นยำจากความหนาไม่ได้
  • เมื่อริบบิ้นเยอะจะทับกันจนตามเส้นเดียวไม่ได้
  • ทิศทางไม่ชัดถ้าไม่ใช้สีหรือความหนาที่ต่างกันสองปลาย

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

  1. ดูความยาวส่วนโค้งของแต่ละกลุ่มก่อน
  2. หาริบบิ้นที่หนาที่สุด
  3. ตามริบบิ้นจากปลายหนึ่งไปอีกปลาย

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

  • คู่ไหนมีการไหลมากที่สุด
  • กลุ่มไหนเป็นศูนย์กลาง
  • การไหลสองทางระหว่างคู่นี้สมดุลไหม

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

  • ริบบิ้นเกิน 20 เส้นจนทับกัน
  • ไม่บอกทิศทางของการไหล
  • ไม่มีตัวเลขกำกับเลย

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

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

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

  1. ระบายสีริบบิ้นตามต้นทางเพื่อบอกทิศทาง
  2. ติดชื่อกลุ่มไว้นอกวงพร้อมปริมาณรวม
  3. เน้นริบบิ้นที่เป็นประเด็นและทำเส้นอื่นจาง

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

การไหลระหว่าง <กลุ่ม> และ <กลุ่ม> มากที่สุดที่ <ปริมาณ>

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

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

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

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

df = pd.read_csv("chord-diagram-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "arc"   # ← ค่าจาก Playground

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

# matplotlib ไม่มี chord ในตัว — แสดงเป็นเมทริกซ์การไหลแทน (อ่านแม่นกว่าเมื่อเส้นเยอะ)
nodes = sorted(set(df["source"]) | set(df["target"]))
m = np.zeros((len(nodes), len(nodes)))
for _, r in df.iterrows():
    m[nodes.index(r["source"]), nodes.index(r["target"])] = r["value"]
im = ax.imshow(m, cmap="Blues", aspect="auto")
ax.set_xticks(range(len(nodes))); ax.set_xticklabels(nodes, rotation=40, ha="right", fontsize=8)
ax.set_yticks(range(len(nodes))); ax.set_yticklabels(nodes, fontsize=8)
ax.set_ylabel("ต้นทาง"); ax.set_xlabel("ปลายทาง")
fig.colorbar(im, ax=ax, label="ปริมาณ", shrink=0.7)

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

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

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

ข้อมูลตัวอย่าง · 8 แถว · seed 239● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ส่วนโค้งยาวคือกลุ่มที่มีปริมาณไหลผ่านมาก
เข้าชมเว็บเข้าชมเว็บ · 12,053ดูสินค้าดูสินค้า · 16,170ออกทันทีออกทันที · 4,078ใส่ตะกร้าใส่ตะกร้า · 6,201ออกกลางทางออกกลางทาง · 5,112กรอกที่อยูกรอกที่อยู่ · 3,827ทิ้งตะกร้าทิ้งตะกร้า · 1,166ชำระเงินสำชำระเงินสำเร็จ · 1,418เข้าชมเว็บ → ดูสินค้า · 7,975เข้าชมเว็บ → ออกทันที · 4,078ดูสินค้า → ใส่ตะกร้า · 3,083ดูสินค้า → ออกกลางทาง · 5,112ใส่ตะกร้า → กรอกที่อยู่ · 1,952ใส่ตะกร้า → ทิ้งตะกร้า · 1,166กรอกที่อยู่ → ชำระเงินสำเร็จ · 1,418

เส้นที่พาดผ่านกลางวงทับกันมาก — ถ้าเส้นเกิน 20 เส้นให้ใช้ adjacency matrix แทน

จำนวนกลุ่ม8
กลุ่มที่ไหลผ่านมากสุดดูสินค้า
จำนวนเส้นเชื่อม8
ดูข้อมูลเป็นตาราง (8 แถว)
chord diagram 8 กลุ่ม
จากไปปริมาณ
เข้าชมเว็บดูสินค้า7,975
เข้าชมเว็บออกทันที4,078
ดูสินค้าใส่ตะกร้า3,083
ดูสินค้าออกกลางทาง5,112
ใส่ตะกร้ากรอกที่อยู่1,952
ใส่ตะกร้าทิ้งตะกร้า1,166
กรอกที่อยู่ชำระเงินสำเร็จ1,418
กรอกที่อยู่ชำระไม่สำเร็จ457

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

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

ข้อควรระวัง

  1. ใส่ริบบิ้นเกิน 20 เส้นจนทับกันจนอ่านไม่ได้
  2. ไม่บอกทิศทางของการไหล ทำให้ไม่รู้ว่าใครส่งให้ใคร
  3. ใช้กับข้อมูลที่ไหลทางเดียว ซึ่ง sankey อ่านง่ายกว่ามาก
  4. ไม่ใส่ตัวเลขกำกับ ทำให้ต้องเดาจากความหนาที่อ่านได้หยาบ

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

  • การไหลเป็นทางเดียวและมีขั้นชัดเจนใช้แทน: sankey-diagram
  • มีเส้นเชื่อมเกิน 20 เส้นใช้แทน: adjacency-matrix
  • ต้องอ่านค่าให้แม่นใช้แทน: heatmap-matrix ของการไหล

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

เทคนิคถัดไป · แผนภาพส่วนโค้ง