01ภาพรวมของกราฟนี้
Horizon chart บีบความสูงของกราฟพื้นที่ด้วยการตัดค่าที่เกินแล้วพับกลับมาซ้อนเป็นชั้นที่เข้มขึ้น ผลคือใส่อนุกรมได้หลายสิบเส้นในหน้าเดียว แลกกับการที่ผู้อ่านต้องเรียนรู้วิธีอ่านก่อน
เปรียบเทียบให้เห็นภาพ
เหมือนแผนที่ระดับความสูงที่ใช้สีเข้มขึ้นแทนความสูงที่มากขึ้น แทนที่จะวาดภูเขาให้สูงจริงจนเกินกระดาษ
ใช้ที่ไหนบ้าง — ติดตามตัวชี้วัดหลายสิบตัวพร้อมกัน เซิร์ฟเวอร์หลายเครื่อง เซ็นเซอร์หลายจุด หรือหุ้นหลายตัวในหน้าเดียว
สร้างอย่างไร
- ขั้นที่ 1กำหนดจำนวนชั้นที่จะพับ ปกติ 3 ชั้น
- ขั้นที่ 2ตัดค่าที่เกินแต่ละชั้นแล้วพับกลับ
- ขั้นที่ 3ให้ชั้นที่สูงกว่าใช้สีเข้มขึ้น
- ขั้นที่ 4ใส่คำอธิบายวิธีอ่านไว้ข้างกราฟ
ตัวอย่างคลาสสิก · Horizon graph ของ Panopticon และงานวิจัยของ Heer, Kong และ Agrawala
ทีมวิจัยทดลองกับผู้ใช้จริงเพื่อหาว่ากราฟฮอไรซันบีบได้แค่ไหนก่อนที่ความแม่นจะตก ผลคือการพับ 2-3 ชั้นให้ประสิทธิภาพดีที่สุด และการบีบให้เตี้ยลงมากยังอ่านได้ดีกว่าที่คาด ซึ่งกลายเป็นข้อแนะนำมาตรฐานจนถึงวันนี้
02อธิบายภาษาคนเข้าใจง่าย ๆ
ถ้าต้องดูแนวโน้มของเซิร์ฟเวอร์ 30 เครื่องพร้อมกัน การวางกราฟเส้น 30 อันเรียงกันจะกินพื้นที่มหาศาลและต้องเลื่อนหน้าไปมาจนเทียบกันไม่ได้
Horizon chart บีบความสูงด้วยกลอุบายง่าย ๆ คือแบ่งช่วงค่าเป็นชั้น ๆ แล้วแทนที่จะวาดชั้นที่สองต่อขึ้นไปในแนวตั้ง ก็พับมันลงมาทับชั้นแรกโดยใช้สีเข้มขึ้น
ผลคือความสูงของแต่ละแถวเหลือแค่หนึ่งในสามหรือหนึ่งในสี่ แต่ข้อมูลยังอยู่ครบ เพียงแค่ย้ายจากการเข้ารหัสด้วยความสูงไปเป็นการเข้ารหัสด้วยความเข้มของสีบางส่วน
ราคาที่จ่ายชัดเจนคือผู้อ่านต้องเรียนรู้ก่อน เพราะถ้าไม่รู้กติกา สีเข้มจะดูเหมือนแค่การตกแต่ง ต้องมีคำอธิบายวิธีอ่านอยู่ข้างกราฟเสมอ
ข้อดีที่ได้กลับมาคุ้มเมื่อจำนวนอนุกรมเยอะจริง ๆ เพราะทุกแถวอยู่ในหน้าจอเดียวกัน ตาจึงเทียบรูปแบบข้ามแถวได้ ซึ่งเป็นสิ่งที่การเลื่อนหน้าทำลายไปหมด
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
date | เวลา | เวลา | x | 30–500 จุด | ทุกอนุกรมต้องมีจุดเวลาตรงกัน |
series | อนุกรม | หมวดหมู่ | row | 5–40 แถว | จุดแข็งของกราฟนี้คือรองรับแถวได้เยอะ |
value | ค่า | ตัวเลขต่อเนื่อง | y | ต่อเนื่อง | ควรใช้สเกลร่วมกันทุกแถวเพื่อให้เทียบข้ามแถวได้ |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- จัดให้ทุกอนุกรมมีจุดเวลาตรงกัน
- เลือกสเกลร่วมหรือสเกลรายแถวและระบุให้ชัด
- กำหนดจำนวนชั้นที่จะพับ
ค่าที่หายไป — ช่วงที่ขาดข้อมูลต้องเว้นว่างให้เห็น ห้ามเติมศูนย์เพราะศูนย์จะกลายเป็นชั้นอ่อนสุดที่ดูเหมือนมีข้อมูล
สเกลของแกน — linear และควรใช้สเกลร่วมทุกแถวเมื่อต้องการเทียบข้ามแถว
กราฟจะเริ่มพังเมื่อไร
น้อยกว่า 5 แถวไม่คุ้มกับความยากในการอ่าน — ใช้ small-multiples แทน
หน้าตาไฟล์ที่ต้องเตรียม
date,series,value
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- แถวไหนที่มีช่วงค่าสูงบ่อย จากปริมาณสีเข้ม
- ช่วงเวลาที่หลายแถวสูงพร้อมกัน ซึ่งมักเป็นเหตุการณ์ร่วม
- รูปแบบที่ซ้ำกันข้ามแถว
สิ่งที่กราฟนี้ตอบไม่ได้
- อ่านค่าที่แม่นยำไม่ได้ เพราะความสูงถูกตัดและพับ
- ผู้ที่ไม่รู้กติกาจะอ่านผิดทั้งหมด
อ่านตามลำดับนี้
- อ่านคำอธิบายจำนวนชั้นและช่วงค่าของแต่ละชั้นก่อน
- ดูปริมาณและความเข้มของสีในแต่ละแถว
- มองแนวตั้งเพื่อหาช่วงเวลาที่หลายแถวเข้มพร้อมกัน
คำถามที่ตอบได้
- มีช่วงเวลาไหนที่ทุกอย่างพุ่งพร้อมกัน
- แถวไหนที่ผิดปกติเมื่อเทียบกับแถวอื่น
สัญญาณว่ามีอะไรผิด
- ไม่มีคำอธิบายวิธีอ่าน
- แต่ละแถวใช้สเกลของตัวเองแต่ให้ผู้อ่านเทียบข้ามแถว
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- ใส่คำอธิบายจำนวนชั้นและช่วงค่าไว้ข้างกราฟเสมอ
- เขียนค่าสูงสุดของแต่ละแถวไว้ท้ายแถว
รูปแบบชื่อกราฟที่ควรใช้
<จำนวน> อนุกรมในหน้าเดียว · สีเข้มขึ้นหมายถึงค่าที่สูงขึ้นอีกชั้น
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ horizon-chart-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด horizon-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("horizon-chart-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "bands" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
df["date"] = pd.to_datetime(df["date"])
names = list(df["series"].unique()); bands = 3
vmax = df["value"].max(); step = vmax / bands
fig.clf(); fig.set_size_inches(7.6, 0.9 * len(names) + 0.5)
for i, name in enumerate(names):
g = df[df["series"] == name].sort_values("date")
a = fig.add_subplot(len(names), 1, i + 1)
for b in range(bands):
lo = b * step
a.fill_between(g["date"], 0, (g["value"] - lo).clip(0, step), # ตัดแล้วพับกลับ
color=["#9ec5f4", "#3987e5", "#184f95"][b])
a.set_ylim(0, step); a.axis("off")
a.text(0, 0.5, name, transform=a.transAxes, ha="right", fontsize=9)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("horizon-chart.png", dpi=160)
print("เขียน horizon-chart.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
horizon chart ต้องอธิบายวิธีอ่านก่อนใช้ — สีเข้มขึ้นหมายถึงค่าที่พับทับกันอีกชั้น
ดูข้อมูลเป็นตาราง (3 แถว)
| อนุกรม | ต่ำสุด | สูงสุด | เฉลี่ย |
|---|---|---|---|
| หน้าร้าน | 56.0 | 71.3 | 62.2 |
| เว็บไซต์ | 53.4 | 86.8 | 71.8 |
| แอป | 31.6 | 84.4 | 56.5 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ลองอ่านแถวที่มีสีเข้มสุดโดยไม่ดูตาราง แล้วเช็ค จะเห็นว่ากติกาการพับต้องอธิบายก่อนเสมอ ไม่มีใครเดาถูกเอง
ข้อควรระวัง
- ไม่ใส่คำอธิบายวิธีอ่าน ทำให้ผู้อ่านตีความสีเข้มเป็นแค่การตกแต่ง
- ใช้กับอนุกรมน้อย ๆ ซึ่งไม่คุ้มกับความยากในการอ่าน
- ให้แต่ละแถวใช้สเกลของตัวเองแล้วให้ผู้อ่านเทียบข้ามแถว
- ใช้จำนวนชั้นมากเกินไปจนแยกความเข้มไม่ออก
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีอนุกรมน้อยกว่า 5 อนุกรม→ใช้แทน: small-multiples หรือ multi-line-chart
- ผู้อ่านไม่เคยเห็นกราฟชนิดนี้มาก่อน→ใช้แทน: small-multiples
- ต้องอ่านค่าที่แม่นยำ→ใช้แทน: line-chart