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

แผนที่ช่องเท่ากันTile Grid Map

ทุกเขตได้พื้นที่เท่ากัน จึงไม่มีใครครองสายตาเกินจริง

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

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

Tile grid map แทนแต่ละเขตด้วยช่องขนาดเท่ากันที่วางใกล้ตำแหน่งจริง แก้ปัญหาพื้นที่ครองสายตาแบบเดียวกับ cartogram แต่ผลลัพธ์อ่านง่ายกว่ามากเพราะทุกช่องเป็นสี่เหลี่ยมเท่ากันและใส่ตัวเลขลงในช่องได้

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

เหมือนตารางธาตุที่ตำแหน่งบอกความสัมพันธ์คร่าว ๆ แต่ทุกช่องมีขนาดเท่ากันเพื่อให้อ่านง่าย

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

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

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

ตัวอย่างคลาสสิก · Tile grid map ผลการเลือกตั้งรายรัฐของสหรัฐ

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

Wikipedia · Tile map

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

Choropleth และ cartogram อยู่คนละขั้ว อันแรกรักษารูปร่างจริงแต่พื้นที่บิดความสำคัญ อันหลังพื้นที่ถูกต้องแต่รูปร่างบิดจนอ่านยาก

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

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

ราคาที่จ่ายคือภูมิศาสตร์หายไปเกือบหมด ระยะทาง รูปร่าง และขนาดพื้นที่ไม่มีความหมายเลย เหลือแค่ความเป็นเพื่อนบ้านคร่าว ๆ

ซึ่งแปลว่ามันใช้ไม่ได้เมื่อคำถามเกี่ยวกับภูมิศาสตร์จริง เช่น อะไรกระจายตามแนวชายฝั่ง แต่ใช้ได้ดีมากเมื่อคำถามคือเขตไหนมีค่าเท่าไรและเทียบกันอย่างไร

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

รูปทรงของข้อมูลGeoJSON + ตารางค่าที่ join ด้วย key
จำนวนมิติที่เข้ารหัสได้2 มิติ
จำนวนแถวที่เหมาะ15–50 เขตขั้นต่ำ 8 แถว
เส้นฐานศูนย์ไม่เกี่ยวข้องค่าเข้ารหัสด้วยสี ไม่มีแกนค่า

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

คอลัมน์ทำหน้าที่ชนิดเข้ารหัสด้วยจำนวนค่าที่เหมาะหมายเหตุ
provinceเขตพื้นที่เชิงพื้นที่shape10–60 เขตต้องมีผังช่องที่ออกแบบไว้
region
ไม่บังคับ
ภูมิภาคหมวดหมู่row4–8 กลุ่มใช้จัดกลุ่มช่องได้
rateค่าที่วัดตัวเลขต่อเนื่องcolorต่อเนื่องใส่เป็นตัวเลขในช่องได้ด้วย

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

  1. ★ ออกแบบผังช่องหนึ่งครั้งแล้วใช้ซ้ำทุกภาพ
  2. ตรวจว่าเขตที่ติดกันจริงยังอยู่ใกล้กันในผัง
  3. เตรียมตัวย่อชื่อเขตที่สั้นพอใส่ในช่อง

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

สเกลของแกน — ใช้สเกลสีลำดับเดียว และเมื่อใส่ตัวเลขในช่องต้องตรวจความต่างของสีตัวอักษรกับพื้นหลัง

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

เกิน 60 เขต ผังช่องออกแบบให้ใกล้ตำแหน่งจริงได้ยาก

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

province,region,rate
กรุงเทพฯ,เหนือ,26.6
เชียงใหม่,อีสาน,34.7

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

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

  • เขตที่มีค่าสูงสุดและต่ำสุดโดยเทียบกันอย่างยุติธรรม
  • รูปแบบระดับภูมิภาคคร่าว ๆ
  • ค่าที่แน่นอนของทุกเขตเมื่อใส่ตัวเลขในช่อง

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

  • ★ อะไรที่เกี่ยวกับภูมิศาสตร์จริง เพราะระยะทาง รูปร่าง และขนาดถูกทิ้งไปหมด
  • รูปแบบที่ขึ้นกับลักษณะภูมิประเทศ เช่น การกระจายตามแนวชายฝั่ง

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

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

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

  • เขตไหนมีค่าสูงที่สุด
  • ค่าของเขตนี้เท่าไร
  • ภูมิภาคไหนมีค่าสูงโดยรวม

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

  • ผังช่องเปลี่ยนไปมาระหว่างภาพ
  • เขตที่ติดกันจริงอยู่ห่างกันมากในผัง
  • ตัวเลขในช่องอ่านไม่ออกเพราะสีพื้นเข้ม

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

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

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

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

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

<ตัวชี้วัด> รายเขต โดยทุกเขตแสดงด้วยช่องขนาดเท่ากัน

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

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

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

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

