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

กราฟหลายเส้นMulti-line Chart

เส้นไหนนำ เส้นไหนตาม และตัดกันเมื่อไร

2
ต่อยอดโดยตรงควรรู้ก่อน · อ่านกราฟเส้นเป็น
ลองเล่น

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

Multi-line chart เทียบแนวโน้มของหลายอนุกรมพร้อมกัน สิ่งที่มีค่าที่สุดคือจุดตัดและช่องว่างระหว่างเส้น ซึ่งบอกเรื่องที่กราฟเส้นเดียวเล่าไม่ได้ ข้อจำกัดคือจำนวนเส้น เพราะเกิน 5-6 เส้นจะกลายเป็นพันกันจนอ่านไม่ได้

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

เหมือนดูการแข่งวิ่งจากด้านข้าง เราเห็นว่าใครนำอยู่ ใครกำลังไล่ และแซงกันตอนไหน ซึ่งการดูเวลาเข้าเส้นชัยอย่างเดียวบอกไม่ได้

ใช้ที่ไหนบ้าง — เทียบยอดขายหลายช่องทางตามเวลา เทียบจำนวนผู้ใช้หลายแพลตฟอร์ม หรือเทียบตัวชี้วัดของเรากับคู่แข่ง

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

  1. ขั้นที่ 1ตรวจว่าทุกอนุกรมใช้หน่วยเดียวกัน
  2. ขั้นที่ 2จำกัดจำนวนเส้นไม่เกิน 5-6 เส้น
  3. ขั้นที่ 3ติดป้ายชื่อไว้ปลายเส้นแทนการพึ่ง legend
  4. ขั้นที่ 4เน้นเส้นที่เป็นประเด็นและทำเส้นอื่นเป็นสีเทา

ตัวอย่างคลาสสิก · กราฟเปรียบเทียบการระบาดของโรคระหว่างประเทศ

ช่วงการระบาดใหญ่ กราฟหลายเส้นที่วางจำนวนผู้ติดเชื้อของแต่ละประเทศบนแกนเดียวกันกลายเป็นภาพที่คนทั้งโลกดูทุกวัน และเป็นบทเรียนสาธารณะครั้งใหญ่ว่าการเลือกสเกลแบบ log หรือ linear เปลี่ยนข้อสรุปได้มากแค่ไหน

Our World in Data · COVID-19 data explorer

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

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

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

ทางแก้ที่ถูกต้องเมื่อหน่วยต่างกันมีสองทาง คือแยกเป็นกราฟย่อยหลายอัน หรือแปลงทุกเส้นเป็นดัชนีที่เริ่มจากฐานเดียวกัน เช่น ให้ทุกเส้นเริ่มที่ 100 แล้วดูการเติบโตเป็นเปอร์เซ็นต์

จำนวนเส้นเป็นข้อจำกัดจริง เกิน 5-6 เส้นแล้วภาพจะกลายเป็นก้อนเส้นพันกัน ทางออกคือเน้นเส้นเดียวที่เป็นประเด็นด้วยสีเข้ม แล้วทำเส้นที่เหลือเป็นสีเทาจาง ๆ เป็นฉากหลัง

ป้ายชื่อควรติดไว้ที่ปลายเส้นทางขวา แทนที่จะให้ผู้อ่านสลับสายตาไปมาระหว่างกราฟกับ legend ซึ่งเป็นภาระทางความคิดที่ตัดออกได้ฟรี

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

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

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
dateเวลาเวลาx10–200 จุดทุกอนุกรมควรมีจุดเวลาเดียวกัน
seriesชื่ออนุกรมหมวดหมู่color2–6 เส้นเกิน 6 เส้นให้ fold เป็น "อื่น ๆ" หรือแยกเป็น small multiples
valueค่าที่วัดได้ตัวเลขต่อเนื่องyต่อเนื่อง★ ทุกอนุกรมต้องเป็นหน่วยเดียวกัน ห้ามใช้แกนที่สอง

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

  1. ตรวจว่าทุกอนุกรมใช้หน่วยเดียวกัน
  2. จัดให้ทุกอนุกรมมีจุดเวลาตรงกัน
  3. ถ้าหน่วยต่างกันให้แปลงเป็นดัชนีฐานเดียวกันก่อน
  4. ตัดสินใจว่าเส้นไหนคือพระเอกของเรื่อง

ค่าที่หายไป — หักเส้นตรงช่วงที่ไม่มีข้อมูลของอนุกรมนั้น และอย่าปล่อยให้เส้นอื่นทำให้ดูเหมือนข้อมูลครบ

สเกลของแกน — linear เมื่อสนใจค่าสัมบูรณ์ ใช้ log หรือดัชนีฐาน 100 เมื่อสนใจอัตราการเติบโตเทียบกัน

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

เกิน 6 เส้น ภาพกลายเป็นก้อนเส้นพันกัน — ใช้ small-multiples หรือ highlight ทีละเส้น

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

