01ภาพรวมของกราฟนี้
Streamgraph คือพื้นที่ซ้อนที่ย้ายเส้นฐานมาไว้กึ่งกลางแล้วให้แถบขยายออกสองทาง ผลคือไม่มีชั้นไหนวางบนเส้นตรงเลย แลกกับภาพรวมที่ลื่นตาและเหมาะกับการเล่าเรื่องมากกว่าการอ่านค่า
เปรียบเทียบให้เห็นภาพ
เหมือนมองสายน้ำจากด้านบนที่มีลำธารหลายสายไหลรวมกัน เราเห็นว่าสายไหนกว้างขึ้นหรือแคบลงตามระยะทาง แต่วัดความกว้างเป็นเมตรไม่ได้
ใช้ที่ไหนบ้าง — ความนิยมของหมวดเพลงหรือหัวข้อข่าวตามเวลา ปริมาณการพูดถึงแบรนด์ หรืองานนำเสนอที่ต้องการภาพสวยและเล่าภาพรวม
สร้างอย่างไร
- ขั้นที่ 1ตรวจว่าค่าบวกกันได้
- ขั้นที่ 2จัดเส้นฐานให้อยู่กึ่งกลาง
- ขั้นที่ 3เรียงชั้นให้หมวดที่นิ่งอยู่กลาง
- ขั้นที่ 4ติดป้ายชื่อในชั้นที่หนาพอ
ตัวอย่างคลาสสิก · The Ebb and Flow of Movies ของ New York Times ปี 2008
ภาพรายได้ของภาพยนตร์กว่า 7,500 เรื่องตลอด 20 ปี ที่แต่ละเรื่องเป็นสายน้ำที่ผุดขึ้นและจางหายไป เป็นงานที่ทำให้ streamgraph เป็นที่รู้จักในวงกว้าง และเป็นตัวอย่างที่ชัดว่ากราฟชนิดนี้เหมาะกับการเล่าเรื่องมากกว่าการอ่านค่า
02อธิบายภาษาคนเข้าใจง่าย ๆ
Streamgraph เกิดจากความไม่พอใจข้อหนึ่งของพื้นที่ซ้อน คือชั้นบนต้องขึ้นลงตามชั้นล่างจนดูกระโดก การย้ายเส้นฐานมาไว้กลางแล้วให้แถบขยายสองทางทำให้ขอบทุกด้านโค้งลื่นขึ้น
ผลที่ได้คือภาพที่อ่านง่ายในแง่ "ภาพรวม" เราเห็นทันทีว่าช่วงไหนที่กระแสรวมกว้างขึ้น และหมวดไหนที่กำลังเบียดหมวดอื่นออกไป
แต่ราคาที่จ่ายหนักกว่าพื้นที่ซ้อนธรรมดา เพราะตอนนี้ไม่มีชั้นไหนเลยที่วางบนเส้นตรง การอ่านค่าของชั้นใดชั้นหนึ่งจึงต้องวัดความหนา ซึ่งตาทำได้แย่มาก
นอกจากนี้แกนตั้งก็เสียความหมายไปด้วย เพราะเส้นฐานเลื่อนไปมา ตัวเลขบนแกนจึงไม่ได้บอกอะไร ส่วนใหญ่จึงซ่อนแกนตั้งไปเลย
สรุปคือใช้เมื่อเป้าหมายคือความรู้สึกและภาพรวม ไม่ใช่การอ่านค่า ถ้าผู้อ่านต้องตอบว่าหมวดนี้มีเท่าไร ต้องเปลี่ยนไปใช้พื้นที่ซ้อนธรรมดาหรือ small multiples
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
date | เวลา | เวลา | x | 20–200 จุด | ยิ่งจุดเยอะขอบยิ่งลื่น |
series | หมวด | หมวดหมู่ | color | 3–8 หมวด | รองรับหมวดได้มากกว่าพื้นที่ซ้อนเพราะไม่ต้องอ่านค่า |
value | ปริมาณ | ตัวเลขต่อเนื่อง | y | บวกเท่านั้น | ต้องบวกกันได้จริง |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ตรวจว่าค่าบวกกันได้
- เรียงชั้นโดยวางหมวดที่นิ่งไว้กลางเพื่อลดการกระเพื่อม
- ทำให้จุดเวลาถี่พอที่ขอบจะลื่น
ค่าที่หายไป — ช่วงที่ขาดข้อมูลของหมวดใดจะทำให้กระแสรวมแคบลงโดยไม่มีสัญญาณเตือน ต้องทำเครื่องหมายช่วงนั้นไว้
สเกลของแกน — linear เท่านั้น และมักซ่อนแกนตั้งเพราะเส้นฐานเลื่อน
กราฟจะเริ่มพังเมื่อไร
ถ้าจุดเวลาน้อยกว่า 20 ขอบจะเหลี่ยมและเสียข้อดีเรื่องความลื่น
หน้าตาไฟล์ที่ต้องเตรียม
date,series,value
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- ช่วงที่กระแสรวมกว้างขึ้นหรือแคบลง
- หมวดที่กำลังเบียดหมวดอื่นออกไป
- จังหวะการเกิดและหายของหมวดใหม่
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ อ่านค่าของหมวดใดหมวดหนึ่งไม่ได้ เพราะไม่มีชั้นไหนวางบนเส้นตรง
- แกนตั้งไม่มีความหมาย เพราะเส้นฐานเลื่อนตามยอดรวม
อ่านตามลำดับนี้
- ดูความกว้างรวมของกระแสก่อน
- ดูว่าแถบสีไหนหนาขึ้นตามเวลา
- อย่าพยายามอ่านค่าจากแกนตั้ง
คำถามที่ตอบได้
- ภาพรวมโตขึ้นไหม
- หมวดไหนกำลังมาแรง
- มีหมวดไหนที่โผล่ขึ้นมาแล้วหายไป
สัญญาณว่ามีอะไรผิด
- มีแกนตั้งพร้อมตัวเลข ซึ่งชวนให้อ่านค่าที่อ่านไม่ได้
- ใช้กับหมวดที่ต้องอ่านค่าจริง
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ติดชื่อหมวดลงในแถบที่หนาพอ
- ทำเครื่องหมายช่วงเวลาที่เป็นเหตุการณ์สำคัญ
- ซ่อนแกนตั้งและเขียนยอดรวมเป็นข้อความแทน
รูปแบบชื่อกราฟที่ควรใช้
<หมวด> ขยายส่วนแบ่งอย่างต่อเนื่องตั้งแต่ <เวลา> จนเบียด <หมวดอื่น>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ streamgraph-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด streamgraph-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("streamgraph-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)
df["date"] = pd.to_datetime(df["date"])
pivot = df.pivot_table(index="date", columns="series", values="value", aggfunc="sum").fillna(0)
ax.stackplot(pivot.index, *[pivot[c] for c in pivot.columns], labels=list(pivot.columns),
baseline="sym", colors=[C1, C2, C3][: len(pivot.columns)]) # sym = จัดกึ่งกลาง
ax.set_yticks([]) # แกนตั้งไม่มีความหมายเมื่อเส้นฐานเลื่อน
ax.legend(frameon=False, ncols=3, loc="upper left")
fig.autofmt_xdate()
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("streamgraph.png", dpi=160)
print("เขียน streamgraph.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (26 แถว)
| วันที่ | หน้าร้าน | เว็บไซต์ | แอป |
|---|---|---|---|
| 1/1/2568 | 70.7 | 53.4 | 31.7 |
| 8/1/2568 | 71.3 | 56.1 | 31.8 |
| 15/1/2568 | 68.6 | 58.6 | 31.6 |
| 22/1/2568 | 69.3 | 57.8 | 35.5 |
| 29/1/2568 | 64.7 | 60.9 | 41.4 |
| 5/2/2568 | 64.9 | 65.0 | 40.1 |
| 12/2/2568 | 62.2 | 67.2 | 40.9 |
| 19/2/2568 | 64.4 | 67.5 | 44.3 |
| 26/2/2568 | 63.0 | 65.4 | 48.8 |
| 5/3/2568 | 62.4 | 65.7 | 52.9 |
| 12/3/2568 | 62.3 | 68.5 | 51.8 |
| 19/3/2568 | 63.3 | 72.2 | 51.1 |
| 26/3/2568 | 63.3 | 72.4 | 50.1 |
| 2/4/2568 | 60.2 | 70.8 | 52.2 |
| 9/4/2568 | 56.1 | 73.0 | 56.5 |
| 16/4/2568 | 59.6 | 77.2 | 61.7 |
| 23/4/2568 | 60.1 | 78.0 | 66.8 |
| 30/4/2568 | 58.7 | 80.2 | 67.6 |
| 7/5/2568 | 59.6 | 81.7 | 70.1 |
| 14/5/2568 | 61.8 | 80.9 | 73.8 |
| 21/5/2568 | 60.8 | 78.4 | 73.7 |
| 28/5/2568 | 60.1 | 80.1 | 75.3 |
| 4/6/2568 | 57.9 | 82.6 | 77.7 |
| 11/6/2568 | 56.0 | 83.7 | 78.3 |
| 18/6/2568 | 57.0 | 86.8 | 79.8 |
| 25/6/2568 | 58.3 | 83.5 | 84.4 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ลองอ่านค่าของหมวดกลางที่จุดเวลาหนึ่งจากภาพ แล้วเปิดตารางเช็ค จะเห็นว่ากราฟนี้ไม่ได้ออกแบบมาให้อ่านค่าเลย
ข้อควรระวัง
- ใส่แกนตั้งพร้อมตัวเลข ทั้งที่เส้นฐานเลื่อนจนตัวเลขไม่มีความหมาย
- ใช้กับข้อมูลที่ผู้อ่านต้องอ่านค่าจริง
- จัดลำดับชั้นโดยไม่คิด ทำให้ขอบกระเพื่อมจนอ่านยากกว่าเดิม
- ใช้กับจุดเวลาน้อย ๆ จนขอบเป็นเหลี่ยมและเสียข้อดีเรื่องความลื่น
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ต้องอ่านค่าของแต่ละหมวด→ใช้แทน: stacked-area หรือ small-multiples
- สนใจสัดส่วนมากกว่าปริมาณ→ใช้แทน: percent-stacked-bar
- มีหมวดน้อยกว่า 3 หมวด→ใช้แทน: multi-line-chart