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

กราฟเมฆฝนRaincloud Plot

ได้ทั้งรูปร่าง ค่าสรุป และจุดจริงพร้อมกัน

4
ขั้นสูงควรรู้ก่อน · อ่าน box plot และ violin plot เป็น
ลองเล่น

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

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

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

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

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

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

  1. ขั้นที่ 1วาดครึ่งไวโอลินด้านหนึ่ง
  2. ขั้นที่ 2วางกล่องสรุปไว้ตรงกลาง
  3. ขั้นที่ 3โปรยจุดดิบไว้อีกด้าน
  4. ขั้นที่ 4จัดให้ทั้งสามส่วนไม่ทับกัน

ตัวอย่างคลาสสิก · Allen และคณะเสนอ raincloud plot ในปี 2019

ทีมนักประสาทวิทยาเสนอรูปแบบนี้เพื่อตอบข้อวิจารณ์ว่างานวิจัยแสดงแต่ค่าเฉลี่ยกับแท่ง ซึ่งซ่อนข้อมูลจริงไว้ พวกเขาออกแบบให้รวมทั้งสามชั้นโดยไม่ทับกัน และเผยแพร่โค้ดสำหรับ R, Python และ MATLAB พร้อมกันเพื่อให้ใช้ได้ทันที

Allen et al. · Raincloud plots (Wellcome Open Research)

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

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

Raincloud plot ไม่เลือก มันวางทั้งสามอย่างไว้ในแถวเดียวกันแต่แยกตำแหน่งไม่ให้ทับกัน ครึ่งไวโอลินอยู่ด้านบนเป็น "เมฆ" และจุดดิบโปรยอยู่ด้านล่างเป็น "ฝน"

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

ผลที่ได้คือความโปร่งใส ผู้อ่านที่เชื่อค่าสรุปก็ดูกล่อง ผู้อ่านที่อยากเห็นรูปร่างก็ดูเมฆ และผู้อ่านที่อยากตรวจสอบก็นับจุดฝนได้

ข้อแลกเปลี่ยนคือใช้พื้นที่มากกว่าและอาจดูรกถ้ามีหลายกลุ่ม ในทางปฏิบัติใช้ได้ดีที่ 2-5 กลุ่ม เกินกว่านั้นควรกลับไปใช้ box plot หรือ violin plot

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

รูปทรงของข้อมูลข้อมูลดิบรายแถว (ยังไม่สรุป)
จำนวนมิติที่เข้ารหัสได้3 มิติ
จำนวนแถวที่เหมาะ2–4 กลุ่ม × 30–300 จุดขั้นต่ำ 60 แถว
เส้นฐานศูนย์เลือกได้อ่านจากตำแหน่งบนแกนค่าร่วม

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
groupกลุ่มหมวดหมู่x2–5 กลุ่มเกิน 5 กลุ่มภาพจะรกเพราะแต่ละกลุ่มกินพื้นที่มาก
valueค่าที่วัดได้ตัวเลขต่อเนื่องyต่อเนื่องข้อมูลดิบ 30 ถึง 300 จุดต่อกลุ่มกำลังดี

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

  1. ตัดค่าว่างออก
  2. เลือก bandwidth ของครึ่งไวโอลิน
  3. จัดพื้นที่ให้ทั้งสามชั้นไม่ทับกัน

ค่าที่หายไป — ตัดค่าว่างและรายงานจำนวน เพราะผู้อ่านจะนับจุดฝนได้

สเกลของแกน — linear และทุกกลุ่มใช้สเกลเดียวกัน

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

เกิน 500 จุดต่อกลุ่ม ชั้นจุดจะทับกันจนไม่ช่วยอะไร

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

