01ภาพรวมของกราฟนี้
Horizontal bar chart คือกราฟแท่งที่สลับแกน ให้หมวดอยู่แกนตั้งและค่าอยู่แกนนอน การพลิกนี้แก้ปัญหาใหญ่ที่สุดของแท่งตั้งคือป้ายชื่อยาวที่ต้องเอียงจนอ่านลำบาก และยังเพิ่มจำนวนรายการได้มากโดยแค่เลื่อนหน้าลง
เปรียบเทียบให้เห็นภาพ
เหมือนเปลี่ยนจากการวัดส่วนสูงคนที่ยืนอยู่ มาเป็นให้ทุกคนนอนเรียงกันแล้ววัดความยาว ชื่อของแต่ละคนจึงเขียนไว้ต้นแถวได้เต็ม ๆ
ใช้ที่ไหนบ้าง — จัดอันดับจังหวัด สินค้า สาเหตุของปัญหา หรือผลสำรวจที่ตัวเลือกเป็นประโยคยาว
สร้างอย่างไร
- ขั้นที่ 1เรียงจากค่ามากไปน้อย
- ขั้นที่ 2วางชื่อหมวดชิดขวาที่แกนตั้ง
- ขั้นที่ 3วาดแท่งจากศูนย์ไปทางขวา
- ขั้นที่ 4ติดค่าไว้ปลายแท่ง
ตัวอย่างคลาสสิก · กราฟอันดับสาเหตุการเสียชีวิต ที่ชื่อสาเหตุยาวเกินกว่าจะเขียนใต้แท่งตั้ง
ข้อมูลสาธารณสุขมีชื่อสาเหตุอย่าง "โรคหลอดเลือดสมอง" หรือ "การบาดเจ็บจากอุบัติเหตุทางถนน" ซึ่งยาวเกินกว่าจะวางใต้แท่งตั้งได้ งานกราฟิกของ Our World in Data จึงใช้แท่งแนวนอนกับข้อมูลกลุ่มนี้แทบทุกครั้ง
02อธิบายภาษาคนเข้าใจง่าย ๆ
ปัญหาที่เจอบ่อยกับกราฟแท่งตั้งคือชื่อหมวดยาวเกินความกว้างของแท่ง พอชื่อชนกันก็ต้องเอียงป้าย 45 องศา ซึ่งทำให้คนอ่านต้องเอียงคอตามและอ่านช้าลงอย่างมาก
ทางแก้ง่ายที่สุดคือพลิกกราฟ 90 องศา ให้ชื่ออยู่ทางซ้ายในแนวนอนเหมือนอ่านรายการปกติ ส่วนแท่งยื่นไปทางขวา วิธีนี้ไม่เปลี่ยนความหมายของข้อมูลเลยแม้แต่น้อย แต่เปลี่ยนความเร็วในการอ่านอย่างมาก
ข้อดีอีกอย่างคือจำนวนรายการ แท่งตั้งเริ่มอึดอัดที่ประมาณ 8-10 หมวดเพราะความกว้างจอมีจำกัด แต่แท่งนอนเพิ่มได้ถึง 20-30 รายการโดยแค่ให้หน้าเลื่อนลง ซึ่งเป็นสิ่งที่ผู้อ่านคุ้นเคยอยู่แล้ว
เพราะรองรับรายการเยอะ กราฟแบบนี้จึงกลายเป็นเครื่องมือจัดอันดับโดยธรรมชาติ และเมื่อใช้จัดอันดับ การเรียงจากมากไปน้อยจึงเกือบจะเป็นข้อบังคับ เพราะคนอ่านคาดหวังว่ารายการบนสุดคืออันดับหนึ่ง
สิ่งที่ยังเหมือนเดิมทุกอย่างคือแกนค่าต้องเริ่มที่ศูนย์ การพลิกแกนไม่ได้ยกเว้นกฎข้อนี้ ภาพจำคือ ถ้าชื่อหมวดยาวกว่าประมาณหนึ่งคำ หรือมีเกิน 8 รายการ ให้พลิกเป็นแนวนอนไว้ก่อนเสมอ
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
category | รายการที่จัดอันดับ | หมวดหมู่ | y | 3–30 รายการ | ชื่อยาวได้ เพราะเขียนในแนวนอน |
value | ปริมาณ | ตัวเลขต่อเนื่อง | x | ต่อเนื่อง | ต้องมีศูนย์ที่มีความหมาย |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- เรียงจากมากไปน้อย
- ตัดสินใจว่าจะแสดง top N เท่าไร และบอกใน caption
- รวมรายการเล็กเป็น "อื่น ๆ" ถ้าตัดออก
ค่าที่หายไป — รายการที่ไม่มีข้อมูลให้แสดงเป็นแถวว่างพร้อมคำว่า "ไม่มีข้อมูล" ห้ามตัดออกเงียบ ๆ เพราะผู้อ่านจะไม่รู้ว่ามันหายไป
สเกลของแกน — แกนค่าใช้ linear เสมอ ถ้าค่าต่างกันหลายเท่าจนแท่งท้าย ๆ มองไม่เห็น ให้เปลี่ยนไปใช้ dot-plot ที่รองรับสเกล log ได้
กราฟจะเริ่มพังเมื่อไร
เกิน 30 รายการ ผู้อ่านต้องเลื่อนหน้าจนเทียบหัวกับท้ายไม่ได้ — ให้ตัดเหลือ top N แล้วรวมที่เหลือเป็น "อื่น ๆ"
หน้าตาไฟล์ที่ต้องเตรียม
category,value
กรุงเทพฯ,502
เชียงใหม่,455
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- อันดับของทุกรายการในภาพเดียว
- ช่องว่างระหว่างอันดับติดกัน
- จุดที่ค่าเริ่มลดฮวบ ซึ่งมักเป็นเส้นแบ่งกลุ่มธรรมชาติ
- สัดส่วนที่อันดับต้น ๆ กินไปจากทั้งหมด
สิ่งที่กราฟนี้ตอบไม่ได้
- ไม่บอกว่าอันดับเปลี่ยนไปอย่างไรตามเวลา ต้องใช้ bump-chart หรือ slope-chart
- ไม่บอกว่าความต่างระหว่างอันดับติดกันมีนัยสำคัญหรือไม่
- ไม่บอกโครงสร้างภายในของแต่ละรายการ
อ่านตามลำดับนี้
- อ่านจากบนลงล่าง เพราะบนสุดคืออันดับหนึ่ง
- หาจุดที่ความยาวลดลงฮวบ ๆ
- เทียบรายการที่สนใจกับรายการบนสุด
- ตรวจว่า caption บอกไหมว่าตัดเหลือ top เท่าไร
คำถามที่ตอบได้
- อันดับหนึ่งถึงห้าคือใคร
- รายการที่เราสนใจอยู่อันดับที่เท่าไร
- ต้องรวมกี่รายการแรกถึงจะได้ครึ่งหนึ่งของยอดรวม
สัญญาณว่ามีอะไรผิด
- ไม่ได้เรียงลำดับทั้งที่เป็นการจัดอันดับ
- ตัดเหลือ top 5 โดยไม่บอก ทำให้ดูเหมือนมีแค่ 5 รายการ
- แกนไม่เริ่มที่ศูนย์
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เน้นแถวที่เป็นของเราเองด้วยสีต่าง ให้ที่เหลือเป็นเทา
- เขียนค่าไว้ปลายแท่งทุกแถวได้ เพราะแนวนอนมีที่ว่างพอ
- ถ้าตัดเหลือ top N ให้เขียนไว้ใต้กราฟว่าตัดจากทั้งหมดกี่รายการ
รูปแบบชื่อกราฟที่ควรใช้
<รายการอันดับ 1> นำเป็นอันดับหนึ่งด้วย <ค่า> จาก <จำนวนทั้งหมด> รายการ
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ horizontal-bar-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด horizontal-bar-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("horizontal-bar-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
SORT = "value-desc"
LIMIT = 12 # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
d = df.sort_values("value").tail(LIMIT) # tail เพราะ barh วาดจากล่างขึ้นบน
bars = ax.barh(d["category"], d["value"], color=C1, height=0.7)
bars[-1].set_color("#eb6834")
ax.bar_label(bars, fmt="%.0f", padding=4, fontsize=9)
ax.set_xlim(0, None)
ax.set_xlabel("ยอดขาย (ล้านบาท)")
ax.set_title("อันดับยอดขายรายจังหวัด", loc="left")
ax.grid(axis="x", alpha=0.25); ax.set_axisbelow(True)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("horizontal-bar.png", dpi=160)
print("เขียน horizontal-bar.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (12 แถว)
| หมวด | ค่า |
|---|---|
| กรุงเทพฯ | 502 |
| ชลบุรี | 464 |
| ขอนแก่น | 457 |
| เชียงใหม่ | 455 |
| ภูเก็ต | 419 |
| สงขลา | 363 |
| นครราชสีมา | 344 |
| สุราษฎร์ธานี | 275 |
| อุดรธานี | 267 |
| พิษณุโลก | 216 |
| ระยอง | 183 |
| นครปฐม | 172 |
ลองแล้วจะเห็นอะไร
- การเรียงลำดับ: สลับเป็นตามตัวอักษรแล้วลองหาอันดับหนึ่ง จะรู้สึกได้ทันทีว่าช้าลงมาก
- แสดงกี่รายการ: ลดเหลือ 5 แล้วสังเกตว่ากราฟดูสะอาดขึ้น แต่ผู้อ่านจะไม่รู้เลยว่ายังมีอีก 7 รายการ ถ้าไม่เขียนบอก
ข้อควรระวัง
- ไม่เรียงลำดับทั้งที่ใช้จัดอันดับ ทำให้คนอ่านต้องกวาดหาเอง
- ตัดเหลือ top N โดยไม่บอกว่าตัดมาจากทั้งหมดเท่าไร
- แกนค่าไม่เริ่มที่ศูนย์
- ใส่รายการมากเกิน 30 จนต้องเลื่อนยาวและเทียบหัวท้ายไม่ได้
- ใช้กับข้อมูลที่หมวดมีลำดับตามธรรมชาติอยู่แล้ว เช่น เดือน แล้วเรียงใหม่ตามค่าจนลำดับเดิมหาย
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีไม่เกิน 5 หมวดและชื่อสั้น→ใช้แทน: bar-chart แนวตั้งที่คนคุ้นเคยกว่า
- ค่าต่างกันหลาย order of magnitude→ใช้แทน: dot-plot บนสเกล log
- ต้องการเทียบสองช่วงเวลา→ใช้แทน: dumbbell-chart