01ภาพรวมของกราฟนี้
Nested proportional area ซ้อนรูปทรงที่พื้นที่แปรตามค่าไว้ที่ฐานเดียวกัน ทำให้เทียบขนาดที่ต่างกันหลายเท่าได้ในพื้นที่จำกัด แต่เพราะพื้นที่อ่านได้หยาบและวงเล็กถูกวงใหญ่บังบางส่วน จึงเหมาะกับการสื่อสารเชิงความรู้สึกมากกว่าการวิเคราะห์
เปรียบเทียบให้เห็นภาพ
เหมือนวางเหรียญหลายขนาดซ้อนกันเพื่อเทียบว่าเหรียญไหนใหญ่กว่ากันเท่าไร
ใช้ที่ไหนบ้าง — อินโฟกราฟิกที่เทียบขนาดที่ต่างกันมาก เช่น งบประมาณของประเทศเทียบกับของเมือง หรือเปรียบเทียบขนาดที่คนนึกภาพไม่ออก
สร้างอย่างไร
- ขั้นที่ 1คำนวณรัศมีจากรากที่สองของค่า
- ขั้นที่ 2วางทุกวงให้ฐานล่างตรงกัน
- ขั้นที่ 3ลากเส้นจากขอบบนของแต่ละวงไปยังป้าย
- ขั้นที่ 4เขียนค่าจริงกำกับทุกวง
ตัวอย่างคลาสสิก · ภาพเทียบขนาดในอินโฟกราฟิกสาธารณะ
เมื่อต้องสื่อสารว่างบประมาณก้อนหนึ่งใหญ่แค่ไหนเทียบกับอีกก้อน การซ้อนวงกลมเป็นวิธีที่ใช้กันแพร่หลายเพราะรับมือกับค่าที่ต่างกันหลายสิบเท่าได้ในพื้นที่จำกัด แต่ข้อวิจารณ์ที่พบเสมอคือผู้อ่านมักประเมินอัตราส่วนของพื้นที่ต่ำกว่าความจริง จึงต้องมีตัวเลขกำกับเสมอ
02อธิบายภาษาคนเข้าใจง่าย ๆ
เมื่อค่าต่างกันหลายเท่า เช่น 500 กับ 5 กราฟแท่งจะมีแท่งหนึ่งยาวและอีกแท่งเป็นขีดบาง ๆ ซึ่งอ่านยากและเสียพื้นที่
การซ้อนวงกลมที่พื้นที่แปรตามค่าช่วยได้ เพราะพื้นที่โตช้ากว่าความยาว ค่าที่ต่างกัน 100 เท่าจะได้วงที่รัศมีต่างกัน 10 เท่า ซึ่งยังใส่ในภาพเดียวได้
กติกาที่ห้ามละเมิดคือรัศมีต้องแปรตามรากที่สองของค่า เหมือนกับกราฟฟอง เพราะสายตาอ่านพื้นที่ไม่ใช่รัศมี
การวางให้ฐานล่างตรงกันช่วยการเทียบมาก เพราะได้จุดอ้างอิงร่วมหนึ่งจุด ทำให้เทียบความสูงได้ด้วย ไม่ใช่เทียบพื้นที่อย่างเดียว
ข้อควรระวังคือวงเล็กจะถูกวงใหญ่บังบางส่วน ทำให้ประเมินขนาดผิด และเพราะพื้นที่อ่านได้หยาบ จึงต้องเขียนค่าจริงกำกับทุกวงเสมอ
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
category | รายการ | หมวดหมู่ | text | 2–6 รายการ | เกิน 6 วงจะซ้อนกันจนแยกไม่ออก |
value | ขนาด | ตัวเลขต่อเนื่อง | area | บวกเท่านั้น | ★ รัศมีต้องแปรตามรากที่สองของค่า |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- เรียงจากใหญ่ไปเล็ก
- คำนวณรัศมีจากรากที่สอง
- ตรวจว่าอัตราส่วนใหญ่สุดต่อเล็กสุดไม่เกินประมาณ 100 เท่า
ค่าที่หายไป — รายการที่ไม่มีค่าต้องแสดงเป็นป้ายพร้อมข้อความ ไม่ใช่วงขนาดศูนย์ที่มองไม่เห็น
สเกลของแกน — พื้นที่แปรตรงกับค่า ซึ่งแปลว่ารัศมีแปรตามรากที่สอง ห้ามใช้สเกลอื่น
กราฟจะเริ่มพังเมื่อไร
เกิน 6 วง หรือเมื่อค่าใกล้เคียงกันจนวงซ้อนทับกันเกือบสนิท
หน้าตาไฟล์ที่ต้องเตรียม
category,value
กรุงเทพฯ,298
เชียงใหม่,251
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- อัตราส่วนคร่าว ๆ ระหว่างรายการที่ต่างกันหลายเท่า
- รายการที่ใหญ่ที่สุด
- ความรู้สึกถึงขนาดที่ตัวเลขอย่างเดียวสื่อไม่ได้
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ อ่านค่าที่แม่นยำไม่ได้ เพราะพื้นที่เป็นช่องทางที่หยาบที่สุดช่องทางหนึ่ง
- วงเล็กที่ถูกบังบางส่วนจะประเมินขนาดผิด
อ่านตามลำดับนี้
- ดูฐานล่างที่ตรงกันเป็นจุดอ้างอิง
- เทียบความสูงของแต่ละวง
- อ่านค่าจริงจากป้ายกำกับ
คำถามที่ตอบได้
- ใหญ่กว่ากันประมาณกี่เท่า
- ขนาดนี้ใหญ่แค่ไหนเมื่อเทียบกับสิ่งที่คุ้นเคย
สัญญาณว่ามีอะไรผิด
- ใช้รัศมีแปรตรงกับค่า ทำให้ขนาดโกหกหลายเท่า
- ไม่เขียนค่าจริงกำกับ
- วงซ้อนกันจนวงเล็กมองไม่เห็น
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เขียนค่าจริงกำกับทุกวง
- ลากเส้นจากขอบบนของวงไปยังป้ายเพื่อไม่ให้ป้ายทับวง
- เทียบกับสิ่งที่คุ้นเคยถ้าทำได้
รูปแบบชื่อกราฟที่ควรใช้
<รายการ> ใหญ่กว่า <รายการ> ประมาณ <เท่า> เท่า
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ nested-area-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด nested-area-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("nested-area-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)
max_v = d["value"].max()
for i, r in enumerate(d.itertuples()):
rad = np.sqrt(r.value / max_v) * 0.5 # ★ sqrt เพราะสายตาอ่านพื้นที่
circle = plt.Circle((0.35, rad), rad, fill=False, edgecolor=[C1, C2, C3, "#eda100", "#e87ba4"][i % 5],
linewidth=2.4)
ax.add_patch(circle)
ax.plot([0.35, 0.72], [rad * 2, rad * 2], color="#c9c6bd", linestyle="--", linewidth=1)
ax.text(0.74, rad * 2, f"{r.category} · {r.value:,.0f}", va="center", fontsize=9)
ax.set_xlim(-0.2, 1.1); ax.set_ylim(0, 1.1); ax.set_aspect("equal"); ax.axis("off")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("nested-area.png", dpi=160)
print("เขียน nested-area.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
รัศมีคำนวณจากรากที่สองของค่าเสมอ ถ้าใช้ค่าตรง ๆ วงจะดูใหญ่เกินจริงหลายเท่า
ดูข้อมูลเป็นตาราง (5 แถว)
| หมวด | ค่า | สัดส่วน |
|---|---|---|
| กรุงเทพฯ | 298 | 21.0% |
| ชลบุรี | 260 | 18.3% |
| ขอนแก่น | 253 | 17.9% |
| เชียงใหม่ | 251 | 17.7% |
| ภูเก็ต | 215 | 15.2% |
ลองแล้วจะเห็นอะไร
- จำนวนวง: เพิ่มจำนวนวงแล้วลองบอกว่าวงที่ 3 กับที่ 4 ต่างกันกี่เท่า จะเห็นว่าทำไม่ได้เลยถ้าไม่อ่านตัวเลข — นี่คือเหตุผลที่ต้องเขียนค่ากำกับเสมอ
ข้อควรระวัง
- ★ ใช้รัศมีแปรตรงกับค่าแทนรากที่สอง ทำให้ขนาดโกหกหลายเท่า
- ไม่เขียนค่าจริงกำกับ ทำให้ผู้อ่านต้องเดาจากพื้นที่ที่อ่านได้หยาบ
- ใส่วงมากเกินไปจนวงเล็กถูกบังจนมองไม่เห็น
- ใช้กับค่าที่ใกล้เคียงกัน ซึ่งวงจะซ้อนทับกันเกือบสนิทและแยกไม่ออก
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ค่าใกล้เคียงกัน→ใช้แทน: bar-chart หรือ dot-plot
- ต้องการอ่านค่าให้แม่น→ใช้แทน: bar-chart
- มีมากกว่า 6 รายการ→ใช้แทน: horizontal-bar บนสเกล log