01ภาพรวมของกราฟนี้
Data table with visuals ใส่แถบหรือเส้นย่อไว้ในเซลล์ของตาราง ทำให้ได้ทั้งค่าที่แน่นอนซึ่งกราฟให้ไม่ได้ และรูปแบบที่กวาดสายตาเห็นซึ่งตารางเปล่าให้ไม่ได้ จึงเป็นทางออกที่ดีที่สุดเมื่อผู้อ่านต้องการทั้งสองอย่าง
เปรียบเทียบให้เห็นภาพ
เหมือนตารางคะแนนลีกที่มีแถบชนะแพ้เสมออยู่ข้างตัวเลข ซึ่งอ่านได้ทั้งสองแบบ
ใช้ที่ไหนบ้าง — รายงานที่ผู้อ่านต้องอ้างอิงตัวเลขจริงแต่ก็อยากเห็นภาพรวม ตารางอันดับ หรือรายงานประจำเดือนที่ต้องส่งต่อ
สร้างอย่างไร
- ขั้นที่ 1★ เลือกคอลัมน์ที่ควรมีภาพในเซลล์ ไม่ใช่ใส่ทุกคอลัมน์
- ขั้นที่ 2เรียงตามคอลัมน์ที่สำคัญที่สุด
- ขั้นที่ 3ใช้แถบที่เริ่มจากฐานเดียวกันทุกแถว
- ขั้นที่ 4จัดตัวเลขให้ตรงหลักและใช้ฟอนต์ที่ความกว้างเท่ากัน
ตัวอย่างคลาสสิก · ตารางพร้อมแถบในรายงานทางการเงิน
รายงานทางการเงินต้องมีตัวเลขที่แน่นอนเพราะผู้อ่านต้องอ้างอิงและคำนวณต่อ แต่ตารางเปล่าทำให้เห็นรูปแบบยาก การใส่แถบเล็ก ๆ ไว้ในเซลล์กลายเป็นวิธีมาตรฐานที่ให้ทั้งสองอย่างโดยไม่ต้องแลก และเครื่องมือตารางเกือบทุกตัวรองรับเป็นฟีเจอร์พื้นฐาน
02อธิบายภาษาคนเข้าใจง่าย ๆ
การถกเถียงระหว่างตารางกับกราฟมักจบลงที่การเลือกอย่างใดอย่างหนึ่ง ทั้งที่ทั้งสองแบบมีจุดแข็งคนละอย่าง
ตารางให้ค่าที่แน่นอนซึ่งจำเป็นเมื่อผู้อ่านต้องอ้างอิงหรือคำนวณต่อ แต่รูปแบบอย่างแถวไหนสูงผิดปกติต้องอ่านทีละแถวจึงจะเห็น
กราฟให้รูปแบบทันทีแต่อ่านค่าที่แน่นอนไม่ได้ ซึ่งทำให้คนที่ต้องเอาตัวเลขไปใช้ต่อต้องไปหาข้อมูลดิบอยู่ดี
ตารางที่มีภาพในเซลล์ไม่ต้องเลือก เพราะตัวเลขยังอยู่ครบและแถบที่อยู่ข้าง ๆ ก็ทำให้กวาดสายตาเห็นรูปแบบได้ทันที
หลักการสำคัญคือแถบต้องเริ่มจากฐานเดียวกันทุกแถว ไม่อย่างนั้นการเทียบด้วยสายตาก็ใช้ไม่ได้ และควรใส่ภาพเฉพาะคอลัมน์ที่สำคัญ
ถ้าใส่แถบทุกคอลัมน์ ตารางจะกลายเป็นภาพรกที่ไม่มีอะไรเด่น ซึ่งเสียทั้งความชัดของตารางและความเร็วของกราฟไปพร้อมกัน
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
category | หมวด | หมวดหมู่ | row | 5–50 แถว | คอลัมน์ซ้ายสุด |
value | ค่า | ตัวเลขต่อเนื่อง | length | ต่อเนื่อง | แสดงทั้งเป็นตัวเลขและแถบ |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ★ เลือกคอลัมน์ที่จะใส่ภาพ ไม่ใช่ใส่ทุกคอลัมน์
- เรียงตามคอลัมน์ที่สำคัญที่สุด
- ตัดสินใจว่าจะปัดตัวเลขที่ระดับไหน
ค่าที่หายไป — ค่าที่หายไปต้องแสดงเป็นขีดหรือข้อความ ไม่ใช่ศูนย์หรือช่องว่าง
สเกลของแกน — แถบในคอลัมน์เดียวกันต้องใช้สเกลเดียวกันและเริ่มจากฐานเดียวกัน
กราฟจะเริ่มพังเมื่อไร
เกิน 60 แถว ต้องมีการค้นหาและแบ่งหน้า
หน้าตาไฟล์ที่ต้องเตรียม
category,value
กรุงเทพฯ,433
เชียงใหม่,416
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- ค่าที่แน่นอนของทุกแถว
- แถวที่โดดจากแถวอื่นซึ่งเห็นได้จากความยาวแถบ
- สัดส่วนของแต่ละแถวต่อยอดรวม
- ระยะห่างระหว่างอันดับ
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ รูปแบบที่ซับซ้อนกว่าการเทียบค่ารายแถว ซึ่งต้องใช้กราฟเต็มรูปแบบ
- แนวโน้มตามเวลา เว้นแต่จะใส่เส้นย่อในเซลล์
อ่านตามลำดับนี้
- กวาดสายตาดูความยาวแถบเพื่อหาแถวที่โดด
- อ่านตัวเลขของแถวที่สนใจ
- ตรวจว่าเรียงตามคอลัมน์ไหน
คำถามที่ตอบได้
- ค่าของแถวนี้เท่าไรกันแน่
- แถวไหนสูงที่สุด
- อันดับหนึ่งกับอันดับสองต่างกันมากไหม
สัญญาณว่ามีอะไรผิด
- แถบไม่เริ่มจากฐานเดียวกัน
- ใส่แถบทุกคอลัมน์จนภาพรก
- ตัวเลขไม่จัดตรงหลัก
- ไม่เรียงตามคอลัมน์ที่สำคัญ
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ★ ใส่แถบเฉพาะคอลัมน์ที่สำคัญที่สุดหนึ่งถึงสองคอลัมน์
- จัดตัวเลขให้ตรงหลักด้วยฟอนต์ที่ความกว้างเท่ากัน
- เขียนแถวรวมไว้ล่างสุดเมื่อมีความหมาย
รูปแบบชื่อกราฟที่ควรใช้
<ตัวชี้วัด> ราย<หมวด> เรียงจากมากไปน้อย โดย <หมวด> สูงสุดที่ <ค่า>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ data-table-viz-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด data-table-viz-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import pandas as pd
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("data-table-viz-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "both" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
d = df.nlargest(12, "value").reset_index(drop=True)
maxv = d["value"].max()
ax.axis("off")
ax.text(0.02, 1.0, "หมวด", fontsize=10, color="#6b675e", transform=ax.transAxes)
ax.text(0.42, 1.0, "ค่า", fontsize=10, color="#6b675e", ha="right", transform=ax.transAxes)
for i, r in d.iterrows():
y = 0.92 - i * 0.078
ax.text(0.02, y, r["category"], fontsize=10, transform=ax.transAxes)
ax.text(0.42, y, f"{r['value']:,.0f}", fontsize=10, ha="right",
family="monospace", transform=ax.transAxes) # ตรงหลัก
ax.barh(y, r["value"] / maxv * 0.5, left=0.48, height=0.045, # ★ ฐานเดียวกันทุกแถว
color=C1, transform=ax.transAxes)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("data-table-viz.png", dpi=160)
print("เขียน data-table-viz.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (9 แถว)
| หมวด | ค่า | สัดส่วน |
|---|---|---|
| กรุงเทพฯ | 433 | 16.5% |
| เชียงใหม่ | 416 | 15.8% |
| ขอนแก่น | 338 | 12.9% |
| ชลบุรี | 333 | 12.7% |
| ภูเก็ต | 311 | 11.8% |
| นครราชสีมา | 253 | 9.6% |
| สงขลา | 208 | 7.9% |
| อุดรธานี | 170 | 6.5% |
| สุราษฎร์ธานี | 165 | 6.3% |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ลองอ่านค่าที่แน่นอนของแถวที่สาม แล้วลองหาแถวที่โดดที่สุด — ตารางเปล่าทำอย่างแรกได้ กราฟทำอย่างหลังได้ ที่นี่ทำได้ทั้งคู่
ข้อควรระวัง
- ★ ใส่แถบทุกคอลัมน์จนภาพรกและไม่มีอะไรเด่น
- ใช้ฐานหรือสเกลของแถบไม่เหมือนกันในแต่ละแถว ทำให้เทียบด้วยสายตาไม่ได้
- ไม่จัดตัวเลขให้ตรงหลัก ทำให้เทียบจำนวนหลักด้วยสายตาไม่ได้
- ไม่เรียงตามคอลัมน์ที่สำคัญ ทำให้ผู้อ่านต้องไล่หาเอง
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ผู้อ่านไม่ต้องการค่าที่แน่นอน→ใช้แทน: horizontal-bar
- มีมากกว่า 60 แถว→ใช้แทน: heatmap-matrix หรือตารางที่มีการค้นหา
- ต้องเห็นรูปแบบที่ซับซ้อน→ใช้แทน: small-multiples หรือ scatter-plot