1 shapefile?

Shapefile은 확장자로 .shp을 갖고, 벡터방식으로 공간정보를 저장한다. .shp 파일은 점(Point), 선(Line), 면(Polygon) 중 하나의 속성을 갖는다. .shp 파일에서 면(polygon)을 잘라내거나 1 .shp 파일에서 면(polygon)을 합칠 수도 있다. 2

2 성남시

시군구 Shapefile에서 성남시를 추출하고, 성남시를 구성하는 중원구, 수정구, 분당구로 나눠진 것을 확인해보자. 이 단순한 작업을 위해서 대한민국 최신 행정구역(SHP) 다운로드 웹사이트에서 시군구 2019년 2월 업데이트 다운로드 기준 파일을 사용하자.

2.1 시군구 Shapefile

sf 팩키지로 시군구 shapefile을 불러온다. 그리고 나서 인코딩을 CP949에서 UTF-8으로 변경을 한다. 그리고 나서, st_read() 함수로 shapefile을 불러오게 되면 sf data.frame 객체라서 dplry 동사를 자유로이 활용할 수 있다. 따라서 SIG_KOR_NM 칼럼만 추출하여 plot() 함수로 시각화한다.

library(tidyverse)
library(sf)

sigungu_shp <- st_read("data/shapefile/SIG_201902/TL_SCCO_SIG.shp")
Reading layer `TL_SCCO_SIG' from data source `C:\work\spatial\data\shapefile\SIG_201902\TL_SCCO_SIG.shp' using driver `ESRI Shapefile'
Simple feature collection with 250 features and 3 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 746110.3 ymin: 1458754 xmax: 1387948 ymax: 2068444
epsg (SRID):    NA
proj4string:    +proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +units=m +no_defs
## 인코딩 변경
sigungu_shp$SIG_KOR_NM <- iconv(sigungu_shp$SIG_KOR_NM, from = "CP949", to = "UTF-8", sub = NA, mark = TRUE, toRaw = FALSE)

## 시각화
sigungu_shp %>% 
  filter(str_detect(SIG_CD, "^42")) %>% 
  select(SIG_KOR_NM) %>% 
  plot()

다음으로 성남시만 추출하여 동일한 방식으로 시각화한다. 이번에는 성남시관련 전체 칼럼을 지정하여 식가화 시킨다.

sungnam_shp <- sigungu_shp %>% 
  filter(str_detect(SIG_KOR_NM, "성남"))

sungnam_shp %>% 
  plot()

나중에 성남시만 별도 작업을 하는 경우를 대바하여 sungnam 디렉토리를 생성하고 sungnam.shp 파일명으로 저장시킨다.

dir.create('data/shapefile/SIG_201902/sungnam')
st_write(sungnam_shp, "data/shapefile/SIG_201902/sungnam/sungnam.shp", delete_dsn=TRUE)
Deleting source `data/shapefile/SIG_201902/sungnam/sungnam.shp' using driver `ESRI Shapefile'
Writing layer `sungnam' to data source `data/shapefile/SIG_201902/sungnam/sungnam.shp' using driver `ESRI Shapefile'
features:       3
fields:         3
geometry type:  Multi Polygon

2.2 읍면동 Shapefile

시군구 shapefile 작업을 했을 때와 동일한 방식으로 작업을 수행하는데 이번에는 읍면동 shapefile을 사용한다. 읍면동 shapefile에 시군구 정보가 빠져있다 보니 행정안전부 지방행정실 홈페이지에서 “행정동코드(전체) 및 법정동·행정동코드”을 참조하여 수정구, 중원구, 분당구를 구분하는 필드를 SIGUNGU로 추가하여 시각화를 한다.

emd_shp <- st_read("data/shapefile/EMD_201902/TL_SCCO_EMD.shp")
Reading layer `TL_SCCO_EMD' from data source `C:\work\spatial\data\shapefile\EMD_201902\TL_SCCO_EMD.shp' using driver `ESRI Shapefile'
Simple feature collection with 5047 features and 3 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 746110.3 ymin: 1458754 xmax: 1387948 ymax: 2068444
epsg (SRID):    NA
proj4string:    +proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +units=m +no_defs
## 인코딩 변경
emd_shp$EMD_KOR_NM <- iconv(emd_shp$EMD_KOR_NM, from = "CP949", to = "UTF-8", sub = NA, mark = TRUE, toRaw = FALSE)

