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

กราฟสัญลักษณ์Glyph Plot

ทำให้แต่ละรายการมีลายเซ็นทางภาพของตัวเอง

4
ขั้นสูงควรรู้ก่อน · เข้าใจว่าช่องทางการเข้ารหัสมีความไวต่างกัน
ลองเล่น

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

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

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

เหมือนป้ายทะเบียนที่แต่ละคันมีลายเฉพาะ ซึ่งจำและแยกได้เร็วแม้จะไม่ได้อ่านตัวอักษรทีละตัว

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

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

  1. ขั้นที่ 1★ ปรับทุกตัวแปรเป็นสเกลเดียวกัน
  2. ขั้นที่ 2เลือกช่องทางที่มีความไวใกล้เคียงกัน
  3. ขั้นที่ 3วางสัญลักษณ์เรียงเป็นตารางตามเกณฑ์ที่มีความหมาย
  4. ขั้นที่ 4ใส่สัญลักษณ์อ้างอิงที่แสดงค่ากลางไว้เทียบ

ตัวอย่างคลาสสิก · Chernoff faces และการใช้ใบหน้าแทนข้อมูล

Herman Chernoff เสนอในปี 1973 ให้เข้ารหัสตัวแปรเป็นลักษณะของใบหน้า โดยอาศัยว่าคนจำและแยกใบหน้าได้เก่งเป็นพิเศษ แนวคิดนี้ถูกวิจารณ์อย่างหนักเพราะลักษณะใบหน้าแต่ละอย่างมีน้ำหนักทางอารมณ์ไม่เท่ากัน แต่ก็เป็นตัวอย่างที่ชัดที่สุดของหลักการที่ว่าการเลือกช่องทางคือการเลือกว่าตัวแปรไหนจะเด่น

Wikipedia · Chernoff faces

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

บางครั้งคำถามไม่ใช่ค่าเท่าไร แต่เป็นรายการไหนที่หน้าตาไม่เหมือนพวก ซึ่งเป็นงานที่สายตาคนเก่งมาก

Glyph plot ตอบโจทย์นั้นด้วยการทำให้แต่ละรายการมีรูปร่างของตัวเอง โดยเอาหลายตัวแปรมาควบคุมส่วนต่าง ๆ ของสัญลักษณ์

เมื่อวางเรียงเป็นตาราง ผู้อ่านจะกวาดสายตาได้เร็วมากและสะดุดกับสัญลักษณ์ที่ต่างจากเพื่อนบ้านทันที ซึ่งเร็วกว่าการอ่านตารางตัวเลขหลายเท่า

ปัญหาข้อแรกคืออ่านค่าไม่ได้เลย เพราะไม่มีแกนและไม่มีสเกลให้เทียบ ภาพนี้จึงบอกได้แค่ว่ารายการนี้ต่างจากรายการอื่น แต่บอกไม่ได้ว่าต่างกันเท่าไรและต่างที่มิติไหนกันแน่

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

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

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

รูปทรงของข้อมูลตารางแบบกว้าง (หนึ่งแถวหนึ่ง entity)
จำนวนมิติที่เข้ารหัสได้5 มิติ
จำนวนแถวที่เหมาะ8–40 รายการ กับ 4–6 มิติขั้นต่ำ 4 แถว
เส้นฐานศูนย์ต้องเริ่มที่ศูนย์ทุกช่องทางที่เข้ารหัสขนาดต้องเริ่มจากศูนย์เพื่อให้รูปร่างเทียบกันได้

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
itemรายการหมวดหมู่text5–60 รายการแต่ละรายการเป็นหนึ่งสัญลักษณ์
group
ไม่บังคับ
กลุ่มหมวดหมู่color2–6 กลุ่มใช้สีบอกกลุ่ม
ราคามิติที่เข้ารหัสตัวเลขต่อเนื่องsize3–7 มิติ★ เกินเจ็ดมิติแล้วสัญลักษณ์อ่านไม่ออก

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

  1. ★ ปรับทุกตัวแปรเป็นสเกลเดียวกัน
  2. จับคู่ตัวแปรกับช่องทางอย่างตั้งใจโดยคำนึงถึงความไว
  3. เลือกเกณฑ์เรียงสัญลักษณ์ที่มีความหมาย

ค่าที่หายไป — มิติที่ไม่มีค่าต้องทำให้เห็นชัดว่าหายไป ไม่ใช่ปล่อยให้ดูเหมือนค่าต่ำสุด

สเกลของแกน — ทุกมิติต้องใช้ช่วงเดียวกัน และควรมีสัญลักษณ์อ้างอิงที่แสดงค่ากลางไว้ให้เทียบ

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

เกิน 60 รายการหรือเกิน 7 มิติ สัญลักษณ์อ่านไม่ออก

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

