01ภาพรวมของกราฟนี้
Sparkline คือกราฟเส้นที่เล็กพอจะวางในบรรทัดข้อความหรือในตาราง มันตัดแกน ตัวเลข และ grid ออกทั้งหมด เหลือเพียงรูปร่าง เพราะหน้าที่ของมันคือให้บริบท ไม่ใช่ให้อ่านค่า
เปรียบเทียบให้เห็นภาพ
เหมือนคลื่นเสียงเล็ก ๆ ข้างชื่อไฟล์เพลง เราไม่ได้อ่านค่าเดซิเบล แต่รู้ทันทีว่าเพลงนี้ดังสม่ำเสมอหรือมีท่อนเงียบ
ใช้ที่ไหนบ้าง — ตารางที่แต่ละแถวมีตัวเลขปัจจุบันและต้องการบอกว่ามาถึงจุดนี้ได้อย่างไร dashboard ที่มี KPI หลายตัว หรือรายงานที่แทรกกราฟในประโยค
สร้างอย่างไร
- ขั้นที่ 1เลือกอนุกรมที่สั้นพอ
- ขั้นที่ 2ตัดแกนและ grid ออกทั้งหมด
- ขั้นที่ 3วางข้างตัวเลขปัจจุบัน
- ขั้นที่ 4ทำเครื่องหมายเฉพาะจุดล่าสุดหรือจุดสูงสุด
ตัวอย่างคลาสสิก · Edward Tufte บัญญัติคำว่า sparkline ในหนังสือ Beautiful Evidence
Tufte เสนอแนวคิด "กราฟขนาดเท่าคำ" ที่แทรกอยู่ในประโยคได้ เพื่อให้ตัวเลขในข้อความมีบริบทของตัวเองโดยไม่ต้องตัดไปดูรูปที่หน้าอื่น หลักการที่เขาวางไว้คือให้ความหนาแน่นของข้อมูลสูงที่สุดเท่าที่พื้นที่จะรับได้
02อธิบายภาษาคนเข้าใจง่าย ๆ
ในตารางที่มี 20 แถว การใส่กราฟเต็มรูปแบบให้ทุกแถวเป็นไปไม่ได้ แต่ตัวเลขเดี่ยว ๆ ก็ไม่บอกว่ามันมาจากไหน sparkline คือทางสายกลางที่ Edward Tufte เสนอไว้
หลักการคือตัดทุกอย่างที่ไม่ใช่รูปร่างออก ไม่มีแกน ไม่มี grid ไม่มีตัวเลขบนกราฟ เพราะในพื้นที่ขนาดนี้องค์ประกอบเหล่านั้นกินที่มากกว่าที่ให้ประโยชน์
สิ่งที่ผู้อ่านได้คือคำตอบของคำถามว่า "ตัวเลขนี้ขึ้นมาตลอดหรือเพิ่งเด้งขึ้นเมื่อเดือนที่แล้ว" ซึ่งเปลี่ยนการตีความตัวเลขปัจจุบันไปคนละเรื่อง
เพราะไม่มีแกน sparkline จึงห้ามใช้เดี่ยว ๆ ต้องมีตัวเลขปัจจุบันกำกับเสมอ และถ้าจะให้ดีควรมีค่าต่ำสุดกับสูงสุดเขียนไว้ด้วย
ข้อควรระวังที่สำคัญคือ ถ้าวาง sparkline หลายเส้นเรียงกันแล้วแต่ละเส้นใช้สเกลของตัวเอง ห้ามให้ผู้อ่านเทียบรูปร่างข้ามแถว เพราะเส้นที่ดูชันเท่ากันอาจมาจากการเปลี่ยนแปลงคนละขนาด
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
date | เวลา | เวลา | x | 10–60 จุด | ไม่แสดงแกน แต่ลำดับต้องถูกต้อง |
value | ค่า | ตัวเลขต่อเนื่อง | y | ต่อเนื่อง | ต้องมีตัวเลขปัจจุบันเขียนกำกับข้างกราฟเสมอ |
seriesไม่บังคับ | ชื่อแถว | หมวดหมู่ | row | 1–20 แถว | เมื่อวางหลายเส้นเรียงกัน |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ลดความละเอียดของข้อมูลให้เหลือจำนวนจุดที่พอดี
- ตัดสินใจว่าแต่ละแถวใช้สเกลของตัวเองหรือสเกลร่วม
- เตรียมค่าปัจจุบันไว้เขียนกำกับ
ค่าที่หายไป — หักเส้นตรงช่วงที่ไม่มีข้อมูล แม้ในพื้นที่เล็กก็ห้ามลากข้าม
สเกลของแกน — ใช้สเกลของแต่ละแถวเองเมื่อสนใจรูปร่าง หรือสเกลร่วมเมื่อต้องการให้เทียบข้ามแถวได้ และต้องเขียนบอกว่าใช้แบบไหน
กราฟจะเริ่มพังเมื่อไร
น้อยกว่า 8 จุด รูปร่างจะไม่มีความหมาย และเกิน 80 จุดจะกลายเป็นเส้นหยักทึบ
หน้าตาไฟล์ที่ต้องเตรียม
date,series,value
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- รูปร่างโดยรวมว่าขึ้น ลง หรือทรงตัว
- ความผันผวนว่าเส้นเรียบหรือหยัก
- ตำแหน่งของค่าปัจจุบันเทียบกับประวัติที่ผ่านมา
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ อ่านค่าไม่ได้เลยเพราะไม่มีแกน ต้องมีตัวเลขกำกับเสมอ
- เทียบข้ามแถวไม่ได้ถ้าแต่ละแถวใช้สเกลของตัวเอง
อ่านตามลำดับนี้
- อ่านตัวเลขปัจจุบันก่อน
- ดูรูปร่างของเส้นเพื่อรู้บริบท
- ดูว่าจุดล่าสุดอยู่สูงหรือต่ำในเส้นของตัวเอง
คำถามที่ตอบได้
- ตัวเลขนี้เพิ่งขึ้นหรือขึ้นมาตลอด
- ค่าปัจจุบันสูงหรือต่ำเมื่อเทียบกับที่ผ่านมา
สัญญาณว่ามีอะไรผิด
- ไม่มีตัวเลขกำกับ ทำให้อ่านอะไรไม่ได้เลย
- เทียบรูปร่างข้ามแถวทั้งที่ใช้คนละสเกล
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เขียนค่าปัจจุบันเป็นตัวเลขใหญ่ข้างกราฟเสมอ
- ทำเครื่องหมายจุดล่าสุดด้วยจุดกลม
- เขียนช่วงค่าต่ำสุด–สูงสุดไว้ท้ายบรรทัดถ้ามีที่
รูปแบบชื่อกราฟที่ควรใช้
<ตัวชี้วัด> <ค่าปัจจุบัน> (<เปลี่ยนแปลง>%)
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ sparkline-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด sparkline-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("sparkline-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "context" # ← ค่าจาก 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())
fig.set_size_inches(7.6, 0.6 * len(names) + 0.4)
fig.clf()
for i, name in enumerate(names):
g = df[df["series"] == name].sort_values("date")
a = fig.add_subplot(len(names), 1, i + 1)
a.plot(g["date"], g["value"], color=C1, linewidth=1.4)
a.scatter(g["date"].iloc[-1], g["value"].iloc[-1], color=C1, s=14)
a.axis("off") # ตัดแกนและ grid ออกทั้งหมด นี่คือหัวใจของ sparkline
a.set_title(f"{name} {g['value'].iloc[-1]:,.1f}", loc="left", fontsize=9, pad=1)
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("sparkline.png", dpi=160)
print("เขียน sparkline.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
sparkline ไม่มีแกน จึงบอกได้แค่รูปร่าง ต้องมีตัวเลขปัจจุบันกำกับเสมอ
ดูข้อมูลเป็นตาราง (3 แถว)
| อนุกรม | ค่าแรก | ค่าล่าสุด | เปลี่ยน % |
|---|---|---|---|
| หน้าร้าน | 70.7 | 58.3 | -17.5% |
| เว็บไซต์ | 53.4 | 83.5 | 56.4% |
| แอป | 31.7 | 84.4 | 166.2% |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: ปิดตาดูเฉพาะตัวเลขก่อน แล้วค่อยดูรูปร่าง จะเห็นว่าค่าเท่ากันแต่มาจากเส้นทางคนละแบบ ให้ข้อสรุปต่างกันโดยสิ้นเชิง
ข้อควรระวัง
- ใช้ sparkline เดี่ยว ๆ โดยไม่มีตัวเลขกำกับ ทำให้อ่านอะไรไม่ได้
- ให้ผู้อ่านเทียบรูปร่างข้ามแถวทั้งที่แต่ละแถวใช้คนละสเกล
- ใส่จุดข้อมูลมากเกินไปจนเส้นกลายเป็นแถบทึบ
- เติมแกนและ grid กลับเข้าไปจนพื้นที่ไม่เหลือให้เส้น
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ต้องอ่านค่าจากกราฟ→ใช้แทน: line-chart เต็มรูปแบบ
- มีอนุกรมเดียวและมีพื้นที่เหลือเฟือ→ใช้แทน: line-chart หรือ stat-tile
- ต้องเทียบหลายอนุกรมอย่างแม่นยำ→ใช้แทน: small-multiples ที่ใช้สเกลร่วม