## 성남시 행정동 코드: 4113000000
sungnam_emd_shp <- emd_shp %>% 
  mutate(SIGUNGU = case_when(str_detect(EMD_CD, "^41131") ~ "수정구",
                             str_detect(EMD_CD, "^41133") ~ "중원구",
                             str_detect(EMD_CD, "^41135") ~ "분당구")) %>% 
  filter(!is.na(SIGUNGU))

## 시각화
sungnam_emd_shp %>% 
  group_by(SIGUNGU) %>% 
  summarise(`동수` = n()) %>% 
  plot()

이번에는 분당구만 대상으로 동을 지도평면위에 시각화한다.

## 시각화
sungnam_emd_shp %>% 
  filter(SIGUNGU == "분당구") %>% 
  select(EMD_CD) %>% 
  plot()

마지막으로 성남시 시군구 읍면동까지 잘 정리된 shapefile을 저장하여 다음 교차분석을 준비한다.

## shapefile 저장
dir.create('data/shapefile/SIG_201902/sungnam')
st_write(sungnam_emd_shp, "data/shapefile/SIG_201902/sungnam/sungnam_emd.shp", delete_dsn=TRUE)
Deleting source `data/shapefile/SIG_201902/sungnam/sungnam_emd.shp' using driver `ESRI Shapefile'
Writing layer `sungnam_emd' to data source `data/shapefile/SIG_201902/sungnam/sungnam_emd.shp' using driver `ESRI Shapefile'
features:       44
fields:         4
geometry type:  Multi Polygon

2.3 시군구 읍면동 좌표계

대한민국 최신 행정구역(SHP) 다운로드로 작업한 지도파일은 proj4string: "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +units=m +no_defs"을 구글링해서 얻은 정보를 통해 EPSG:5179로 확인되고 네이버지도에서 사용중인 좌표계라고 한다. 3

st_crs(sigungu_shp)
Coordinate Reference System:
  No EPSG code
  proj4string: "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +units=m +no_defs"
st_crs(emd_shp)
Coordinate Reference System:
  No EPSG code
  proj4string: "+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +units=m +no_defs"

3 ggplot 시각화

sf 데이터프레임을 shapefile 변환시키는데 sf:::as_Spatial() 함수를 사용한다. 혹은 as(sungnam_df_shp, 'Spatial')을 사용해도 좋다. 다음으로 SpatialPolygonsDataFrame을 데이터프레임으로 변환시킨다. 이를 geom_path()로 시각화한다.

sungnam_df_shp <-  emd_shp %>% 
    mutate(SIGUNGU = case_when(str_detect(EMD_CD, "^41131") ~ "수정구",
                               str_detect(EMD_CD, "^41133") ~ "중원구",
                               str_detect(EMD_CD, "^41135") ~ "분당구")) %>% 
    filter(!is.na(SIGUNGU))

## sf 데이터프레임 --> shapefile 변환
# sungnam_emd_shp <-  sf:::as_Spatial(sungnam_df_shp$geometry)
sungnam_emd_shp <-  as(sungnam_df_shp, 'Spatial')

class(sungnam_emd_shp)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
## shapefile --> 데이터프레임 변환
sungnam_emd_df <- fortify(sungnam_emd_shp)

## ggplot 시각화
sungnam_emd_df %>% 
  ggplot(aes(x = long, y = lat, group = group)) +
    geom_path(color = 'blue', size = .2) +
    coord_fixed(1.3)

다른 방식으로 geom_polygon() 함수를 사용해서 ggplot 시각화도 가능하다.

sungnam_emd_df %>% 
  ggplot(aes(x = long, y = lat, group = group)) +
    geom_polygon(color = "white", fill="skyblue") +
    coord_fixed(1.3) +
    guides(fill=FALSE) +
    theme_void()