item,group,ราคา,ความเร็ว,ความจุ,น้ำหนัก,คะแนนรีวิว
รุ่น A,รุ่นประหยัด,167,48.5,17.6,30.9,3.17
รุ่น B,รุ่นมาตรฐาน,301,55.7,30.4,20,4.09

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

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

  • รายการที่รูปร่างต่างจากพวกอย่างชัดเจน
  • กลุ่มของรายการที่รูปร่างคล้ายกัน
  • มิติที่แปรผันมากที่สุดข้ามรายการ

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

  • ★ ค่าของตัวแปรใดตัวแปรหนึ่ง เพราะอ่านจากรูปร่างซึ่งไม่มีสเกลให้อ่าน
  • ★ ตัวแปรที่จับคู่กับช่องทางที่อ่อนไหวน้อยจะถูกมองข้าม
  • ความต่างที่ละเอียด

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

  1. อ่านคำอธิบายว่าส่วนไหนของสัญลักษณ์แทนอะไร
  2. กวาดสายตาหาสัญลักษณ์ที่ต่างจากเพื่อนบ้าน
  3. เทียบกับสัญลักษณ์อ้างอิงที่แสดงค่ากลาง

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

  • รายการไหนผิดจากพวก
  • มีรายการไหนที่โปรไฟล์คล้ายกันบ้าง
  • โปรไฟล์โดยรวมของรายการนี้เป็นอย่างไร

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

  • ไม่มีคำอธิบายว่าส่วนไหนแทนอะไร
  • ใช้เกินเจ็ดมิติ
  • จับคู่ตัวแปรสำคัญกับช่องทางที่อ่อนไหวน้อย
  • ไม่มีสัญลักษณ์อ้างอิง

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

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

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

  1. ★ ใส่สัญลักษณ์อ้างอิงพร้อมคำอธิบายว่าส่วนไหนแทนอะไร
  2. ติดชื่อรายการใต้ทุกสัญลักษณ์
  3. ทำเครื่องหมายรายการที่ผิดปกติให้เด่น

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

โปรไฟล์ <จำนวน> รายการใน <จำนวน> มิติ โดย <รายการ> ต่างจากพวกมากที่สุด

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

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

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

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

df = pd.read_csv("glyph-plot-sample.csv")
df["ราคา"] = pd.to_numeric(df["ราคา"], errors="coerce")
df["ความเร็ว"] = pd.to_numeric(df["ความเร็ว"], errors="coerce")
df["ความจุ"] = pd.to_numeric(df["ความจุ"], errors="coerce")
df["น้ำหนัก"] = pd.to_numeric(df["น้ำหนัก"], errors="coerce")
df["คะแนนรีวิว"] = pd.to_numeric(df["คะแนนรีวิว"], errors="coerce")
NOTE = "channel"   # ← ค่าจาก Playground

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

dims = ["ราคา", "ความเร็ว", "ความจุ", "น้ำหนัก", "คะแนนรีวิว"]
norm = df[dims].apply(lambda c: (c - c.min()) / (c.max() - c.min()))   # ★ สเกลเดียวกัน
cols = 4
for i, (_, r) in enumerate(norm.head(12).iterrows()):
    cx, cy = (i % cols) * 2.2, -(i // cols) * 2.2
    for j, v in enumerate(r):
        a = j / len(dims) * 2 * np.pi
        ax.plot([cx, cx + np.cos(a) * v], [cy, cy + np.sin(a) * v],
                color=C1, linewidth=2.4)                # ก้าน = หนึ่งมิติ
    ax.add_patch(plt.Circle((cx, cy), 1.0, fill=False, edgecolor="#e2e0da"))
    ax.text(cx, cy - 1.3, df["item"].iloc[i], ha="center", fontsize=8)
ax.set_aspect("equal"); ax.autoscale_view(); ax.axis("off")

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

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

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

ข้อมูลตัวอย่าง · 12 แถว · seed 197● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ช่องทางไม่เท่ากัน
ราคาความเร็วความจุน้ำหนักคะแนนรีวิว
รุ่น Aรุ่น Aรุ่น Bรุ่น Bรุ่น Cรุ่น Cรุ่น Dรุ่น Dรุ่น Eรุ่น Eรุ่น Fรุ่น Fรุ่น Gรุ่น Gรุ่น Hรุ่น Hรุ่น Iรุ่น Iรุ่น Jรุ่น Jรุ่น Kรุ่น Kรุ่น Lรุ่น L

ต้องเรียนรู้วิธีอ่านก่อนใช้ — คนอ่านต้องจำได้ว่าก้านไหนคือตัวแปรไหน

ตัวแปรต่อ glyph5
จำนวน glyph12
ความยาวก้านแปรตามค่าที่ปรับสเกลแล้ว
ดูข้อมูลเป็นตาราง (12 แถว)
glyph plot 12 รายการ 5 ตัวแปร
รายการราคาความเร็วความจุน้ำหนักคะแนนรีวิว
รุ่น A16748.517.630.93.17
รุ่น B30155.730.420.04.09
รุ่น C39376.143.617.24.14
รุ่น D19538.221.929.53.20
รุ่น E30457.435.123.33.82
รุ่น F43267.938.515.44.47
รุ่น G18642.818.530.03.04
รุ่น H30249.324.125.93.67
รุ่น I39677.544.118.24.41
รุ่น J17339.019.727.53.50
รุ่น K30860.034.222.13.82
รุ่น L42079.146.419.74.27

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

  • สังเกตอะไร: สังเกตว่าความยาวของก้านสะดุดตากว่าความต่างของมุม — ตัวแปรที่จับคู่กับความยาวจึงดูสำคัญกว่าโดยที่ไม่มีใครตั้งใจ

ข้อควรระวัง

  1. ★ จับคู่ตัวแปรกับช่องทางโดยไม่คิด ทำให้ตัวแปรที่อยู่ในช่องทางที่อ่อนไหวมากดูสำคัญกว่าโดยไม่ตั้งใจ
  2. ใช้เกินเจ็ดมิติจนสัญลักษณ์อ่านไม่ออก
  3. ไม่ปรับทุกตัวแปรเป็นสเกลเดียวกัน
  4. ไม่ใส่สัญลักษณ์อ้างอิง ทำให้ไม่มีอะไรให้เทียบ

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

  • ต้องอ่านค่าของแต่ละมิติใช้แทน: heatmap-matrix หรือ tableplot
  • มีรายการมากกว่า 60 รายการใช้แทน: parallel-coordinates หรือ embedding-projection
  • มีรายการน้อยกว่า 4 รายการใช้แทน: radar-chart หรือ grouped-bar

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

เทคนิคถัดไป · เทเบิลพล็อต