R로 지도 차트 그리기

R
GIS
통계집
최근에 정부사업의 현황과 성과를 보여주는 통계집을 작성할 일이 있었다. 그간의 사업성과에 ’24년도 현황을 더하여 업데이트 하는 일이었다. 그 중 지역별 현황의 시각화 부분을 R로 작업한 기록을 남긴다.
Author

STATAID

Published

2025.03.07

1 개요

최근에 정부사업의 현황과 성과를 보여주는 통계집을 작성할 일이 있었다. 그간의 사업성과에 ’24년도 현황을 더하여 업데이트 하는 일이었다. 그 중 지역별 현황의 시각화 부분을 R로 작업한 기록을 남긴다.

2 폴리곤과 지도

2.1 개념

지도를 그린다고 해서 뭔가 거창해보이지만 컴퓨터 입장에선 그다지 어렵지 않다. 그냥 다각형(polygon)1 그리기와 다를 것 없다:

  1. 점을 찍고,
  2. 선으로 잇고,
  3. 내부를 색칠한다.

대상이 지도이므로 사전단계가 좀 더 필요할 뿐이다:

  • 실제 세계 지도의 형태와 축척이 필요하고,
  • 지리 데이터가 구(sphere)인지 원(circle)인지 구분해주면 된다.

2.2 사전준비

근데 사실 대한민국 행정구역에 대해서는 누가 이미 다 해놨다. 실제로 내가 할 일은 이것들을 다운받고, 불러와서, 원하는대로 색만 칠하면 된다.

통계집 작업은 중앙정부 사업이므로, 17개 시·도 데이터를 다운받자. 압축을 풀면 3개의 파일이 있는데 전부 다 필요하다. 각각 이러하다:

  • ctprvn 파일명은 아마도 city 와 province, 즉, 시·도.
  • .shp 파일
    shape 파일. 다각형의 형태를 정의하는 파일로, 가장 중요하다. 지도가 세밀할수록 다각형이 복잡하고 많아지므로 용량이 커진다. 이미 시·도 파일도 용량이 아래 파일들보다 큰데 시·군·구 파일이 더 크다.
  • .shx 파일
    shape index 파일. 용량이 크고 복잡한 폴리곤 파일을 빠르게 읽고 해석할 수 있도록 도움을 주는 파일. 두 파일은 항상 같이 있어야 한다. 폴리곤 연산은 생각보다 무겁다.
  • .dbf 파일
    database 파일. 위에서 그린 다각형에 정보를 부여해준다. dbf파일이 없으면 그냥 짚신벌레 그림자다.

시·도

시·군·구

읍·면·동

3 R로 지도 차트 그리기

3.1 데이터 불러오기

폴리곤 데이터는 sf 패키지의 st_read로 불러온다. .shp 파일을 불러오면 된다. 인코딩 옵션도 넣어주자.

# install.packages("sf")
require(sf)
korea.map <- st_read("rawdata/ctprvn.shp",
                     options = c("ENCODING=EUC-KR"))

korea.map$CTPRVN_CD <- iconv(korea.map$CTPRVN_CD,
                             from = "CP949",
                             to = "UTF-8",
                             sub = NA,
                             mark = TRUE,
                             toRaw = FALSE)

아래처럼 불러와졌으면 성공. geometry 컬럼에 있는 저 숫자들이 바로 다각형의 정보다. 위에서 현실세계 지도 축척비를 누가 옮겨왔다는 바로 그거. 첫번째 컬럼 CTPRVN_CD가 한국정부에서 지정하는 시·도 코드다.

이렇게 가져온 데이터를 sf 객체라 한다. sf 객체는 기본적으로 좌표값 같은 지리적 데이터도 갖고 있고, 인구나 지명같은 비지리적 데이터도 갖고 있다. 이것들을 데이터프레임 형태로 저장하고 있다.