df = pd.read_csv("tile-grid-map-sample.csv")
df["rate"] = pd.to_numeric(df["rate"], errors="coerce")
NOTE = "equal"   # ← ค่าจาก Playground

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

# GRID = {"กรุงเทพ": (4, 2), ...} ผังช่องที่ออกแบบไว้ล่วงหน้า
norm = plt.Normalize(df["rate"].min(), df["rate"].max())
cmap = plt.get_cmap("Blues")
for _, r in df.iterrows():
    col, row = GRID[r["province"]]
    c = cmap(norm(r["rate"]))
    ax.add_patch(plt.Rectangle((col, -row), 0.94, 0.94, facecolor=c, edgecolor="#fcfcfb"))
    ax.text(col + 0.47, -row + 0.58, r["province"][:4], ha="center", fontsize=8,
            color="#fff" if norm(r["rate"]) > 0.55 else "#22201c")
    ax.text(col + 0.47, -row + 0.28, f"{r['rate']:.0f}", ha="center", fontsize=9,
            color="#fff" if norm(r["rate"]) > 0.55 else "#22201c")   # ใส่ตัวเลขได้ = จุดแข็ง
ax.set_aspect("equal"); ax.autoscale_view(); ax.axis("off")

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

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

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

ข้อมูลตัวอย่าง · 16 แถว · seed 331● คำนวณใหม่ในเบราว์เซอร์ทันทีที่ปรับค่า
ทุกเขตได้พื้นที่เท่ากัน
กรุงเทพฯ26.6กรุงเทพฯ · 26.6 ต่อประชากรหมื่นคนเชียงใหม34.7เชียงใหม่ · 34.7 ต่อประชากรหมื่นคนขอนแก่น32.7ขอนแก่น · 32.7 ต่อประชากรหมื่นคนชลบุรี34.4ชลบุรี · 34.4 ต่อประชากรหมื่นคนภูเก็ต26.8ภูเก็ต · 26.8 ต่อประชากรหมื่นคนนครราชสี18.3นครราชสีมา · 18.3 ต่อประชากรหมื่นคนสงขลา10.4สงขลา · 10.4 ต่อประชากรหมื่นคนอุดรธานี23.1อุดรธานี · 23.1 ต่อประชากรหมื่นคนสุราษฎร์20.1สุราษฎร์ธานี · 20.1 ต่อประชากรหมื่นคนพิษณุโลก17.9พิษณุโลก · 17.9 ต่อประชากรหมื่นคนระยอง17.4ระยอง · 17.4 ต่อประชากรหมื่นคนนครปฐม10.5นครปฐม · 10.5 ต่อประชากรหมื่นคน10.434.7

ต้องใช้กับอัตราหรือสัดส่วนเท่านั้น ถ้าใช้กับจำนวนดิบ พื้นที่ที่มีประชากรมากจะเข้มเสมอ

สูงสุดเชียงใหม่ · 34.7
ค่าเฉลี่ย22.7
จำนวนพื้นที่12
ดูข้อมูลเป็นตาราง (12 แถว)
แผนที่ 12 พื้นที่ ค่าสูงสุดที่ เชียงใหม่
จังหวัดภูมิภาคค่า (ต่อประชากรหมื่นคน)
กรุงเทพฯเหนือ26.6
เชียงใหม่อีสาน34.7
ขอนแก่นกลาง32.7
ชลบุรีตะวันออก34.4
ภูเก็ตตะวันตก26.8
นครราชสีมาใต้18.3
สงขลาเหนือ10.4
อุดรธานีอีสาน23.1
สุราษฎร์ธานีกลาง20.1
พิษณุโลกตะวันออก17.9
ระยองตะวันตก17.4
นครปฐมใต้10.5

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

  • สังเกตอะไร: เทียบกับหน้า choropleth-map ที่ใช้ข้อมูลชุดเดียวกัน จะเห็นว่าที่นี่ไม่มีเขตไหนครองสายตาเพราะพื้นที่ใหญ่

ข้อควรระวัง

  1. เปลี่ยนผังช่องไปมาระหว่างภาพ ทำให้ผู้อ่านหาเขตที่คุ้นเคยไม่เจอ
  2. วางเขตที่ติดกันจริงไว้ห่างกันในผัง ทำให้สัญชาตญาณเชิงพื้นที่ใช้ไม่ได้
  3. ไม่ใส่ตัวเลขในช่องทั้งที่มีที่พอ ซึ่งเป็นการทิ้งข้อได้เปรียบหลักไป
  4. ใช้ตอบคำถามที่เกี่ยวกับภูมิศาสตร์จริง

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

  • คำถามเกี่ยวกับภูมิศาสตร์จริง เช่น ระยะทางหรือชายฝั่งใช้แทน: choropleth-map
  • ต้องการให้พื้นที่แทนค่าใช้แทน: cartogram
  • มีเขตมากกว่า 60 เขตใช้แทน: horizontal-bar เรียงตามค่า

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

เทคนิคถัดไป · แท่งคลาดเคลื่อน