group,value

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

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

  • รูปร่างการกระจายจากเมฆ
  • ค่าสรุปจากกล่อง
  • จำนวนและตำแหน่งข้อมูลจริงจากฝน

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

  • ยังไม่บอกว่าความต่างมีนัยสำคัญทางสถิติหรือไม่
  • ไม่เหมาะกับการเทียบหลายกลุ่มพร้อมกัน

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

  1. ดูกล่องก่อนเพื่ออ่านค่าสรุป
  2. ดูเมฆเพื่อตรวจรูปร่าง
  3. ดูฝนเพื่อยืนยันว่ามีข้อมูลจริงกี่จุด

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

  • กลุ่มไหนดีกว่าและมั่นใจแค่ไหน
  • ค่าสรุปที่เห็นมาจากข้อมูลกี่จุด
  • มีรูปร่างแปลก ๆ ซ่อนอยู่ไหม

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

  • ชั้นจุดหนาแน่นจนทับกันและนับไม่ได้
  • ไม่มีกล่องทำให้อ่านค่าสรุปไม่ได้

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

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

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

  1. เขียนจำนวนข้อมูลของแต่ละกลุ่ม
  2. อธิบายว่าเมฆคือความหนาแน่นและฝนคือข้อมูลจริง
  3. ระบุ bandwidth ที่ใช้

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

<กลุ่ม> สูงกว่า <กลุ่ม> โดยรูปร่างการกระจายและจำนวนข้อมูลแสดงไว้ครบในภาพ

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

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

# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด raincloud-plot-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg")   # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import numpy as np

C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a"   # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"

df = pd.read_csv("raincloud-plot-sample.csv")
df["value"] = pd.to_numeric(df["value"], errors="coerce")
NOTE = "layers"   # ← ค่าจาก Playground

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

groups = list(df["group"].unique())
rng = np.random.default_rng(42)
for i, g in enumerate(groups):
    v = df[df["group"] == g]["value"]
    parts = ax.violinplot([v], positions=[i], widths=0.7, showextrema=False)
    for b in parts["bodies"]:                                   # ตัดเหลือครึ่งบน = เมฆ
        b.get_paths()[0].vertices[:, 0] = np.clip(b.get_paths()[0].vertices[:, 0], i, i + 0.4)
        b.set_facecolor("#9ec5f4"); b.set_alpha(0.7)
    ax.boxplot([v], positions=[i - 0.06], widths=0.1, showfliers=False)   # กล่องสรุป
    ax.scatter(np.full(len(v), i - 0.28) + rng.uniform(-0.06, 0.06, len(v)), v,
               s=14, alpha=0.5, color=C1)                        # ฝน = ข้อมูลจริง
ax.set_xticks(range(len(groups))); ax.set_xticklabels(groups)

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

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

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

ข้อมูลตัวอย่าง · 200 แถว · seed 101● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
เมฆคือรูปร่าง กล่องคือสถิติ ฝนคือข้อมูลจริง
สาขา Aสาขา Bสาขา Cสาขา D
50.060.070.080.090.0สาขา Aสาขา Bสาขา Cสาขา Dสาขา A · มัธยฐาน 57.2 · IQR 54.8–59.4 · n=50สาขา B · มัธยฐาน 66.3 · IQR 62.7–70.6 · n=50สาขา C · มัธยฐาน 61.6 · IQR 60.2–64.1 · n=50สาขา D · มัธยฐาน 73.7 · IQR 69.3–76.6 · n=50
กลุ่มที่มัธยฐานสูงสุดสาขา D
กลุ่มที่กระจายมากสุดสาขา B
จำนวนกลุ่ม4
ดูข้อมูลเป็นตาราง (4 แถว)
raincloud plot 4 กลุ่ม
กลุ่มnต่ำสุดQ1มัธยฐานQ3สูงสุด
สาขา A5050.054.857.259.463.6
สาขา B5055.962.766.370.676.6
สาขา C5055.660.261.664.168.1
สาขา D5064.469.373.776.684.9

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

  • สังเกตอะไร: ตรวจสอบข้ามชั้น ลองดูว่ารูปร่างของเมฆสอดคล้องกับที่จุดฝนกระจุกอยู่ไหม ถ้าไม่สอดคล้อง แปลว่า bandwidth ของเมฆกว้างเกินไป

ข้อควรระวัง

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

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

  • มีกลุ่มมากกว่า 5 กลุ่มใช้แทน: box-plot หรือ violin-plot
  • พื้นที่จำกัดใช้แทน: box-plot
  • ข้อมูลมากกว่า 500 จุดต่อกลุ่มใช้แทน: violin-plot

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

เทคนิคถัดไป · แผนภาพกระจาย