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

กราฟรัศมีซ้อนชั้นSunburst Chart

ลำดับชั้นหลายระดับที่อ่านจากในออกนอก

4
ขั้นสูงควรรู้ก่อน · เข้าใจลำดับชั้นและรู้ว่าการอ่านมุมแม่นน้อยกว่าความยาว
ลองเล่น

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

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

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

เหมือนวงปีของต้นไม้ที่แต่ละวงบอกช่วงเวลาหนึ่ง เพียงแต่ที่นี่แต่ละวงบอกระดับหนึ่งของโครงสร้าง

ใช้ที่ไหนบ้าง — โครงสร้างองค์กร เส้นทางการคลิกในเว็บไซต์ หมวดหมู่สินค้าหลายระดับ หรือโครงสร้างงบประมาณที่ลึกหลายชั้น

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

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

ตัวอย่างคลาสสิก · Sunburst ในเครื่องมือวิเคราะห์เส้นทางผู้ใช้เว็บไซต์

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

Wikipedia · Sunburst chart

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

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

Sunburst แก้ด้วยการใช้รัศมีแทนความลึก วงในสุดคือราก วงถัดออกมาคือลูก วงถัดไปคือหลาน ผู้อ่านจึงนับจำนวนวงแล้วรู้ทันทีว่าโครงสร้างลึกกี่ชั้น

การอ่านก็เป็นธรรมชาติ ลากสายตาจากในออกนอกคือการเดินลงลำดับชั้น และมุมที่ครองอยู่คือสัดส่วนของสาขานั้น

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

ผลคือรายการย่อยในชั้นลึกดูสำคัญกว่าความจริง ซึ่งเป็นการบิดที่แก้ไม่ได้ในเชิงโครงสร้าง ถ้าต้องการความแม่นให้ใช้ icicle chart ที่เป็นแท่งตรงแทน

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

รูปทรงของข้อมูลลำดับชั้น parent–child
จำนวนมิติที่เข้ารหัสได้3 มิติ
จำนวนแถวที่เหมาะ2–4 ระดับ × 10–60 โหนดขั้นต่ำ 6 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องค่าเข้ารหัสด้วยมุม

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
idชื่อโหนดโหนดangle10–100 โหนดต้องไม่ซ้ำกัน
parentโหนดแม่โหนดrowอ้างถึง id ที่มีจริงรากใช้ค่าว่าง
valueขนาดตัวเลขต่อเนื่องareaบวกเท่านั้นใส่ค่าเฉพาะที่ใบ

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

  1. ตรวจโครงสร้างว่าไม่มีวงจร
  2. ใส่ค่าเฉพาะที่ใบ
  3. จำกัดความลึกไม่เกิน 4 ระดับ

ค่าที่หายไป — โหนดที่ไม่มีค่าจะหายไปพร้อมลูกทั้งหมดของมัน ต้องตรวจผลรวมก่อนวาดเสมอ

สเกลของแกน — มุมแปรตรงกับค่า ส่วนความหนาของวงควรเท่ากันทุกชั้นเพื่อไม่ให้ชั้นใดดูสำคัญกว่าโดยการจัดหน้า

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

เกิน 4 ระดับ วงนอกจะบางจนอ่านไม่ได้ และเกิน 100 โหนดมุมจะแคบเกินกด

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

