01ภาพรวมของกราฟนี้
Waterfall chart ตอบคำถามว่า "ทำไมยอดถึงเปลี่ยนจาก A เป็น B" โดยแตกส่วนต่างออกเป็นขั้นย่อยที่บวกและลบ แท่งแต่ละขั้นลอยอยู่ที่ระดับสะสม ทำให้มองเห็นเส้นทางของตัวเลขตั้งแต่ต้นจนจบ
เปรียบเทียบให้เห็นภาพ
เหมือนใบเสร็จที่เริ่มจากยอดรวม แล้วมีบรรทัดบวกค่าบริการและลบส่วนลด จนได้ยอดสุดท้าย เพียงแต่วาดเป็นภาพให้เห็นน้ำหนักของแต่ละบรรทัด
ใช้ที่ไหนบ้าง — อธิบายการเปลี่ยนแปลงของกำไร วิเคราะห์ที่มาของการเติบโตของผู้ใช้ หรือแจกแจงส่วนต่างงบประมาณ
สร้างอย่างไร
- ขั้นที่ 1กำหนดยอดตั้งต้นและยอดปลายทาง
- ขั้นที่ 2แตกส่วนต่างเป็นขั้นที่อธิบายได้
- ขั้นที่ 3เรียงขั้นตามลำดับที่มีเหตุผล
- ขั้นที่ 4ปิดท้ายด้วยแท่งยอดรวม
ตัวอย่างคลาสสิก · กราฟสะพานอธิบายการเปลี่ยนแปลงของกำไรในรายงานประจำปี
บริษัทจดทะเบียนมักต้องอธิบายให้นักลงทุนเข้าใจว่ากำไรเปลี่ยนจากปีก่อนเพราะอะไร waterfall chart กลายเป็นรูปแบบมาตรฐานของงานนี้เพราะบังคับให้ผู้เขียนแตกส่วนต่างออกมาให้ครบทุกบาท จะซ่อนส่วนที่อธิบายไม่ได้ไว้เฉย ๆ ไม่ได้
02อธิบายภาษาคนเข้าใจง่าย ๆ
เวลาบอกว่ากำไรปีนี้ลดลง 12% คำถามถัดไปที่ทุกคนถามคือ "เพราะอะไร" กราฟแท่งธรรมดาตอบไม่ได้ เพราะมันแสดงแค่สองยอดโดยไม่บอกว่าอะไรอยู่ระหว่างกลาง
Waterfall แตกส่วนต่างออกเป็นขั้น ๆ เช่น ลูกค้าใหม่ทำให้เพิ่ม ส่วนลดทำให้ลด ลูกค้าเลิกใช้ทำให้ลด ทุกขั้นวางต่อกันเหมือนบันไดจากยอดแรกไปยอดสุดท้าย
สิ่งที่ทำให้อ่านง่ายคือสี แท่งที่ดันขึ้นใช้สีหนึ่ง แท่งที่ดึงลงใช้อีกสีหนึ่ง และแท่งยอดรวมใช้สีกลาง ผู้อ่านจึงแยกออกทันทีโดยไม่ต้องดูเครื่องหมาย
ข้อบังคับที่สำคัญคือทุกขั้นต้องบวกกันแล้วได้ส่วนต่างจริงพอดี ถ้ามีส่วนที่อธิบายไม่ได้ ต้องใส่แท่ง "อื่น ๆ" ไว้ ห้ามปัดทิ้งเงียบ ๆ เพราะจะทำให้ภาพโกหก
ลำดับของขั้นเป็นการตัดสินใจเชิงบรรณาธิการ เรียงตามขนาดจะเห็นตัวที่สำคัญก่อน เรียงตามกระบวนการจริงจะเล่าเรื่องได้ดีกว่า ไม่ว่าเลือกแบบไหนต้องเขียนบอก
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
step | ขั้นตอน | มีลำดับ | x | 4–10 ขั้น | ลำดับมีความหมาย ห้ามเรียงใหม่ตามใจ |
delta | ส่วนเปลี่ยนของขั้นนั้น | ตัวเลขต่อเนื่อง | y | บวกหรือลบ | ขั้นแรกคือยอดตั้งต้น ขั้นที่เหลือคือส่วนเปลี่ยน |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- ตรวจว่าผลรวมของทุกขั้นเท่ากับส่วนต่างจริง
- รวมขั้นที่เล็กกว่า 3% เป็น "อื่น ๆ"
- ตัดสินใจลำดับของขั้นและเขียนเหตุผล
ค่าที่หายไป — ส่วนที่อธิบายไม่ได้ต้องใส่เป็นแท่ง "อื่น ๆ" หรือ "ยังอธิบายไม่ได้" เสมอ การละทิ้งจะทำให้บันไดไปไม่ถึงยอดปลาย
สเกลของแกน — linear และควรให้เห็นเส้นศูนย์ในภาพ
กราฟจะเริ่มพังเมื่อไร
เกิน 12 ขั้น ผู้อ่านจะตามเส้นทางไม่ไหว — รวมขั้นเล็กเป็น "อื่น ๆ"
หน้าตาไฟล์ที่ต้องเตรียม
step,delta
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- ขั้นไหนดันยอดขึ้นมากที่สุด
- ขั้นไหนดึงยอดลงมากที่สุด
- ผลลัพธ์สุดท้ายเทียบกับยอดตั้งต้น
สิ่งที่กราฟนี้ตอบไม่ได้
- ไม่บอกว่าขั้นเหล่านี้เกิดขึ้นเมื่อไรหรือพร้อมกันหรือไม่
- ไม่บอกว่าขั้นต่าง ๆ ส่งผลต่อกันหรือเป็นอิสระ
อ่านตามลำดับนี้
- เริ่มที่แท่งซ้ายสุดซึ่งคือยอดตั้งต้น
- ไล่ตามบันไดทีละขั้นและสังเกตสี
- จบที่แท่งขวาสุดซึ่งคือยอดปลาย
คำถามที่ตอบได้
- ทำไมยอดถึงเปลี่ยน
- ถ้าแก้ขั้นที่แย่ที่สุดได้จะช่วยเท่าไร
- ตัวบวกชนะตัวลบหรือไม่
สัญญาณว่ามีอะไรผิด
- ผลรวมของขั้นไม่เท่ากับส่วนต่างจริง
- ไม่มีแท่งยอดรวมปิดท้าย ทำให้ไม่รู้ว่าจบที่เท่าไร
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เขียนตัวเลขบวกลบไว้บนทุกขั้น
- ลากเส้นประเชื่อมระหว่างขั้นเพื่อให้ตามบันไดได้ง่าย
- เน้นขั้นที่ดึงลงมากที่สุดด้วยสีเข้ม
รูปแบบชื่อกราฟที่ควรใช้
ยอดลดจาก <ต้น> เหลือ <ปลาย> โดย <ขั้น> เป็นตัวดึงลงมากที่สุดที่ <ค่า>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ waterfall-chart-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด waterfall-chart-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("waterfall-chart-sample.csv")
df["delta"] = pd.to_numeric(df["delta"], errors="coerce")
NOTE = "path" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
vals = df["delta"].to_numpy()
starts = np.concatenate([[0], np.cumsum(vals)[:-1]])
starts[0] = 0
colors = ["#256abf"] + ["#008300" if v >= 0 else "#e34948" for v in vals[1:]]
ax.bar(df["step"], vals, bottom=starts, color=colors, width=0.62)
total = vals.sum()
ax.bar(["ยอดปลายงวด"], [total], color="#256abf", width=0.62) # ต้องมีแท่งยอดรวมปิดท้าย
ax.axhline(0, color=INK, linewidth=1)
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("waterfall-chart.png", dpi=160)
print("เขียน waterfall-chart.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
ดูข้อมูลเป็นตาราง (6 แถว)
| ขั้น | ส่วนเปลี่ยน | ยอดสะสม |
|---|---|---|
| ยอดต้นปี | 420 | 420 |
| ลูกค้าใหม่ | 47.0 | 467 |
| ขายเพิ่ม | 62.0 | 529 |
| ลดราคา | -80.0 | 449 |
| ลูกค้าเลิกใช้ | -40.0 | 409 |
| คืนสินค้า | -33.0 | 376 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: สังเกตว่าแท่งกลาง ๆ ลอยอยู่คนละระดับ การเทียบขนาดของสองขั้นที่ไม่ติดกันจึงยากกว่าที่คิด
ข้อควรระวัง
- ผลรวมของขั้นไม่เท่ากับส่วนต่างจริง ทำให้บันไดไปไม่ถึงยอดปลาย
- ใส่ขั้นมากเกินไปจนผู้อ่านตามเรื่องไม่ทัน
- ใช้สีที่ไม่ได้แยกบวกกับลบอย่างชัดเจน
- จัดลำดับขั้นใหม่เพื่อให้ข้อสรุปดูดีขึ้น ซึ่งเป็นการบิดเรื่องเล่า
เมื่อไหร่ไม่ควรใช้กราฟนี้
- ต้องการดูองค์ประกอบ ณ จุดเวลาเดียว→ใช้แทน: stacked-bar หรือ treemap
- มีหลายช่วงเวลาต่อเนื่อง→ใช้แทน: line-chart หรือ stacked-area
- ขั้นแต่ละขั้นคือการหลุดของคนในกรวย→ใช้แทน: funnel-chart