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

กราฟแท่งแนวนอนHorizontal Bar Chart

เหมือนแท่งตั้ง แต่ชื่อยาวแค่ไหนก็อ่านได้

1
พื้นฐานควรรู้ก่อน · อ่านกราฟแท่งเป็น
ลองเล่น

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

Horizontal bar chart คือกราฟแท่งที่สลับแกน ให้หมวดอยู่แกนตั้งและค่าอยู่แกนนอน การพลิกนี้แก้ปัญหาใหญ่ที่สุดของแท่งตั้งคือป้ายชื่อยาวที่ต้องเอียงจนอ่านลำบาก และยังเพิ่มจำนวนรายการได้มากโดยแค่เลื่อนหน้าลง

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

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

ใช้ที่ไหนบ้าง — จัดอันดับจังหวัด สินค้า สาเหตุของปัญหา หรือผลสำรวจที่ตัวเลือกเป็นประโยคยาว

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

  1. ขั้นที่ 1เรียงจากค่ามากไปน้อย
  2. ขั้นที่ 2วางชื่อหมวดชิดขวาที่แกนตั้ง
  3. ขั้นที่ 3วาดแท่งจากศูนย์ไปทางขวา
  4. ขั้นที่ 4ติดค่าไว้ปลายแท่ง

ตัวอย่างคลาสสิก · กราฟอันดับสาเหตุการเสียชีวิต ที่ชื่อสาเหตุยาวเกินกว่าจะเขียนใต้แท่งตั้ง

ข้อมูลสาธารณสุขมีชื่อสาเหตุอย่าง "โรคหลอดเลือดสมอง" หรือ "การบาดเจ็บจากอุบัติเหตุทางถนน" ซึ่งยาวเกินกว่าจะวางใต้แท่งตั้งได้ งานกราฟิกของ Our World in Data จึงใช้แท่งแนวนอนกับข้อมูลกลุ่มนี้แทบทุกครั้ง

Our World in Data · Causes of death

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

ปัญหาที่เจอบ่อยกับกราฟแท่งตั้งคือชื่อหมวดยาวเกินความกว้างของแท่ง พอชื่อชนกันก็ต้องเอียงป้าย 45 องศา ซึ่งทำให้คนอ่านต้องเอียงคอตามและอ่านช้าลงอย่างมาก

ทางแก้ง่ายที่สุดคือพลิกกราฟ 90 องศา ให้ชื่ออยู่ทางซ้ายในแนวนอนเหมือนอ่านรายการปกติ ส่วนแท่งยื่นไปทางขวา วิธีนี้ไม่เปลี่ยนความหมายของข้อมูลเลยแม้แต่น้อย แต่เปลี่ยนความเร็วในการอ่านอย่างมาก

ข้อดีอีกอย่างคือจำนวนรายการ แท่งตั้งเริ่มอึดอัดที่ประมาณ 8-10 หมวดเพราะความกว้างจอมีจำกัด แต่แท่งนอนเพิ่มได้ถึง 20-30 รายการโดยแค่ให้หน้าเลื่อนลง ซึ่งเป็นสิ่งที่ผู้อ่านคุ้นเคยอยู่แล้ว

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

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

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

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

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

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

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

  1. เรียงจากมากไปน้อย
  2. ตัดสินใจว่าจะแสดง top N เท่าไร และบอกใน caption
  3. รวมรายการเล็กเป็น "อื่น ๆ" ถ้าตัดออก

ค่าที่หายไป — รายการที่ไม่มีข้อมูลให้แสดงเป็นแถวว่างพร้อมคำว่า "ไม่มีข้อมูล" ห้ามตัดออกเงียบ ๆ เพราะผู้อ่านจะไม่รู้ว่ามันหายไป

สเกลของแกน — แกนค่าใช้ linear เสมอ ถ้าค่าต่างกันหลายเท่าจนแท่งท้าย ๆ มองไม่เห็น ให้เปลี่ยนไปใช้ dot-plot ที่รองรับสเกล log ได้

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