CTPRVN_CD CTP_ENG_NM CTP_KOR_NM geometry
11 Seoul 서울특별시 MULTIPOLYGON (((966987.2 19…
26 Busan 부산광역시 MULTIPOLYGON (((1148195 168…
27 Daegu 대구광역시 MULTIPOLYGON (((1087860 176…
28 Incheon 인천광역시 MULTIPOLYGON (((847834.8 18…
29 Gwangju 광주광역시 MULTIPOLYGON (((932712.7 16…

3.2 그림 그리기

ggplot()은 이 sf 객체를 바로 읽을 수 있다. 원래는 안됐었다. ggplot()이 읽을 수 있는 형태로 바꿔줘야 했었다. 이제는 ggplot()sf 패키지가 통합되어 geom_sf()로 바로 읽어주면 된다.

혹시 ggplot()이 아닌 다른 패키지로 그림을 그린다면 sf 객체를 데이터프레임 객체로 바꿔주어야 한다. 그럴 땐 아래의 코드를 사용하자. 물론 변환하고 나서도 ggplot()에 써도 된다. 여기서는 geom_sf()를 활용한다.

Code
# install.packages("sp")
require(sp)
korea.map.shp <- sp::as(korea.map, "Spatial")
korea.df <- ggplot2::fortify(korea.map.shp)

위에서 지도 데이터는 다각형이라고 소개했다. 아래 그림을 보면 바로 이해가 된다. 독도도 있다.

ggplot(data = korea.map) +
  geom_sf()

통계집 보고서 테마에 맞게 몇가지 간단한 수정을 해주자.

ggplot(data = korea.map) +
  geom_sf(fill = "darkgrey", color = "white", size = 2) +
  theme_void()

위에서 봤듯 sf 객체 korea.mapCTP_ENG_NM 열이 지역명이므로, 이 부분을 통해 인구구조데이터, 소득데이터 등과 연결하여 색을 칠할 수 있다. 여기서는 간단히 수도권만 색칠해보자.

capital_area <- ggplot(data = korea.map) +
  geom_sf(aes(fill = CTP_ENG_NM), color = "white", size = 0.05) +
  scale_fill_manual(values = c("Seoul" = "#8d4432",
                               "Gyeonggi-do" = "#a6633c",
                               "Incheon" = "#b6844c",
                               rep("darkgrey", 14))) +
  theme_void() +
  theme(legend.position = "none")

capital_area %>% print()

3.3 그림파일로 저장

png 파일로 저장하자.

ggsave("fig/capital_area.png",
       capital_area,
       width = 67, height = 70, dpi = 300, units = "mm")

여백이 많으니 자동으로 자르는 명령어도 넣어주자. 최대한 .hwp 파일을 안 만지고 싶다(…). magick 패키지를 사용하면 간단하게 된다.

# install.packages("magick")
require(magick)

img <- image_read("fig/capital_area.png")
img_cropped <- image_trim(img)
image_write(img_cropped, "fig/capital_area.png")

4 마무리

이렇게 필요한 지역만 잘라서 보여줄 수도 있다. 경기도가 정말 크긴 크다.

ggplot(data = korea.map %>% 
                         filter(CTPRVN_CD %in% c(11, 28, 41))) +
  geom_sf(aes(fill = CTP_ENG_NM), color = "white", size = 0.05) +
  scale_fill_manual(values = c("Seoul" = "#8d4432",
                               "Gyeonggi-do" = "#a6633c",
                               "Incheon" = "#b6844c")) +
  theme_void() +
  theme(legend.position = "none")

지도 데이터와 지도 차트 작성에는 좌표계에 대한 이해가 필요하다. 위도 및 경도, 구모양 공간데이터의 평면화 등 신경써야할 것이 많다.

물론, 통계집 정도에 들어갈 차트에는 몰라도 된다.

Footnotes

  1. poly는 ‘많이’, gon은 ’각(angle)’을 뜻한다.↩︎