date,series,value

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

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

  • เส้นไหนนำและตามในแต่ละช่วง
  • จุดที่เส้นตัดกัน ซึ่งมักเป็นเหตุการณ์สำคัญ
  • ช่องว่างระหว่างเส้นกว้างขึ้นหรือแคบลง
  • เส้นที่เคลื่อนไปคนละทางกับเส้นอื่น

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

  • ไม่บอกยอดรวมของทุกอนุกรม ต้องใช้ stacked-area
  • ไม่บอกว่าเส้นที่เคลื่อนไปด้วยกันเป็นเหตุและผลกัน

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

  1. หาเส้นที่เป็นประเด็นก่อนจากสีที่เด่น
  2. ดูว่ามีจุดตัดกันตรงไหนบ้าง
  3. ดูว่าช่องว่างระหว่างเส้นเปลี่ยนไปอย่างไร

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

  • ใครนำอยู่ตอนนี้
  • แซงกันเมื่อไร
  • ช่องว่างระหว่างสองกลุ่มกำลังปิดหรือไม่

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

  • ★ มีแกน y สองแกน ซึ่งทำให้เลือกได้ว่าจะให้เส้นไหนดูสูงกว่า
  • เส้นเกิน 6 เส้นสีใกล้เคียงกัน
  • ไม่มีป้ายชื่อที่ปลายเส้น

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

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

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

  1. ติดชื่ออนุกรมไว้ปลายเส้นขวาสุดแทน legend
  2. ทำเครื่องหมายจุดตัดที่สำคัญ
  3. ทำเส้นที่ไม่ใช่ประเด็นเป็นสีเทา

รูปแบบชื่อกราฟที่ควรใช้

<อนุกรม> แซง <อนุกรม> เมื่อ <เวลา> และทิ้งห่างเป็น <ช่องว่าง>

06เอาไปใช้ต่อ

โค้ดทุกชิ้นอ่านไฟล์ multi-line-chart-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง

# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด multi-line-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("multi-line-chart-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "cross"   # ← ค่าจาก Playground

fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)

df["date"] = pd.to_datetime(df["date"])
for i, (name, g) in enumerate(df.groupby("series")):
    g = g.sort_values("date")
    ax.plot(g["date"], g["value"], color=[C1, C2, C3][i % 3], linewidth=2, label=name)
    ax.annotate(name, (g["date"].iloc[-1], g["value"].iloc[-1]), xytext=(6, 0),
                textcoords="offset points", fontsize=9, color=[C1, C2, C3][i % 3])  # ป้ายที่ปลายเส้น
ax.grid(axis="y", alpha=0.25); ax.set_axisbelow(True)
fig.autofmt_xdate()

ax.spines[["top", "right"]].set_visible(False)   # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("multi-line-chart.png", dpi=160)
print("เขียน multi-line-chart.png แล้ว ·", len(df), "แถว")

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

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

ข้อมูลตัวอย่าง · 26 แถว · seed 29● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
จุดตัดคือสิ่งที่กราฟเส้นเดียวบอกไม่ได้
หน้าร้านเว็บไซต์แอป
0.0020.040.060.080.0100ก.พ. 68เม.ย. 68มิ.ย. 68หน้าร้าน · ล่าสุด 58.3หน้าร้านเว็บไซต์ · ล่าสุด 83.5เว็บไซต์แอป · ล่าสุด 84.4แอป
เส้นที่นำอยู่ล่าสุดแอป
จำนวนอนุกรม3
ช่วงห่างล่าสุด26.1
ดูข้อมูลเป็นตาราง (26 แถว)
กราฟหลายเส้น 3 อนุกรม 26 จุดเวลา
วันที่หน้าร้านเว็บไซต์แอป
1/1/256870.753.431.7
8/1/256871.356.131.8
15/1/256868.658.631.6
22/1/256869.357.835.5
29/1/256864.760.941.4
5/2/256864.965.040.1
12/2/256862.267.240.9
19/2/256864.467.544.3
26/2/256863.065.448.8
5/3/256862.465.752.9
12/3/256862.368.551.8
19/3/256863.372.251.1
26/3/256863.372.450.1
2/4/256860.270.852.2
9/4/256856.173.056.5
16/4/256859.677.261.7
23/4/256860.178.066.8
30/4/256858.780.267.6
7/5/256859.681.770.1
14/5/256861.880.973.8
21/5/256860.878.473.7
28/5/256860.180.175.3
4/6/256857.982.677.7
11/6/256856.083.778.3
18/6/256857.086.879.8
25/6/256858.383.584.4

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

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

ข้อควรระวัง

  1. ★ ใช้แกน y สองแกนเมื่อหน่วยต่างกัน ซึ่งเป็นความผิดพลาดอันดับหนึ่งของการทำกราฟ
  2. ใส่เส้นเกิน 6 เส้นจนพันกันและสีแยกไม่ออกสำหรับคนตาบอดสี
  3. ให้ทุกเส้นเด่นเท่ากันทั้งที่มีเส้นเดียวที่เป็นประเด็น
  4. ใช้ legend แทนป้ายที่ปลายเส้น ทำให้ผู้อ่านต้องสลับสายตาไปมา

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

  • หน่วยของแต่ละอนุกรมต่างกันใช้แทน: small-multiples หรือแปลงเป็นดัชนีฐาน 100 ก่อน
  • มีมากกว่า 6 อนุกรมใช้แทน: small-multiples หรือ horizon-chart
  • สนใจยอดรวมของทุกอนุกรมใช้แทน: stacked-area
  • สนใจอันดับมากกว่าค่าใช้แทน: bump-chart

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

เทคนิคถัดไป · กราฟพื้นที่