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

กราฟจุดคลีฟแลนด์Cleveland Dot Plot

อ่านความต่างเล็ก ๆ ได้ เพราะตัดแกนได้อย่างถูกต้อง

2
ต่อยอดโดยตรงควรรู้ก่อน · อ่านกราฟแท่งเป็น
ลองเล่น

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

Cleveland dot plot ทิ้งทั้งแท่งและก้าน เหลือเพียงจุดเดียวต่อรายการ เพราะไม่มีองค์ประกอบใดสื่อ "ความยาวจากศูนย์" อีกแล้ว การย่อช่วงแกนจึงทำได้อย่างซื่อสัตย์ นี่ทำให้มันเป็นเครื่องมือเดียวในกลุ่มนี้ที่อ่านความต่างระดับไม่กี่เปอร์เซ็นต์ได้

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

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

ใช้ที่ไหนบ้าง — เทียบอายุขัยเฉลี่ยระหว่างประเทศที่ต่างกันไม่กี่ปี เทียบคะแนนความพึงพอใจที่อยู่ระหว่าง 4.1 ถึง 4.6 หรือเทียบค่าที่ต่างกันน้อยแต่สำคัญ

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

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

ตัวอย่างคลาสสิก · การทดลองของ Cleveland และ McGill ปี 1984

ทั้งสองทดลองกับคนจริงว่าช่องทางการเข้ารหัสภาพแบบไหนอ่านค่าได้แม่นที่สุด ผลคือ "ตำแหน่งบนแกนร่วม" ชนะทุกอย่าง และนำไปสู่การเสนอ dot plot เป็นทางเลือกแทนกราฟแท่งในกรณีที่ค่าต่างกันน้อย ซึ่งเป็นงานที่ยังถูกอ้างอิงจนถึงทุกวันนี้

Cleveland & McGill · Graphical Perception (JASA 1984)

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

ปัญหาที่กราฟแท่งแก้ไม่ได้คือ เมื่อค่าทุกตัวใกล้กันมาก เช่น อายุขัยของประเทศพัฒนาแล้วที่อยู่ระหว่าง 79 ถึง 84 ปี แท่งทุกแท่งจะยาวเกือบเท่ากันจนแยกไม่ออก

เราแก้ด้วยการตัดแกนไม่ได้ เพราะแท่งสื่อความยาว การตัดแกนจะทำให้ภาพโกหกทันที นี่คือทางตันที่ dot plot เกิดขึ้นมาเพื่อแก้

วิธีคือทิ้งทั้งแท่งและก้าน เหลือแค่จุดเดียวที่ตำแหน่งของค่า พอไม่มีอะไรสื่อ "ระยะจากศูนย์" แล้ว การซูมแกนเข้าไปที่ช่วง 78-85 ปีจึงไม่ได้บิดอะไรเลย มันเป็นแค่การเปลี่ยนกำลังขยายของกล้อง

ข้อแลกเปลี่ยนคือคนอ่านต้องดูแกนก่อนเสมอ ซึ่งต่างจากกราฟแท่งที่อ่านความยาวได้เลย ดังนั้นต้องเขียนให้ชัดว่าแกนเริ่มที่เท่าไร และควรใส่ค่าอ้างอิงเช่นค่าเฉลี่ยไว้ในภาพ

William Cleveland ผู้เสนอวิธีนี้ทำการทดลองกับคนจริงและพบว่ามันอ่านได้แม่นกว่ากราฟแท่งในสถานการณ์แบบนี้ ภาพจำคือ ค่าต่างกันมาก ใช้แท่ง ค่าต่างกันน้อย ใช้จุด

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

รูปทรงของข้อมูลตารางแบบยาว (หนึ่งแถวหนึ่งสังเกต)
จำนวนมิติที่เข้ารหัสได้2 มิติ
จำนวนแถวที่เหมาะ8–35 รายการขั้นต่ำ 5 แถว
เส้นฐานศูนย์เลือกได้ไม่มี mark ใดสื่อความยาวจากศูนย์ การย่อช่วงแกนจึงไม่บิดความหมาย แต่ต้องเขียนบอกให้ผู้อ่านรู้ว่าแกนไม่ได้เริ่มที่ศูนย์

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
categoryรายการหมวดหมู่y5–40 รายการรองรับรายการเยอะเพราะแต่ละแถวใช้ที่น้อย
valueค่าตัวเลขต่อเนื่องxต่อเนื่องไม่จำเป็นต้องมีศูนย์ที่มีความหมาย เช่น อุณหภูมิหรือดัชนี

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

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

