01ภาพรวมของกราฟนี้
Dumbbell chart วางค่าของสองช่วงเวลา (หรือสองกลุ่ม) ไว้บนแถวเดียวกันแล้วเชื่อมด้วยเส้น ผลคือคนอ่านได้ข้อมูลสามอย่างในภาพเดียว คือค่าเริ่ม ค่าจบ และความยาวของเส้นซึ่งคือขนาดของการเปลี่ยนแปลง
เปรียบเทียบให้เห็นภาพ
เหมือนบันทึกน้ำหนักก่อนและหลังของแต่ละคนแล้วลากเส้นเชื่อม เราเห็นทั้งว่าใครหนักเท่าไรตอนเริ่ม ใครหนักเท่าไรตอนจบ และใครเปลี่ยนมากที่สุด
ใช้ที่ไหนบ้าง — เทียบยอดขายปีนี้กับปีก่อนรายสาขา เทียบคะแนนก่อนและหลังอบรม หรือเทียบค่าจ้างระหว่างสองกลุ่มในแต่ละอาชีพ
สร้างอย่างไร
- ขั้นที่ 1จัดข้อมูลให้หนึ่งแถวมีทั้งค่าก่อนและค่าหลัง
- ขั้นที่ 2เรียงตามขนาดการเปลี่ยนแปลง
- ขั้นที่ 3วาดจุดสองจุดและเส้นเชื่อม
- ขั้นที่ 4ใช้สีหรือความเข้มบอกว่าจุดไหนคือก่อนหรือหลัง
ตัวอย่างคลาสสิก · ช่องว่างค่าจ้างระหว่างเพศในแต่ละอาชีพ
กราฟดัมเบลกลายเป็นรูปแบบมาตรฐานของการรายงานช่องว่างค่าจ้าง เพราะมันแสดงทั้งระดับค่าจ้างของทั้งสองกลุ่มและขนาดของช่องว่างในภาพเดียว ผู้อ่านเห็นทันทีว่าอาชีพไหนช่องว่างกว้างที่สุด และเห็นด้วยว่าอาชีพนั้นค่าจ้างอยู่ระดับสูงหรือต่ำ
02อธิบายภาษาคนเข้าใจง่าย ๆ
เวลาอยากบอกว่า "ปีนี้ดีขึ้นกว่าปีที่แล้วไหม" แยกตามสาขา คนมักวาดกราฟแท่งกลุ่มที่มีสองแท่งต่อสาขา ซึ่งอ่านค่าได้ แต่ขนาดของการเปลี่ยนแปลงต้องคำนวณในหัวเอง
Dumbbell แก้ด้วยการวางค่าทั้งสองไว้บนเส้นเดียวกันแล้วเชื่อมด้วยเส้นตรง ทีนี้ "ความยาวของเส้น" กลายเป็นตัวแทนของการเปลี่ยนแปลงโดยตรง ยาวแปลว่าเปลี่ยนมาก สั้นแปลว่าเกือบเท่าเดิม
ทิศทางก็อ่านได้ฟรีเช่นกัน ถ้าจุดสีเข้มอยู่ขวาของจุดสีอ่อนแปลว่าเพิ่มขึ้น ถ้าอยู่ซ้ายแปลว่าลดลง คนอ่านจึงได้ข้อมูลสามอย่างโดยแทบไม่ต้องคิด
การเรียงลำดับเป็นเครื่องมือสำคัญ ถ้าเรียงตามขนาดการเปลี่ยนแปลง เราจะเห็นทันทีว่าใครขยับมากที่สุด แต่ถ้าเรียงตามค่าปัจจุบัน เราจะเห็นอันดับล่าสุดแทน สองแบบนี้ตอบคนละคำถาม
ข้อจำกัดคือรองรับได้แค่สองจุดเวลา ถ้ามีสามช่วงขึ้นไปเส้นจะเริ่มสับสน ให้เปลี่ยนไปใช้ slope chart หรือ multi-line chart ภาพจำคือ สองจุดใช้ดัมเบล สามจุดขึ้นไปใช้เส้น
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
category | รายการ | หมวดหมู่ | y | 5–25 รายการ | หนึ่งแถวหนึ่งรายการ |
before | ค่าก่อน | ตัวเลขต่อเนื่อง | x | ต่อเนื่อง | ต้องเป็นหน่วยเดียวกับ after |
after | ค่าหลัง | ตัวเลขต่อเนื่อง | x | ต่อเนื่อง | ถ้าหน่วยต่างกันจะเทียบไม่ได้ ต้องแปลงให้เหมือนกันก่อน |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- จัดข้อมูลเป็นแบบกว้าง ให้ค่าก่อนและหลังอยู่แถวเดียวกัน
- คำนวณส่วนต่างไว้ใช้เรียงลำดับ
- ตัดสินใจว่าจะเรียงตามส่วนต่างหรือตามค่าล่าสุด
ค่าที่หายไป — รายการที่ขาดค่าใดค่าหนึ่งวาดเส้นไม่ได้ ต้องแยกไปแสดงเป็นจุดเดี่ยวพร้อมหมายเหตุ ไม่ใช่ตัดออกเงียบ ๆ
สเกลของแกน — linear และใช้สเกลเดียวกันทั้งสองจุดเสมอ ถ้าค่ากินหลายเท่าให้ใช้ log แต่ต้องรู้ว่าความยาวเส้นจะไม่แปรตามส่วนต่างอีกต่อไป
กราฟจะเริ่มพังเมื่อไร
เกิน 30 รายการ เส้นจะชิดจนอ่านทิศทางไม่ออก
หน้าตาไฟล์ที่ต้องเตรียม
category,before,after
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- รายการที่เปลี่ยนแปลงมากที่สุด จากความยาวของเส้น
- ทิศทางของการเปลี่ยนแปลงรายรายการ
- รายการที่เกือบไม่เปลี่ยนเลย
- การสลับอันดับ — รายการที่แซงกันระหว่างสองช่วง
สิ่งที่กราฟนี้ตอบไม่ได้
- ไม่บอกว่าเกิดอะไรขึ้นระหว่างสองจุดเวลา — อาจขึ้นแล้วลงหรือขึ้นตรง ๆ ก็ได้
- ไม่บอกว่าการเปลี่ยนแปลงมีนัยสำคัญทางสถิติหรือไม่
- ไม่รองรับมากกว่าสองจุดเวลา
อ่านตามลำดับนี้
- ดูความยาวของเส้นเพื่อหาผู้ที่เปลี่ยนมากที่สุด
- ดูทิศทางว่าจุดหลังอยู่ซ้ายหรือขวาของจุดก่อน
- หารายการที่เส้นสั้นมากซึ่งแปลว่าแทบไม่เปลี่ยน
- ตรวจว่ามีรายการที่สลับอันดับกันหรือไม่
คำถามที่ตอบได้
- ใครดีขึ้นมากที่สุด
- มีกี่รายการที่แย่ลง
- ช่องว่างระหว่างสองกลุ่มแคบลงหรือกว้างขึ้น
สัญญาณว่ามีอะไรผิด
- ไม่มี legend บอกว่าจุดสีไหนคือก่อนหรือหลัง
- เส้นทับกันจนแยกไม่ออกว่าเส้นไหนของใคร
- ใช้สองสีที่ดูเท่ากันจนไม่รู้ว่าอันไหนมาก่อน
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ใช้สีอ่อนสำหรับค่าก่อนและสีเข้มสำหรับค่าหลัง เพื่อสื่อลำดับเวลาโดยไม่ต้องอ่าน legend
- ติดตัวเลขส่วนต่างไว้ปลายเส้นของรายการที่เด่นที่สุด
- ลากเส้นแนวตั้งของค่าเฉลี่ยทั้งสองช่วงเพื่อให้เห็นภาพรวม
รูปแบบชื่อกราฟที่ควรใช้
<รายการ> เปลี่ยนมากที่สุดที่ <ส่วนต่าง> ขณะที่ <จำนวน> รายการแทบไม่ขยับ
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ dumbbell-chart-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด dumbbell-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("dumbbell-chart-sample.csv")
df["before"] = pd.to_numeric(df["before"], errors="coerce")
df["after"] = pd.to_numeric(df["after"], errors="coerce")
SORT = "delta" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
df["delta"] = df["after"] - df["before"]
d = df.sort_values("delta")
ax.hlines(d["category"], d["before"], d["after"], color="#9ec5f4", linewidth=3)
ax.plot(d["before"], d["category"], "o", markersize=9, color="#9ec5f4", label="ก่อน")
ax.plot(d["after"], d["category"], "o", markersize=9, color="#1c5cab", label="หลัง")
ax.legend(frameon=False, ncols=2) # ต้องมี legend เพราะสีเป็นตัวบอกลำดับเวลา
ax.set_xlabel("คะแนน")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("dumbbell-chart.png", dpi=160)
print("เขียน dumbbell-chart.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (12 แถว)
| หมวด | ก่อน | หลัง | ส่วนต่าง |
|---|---|---|---|
| ชลบุรี | 47.0 | 63.0 | 16.0 |
| กรุงเทพฯ | 42.0 | 56.0 | 14.0 |
| เชียงใหม่ | 45.0 | 53.0 | 8.00 |
| สงขลา | 59.0 | 66.0 | 7.00 |
| นครปฐม | 74.0 | 81.0 | 7.00 |
| สุราษฎร์ธานี | 68.0 | 73.0 | 5.00 |
| ระยอง | 69.0 | 73.0 | 4.00 |
| นครราชสีมา | 64.0 | 67.0 | 3.00 |
| ขอนแก่น | 48.0 | 49.0 | 1.00 |
| อุดรธานี | 71.0 | 68.0 | -3.00 |
| พิษณุโลก | 67.0 | 64.0 | -3.00 |
| ภูเก็ต | 61.0 | 55.0 | -6.00 |
ลองแล้วจะเห็นอะไร
- เรียงตาม: สลับสองแบบแล้วสังเกตว่าภาพเล่าคนละเรื่อง — เรียงตามส่วนต่างตอบว่า "ใครขยับมากสุด" ส่วนเรียงตามค่าล่าสุดตอบว่า "ตอนนี้ใครนำ"
ข้อควรระวัง
- ไม่บอกว่าจุดสีไหนคือก่อนและสีไหนคือหลัง ทำให้อ่านทิศทางกลับด้าน
- ใช้กับสามจุดเวลาขึ้นไป ซึ่งเส้นจะเริ่มสับสน
- ลืมว่ากราฟไม่บอกเส้นทางระหว่างสองจุด — อาจมีการขึ้นลงที่ซ่อนอยู่
- ใช้สเกลต่างกันระหว่างค่าก่อนกับค่าหลัง ทำให้ความยาวเส้นไม่มีความหมาย
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีมากกว่าสองจุดเวลา→ใช้แทน: slope-chart หรือ multi-line-chart
- สนใจแค่ขนาดการเปลี่ยนแปลง ไม่สนใจค่าเริ่มต้น→ใช้แทน: diverging-bar ของส่วนต่าง
- รายการเกิน 30 รายการ→ใช้แทน: scatter-plot ที่มีแกนก่อนและแกนหลัง