01ภาพรวมของกราฟนี้
Sankey diagram แสดงการไหลของปริมาณจากโหนดหนึ่งไปอีกโหนด โดยความหนาของเส้นแปรตามปริมาณ จุดแข็งคือทำให้ "การสูญเสียระหว่างทาง" กลายเป็นสิ่งที่เห็นได้ เพราะความกว้างที่หดลงคือปริมาณที่หายไป
เปรียบเทียบให้เห็นภาพ
เหมือนแผนที่แม่น้ำที่สายน้ำใหญ่แตกเป็นสายย่อย บางสายไหลต่อไปทะเล บางสายซึมหายไปกลางทาง ความกว้างของสายบอกปริมาณน้ำ
ใช้ที่ไหนบ้าง — กรวยการขายที่ตามรอยผู้ใช้ทีละขั้น การไหลของพลังงานจากแหล่งถึงการใช้งาน งบประมาณจากแหล่งรายได้ถึงรายจ่าย หรือการย้ายถิ่น
สร้างอย่างไร
- ขั้นที่ 1จัดข้อมูลเป็นรายการเส้นเชื่อม source, target, value
- ขั้นที่ 2ตรวจว่าผลรวมขาเข้าและขาออกของโหนดกลางสมดุล
- ขั้นที่ 3จัดเรียงโหนดให้เส้นตัดกันน้อยที่สุด
- ขั้นที่ 4ติดตัวเลขที่โหนดและเส้นหลัก
ตัวอย่างคลาสสิก · แผนภาพการเดินทัพของนโปเลียนโดย Charles Minard ปี 1869
Minard วาดการเดินทัพไปมอสโกและถอยกลับ โดยความหนาของแถบคือจำนวนทหารที่เหลือ จาก 422,000 คนเหลือ 10,000 คน ความกว้างที่หดลงเรื่อย ๆ บอกเรื่องราวได้ชัดกว่าตัวเลขใด ๆ Edward Tufte เรียกมันว่าอาจเป็นกราฟสถิติที่ดีที่สุดเท่าที่เคยมีมา
02อธิบายภาษาคนเข้าใจง่าย ๆ
คำถามที่กราฟทั่วไปตอบไม่ได้คือ "ของ 100 ชิ้นที่เข้ามา ไปจบที่ไหนบ้าง" เพราะมันต้องตามรอยข้ามหลายขั้นพร้อมกัน
Sankey ตอบด้วยการให้ความหนาของเส้นแทนปริมาณ เส้นใหญ่คือทางที่ของส่วนใหญ่ไหลไป เส้นเล็กคือทางที่มีน้อย และการที่เส้นแตกออกก็คือการแยกทาง
สิ่งที่ทรงพลังที่สุดคือมันทำให้การสูญเสียเห็นได้ ถ้าโหนดหนึ่งรับเข้ามากว้าง 100 แต่ส่งออกรวมกว้างแค่ 60 ช่องว่าง 40 นั้นคือสิ่งที่หายไป ซึ่งเป็นคำถามที่สำคัญที่สุดในงานวิเคราะห์กรวย
ข้อบังคับที่ต้องตรวจก่อนวาดเสมอคือความสมดุล ผลรวมขาเข้าและขาออกของโหนดกลางต้องเท่ากัน ถ้าไม่เท่าแปลว่าข้อมูลขาดหรือนับซ้ำ และต้องเพิ่มโหนด "สูญเสีย" ให้เห็นแทนการปล่อยผ่าน
ข้อจำกัดคือจำนวนเส้น เกินประมาณ 60 เส้นภาพจะพันกันจนตามรอยไม่ได้ ทางแก้คือรวมโหนดเล็กเป็น "อื่น ๆ" ก่อนวาดเสมอ
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
source | ต้นทาง | โหนด | path | 3–20 โหนด | ★ ชื่อโหนดต้องสะกดตรงกันทุกแถว ระบบไม่รวมชื่อที่พิมพ์ต่างกันให้ |
target | ปลายทาง | โหนด | path | 3–20 โหนด | ห้ามสร้างวงจรย้อนกลับ กราฟนี้รองรับเฉพาะการไหลไปข้างหน้า |
value | ปริมาณที่ไหล | ตัวเลขต่อเนื่อง | size | บวกเท่านั้น | ค่าติดลบวาดไม่ได้ ถ้ามีการไหลกลับให้แยกเป็นเส้นของตัวเอง |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ทำให้ชื่อโหนดเป็นมาตรฐานเดียวกัน ตัดช่องว่างและจัดตัวพิมพ์
- ตรวจว่าผลรวมขาเข้าและขาออกของโหนดกลางสมดุลกัน ถ้าไม่สมดุลต้องเพิ่มโหนด "สูญเสีย" ให้เห็น
- รวมโหนดที่ปริมาณน้อยกว่า 2% เป็น "อื่น ๆ" ก่อนวาด
- ตรวจว่าไม่มีวงจร เพราะ layout algorithm จะวนไม่จบ
ค่าที่หายไป — แถวที่ขาด source, target หรือ value ต้องตัดออกและรายงาน เพราะจะทำให้ยอดรวมของโหนดผิดโดยที่ภาพยังดูปกติ
สเกลของแกน — ความหนาของเส้นแปรตรงกับค่า ห้ามใช้ log เพราะจะทำลายคุณสมบัติ "ผลรวมของเส้นย่อยเท่ากับเส้นใหญ่" ซึ่งเป็นเหตุผลเดียวที่ใช้กราฟนี้
กราฟจะเริ่มพังเมื่อไร
เกิน 60 เส้น เส้นจะพันกันจนตามรอยไม่ได้ — เปลี่ยนไป alluvial-diagram ที่จัดเป็นขั้นชัดเจน หรือรวมโหนดเล็กเป็น "อื่น ๆ"
หน้าตาไฟล์ที่ต้องเตรียม
source,target,value
เข้าชมเว็บ,ดูสินค้า,7975
เข้าชมเว็บ,ออกทันที,4078
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- เส้นทางไหนใหญ่ที่สุด ปริมาณส่วนใหญ่ไหลไปทางไหน
- หายที่ขั้นไหนมากที่สุด ความกว้างที่หดลงคือการสูญเสีย
- โหนดไหนเป็นคอขวดที่ทุกอย่างต้องผ่าน
- เส้นทางที่ไม่คาดคิด เช่น การย้อนกลับไปขั้นก่อนหน้า
สิ่งที่กราฟนี้ตอบไม่ได้
- อ่านตัวเลขที่แม่นยำจากความหนาไม่ได้ ต้องติดป้ายกำกับ
- ไม่บอกว่าเวลาผ่านไปเท่าไรระหว่างขั้น
- เทียบสองช่วงเวลาบนภาพเดียวไม่ได้ ต้องวาดสองภาพ
อ่านตามลำดับนี้
- หาเส้นที่หนาที่สุดจากต้นทางก่อน
- ตามเส้นนั้นไปจนสุดปลายทาง
- ดูโหนดที่ความกว้างขาออกน้อยกว่าขาเข้า ซึ่งคือจุดที่สูญเสีย
คำถามที่ตอบได้
- ของที่เข้ามาไปจบที่ไหนบ้าง
- หายมากที่สุดตรงขั้นไหน
- เส้นทางหลักคืออะไร
สัญญาณว่ามีอะไรผิด
- ผลรวมขาเข้าไม่เท่าขาออกที่โหนดกลาง แปลว่าข้อมูลขาดหรือมีการนับซ้ำ
- เส้นเล็กจำนวนมากจนดูเป็นฝอย แปลว่ายังไม่ได้รวมเป็น "อื่น ๆ"
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ติดตัวเลขที่โหนดทุกโหนดและที่เส้นหลัก
- ทำเครื่องหมายจุดที่สูญเสียมากที่สุด
- ใช้สีตามต้นทางเพื่อให้ตามสายได้
รูปแบบชื่อกราฟที่ควรใช้
จาก <ปริมาณ> ที่เข้ามา เหลือ <ปริมาณ> ที่ปลายทาง โดยหายมากที่สุดที่ <ขั้น>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ sankey-diagram-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด sankey-diagram-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("sankey-diagram-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
MINSHARE = 0 # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
# matplotlib ไม่มี sankey ที่ใช้งานง่าย — แสดงเป็นตารางการไหลแทน
pivot = df.pivot_table(index="source", columns="target", values="value", aggfunc="sum").fillna(0)
im = ax.imshow(pivot, cmap="Blues", aspect="auto")
ax.set_xticks(range(len(pivot.columns))); ax.set_xticklabels(pivot.columns, rotation=35, ha="right", fontsize=8)
ax.set_yticks(range(len(pivot.index))); ax.set_yticklabels(pivot.index, fontsize=8)
for i in range(len(pivot.index)):
for j in range(len(pivot.columns)):
if pivot.iloc[i, j] > 0:
ax.text(j, i, f"{pivot.iloc[i, j]:,.0f}", ha="center", va="center", fontsize=7)
fig.colorbar(im, ax=ax, label="ปริมาณที่ไหล", shrink=0.7)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("sankey-diagram.png", dpi=160)
print("เขียน sankey-diagram.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (8 แถว)
| จาก | ไป | ปริมาณ |
|---|---|---|
| เข้าชมเว็บ | ดูสินค้า | 7,975 |
| เข้าชมเว็บ | ออกทันที | 4,078 |
| ดูสินค้า | ใส่ตะกร้า | 3,083 |
| ดูสินค้า | ออกกลางทาง | 5,112 |
| ใส่ตะกร้า | กรอกที่อยู่ | 1,952 |
| ใส่ตะกร้า | ทิ้งตะกร้า | 1,166 |
| กรอกที่อยู่ | ชำระเงินสำเร็จ | 1,418 |
| กรอกที่อยู่ | ชำระไม่สำเร็จ | 457 |
ลองแล้วจะเห็นอะไร
- รวมเส้นที่เล็กกว่า (%): เพิ่มเกณฑ์แล้วสังเกตว่าภาพสะอาดขึ้นมากแต่ข้อมูลบางส่วนหายไป — การรวมเส้นเล็กเป็นการตัดสินใจเชิงบรรณาธิการที่ต้องเขียนบอกเสมอ
ข้อควรระวัง
- ผลรวมขาเข้าไม่เท่าขาออกที่โหนดกลาง โดยไม่เพิ่มโหนด "สูญเสีย" ให้เห็น
- ใส่เส้นมากเกินไปจนพันกันและตามรอยไม่ได้
- ใช้สเกล log กับความหนาของเส้น ซึ่งทำลายคุณสมบัติการบวกที่เป็นเหตุผลเดียวที่ใช้กราฟนี้
- ชื่อโหนดสะกดไม่ตรงกันจนกลายเป็นคนละโหนด
- ใช้กับข้อมูลที่ไม่ใช่การไหลจริง เช่น เอาความสัมพันธ์ทั่วไปมาวาดเป็นการไหล
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีขั้นเดียวและไม่มีการแตกสาย→ใช้แทน: funnel-chart
- ทุกขั้นมีชุดหมวดเดียวกัน→ใช้แทน: alluvial-diagram
- การไหลเป็นสองทางหรือมีวงจร→ใช้แทน: chord-diagram
- สนใจสัดส่วน ณ จุดเวลาเดียว→ใช้แทน: treemap หรือ stacked-bar