01ภาพรวมของกราฟนี้
Donut chart คือกราฟวงกลมที่เจาะรูตรงกลาง สิ่งที่ได้คือที่ว่างสำหรับใส่ยอดรวม ซึ่งเป็นตัวเลขที่กราฟวงกลมซ่อนไว้เสมอ สิ่งที่เสียคือความแม่นในการอ่านมุม เพราะไม่มีจุดยอดของชิ้นให้สายตาใช้เป็นจุดอ้างอิงอีกต่อไป
เปรียบเทียบให้เห็นภาพ
เหมือนเปลี่ยนจากพิซซาเป็นโดนัทที่หั่นเป็นชิ้น เรายังเห็นว่าใครได้ส่วนไหน แต่ตรงกลางมีที่ว่างให้เขียนว่าโดนัททั้งอันหนักกี่กรัม
ใช้ที่ไหนบ้าง — การ์ด KPI ที่ต้องการทั้งยอดรวมและองค์ประกอบ dashboard ที่พื้นที่จำกัด หรือสไลด์ที่อยากให้ยอดรวมเป็นตัวเลขนำ
สร้างอย่างไร
- ขั้นที่ 1คำนวณสัดส่วนเหมือนกราฟวงกลม
- ขั้นที่ 2เจาะรูกลางประมาณ 50-60% ของรัศมี
- ขั้นที่ 3ใส่ยอดรวมหรือตัวเลขนำไว้กลางรู
- ขั้นที่ 4ติดป้ายเปอร์เซ็นต์ที่ทุกชิ้น
ตัวอย่างคลาสสิก · โดนัทบนการ์ด KPI ของ dashboard สมัยใหม่
รูปแบบที่พบทั่วไปใน dashboard คือโดนัทที่มีตัวเลขนำอยู่ตรงกลางและองค์ประกอบอยู่รอบวง ซึ่งเป็นการใช้จุดแข็งของโดนัทอย่างตรงจุด คือให้ทั้งคำตอบหลักและบริบทในพื้นที่ของการ์ดใบเดียว
02อธิบายภาษาคนเข้าใจง่าย ๆ
ข้อเสียหนึ่งของกราฟวงกลมที่คนมักไม่พูดถึงคือมันซ่อนยอดรวมไว้ ผู้อ่านเห็นว่าส่วนหนึ่งคิดเป็น 40% แต่ไม่รู้เลยว่า 40% ของเท่าไร
โดนัทแก้ข้อนี้ด้วยการเจาะรูตรงกลางแล้วเอาพื้นที่นั้นมาใส่ยอดรวม ผลคือผู้อ่านได้ทั้งตัวเลขนำและองค์ประกอบในภาพเดียว ซึ่งเป็นสิ่งที่การ์ด KPI ต้องการพอดี
ราคาที่จ่ายคือความแม่น เวลาอ่านกราฟวงกลม สายตาใช้จุดยอดของชิ้นที่มาบรรจบกลางวงเป็นจุดอ้างอิงในการประเมินมุม พอเจาะรูออก จุดนั้นหายไป เหลือแต่ความยาวของส่วนโค้งให้เทียบ
ในทางปฏิบัติความต่างนี้ไม่มาก เพราะกราฟวงกลมเองก็อ่านมุมได้แย่อยู่แล้ว การเลือกระหว่างสองอย่างจึงมักตัดสินที่ว่าต้องการที่ว่างตรงกลางหรือไม่
กติกาอื่นเหมือนกราฟวงกลมทุกประการ คือไม่เกิน 5 ชิ้น ต้องรวมกันเป็นทั้งหมดจริง และต้องติดป้ายเปอร์เซ็นต์เพราะอ่านจากมุมไม่แม่น
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
category | ส่วนย่อย | หมวดหมู่ | color | 2–5 ส่วน | ข้อจำกัดเดียวกับกราฟวงกลม |
value | ปริมาณ | ตัวเลขต่อเนื่อง | angle | บวกเท่านั้น | ต้องรวมกันเป็นทั้งหมดจริง |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ตรวจว่าผลรวมเป็นทั้งหมดจริง
- รวมส่วนเล็กเป็น "อื่น ๆ"
- เตรียมยอดรวมหรือตัวเลขนำที่จะใส่ตรงกลาง
ค่าที่หายไป — เหมือนกราฟวงกลม คือต้องใส่ชิ้น "ไม่ทราบ" ไว้ให้เห็น ห้ามตัดออกแล้วปรับสัดส่วนที่เหลือ
สเกลของแกน — มุมแปรตรงกับสัดส่วน และขนาดรูไม่ควรเกิน 60% ของรัศมี
กราฟจะเริ่มพังเมื่อไร
เกิน 5 ชิ้นเหมือนกราฟวงกลม และถ้ารูใหญ่เกิน 70% ของรัศมี ส่วนโค้งจะบางจนอ่านไม่ได้
หน้าตาไฟล์ที่ต้องเตรียม
category,value
กรุงเทพฯ,366
เชียงใหม่,319
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- ยอดรวมจากตัวเลขตรงกลาง ซึ่งเป็นสิ่งที่กราฟวงกลมซ่อนไว้
- ส่วนที่ใหญ่ที่สุด
- สัดส่วนคร่าว ๆ ของแต่ละส่วน
สิ่งที่กราฟนี้ตอบไม่ได้
- เทียบชิ้นที่ขนาดใกล้กันไม่ได้ และแม่นน้อยกว่ากราฟวงกลมเล็กน้อยเพราะไม่มีจุดยอดให้อ้างอิง
- เทียบข้ามโดนัทสองอันไม่ได้ถ้ายอดรวมต่างกัน
อ่านตามลำดับนี้
- อ่านยอดรวมตรงกลางก่อน
- ดูส่วนที่ใหญ่ที่สุด
- อ่านป้ายเปอร์เซ็นต์สำหรับชิ้นที่ใกล้เคียงกัน
คำถามที่ตอบได้
- ยอดรวมเท่าไร และแบ่งเป็นส่วนไหนบ้าง
- ส่วนไหนใหญ่ที่สุด
สัญญาณว่ามีอะไรผิด
- รูใหญ่เกินไปจนส่วนโค้งบางมาก
- ไม่ใส่อะไรตรงกลาง ซึ่งเสียประโยชน์เดียวที่โดนัทมีเหนือกราฟวงกลม
- มีเกิน 5 ชิ้น
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ใส่ยอดรวมเป็นตัวเลขใหญ่ตรงกลางเสมอ นี่คือเหตุผลเดียวที่ใช้โดนัทแทนพาย
- ติดป้ายชื่อและเปอร์เซ็นต์ที่ทุกชิ้น
- เริ่มชิ้นใหญ่สุดที่ 12 นาฬิกา
รูปแบบชื่อกราฟที่ควรใช้
ยอดรวม <ค่า> โดย <ส่วน> คิดเป็น <เปอร์เซ็นต์>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ donut-chart-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด donut-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("donut-chart-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
SLICES = 5 # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
d = df.sort_values("value", ascending=False).head(SLICES)
total = d["value"].sum()
ax.pie(d["value"], labels=d["category"], autopct="%1.1f%%", startangle=90, counterclock=False,
colors=[C1, C2, C3, "#eda100", "#e87ba4"],
wedgeprops=dict(width=0.42, edgecolor=SURFACE, linewidth=2)) # width < 1 = เจาะรู
ax.text(0, 0.08, "ยอดรวม", ha="center", fontsize=11, color="#52514e")
ax.text(0, -0.12, f"{total:,.0f}", ha="center", fontsize=22) # ที่ว่างกลางคือเหตุผลที่ใช้โดนัท
ax.set_aspect("equal")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("donut-chart.png", dpi=160)
print("เขียน donut-chart.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
เกิน 5 ส่วนแล้ว มุมที่ใกล้กันแยกด้วยตาไม่ออก — ใช้กราฟแท่งแทนจะอ่านง่ายกว่า
ดูข้อมูลเป็นตาราง (6 แถว)
| ส่วน | ค่า | สัดส่วน |
|---|---|---|
| กรุงเทพฯ | 366 | 16.8% |
| ชลบุรี | 328 | 15.0% |
| ขอนแก่น | 321 | 14.7% |
| เชียงใหม่ | 319 | 14.6% |
| ภูเก็ต | 283 | 13.0% |
| อื่น ๆ (3 หมวด) | 566 | 25.9% |
ลองแล้วจะเห็นอะไร
- จำนวนชิ้นก่อนรวมเป็น "อื่น ๆ": สังเกตว่าไม่ว่าจำนวนชิ้นเปลี่ยนอย่างไร ยอดรวมตรงกลางไม่เปลี่ยน — นั่นคือข้อมูลที่กราฟวงกลมไม่เคยแสดง
ข้อควรระวัง
- ไม่ใส่อะไรตรงกลาง ซึ่งเสียประโยชน์เดียวที่โดนัทมีเหนือกราฟวงกลม
- เจาะรูใหญ่เกินไปจนส่วนโค้งบางและอ่านสัดส่วนยากมาก
- ใส่เกิน 5 ชิ้นเหมือนกราฟวงกลม
- ใช้เทียบสองโดนัทที่ยอดรวมต่างกัน
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ไม่มีตัวเลขที่จะใส่ตรงกลาง→ใช้แทน: pie-chart หรือดีกว่านั้นคือ horizontal-bar
- มีมากกว่า 5 ส่วน→ใช้แทน: horizontal-bar
- ต้องการเทียบสัดส่วนข้ามกลุ่ม→ใช้แทน: percent-stacked-bar