ค่าที่หายไป — แสดงแถวไว้พร้อมเครื่องหมายว่าไม่มีข้อมูล เพื่อให้ผู้อ่านรู้ว่ารายการนี้มีอยู่

สเกลของแกน — linear หรือ log ก็ได้ เพราะไม่มีองค์ประกอบใดสื่อความยาว แต่ต้องระบุสเกลให้ชัด

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

เกิน 45 รายการ แถวจะชิดจนกดและอ่านลำบาก

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

category,value

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

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

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

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

  • ไม่บอกสัดส่วน — จุดที่อยู่ขวาสุดไม่ได้แปลว่ามีค่าเป็นสองเท่าของจุดซ้ายสุด
  • ไม่บอกว่าความต่างมีนัยสำคัญหรือไม่ ต้องเพิ่ม error bar

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

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

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

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

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

  • ไม่ระบุว่าแกนเริ่มที่เท่าไร
  • ช่วงแกนบีบจนความต่าง 0.1% ดูเหมือนคนละโลก
  • ไม่มีค่าอ้างอิงให้เทียบ

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

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

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

  1. เขียนตัวใหญ่ว่าแกนเริ่มที่เท่าไร
  2. ลากเส้นค่าเฉลี่ยหรือค่ามัธยฐานไว้ให้เทียบ
  3. ระบายสีจุดของรายการที่สนใจ

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

<รายการ> อยู่ที่ <ค่า> สูงกว่าค่ากลางที่ <ค่ากลาง> อยู่ <ส่วนต่าง>

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

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

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

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

d = df.sort_values("value")
ax.hlines(d["category"], d["value"].min() * 0.98, d["value"], color="#e6e4de", linewidth=1)  # เส้นนำสายตา
ax.plot(d["value"], d["category"], "o", markersize=9, color=C1)
ax.axvline(d["value"].mean(), color=INK, linestyle="--", linewidth=1.2)   # ค่าอ้างอิงให้เทียบ
ax.set_xlim(d["value"].min() * 0.95, d["value"].max() * 1.05)   # ตัดแกนได้ เพราะไม่มี mark ใดสื่อความยาว
ax.set_xlabel("ยอดขาย (แกนไม่ได้เริ่มที่ศูนย์)")

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

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

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

ข้อมูลตัวอย่าง · 12 แถว · seed 42● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ลำดับของแถว
กรุงเทพฯชลบุรีขอนแก่นเชียงใหม่ภูเก็ตสงขลานครราชสีมาสุราษฎร์ธานีอุดรธานีพิษณุโลกระยองนครปฐม0.00100200300400500600กรุงเทพฯ · 502ชลบุรี · 464ขอนแก่น · 457เชียงใหม่ · 455ภูเก็ต · 419สงขลา · 363นครราชสีมา · 344สุราษฎร์ธานี · 275อุดรธานี · 267พิษณุโลก · 216ระยอง · 183นครปฐม · 172502
อันดับ 1กรุงเทพฯ
ค่าสูงสุด502
จำนวนหมวด12
ดูข้อมูลเป็นตาราง (12 แถว)
กราฟแนวนอนเรียงอันดับ 12 หมวด อันดับหนึ่งคือ กรุงเทพฯ
หมวดค่า
กรุงเทพฯ502
ชลบุรี464
ขอนแก่น457
เชียงใหม่455
ภูเก็ต419
สงขลา363
นครราชสีมา344
สุราษฎร์ธานี275
อุดรธานี267
พิษณุโลก216
ระยอง183
นครปฐม172

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

  • การเรียงลำดับ: เรียงตามค่าแล้วจะเห็นทันทีว่ารายการแบ่งเป็นกี่กลุ่ม ซึ่งเป็นสิ่งที่กราฟชนิดนี้ทำได้ดีกว่ากราฟแท่ง

ข้อควรระวัง

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

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

  • ค่าต่างกันหลายเท่าและศูนย์มีความหมายใช้แทน: bar-chart หรือ horizontal-bar
  • ผู้ชมดูผ่าน ๆ และไม่มีเวลาตรวจแกนใช้แทน: bar-chart ที่ตีความผิดได้ยากกว่า
  • ต้องเทียบสองจุดเวลาใช้แทน: dumbbell-chart

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

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