เกิน 30 รายการ ผู้อ่านต้องเลื่อนหน้าจนเทียบหัวกับท้ายไม่ได้ — ให้ตัดเหลือ top N แล้วรวมที่เหลือเป็น "อื่น ๆ"

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

category,value
กรุงเทพฯ,502
เชียงใหม่,455

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

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

  • อันดับของทุกรายการในภาพเดียว
  • ช่องว่างระหว่างอันดับติดกัน
  • จุดที่ค่าเริ่มลดฮวบ ซึ่งมักเป็นเส้นแบ่งกลุ่มธรรมชาติ
  • สัดส่วนที่อันดับต้น ๆ กินไปจากทั้งหมด

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

  • ไม่บอกว่าอันดับเปลี่ยนไปอย่างไรตามเวลา ต้องใช้ bump-chart หรือ slope-chart
  • ไม่บอกว่าความต่างระหว่างอันดับติดกันมีนัยสำคัญหรือไม่
  • ไม่บอกโครงสร้างภายในของแต่ละรายการ

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

  1. อ่านจากบนลงล่าง เพราะบนสุดคืออันดับหนึ่ง
  2. หาจุดที่ความยาวลดลงฮวบ ๆ
  3. เทียบรายการที่สนใจกับรายการบนสุด
  4. ตรวจว่า caption บอกไหมว่าตัดเหลือ top เท่าไร

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

  • อันดับหนึ่งถึงห้าคือใคร
  • รายการที่เราสนใจอยู่อันดับที่เท่าไร
  • ต้องรวมกี่รายการแรกถึงจะได้ครึ่งหนึ่งของยอดรวม

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

  • ไม่ได้เรียงลำดับทั้งที่เป็นการจัดอันดับ
  • ตัดเหลือ top 5 โดยไม่บอก ทำให้ดูเหมือนมีแค่ 5 รายการ
  • แกนไม่เริ่มที่ศูนย์

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

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

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

  1. เน้นแถวที่เป็นของเราเองด้วยสีต่าง ให้ที่เหลือเป็นเทา
  2. เขียนค่าไว้ปลายแท่งทุกแถวได้ เพราะแนวนอนมีที่ว่างพอ
  3. ถ้าตัดเหลือ 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), "แถว")

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

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

ข้อมูลตัวอย่าง · 12 แถว · seed 42● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ลำดับของแถว
ตัดให้เหลือ top N
กรุงเทพฯชลบุรีขอนแก่นเชียงใหม่ภูเก็ตสงขลานครราชสีมาสุราษฎร์ธานีอุดรธานีพิษณุโลกระยองนครปฐม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

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

  • การเรียงลำดับ: สลับเป็นตามตัวอักษรแล้วลองหาอันดับหนึ่ง จะรู้สึกได้ทันทีว่าช้าลงมาก
  • แสดงกี่รายการ: ลดเหลือ 5 แล้วสังเกตว่ากราฟดูสะอาดขึ้น แต่ผู้อ่านจะไม่รู้เลยว่ายังมีอีก 7 รายการ ถ้าไม่เขียนบอก

ข้อควรระวัง

  1. ไม่เรียงลำดับทั้งที่ใช้จัดอันดับ ทำให้คนอ่านต้องกวาดหาเอง
  2. ตัดเหลือ top N โดยไม่บอกว่าตัดมาจากทั้งหมดเท่าไร
  3. แกนค่าไม่เริ่มที่ศูนย์
  4. ใส่รายการมากเกิน 30 จนต้องเลื่อนยาวและเทียบหัวท้ายไม่ได้
  5. ใช้กับข้อมูลที่หมวดมีลำดับตามธรรมชาติอยู่แล้ว เช่น เดือน แล้วเรียงใหม่ตามค่าจนลำดับเดิมหาย

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

  • มีไม่เกิน 5 หมวดและชื่อสั้นใช้แทน: bar-chart แนวตั้งที่คนคุ้นเคยกว่า
  • ค่าต่างกันหลาย order of magnitudeใช้แทน: dot-plot บนสเกล log
  • ต้องการเทียบสองช่วงเวลาใช้แทน: dumbbell-chart

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

เทคนิคถัดไป · กราฟแท่งกลุ่ม