id,parent,value
บริษัท,,0
สินค้าอุปโภค,บริษัท,0

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

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

  • ความลึกของโครงสร้างจากจำนวนวง
  • สาขาที่กินสัดส่วนมากที่สุดจากมุมที่ครอง
  • สาขาที่แตกย่อยมากกับสาขาที่มีลูกน้อย

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

  • ★ เทียบขนาดข้ามชั้นไม่ได้ เพราะวงนอกมีพื้นที่มากกว่าที่มุมเท่ากัน
  • อ่านค่าที่แม่นยำไม่ได้จากมุม
  • ชื่อโหนดในวงนอกมักยาวเกินกว่าจะเขียนได้

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

  1. เริ่มที่วงในสุดแล้วลากสายตาออกนอก
  2. ดูมุมที่แต่ละสาขาครองเพื่ออ่านสัดส่วน
  3. นับจำนวนวงเพื่อรู้ความลึก

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

  • โครงสร้างลึกกี่ชั้น
  • สาขาไหนใหญ่ที่สุด
  • ภายในสาขานี้แบ่งย่อยอย่างไร

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

  • วงนอกบางมากจนอ่านไม่ได้
  • ความหนาของวงไม่เท่ากันโดยไม่มีเหตุผล
  • มีเกิน 4 ระดับ

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

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

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

  1. ใช้สีเดียวกันตลอดสายเพื่อให้ตามสาขาได้
  2. ติดป้ายเฉพาะวงในที่มีที่พอ และใช้ tooltip สำหรับวงนอก
  3. ใส่ยอดรวมไว้กลางวง

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

<สาขา> ครอง <เปอร์เซ็นต์> ของทั้งหมด โดยแตกย่อยเป็น <จำนวน> รายการ

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

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

# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด sunburst-chart-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("sunburst-chart-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "rings"   # ← ค่าจาก Playground

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

# matplotlib ไม่มี sunburst ในตัว — วาดด้วย wedge สองชั้น
leaves = df[df["value"] > 0]
groups = leaves.groupby("parent")["value"].sum()
total = groups.sum()
ax.pie(groups.values, radius=1.0, labels=groups.index, labeldistance=0.75,
       colors=[C1, C2, C3, "#eda100"][: len(groups)],
       wedgeprops=dict(width=0.34, edgecolor=SURFACE, linewidth=2))
inner_colors = [[C1, C2, C3, "#eda100"][list(groups.index).index(p) % 4] for p in leaves["parent"]]
ax.pie(leaves["value"], radius=1.36, colors=inner_colors,     # วงนอก = ระดับลึกกว่า
       wedgeprops=dict(width=0.34, edgecolor=SURFACE, linewidth=2, alpha=0.65))
ax.text(0, 0, f"{total:,.0f}", ha="center", va="center", fontsize=15)
ax.set_aspect("equal")

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

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

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

ข้อมูลตัวอย่าง · 11 แถว · seed 211● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
วงในคือกลุ่ม วงนอกคือรายการย่อย
สินค้าอุปโภคอาหารบริการ
ทั้งหมด632สินค้าอุปโภค · 198ของใช้ในบ้าน · 91.0ของใช้ส่วนตัว · 107อาหาร · 245เครื่องดื่ม · 87.0ขนม · 117อาหารแช่แข็ง · 41.0บริการ · 189ซ่อมบำรุง · 102จัดส่ง · 87.0

วงนอกมีพื้นที่มากกว่าวงในที่มุมเท่ากัน จึงดูสำคัญกว่าความจริง

จำนวนชั้น2 ชั้นรอบแกน
กลุ่มใหญ่สุดอาหาร
จำนวนรายการ7
ดูข้อมูลเป็นตาราง (7 แถว)
sunburst 7 รายการ
กลุ่มรายการค่าสัดส่วน
สินค้าอุปโภคของใช้ในบ้าน91.014.4%
สินค้าอุปโภคของใช้ส่วนตัว10716.9%
อาหารเครื่องดื่ม87.013.8%
อาหารขนม11718.5%
อาหารอาหารแช่แข็ง41.06.5%
บริการซ่อมบำรุง10216.1%
บริการจัดส่ง87.013.8%

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

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

ข้อควรระวัง

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

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

  • ต้องการเทียบขนาดให้แม่นใช้แทน: icicle-chart ที่เป็นแท่งตรง หรือ treemap
  • ชื่อโหนดยาวใช้แทน: icicle-chart ที่เขียนชื่อในแนวนอนได้
  • มีระดับเดียวใช้แทน: pie-chart หรือ horizontal-bar

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

เทคนิคถัดไป · กราฟน้ำแข็งย้อย