Trong nghiên cứu y học nhu cầu vẽ đồ thị bản đồ thường có trong những nghiên cứu dịch tễ, biểu diễn tần suất bịnh liên quan đến địa phương.
Biểu đồ Barplot cho ta ý niệm về tần suất (frequency), phần trăm, tuy nhiên thông tin về các vùng địa lí không được thể hiện. Vì thế không gợi ý cho ta mối liên quan về tần suất bệnh và địa phương.
Trong biểu đồ Barplot bên trái, các địa phương Hà Nội, Hòa Bình, Thái Nguyên và Bắc Giang nằm xa nhau. Vì thế không gợi ý cho ta mối liên hệ có thể có giữa các địa phương này với vấn đề dịch tễ đang được nghiên cứu.
Trong bản đồ bên phải, trực quan đặt cho ta câu hỏi vì sao các địa phương gần nhau ở trên đều có vấn đề dịch tễ này.
Điều đó nói lên tầm quan trọng của vẽ bản đồ trong nghiên cứu y học.
Để vẽ được bản đồ dịch tễ ta cần chuẩn bị:
Một file bản đồ bao gồm các địa phương: Đó là shapefile có đuôi là .shp. File này thường được download trên internet về. VD dùng từ khóa Vietnam Map shapefile để search và download về máy tính. Copy đường file path để giúp R đọc được nó.
Một dataset có variable về tên các địa phương (Provinces) và một variable về tần suất biến cố mà ta đang muốn biểu diễn lên bản đồ (Events).
Những R packages liên quan đến vẽ bản đồ như dưới đây.
Đọc dataset vào R
library("tmap")
library("tmaptools")
library("sf")
library("leaflet")
library("readxl")
data <- read_xlsx("D:/Vnprovinces.xlsx")
head(data)
## # A tibble: 6 x 3
## id Provinces Events
## <dbl> <chr> <dbl>
## 1 1.00 Ha Noi City|Hanoi 7.00
## 2 2.00 Thai Nguyen 3.00
## 3 3.00 Hoa Binh 1.00
## 4 4.00 Nghe An 4.00
## 5 5.00 Thai Binh 2.00
## 6 6.00 Yen Bai 3.00
Đọc bản đồ vào R
vnshapefile <- "F:/R/Data/Vietnam_shapefile_maps/National Only/Provinces.shp"
vngeo <- read_shape(file = vnshapefile, as.sf = TRUE)
Kiểm tra bản đồ đã đọc được chính xác chưa. Nếu đọc đúng, sẽ vẽ được một bản đồ trống
qtm(vngeo)
head(vngeo)
## Simple feature collection with 6 features and 7 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: 103.8718 ymin: 10.13411 xmax: 108.0788 ymax: 22.73976
## epsg (SRID): 4326
## proj4string: +proj=longlat +datum=WGS84 +no_defs
## ISOCODE_2 NAME_1 ID_2 NAME_2 VARNAME_2
## 0 VN-07 Ðông B?c 34 Tuyên Quang Tuyen Quang
## 1 VN-53 Ðông B?c 26 B?c K?n Bac Kan|Bac Can
## 2 VN-45 d?ng b?ng sông C?u Long 1 Ð?ng Tháp Dong Thap
## 3 VN-13 Ðông B?c 32 Qu?ng Ninh Quang Ninh
## 4 VN-22 B?c Trung B? 45 Ngh? An Nghe An
## 5 VN-54 Ðông B?c 25 B?c Giang Bac Giang
## TYPE_2 ENGTYPE_2 geometry
## 0 T?nh Province MULTIPOLYGON (((105.1785 22...
## 1 T?nh Province MULTIPOLYGON (((105.7406 22...
## 2 T?nh Province MULTIPOLYGON (((105.4328 10...
## 3 T?nh Province MULTIPOLYGON (((107.151 20....
## 4 T?nh Province MULTIPOLYGON (((105.7822 18...
## 5 T?nh Province MULTIPOLYGON (((106.1623 21...
Đến đây ta đã đưa được bản đồ vào R. Việc kế tiếp là kết nối dữ liệu với bản đồ.
Nhìn vào kết quả của head(vngeo) ta thấy VARNAME_2 chính là variable để kết nối với variable Provinces trong dataset. Chúng ta kết nối dữ liệu với bản đồ như sau:
vnmap <- append_data(vngeo, data, key.shp = "VARNAME_2", key.data ="Provinces")
Một message xuất hiện:
“Under coverage: 1 out of 63 shape features did not get appended data. Run under_coverage() to get the corresponding feature id numbers and key values.”
Nó cho biết có 1 địa phương không xuất hiện trong dữ liệu, chúng ta phải tìm ra địa phương này để check lại dataset bằng cách chạy under_coverage()
under_coverage()
## $result
## [1] "Under coverage: 1 out of 63 shape features did not get appended data."
##
## $call
## [1] "append_data(shp = vngeo, data = data, key.shp = \"VARNAME_2\", "
## [2] " key.data = \"Provinces\")"
##
## $id
## [1] 49
##
## $value
## [1] Quang Tri
## 63 Levels: An Giang Ba Ria - VTau|Ba Ria-Vung Tau ... Yen Bai
Trong danh sách của file bản đổ (VARNAME_2) có Quang Tri, nhưng trong dataset không có Quang Tri. Phải kiểm tra lại dataset của bạn.
Khi bạn chắc về error trên, chúng ta vẽ bản đồ:
qtm(vnmap, "Events")
Chúng ta đã có một bản đồ bằng tmaps package đầy đủ các tỉnh. Trong đó màu sắc thể hiện frequency của Events từ 0 đến 7. Trong đó dữ liệu của tỉnh Quảng Trị bị missing.
Nếu muốn tỉnh Quảng Trị không bị mất trên bản đồ, bạn mở dataset nhập vào dòng Quang Tri với Events = 0. Nhưng ở đây tôi không nhập Quang tri để muốn minh họa cho các bạn thấy khi một địa phương bị mất dữ liệu thì trên bản đồ thể hiện ra sao.
ggplot2 cho ta nhiều tính năng vẽ bản đồ sinh động hơn về màu sắc, scale về sắc độ, text…
Bây giờ chúng ta hãy thử vẽ với ggplot2
library(rgeos)
library(maptools)
library(rgdal)
library(gpclib)
library(ggplot2)
vnshapefile <- "F:/R/Data/Vietnam_shapefile_maps/National Only/Provinces.shp"
vngeo2 <- readOGR(vnshapefile)
## OGR data source with driver: ESRI Shapefile
## Source: "F:/R/Data/Vietnam_shapefile_maps/National Only/Provinces.shp", layer: "Provinces"
## with 63 features
## It has 7 fields
vngeo2 <- fortify(vngeo2, region = "VARNAME_2")
Dữ liệu đã được đọc vào R với packages khác tương hợp với ggplot2
Vẽ với ggplot2
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat)
Có những tồn tại làm cho bạn chưa thật hài lòng với bản đồ này. Chúng ta phải cải thiện màu sắc, sắc độ của nó thôi. Tỉnh Quảng Trị bị mất trong dataset nên không được thể hiện trên bản đồ.
library(scales)
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat) +
scale_fill_gradient2(low = muted("red"),
mid = "white", midpoint = 2, high = muted("blue"), limits = c(0, 7))
Màu xanh đậm thể hiện frequency cao nhất, màu nâu ngược lại, màu trắng cho freqnency trung gian. Chưa logic lắm.
Nếu bạn không thích logic này, thay vào đó logic màu sắc khác, bạn viết code như sau:
# color changing
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat) +
scale_fill_gradientn(colours = c("white","green" , "yellow", "brown", "darkred"))
Màu nâu đậm đại diện cho vùng có frequency cao nhất, màu trắng chỉ vùng có freqnency thấp nhất. Chấp nhận được.
Còn nữa, nếu bạn muốn một màu mà thôi thì thử làm như sau:
# one color
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat) +
scale_fill_gradient(low="white", high="blue")
Nếu bạn hài lòng với cách thể hiện sắc độ này thì phần tiếp theo là đưa text vào bản đồ cho dễ hiểu hơn.
library(plyr)
provincecenters <- ddply(vngeo2, .(id), summarize, clat = mean(lat), clong = mean(long))
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat) +
scale_fill_gradient(low="white", high="blue") +
geom_text(data = provincecenters, aes(x = clong, y = clat, label = id), size = 2.7)+
ggtitle("Events By Provices")
Nếu bạn muốn có 1 bản đồ không có trục x, y, không có kinh tuyến, vĩ tuyến thì bạn làm như sau:
library(ggthemes)
ggplot() + geom_map(data = data, aes(map_id = Provinces, fill = Events),
map = vngeo2) + expand_limits(x = vngeo2$long, y = vngeo2$lat) +
theme_few()+
theme(legend.position = "right",
axis.ticks = element_blank(),
axis.title = element_blank(),
axis.text = element_blank()) +
scale_fill_gradient(low="white", high="blue") +
guides(fill = guide_colorbar(barwidth = 0.6, barheight = 10)) +
geom_text(data = provincecenters, aes(x = clong, y = clat, label = id), size = 2.9)+
ggtitle("Events By Provices")
Bạn có thể thay đổi các chỉ số để có được màu sắc, font size như mong muốn.
Chúc các bạn có những trãi nghiệm thú vị.