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

กราฟขีดข้อมูลRug Plot

ขีดเล็ก ๆ ที่บอกว่าข้อมูลจริงอยู่ตรงไหน

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

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

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

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

เหมือนรอยเท้าบนหาดทรายใต้ภาพวาดของชายหาด รอยเท้าบอกว่ามีคนเดินผ่านตรงไหนจริง ๆ ส่วนภาพวาดเป็นการตีความ

ใช้ที่ไหนบ้าง — วางใต้กราฟความหนาแน่น วางที่ขอบของ scatter plot หรือใช้เดี่ยวเมื่อข้อมูลมีน้อยมาก

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

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

ตัวอย่างคลาสสิก · Rug plot เป็นชั้นเสริมมาตรฐานในหนังสือ Visualizing Data ของ Cleveland

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

William Cleveland · Visualizing Data

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

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

Rug plot แก้ด้วยการวาดขีดหนึ่งขีดต่อหนึ่งจุดข้อมูลไว้ที่ฐาน ผู้อ่านจึงเห็นด้วยตาตัวเองว่าข้อมูลจริงกระจุกตรงไหน และมีช่วงไหนที่เส้นด้านบนเป็นการประมาณล้วน ๆ

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

เมื่อใช้เดี่ยว ๆ มันเหมาะกับข้อมูลที่น้อยมากจริง ๆ เช่น 10-30 จุด ซึ่งการวาดฮิสโทแกรมจะเป็นการสรุปที่เกินความจำเป็น

ข้อจำกัดคือขีดที่ค่าเท่ากันจะทับกันสนิท ทำให้บริเวณที่หนาแน่นดูเหมือนมีข้อมูลน้อยกว่าความจริง ทางแก้คือใช้ความโปร่งใสหรือเปลี่ยนไปใช้ strip plot

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

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

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
valueค่าที่วัดได้ตัวเลขต่อเนื่องxต่อเนื่องข้อมูลดิบ หนึ่งขีดต่อหนึ่งแถว

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

  1. ตัดค่าว่างออก
  2. ตัดสินใจว่าจะวางเดี่ยวหรือเป็นชั้นเสริม
  3. ปรับความโปร่งใสตามจำนวนข้อมูล

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

สเกลของแกน — ใช้สเกลเดียวกับกราฟหลักที่มันเสริมอยู่เสมอ

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

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

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

value

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

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

  • ตำแหน่งของข้อมูลจริงทุกจุด
  • ช่วงที่ไม่มีข้อมูลเลย
  • จำนวนข้อมูลโดยประมาณ

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

  • ไม่บอกความหนาแน่นที่แม่นยำเมื่อขีดทับกัน
  • ไม่ให้ค่าสรุปใด ๆ

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

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

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

  • ข้อมูลจริงอยู่ตรงไหนบ้าง
  • มีช่วงไหนที่เส้นด้านบนเป็นการประมาณล้วน ๆ

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

  • ขีดทับกันจนกลายเป็นแถบทึบ
  • ใช้เดี่ยวกับข้อมูลจำนวนมาก

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

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

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

  1. เขียนจำนวนขีดทั้งหมด
  2. ทำเครื่องหมายค่าสรุปเช่นควอไทล์ด้วยเส้นที่สูงกว่าขีดปกติ

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

ข้อมูลจริง <จำนวน> จุด กระจุกอยู่ระหว่าง <ช่วง>

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

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

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

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

v = df["value"].dropna()
ax.plot(v, np.zeros_like(v), "|", color=C1, markersize=22, alpha=0.45, markeredgewidth=1.2)
for label, q in [("Q1", 0.25), ("มัธยฐาน", 0.5), ("Q3", 0.75)]:
    val = v.quantile(q)
    ax.plot([val, val], [-0.02, 0.02], color=INK, linewidth=1.6)   # ค่าสรุปใช้ขีดที่สูงกว่า
    ax.annotate(f"{label}\n{val:,.1f}", (val, 0.025), ha="center", fontsize=8)
ax.set_ylim(-0.06, 0.06); ax.set_yticks([]); ax.set_xlabel("ค่าที่วัดได้")

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

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

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

ข้อมูลตัวอย่าง · 80 แถว · seed 89● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ช่วงที่ไม่มีขีดคือช่วงที่ไม่มีข้อมูลจริง
50.055.060.065.070.075.0ค่าที่วัดได้ต่ำสุด 50.2Q1 59.3มัธยฐาน 62.0Q3 65.6สูงสุด 71.7

ขีดที่ทับกันสนิททำให้บริเวณหนาแน่นดูมีข้อมูลน้อยกว่าความจริง

จำนวนขีด80
ช่วง IQR6.27
ค่าซ้ำที่ทับกัน20
ดูข้อมูลเป็นตาราง (5 แถว)
rug plot 80 ค่า
สถิติค่า
ต่ำสุด50.2
Q159.3
มัธยฐาน62.0
Q365.6
สูงสุด71.7

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

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

ข้อควรระวัง

  1. ใช้เดี่ยวกับข้อมูลจำนวนมากจนขีดกลายเป็นแถบทึบ
  2. ไม่ใช้ความโปร่งใส ทำให้ประเมินความหนาแน่นผิด
  3. วางไว้ไกลจากกราฟหลักจนผู้อ่านไม่เชื่อมโยงสองอย่างเข้าด้วยกัน

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

  • มีข้อมูลมากกว่า 500 จุดใช้แทน: histogram หรือ density-plot
  • ต้องการค่าสรุปใช้แทน: box-plot
  • ต้องเทียบหลายกลุ่มใช้แทน: strip-plot

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

เทคนิคถัดไป · กราฟกล่องซ้อนชั้น