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

กราฟน้ำแข็งย้อยIcicle Chart

เหมือน sunburst แต่เป็นแท่งตรงที่อ่านแม่นกว่า

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

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

Icicle chart คือ sunburst ที่คลี่ออกเป็นเส้นตรง แต่ละชั้นเป็นแถวของแท่งที่ความกว้างแปรตามสัดส่วน ข้อดีที่ชัดเจนคือความกว้างเทียบกันได้แม่นกว่ามุม และชื่อเขียนในแนวนอนได้เต็ม ซึ่งเป็นสองปัญหาหลักของ sunburst

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

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

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

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

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

ตัวอย่างคลาสสิก · Icicle plot ในการวิเคราะห์ประสิทธิภาพของโปรแกรม

เครื่องมือวิเคราะห์ประสิทธิภาพใช้ icicle chart แสดงเวลาที่ใช้ในแต่ละฟังก์ชัน โดยแถวบนคือฟังก์ชันที่เรียก และแถวล่างคือฟังก์ชันที่ถูกเรียก ความกว้างคือเวลาที่ใช้ ทำให้เห็นทันทีว่าเวลาหมดไปกับสายการเรียกไหน

Wikipedia · Flame graph

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

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

Icicle แก้ทั้งสองข้อด้วยการคลี่วงออกเป็นเส้นตรง แต่ละชั้นกลายเป็นแถวแนวนอน และแต่ละโหนดเป็นแท่งที่ความกว้างแปรตามสัดส่วน

ทันทีที่เปลี่ยนจากมุมเป็นความกว้าง ความแม่นก็ดีขึ้นมาก เพราะการเทียบความยาวบนเส้นฐานเดียวกันเป็นสิ่งที่สายตาทำได้ดีที่สุด

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

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

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

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

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

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

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

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

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

สเกลของแกน — ความกว้างแปรตรงกับค่า และทุกแถวใช้ความกว้างรวมเท่ากันเสมอ

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

เกิน 6 ระดับ แถวจะเตี้ยจนอ่านชื่อไม่ได้

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

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

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

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

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

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

  • ไม่สื่อความเป็น "ทั้งหมด" ได้ทันทีเหมือนรูปวงกลม
  • แถวล่างที่แท่งแคบยังเขียนชื่อไม่ได้อยู่ดี

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

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

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

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

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

  • แถวเตี้ยจนอ่านชื่อไม่ได้
  • ความกว้างรวมของแต่ละแถวไม่เท่ากัน ซึ่งแปลว่าข้อมูลขาด

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

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

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

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

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

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

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

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

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

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

leaves = df[df["value"] > 0]
groups = leaves.groupby("parent")["value"].sum().sort_values(ascending=False)
total = groups.sum()
ax.barh([2], [total], height=0.7, color="#256abf", edgecolor=SURFACE, linewidth=2)
ax.text(total / 2, 2, f"ทั้งหมด {total:,.0f}", ha="center", va="center", color="white", fontsize=10)
left = 0
for i, (g, v) in enumerate(groups.items()):
    ax.barh([1], [v], left=left, height=0.7, color=[C1, C2, C3, "#eda100"][i % 4],
            edgecolor=SURFACE, linewidth=2)
    if v / total > 0.12: ax.text(left + v / 2, 1, g, ha="center", va="center", color="white", fontsize=9)
    sub_left = left
    for _, r in leaves[leaves["parent"] == g].iterrows():
        ax.barh([0], [r["value"]], left=sub_left, height=0.7, alpha=0.6,
                color=[C1, C2, C3, "#eda100"][i % 4], edgecolor=SURFACE, linewidth=2)
        sub_left += r["value"]
    left += v
ax.set_yticks([0, 1, 2]); ax.set_yticklabels(["รายการย่อย", "กลุ่ม", "ทั้งหมด"]); ax.set_xticks([])

ax.spines[["top", "right"]].set_visible(False)   # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("icicle-chart.png", dpi=160)
print("เขียน icicle-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
ระดับชั้น3 ชั้น
กลุ่มใหญ่สุดอาหาร
จำนวนรายการ7
ดูข้อมูลเป็นตาราง (7 แถว)
icicle chart 7 รายการ
กลุ่มรายการค่า
สินค้าอุปโภคของใช้ในบ้าน91.0
สินค้าอุปโภคของใช้ส่วนตัว107
อาหารเครื่องดื่ม87.0
อาหารขนม117
อาหารอาหารแช่แข็ง41.0
บริการซ่อมบำรุง102
บริการจัดส่ง87.0

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

  • สังเกตอะไร: เปิดหน้า sunburst-chart ที่ใช้ข้อมูลชุดเดียวกัน แล้วลองจัดอันดับสาขาจากทั้งสองภาพ จะเห็นว่าแท่งตรงทำได้ง่ายกว่าชัดเจน

ข้อควรระวัง

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

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

  • ต้องการสื่อความเป็น "ทั้งหมด" อย่างชัดเจนใช้แทน: sunburst-chart หรือ pie-chart
  • มีระดับเดียวใช้แทน: horizontal-bar
  • สนใจโครงสร้างการเชื่อมต่อมากกว่าขนาดใช้แทน: node-link-tree

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

เทคนิคถัดไป · กราฟโมเสก