การวาดแผนที่ประเทศไทยด้วย R นั้น ไม่ยากเลย เราจะใช้แพ็กเกจ geodata สำหรับดึงข้อมูลจาก GADM โดยตรงผ่าน R และใช้ sf ในการจัดการข้อมูลเชิงพื้นที่ นอกจากนี้ยังใช้ ragg เพื่อช่วยให้ ggplot2 แสดงผลฟอนต์ภาษาไทยได้อย่างสวยงามไม่เกิดปัญหาสระลอย
เรียกใช้ package ที่เกี่ยวข้อง
# ติดตั้งแพ็กเกจที่จำเป็น (รันครั้งแรกครั้งเดียว)
# install.packages(c("sf", "tidyverse", "geodata", "leaflet", "viridis", "ragg"))
library (sf)
Linking to GEOS 3.14.1, GDAL 3.12.1, PROJ 9.7.1; sf_use_s2() is TRUE
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.2.1 ✔ readr 2.2.0
✔ forcats 1.0.1 ✔ stringr 1.6.0
✔ ggplot2 4.0.3 ✔ tibble 3.3.1
✔ lubridate 1.9.5 ✔ tidyr 1.3.2
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Loading required package: terra
terra 1.9.11
Attaching package: 'terra'
The following object is masked from 'package:tidyr':
extract
library (leaflet)
library (viridis)
Loading required package: viridisLite
การดึงข้อมูลแผนที่
วิธีที่ 1: ดึงข้อมูลอัตโนมัติจาก GADM ด้วยแพ็กเกจ geodata
วิธีนี้เหมาะมากสำหรับการเขียนโค้ดที่ต้องการให้ผู้อื่นนำไปรันซ้ำได้ทันที (Reproducible Research) โดยไม่ต้องส่งไฟล์ Shapefile แนบไปด้วย
level = 1: ระดับจังหวัด (77 จังหวัด)
level = 2: ระดับอำเภอ
level = 3: ระดับตำบล
# ดึงข้อมูลระดับจังหวัด (Level 1) และแปลงเป็น sf object ทันที
th_prov_gadm <- gadm (country = "THA" , level = 1 , path = tempdir ()) |>
st_as_sf ()
Cached as: C:\Users\kanth\AppData\Local\Temp\RtmpCOWCa9/gadm/gadm41_THA_1_pk.rds
# ดึงข้อมูลระดับอำเภอ (Level 2)
th_amphoe_gadm <- gadm (country = "THA" , level = 2 , path = tempdir ()) |>
st_as_sf ()
Cached as: C:\Users\kanth\AppData\Local\Temp\RtmpCOWCa9/gadm/gadm41_THA_2_pk.rds
# ตรวจสอบข้อมูล (NAME_1 คือชื่อจังหวัดภาษาอังกฤษ, NL_NAME_1 คือชื่อภาษาไทย)
glimpse (th_prov_gadm |> select (GID_1, NAME_1, NL_NAME_1))
Rows: 77
Columns: 4
$ GID_1 <chr> "THA.1_1", "THA.2_1", "THA.3_1", "THA.4_1", "THA.5_1", "THA.…
$ NAME_1 <chr> "Amnat Charoen", "Ang Thong", "Bangkok Metropolis", "Bueng K…
$ NL_NAME_1 <chr> "จังหวัดอำนาจเจริญ", "จังหวัดอ่างทอง", "จังหวัดเชียงใหม่", "บึงกาฬ", "จัง…
$ geometry <GEOMETRY [°]> POLYGON ((104.587 15.60588,..., POLYGON ((100.3837 …
วิธีที่ 2: การใช้ไฟล์ Shapefile มาตรฐานจาก UN OCHA (HDX) (แนะนำสำหรับงานทางการ)
หากต้องการชื่อภาษาไทยและรหัส P-Code ที่อ้างอิงตามสำนักงานสถิติแห่งชาติและกรมการปกครอง 100% แนะนำให้ดาวน์โหลดไฟล์จากเว็บไซต์ Humanitarian Data Exchange (HDX) - Thailand Administrative Boundaries
เมื่อดาวน์โหลดไฟล์ .shp หรือ .gpkg มาไว้ในโปรเจกต์แล้ว สามารถอ่านเข้าสู่ R ด้วย st_read() ได้เลย:
# ตัวอย่างการอ่านไฟล์ Shapefile ที่ดาวน์โหลดมาจาก HDX
# th_prov_hdx <- st_read("data/tha_admbnda_adm1_rtsd_20220121.shp")
# คอลัมน์สำคัญในไฟล์ HDX:
# ADM1_EN = ชื่อจังหวัดภาษาอังกฤษ
# ADM1_TH = ชื่อจังหวัดภาษาไทย
# ADM1_PCODE = รหัสมาตรฐานจังหวัด (เช่น TH13 สำหรับปทุมธานี)
การสร้างแผนที่ระดับจังหวัด (Choropleth Map)
ลองนำข้อมูลระดับจังหวัดที่ได้จาก GADM มาจำลองการเชื่อมข้อมูล (Join Data) และพล็อตกราฟด้วย ggplot2
# จำลองข้อมูลตัวเลขรายจังหวัด
set.seed (2026 )
th_prov_data <- th_prov_gadm |>
mutate (
yield_index = round (runif (n (), min = 350 , max = 850 ), 1 )
)
ggplot (data = th_prov_data) +
geom_sf (aes (fill = yield_index), color = "white" , linewidth = 0.15 ) +
scale_fill_viridis_c (
option = "YlGn" ,
direction = - 1 ,
name = "ดัชนีผลผลิต (กก./ไร่)"
) +
labs (
title = "แผนที่แสดงดัชนีผลผลิตจำลองรายจังหวัด (77 จังหวัด)" ,
subtitle = "ขอบเขตการปกครองจากฐานข้อมูล GADM v4.1" ,
caption = "Source: GADM via geodata R package"
) +
theme_void () +
theme (
plot.title = element_text (face = "bold" , size = 14 ),
plot.subtitle = element_text (size = 11 , color = "gray40" ),
legend.position = "right"
)
Warning in viridisLite::viridis(n, alpha, begin, end, direction, option):
Option 'YlGn' does not exist. Defaulting to 'viridis'.
เทคนิคลดขนาดไฟล์แผนที่ระดับอำเภอด้วย rmapshaper เพื่อให้เว็บโหลดเร็ว
ข้อมูลแผนที่ระดับอำเภอของประเทศไทยมีความละเอียดของจุดพิกัด (Vertices) สูงมาก ถ้านำไปสร้าง Interactive Map ด้วย leaflet ทันที จะทำให้ไฟล์ HTML มีขนาดใหญ่และหน่วงเบราว์เซอร์ เราสามารถแก้ปัญหานี้ได้ด้วยฟังก์ชัน ms_simplify() จากแพ็กเกจ rmapshaper
เปรียบเทียบขนาดข้อมูลก่อนและหลังทำ Simplification
พารามิเตอร์ที่สำคัญของ ms_simplify() คือ: * keep: สัดส่วนจุดพิกัดที่ต้องการเก็บไว้ (ค่าตั้งต้นคือ 0.05 หรือเก็บไว้เพียง 5% ซึ่งเพียงพอสำหรับการแสดงผลบนเว็บ) * keep_shapes = TRUE: ป้องกันไม่ให้อำเภอที่มีขนาดเล็กมากๆ (เช่น เขตในกรุงเทพฯ หรือเกาะเล็กๆ) ถูกลบหายไป
# ติดตั้งแพ็กเกจ (หากยังไม่มี)
# install.packages("rmapshaper")
library (rmapshaper)
# 1. ดึงข้อมูลระดับอำเภอทั้งประเทศ (Level 2) จาก GADM
th_amphoe_full <- gadm (country = "THA" , level = 2 , path = tempdir ()) |>
st_as_sf ()
# 2. ลดขนาดด้วย ms_simplify (เก็บจุดพิกัดไว้ 5%)
th_amphoe_sim <- ms_simplify (th_amphoe_full, keep = 0.05 , keep_shapes = TRUE )
# 3. เปรียบเทียบขนาด Object ในหน่วยความจำ (Memory Size)
size_before <- format (object.size (th_amphoe_full), units = "MB" )
size_after <- format (object.size (th_amphoe_sim), units = "MB" )
tibble (
status = c ("Original" , "Simplified (5%)" ),
districts_count = c (nrow (th_amphoe_full), nrow (th_amphoe_sim)),
memory_size = c (size_before, size_after)
) |>
knitr:: kable (
col.names = c ("Status" , "Number of Districts" , "Memory Size (R)" ),
align = c ("l" , "c" , "c" )
)
Original
928
27.4 Mb
Simplified (5%)
928
2.5 Mb
เปรียบเทียบความคมชัดของเส้นขอบเขต (Visual Comparison)
ลองซูมดูพื้นที่จังหวัดปทุมธานีและพื้นที่ข้างเคียงเพื่อเปรียบเทียบว่า หลังจากลดจำนวนจุดพิกัดลงไปถึง 95% แล้ว รูปทรงของอำเภอยังคงเดิมและรอยต่อระหว่างอำเภอยังแนบสนิทกันหรือไม่
library (patchwork) # สำหรับนำกราฟ 2 รูปมาวางคู่กัน
Attaching package: 'patchwork'
The following object is masked from 'package:terra':
area
p1 <- th_amphoe_full |>
filter (
NAME_1 %in% c ("Pathum Thani" , "Nonthaburi" , "Phra Nakhon Si Ayutthaya" )
) |>
ggplot () +
geom_sf (fill = "#e5f5e0" , color = "#006d2c" , linewidth = 0.3 ) +
labs (title = paste ("Original (ทั้งประเทศ:" , size_before, ")" )) +
theme_void () +
theme (plot.title = element_text (face = "bold" , hjust = 0.5 ))
p2 <- th_amphoe_sim |>
filter (
NAME_1 %in% c ("Pathum Thani" , "Nonthaburi" , "Phra Nakhon Si Ayutthaya" )
) |>
ggplot () +
geom_sf (fill = "#e5f5e0" , color = "#006d2c" , linewidth = 0.3 ) +
labs (title = paste ("Simplified keep = 0.05 (ทั้งประเทศ:" , size_after, ")" )) +
theme_void () +
theme (plot.title = element_text (face = "bold" , hjust = 0.5 ))
p1 + p2