01ภาพรวมของกราฟนี้
Venn diagram ใช้วงกลมทับกันแทนเซต และบริเวณที่ทับซ้อนแทนสมาชิกที่อยู่ในหลายเซตพร้อมกัน จุดแข็งคือสื่อแนวคิดการทับซ้อนได้ทันทีโดยไม่ต้องอธิบาย แต่พื้นที่ของวงไม่ได้แปรตามจำนวนจริง จึงต้องมีตัวเลขกำกับเสมอ
เปรียบเทียบให้เห็นภาพ
เหมือนวงกลมสองวงที่วาดบนพื้นทรายแล้วให้คนยืนในวงที่ตรงกับตัวเอง คนที่เข้าข่ายทั้งสองอย่างก็ยืนตรงที่ทับกัน
ใช้ที่ไหนบ้าง — แสดงว่าผู้ใช้ใช้กี่ช่องทางพร้อมกัน เปรียบเทียบคุณสมบัติของสองสามกลุ่ม หรืออธิบายแนวคิดการทับซ้อนในงานนำเสนอ
สร้างอย่างไร
- ขั้นที่ 1นับสมาชิกในแต่ละชุดค่าผสมของเซต
- ขั้นที่ 2วาดวงกลมให้ทับกันครบทุกชุดค่าผสม
- ขั้นที่ 3เขียนตัวเลขในแต่ละบริเวณ
- ขั้นที่ 4ระบุจำนวนที่ไม่อยู่ในเซตใดเลย
ตัวอย่างคลาสสิก · John Venn เสนอแผนภาพนี้ในปี 1880
Venn ออกแบบเพื่ออธิบายตรรกศาสตร์เชิงเซต ไม่ได้ออกแบบมาเพื่อแสดงข้อมูลเชิงปริมาณ นี่คือเหตุผลที่วงทุกวงขนาดเท่ากัน เพราะสิ่งที่เขาต้องการสื่อคือ "ความเป็นไปได้ของการทับซ้อน" ไม่ใช่ขนาดของแต่ละส่วน
02อธิบายภาษาคนเข้าใจง่าย ๆ
เวลาอยากบอกว่ามีผู้ใช้กี่คนที่ใช้ทั้งแอปและเว็บ ตารางตัวเลขก็ทำได้ แต่แผนภาพเวนน์สื่อแนวคิด "ทับซ้อน" ได้ทันทีโดยไม่ต้องอธิบายอะไรเลย
วิธีอ่านเป็นธรรมชาติมาก วงหนึ่งคือเซตหนึ่ง บริเวณที่วงสองวงทับกันคือคนที่อยู่ในทั้งสองเซต และตรงกลางที่ทับกันหมดคือคนที่อยู่ในทุกเซต
สิ่งที่คนมักเข้าใจผิดคือขนาดของวง ในแผนภาพเวนน์มาตรฐาน วงทุกวงขนาดเท่ากันและทับกันเท่ากันเสมอไม่ว่าข้อมูลจริงจะเป็นอย่างไร ตัวเลขในแต่ละบริเวณคือสิ่งเดียวที่บอกข้อมูล
มีรูปแบบที่ปรับขนาดวงตามจำนวนจริงเรียกว่าแผนภาพออยเลอร์ แต่พอเกินสองเซตก็มักวาดให้ทับกันได้ตรงตามสัดส่วนทุกบริเวณไม่ได้ในเชิงเรขาคณิต
ข้อจำกัดที่เข้มงวดคือจำนวนเซต สามเซตยังพอวาดได้สวย แต่สี่เซตขึ้นไปต้องใช้วงรีที่บิดเบี้ยวและบางบริเวณเล็กจนเขียนตัวเลขไม่ได้ กรณีนั้นต้องเปลี่ยนไปใช้ UpSet plot
03ข้อมูลที่ต้องใช้
คอลัมน์ที่ต้องเตรียม
| คอลัมน์ | ทำหน้าที่ | ชนิด | เข้ารหัสด้วย | จำนวนค่าที่เหมาะ | หมายเหตุ |
|---|---|---|---|---|---|
id | รหัสสมาชิก | หมวดหมู่ | text | หนึ่งแถวหนึ่งสมาชิก | ใช้ระบุว่าแต่ละคนอยู่ในเซตไหนบ้าง |
แอป | อยู่ในเซตนี้หรือไม่ | หมวดหมู่ | color | 0 หรือ 1 | ★ หนึ่งคอลัมน์ต่อหนึ่งเซต และรองรับได้ดีถึง 3 เซตเท่านั้น |
ต้องเตรียมข้อมูลอย่างไรก่อนวาด
- แปลงข้อมูลเป็นคอลัมน์ศูนย์หรือหนึ่งต่อหนึ่งเซต
- นับสมาชิกในทุกชุดค่าผสม
- นับจำนวนที่ไม่อยู่ในเซตใดเลย
ค่าที่หายไป — สมาชิกที่ไม่รู้สถานะของเซตใดเซตหนึ่งต้องแยกออกและรายงาน ห้ามถือว่าไม่อยู่ในเซตนั้น
สเกลของแกน — ไม่มีสเกล ตัวเลขในแต่ละบริเวณคือข้อมูลทั้งหมด
กราฟจะเริ่มพังเมื่อไร
เกิน 3 เซต ต้องใช้วงรีบิดเบี้ยวและบางบริเวณเล็กจนเขียนตัวเลขไม่ได้ — ใช้ upset-plot
หน้าตาไฟล์ที่ต้องเตรียม
id,แอป,เว็บ,หน้าร้าน
user-001,0,1,0
user-002,1,0,0
…04อ่านแล้วเห็นอะไร
สิ่งที่เห็นได้จากภาพ
- จำนวนที่อยู่ในหลายเซตพร้อมกัน
- เซตที่ทับกันมากที่สุด
- จำนวนที่อยู่ในเซตเดียวเท่านั้น
สิ่งที่กราฟนี้ตอบไม่ได้
- ★ ขนาดของวงไม่ได้บอกจำนวนจริง ต้องอ่านจากตัวเลขเท่านั้น
- ไม่รองรับเกินสามเซต
- ไม่บอกว่าสมาชิกที่ทับซ้อนต่างจากคนอื่นอย่างไร
อ่านตามลำดับนี้
- หาบริเวณตรงกลางที่ทับกันหมดก่อน
- อ่านตัวเลขในแต่ละบริเวณ ไม่ใช่กะจากขนาด
- ดูจำนวนที่อยู่นอกทุกวงซึ่งมักเขียนไว้มุมภาพ
คำถามที่ตอบได้
- มีกี่คนที่ใช้ทั้งสองช่องทาง
- กลุ่มไหนทับกันมากที่สุด
- มีคนที่ใช้ทุกช่องทางกี่คน
สัญญาณว่ามีอะไรผิด
- ไม่มีตัวเลขในแต่ละบริเวณ ทำให้อ่านอะไรไม่ได้
- มีเกินสามเซต
- ไม่บอกจำนวนที่อยู่นอกทุกเซต
05เหมาะกับการนำเสนอแบบไหน
ทำอย่างไรให้คนอ่านได้ข้อสรุปโดยไม่ต้องบรรยาย
- เขียนตัวเลขในทุกบริเวณ รวมถึงบริเวณที่เป็นศูนย์
- เขียนจำนวนที่ไม่อยู่ในเซตใดเลยไว้มุมภาพ
- ระบุขนาดของแต่ละเซตรวมไว้ที่ป้ายชื่อ
รูปแบบชื่อกราฟที่ควรใช้
<จำนวน> จาก <ทั้งหมด> อยู่ในทั้ง <เซต> และ <เซต>
06เอาไปใช้ต่อ
โค้ดทุกชิ้นอ่านไฟล์ venn-diagram-sample.csv ชุดเดียวกับที่ Playground ใช้ และตัวเลขในโค้ดเปลี่ยนตามค่าที่คุณปรับด้านล่าง
# ติดตั้ง: pip install "matplotlib==3.10.*" "pandas==2.*"
# ดาวน์โหลด venn-diagram-sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์
import matplotlib
matplotlib.use("Agg") # รันแบบไม่มีหน้าจอ ถ้ารันในเครื่องตัวเองลบบรรทัดนี้ได้
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib_venn import venn3 # pip install matplotlib-venn
C1, C2, C3 = "#2a78d6", "#eb6834", "#1baf7a" # palette ของคลัง เปลี่ยนเป็นสีองค์กรได้
INK, SURFACE = "#0b0b0b", "#fcfcfb"
df = pd.read_csv("venn-diagram-sample.csv")
df["แอป"] = pd.to_numeric(df["แอป"], errors="coerce")
df["เว็บ"] = pd.to_numeric(df["เว็บ"], errors="coerce")
df["หน้าร้าน"] = pd.to_numeric(df["หน้าร้าน"], errors="coerce")
NOTE = "numbers" # ← ค่าจาก Playground
fig, ax = plt.subplots(figsize=(7.6, 4.2), facecolor=SURFACE)
ax.set_facecolor(SURFACE)
sets = ["แอป", "เว็บ", "หน้าร้าน"]
s = [set(df.index[df[c] == 1]) for c in sets]
v = venn3(s, set_labels=sets, ax=ax, set_colors=(C1, C2, C3), alpha=0.42)
outside = len(df) - len(s[0] | s[1] | s[2])
ax.set_title(f"ทั้งหมด {len(df)} คน · ไม่อยู่ช่องทางใดเลย {outside} คน", loc="left", fontsize=10)
# ตัวเลขในแต่ละบริเวณคือข้อมูลจริง ขนาดวงเป็นเพียงภาพประกอบ
ax.spines[["top", "right"]].set_visible(False) # ลดเส้นที่ไม่ได้ให้ข้อมูล
fig.tight_layout()
fig.savefig("venn-diagram.png", dpi=160)
print("เขียน venn-diagram.png แล้ว ·", len(df), "แถว")07ลองเล่นเพื่อเข้าใจ
พื้นที่ของวงไม่ได้แปรตามจำนวนจริง — ตัวเลขในภาพคือสิ่งที่อ่านได้ ไม่ใช่ขนาดวง เกิน 3 เซตให้ใช้ UpSet plot
ดูข้อมูลเป็นตาราง (7 แถว)
| ชุดที่อยู่ | จำนวน |
|---|---|
| แอป | 45 |
| แอป และ เว็บ | 45 |
| เว็บ | 24 |
| แอป และ เว็บ และ หน้าร้าน | 23 |
| แอป และ หน้าร้าน | 23 |
| เว็บ และ หน้าร้าน | 11 |
| หน้าร้าน | 9 |
ลองแล้วจะเห็นอะไร
- สังเกตอะไร: สังเกตว่าวงทั้งสามขนาดเท่ากันหมด ทั้งที่จำนวนสมาชิกต่างกัน — ข้อมูลทั้งหมดอยู่ที่ตัวเลข ไม่ใช่ที่ภาพ
ข้อควรระวัง
- ★ ตีความขนาดของวงว่าแทนจำนวน ทั้งที่วงทุกวงขนาดเท่ากันเสมอ
- ใช้เกินสามเซต ทำให้บางบริเวณเล็กจนเขียนตัวเลขไม่ได้
- ไม่เขียนจำนวนที่ไม่อยู่ในเซตใดเลย ทำให้ไม่รู้ว่ายอดรวมคือเท่าไร
- ไม่ใส่ตัวเลขในบางบริเวณ ทำให้ผู้อ่านต้องเดา
เมื่อไหร่ไม่ควรใช้กราฟนี้
- มีมากกว่า 3 เซต→ใช้แทน: upset-plot
- ต้องการให้ขนาดแทนจำนวนจริง→ใช้แทน: upset-plot หรือ bar-chart ของทุกชุดค่าผสม
- เป็นการแบ่งกลุ่มที่ไม่ทับซ้อนกัน→ใช้แทน: pie-chart หรือ waffle-chart