안녕하십니까? 웹R(web-r.org)의 운영자 문건웅입니다. 오늘부터 총 3회에 걸쳐 Kormaps 패키지를 이용한 단계구분도 쉽게 그리기라는 제목으로 글을 올리겠습니다. 내용은 다음과 같이 진행할까 합니다.

1. Kormaps 패키지 및 tmap패키지를 이용한 단계구분도 쉽게 그리기 
2. Kormaps 패키지 및 leaflet 패키지를 이용한 축소/확대 가능한 지도 쉽게 그리기 
3. Kormaps 패키지의 지도 자료와 나의 데이타 병합하기

이 패키지를 이용하여 웹 어플리케이션을 제작하는 것도 가능합니다. 다음 주소를 가보시면 이를 이용해 구현한 웹앱을 보실수 있습니다.

http://r-meta.com:3838/tmap2

Kormaps 패키지 소개

Kormaps 패키지는 한국한국행정지도 Shape파일을 R에서 사용하기 쉽도록 변환한 패키지입니다. 이 패키지를 이용하면 각종 통계자료와 행정구역을 연계하여 단계구분도(Choropleth map)을 쉽게 만들 수 있게 하기 위하여 패키지를 제작하였습니다. 한국행정지도 Shape파일은 통계지리정보서비스(sgis.go.kr)에서 제공하는 2010년 행정경계구역지도 Shape 파일을 빠른 속도로 단계구분도를 그릴 수 있도록 파일을 단순화한 후 국제규격에 맞게 형식을 변형한 후 만들었습니다. Shape파일 단순화에 대한 자세한 내용은 패키지 제작자가 쓴 “웹에서 클릭만으로 하는 R 통계분석(한나래,2015)” 책을 참조하십시요. static image를 만들고자 할 때는 tmap패키지를 이용하면 쉽게 단계구분도를 그릴 수 있으며 웹상에서 축소/확대가 가능한 단계구분도를 그리고 싶을 때는 leaflet 패키지를 이용하면 좋습니다. 또한 국가통계포털(kosis.kr)에서 제공하는 2010년 인구총조사 데이타와 지도 데이타를 합친 데이터를 제공하므로 단계구분도를 연습해보는데 도움이 될 것입니다. 패키지에서 제공하는 행정구역지도 데이터는 다음과 같습니다.

2010년 인구통계와 병합된 지도데이타도 제공됩니다.

패키지 설치하기

Kormaps 패키지는 CRAN에 등록되어 있지 않습니다. 한국행정구역 지도이기 때문에 함수에 한글이 포함되어 있어 CRAN에 등록하기 어렵습니다. 현재는 Github 에 저장되어 있으며 github에 있는 패키지를 설치하려면 먼저 devtools 패키지를 설치하여야 합니다. 이후 devtools 패키지의 install_github()함수를 이용하여 패키지를 설치합니다.

install.packages("devtools")  # 한번 설치한 경우에는 다시 설치할 필요 없습니다.
devtools::install_github("cardiomoon/Kormaps")

행정구역 지도 그리기

Kormaps 패키지와 tmap 패키지를 이용하면 단계구분도를 쉽게 그릴 수 있습니다. 먼저 시도경계지도는 다음과 같이 그립니다.

require(Kormaps)
require(tmap)


qtm(kormap1)

tm_shape함수를 쓰면 ggplot2와 유사한 문법으로 단계구분도를 쉽게 만들 수 있습니다.

tm_shape(korpopmap1) +
    tm_fill("총인구_명", thres.poly = 0) +
    tm_facets("name", free.coords=TRUE, drop.shapes=TRUE) +
tm_layout(legend.show = FALSE, title.position = c("center", "center"), title.size = 2,fontfamily="AppleGothic")

2010년 인구통계자료와 통합된 지도는 korpopmap1입니다.

korpopmap1
class       : SpatialPolygonsDataFrame 
features    : 16 
extent      : 124.5923, 130.917, 33.15783, 38.61101  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +ellps=WGS84 +datum=WGS84 +units=m +no_defs +lat_0=38N +lon_0=127E +towgs84=0,0,0 
variables   : 42
names       : SP_ID, FID, code, code1,     long,        lat, order,  hole, piece, group, id, FID.data, code.data, code.1,     name, ... 
min values  :     0,   0,   11,    11, 173977.4,   7869.813,     1, FALSE,     1,   0.1,  0,        0,        11,     11,   강원도, ... 
max values  :     9,  15,   39,    39, 422291.4, 525853.783,     1, FALSE,     1,   9.1,  9,       15,        39,     39, 충청북도, ... 

다음은 총인구_명으로 구분된 단계구분도입니다.

qtm(korpopmap1,"총인구_명")+tm_layout(fontfamily="AppleGothic")

인구통계자료에 포함된 항목은 다음과 같습니다.

colnames(korpopmap1@data)
 [1] "SP_ID"                   "FID"                    
 [3] "code"                    "code1"                  
 [5] "long"                    "lat"                    
 [7] "order"                   "hole"                   
 [9] "piece"                   "group"                  
[11] "id"                      "FID.data"               
[13] "code.data"               "code.1"                 
[15] "name"                    "name_eng"               
[17] "base_year"               "C행정구역별_읍면동"     
[19] "행정구역별_읍면동"       "시점"                   
[21] "총인구_명"               "남자_명"                
[23] "여자_명"                 "내국인_계_명"           
[25] "내국인_남자_명"          "내국인_여자_명"         
[27] "외국인_계_명"            "외국인_남자_명"         
[29] "외국인_여자_명"          "가구_계_가구"           
[31] "일반가구_가구"           "집단가구_가구"          
[33] "외국인가구_가구"         "주택_계_호"             
[35] "단독주택_호"             "아파트_호"              
[37] "연립주택_호"             "다세대주택_호"          
[39] "비거주용_건물내_주택_호" "주택이외의_거처_호"     
[41] "region"                  "code1.data"             

시/군/구 지도는 korpopmap2입니다.

qtm(korpopmap2,"총인구_명")+tm_layout(fontfamily="AppleGothic")

지도 중 일부를 선택하기 위해 다음과 같이 submap함수를 만들어보았습니다.

#' Select subdata of map
#'
#' @param map an object of class Shape(SpatialPolygonsDataFrame)
#' @param area a string of area looking for
#'
#' @return Subdata of class Shape of which code matched with area
submap <- function(map,area){
    code<-area2code(area)
    if(length(code)>0) {
        code1=paste0("^",code)
        temp=Reduce(paste_or,code1)
        mydata<-map[grep(temp,map$code),]
    }
}

#' Returns whether x is integer(0)
#'
#' @param x a numeric vector
is.integer0 <- function(x) { is.integer(x) && length(x) == 0L}

#' Paste '|' between vectors
#' @param ... one or more R objects, to be converted to character vectors.
paste_or <- function(...) {
    paste(...,sep="|")
}

#' Seek area from data areacode and returns the code
#'
#' @param area a string looking for
#'
#' @return a code if the area is found, else returns NA
area2code <- function(area){
    result<-c()
    for(i in 1:length(area)){
        pos<-grep(area[i],areacode[[2]])
        if(!is.integer0(pos)) temp<-areacode[pos,1]
        else {
            pos<-grep(area[i],areacode[[3]])
            if(!is.integer0(pos)) temp<-areacode[pos,1]
        }
        result=c(result,temp)
    }
    result
}

submap() 함수는 지도 중에서 원하는 지역만 골라서 지도를 그릴 수 있도록 해줍니다.

Seoul2=submap(korpopmap2,"서울")
qtm(Seoul2,"외국인_계_명")+tm_layout(fontfamily="AppleGothic")

읍/면/동 지도는 korpopmap3입니다. 대구시의 읍/면/동 단계구분도를 보려면 다음과 같이 합니다.

qtm(submap(korpopmap3,"대구"),"아파트_호")+tm_layout(fontfamily="AppleGothic")

서울/경기의 동별 단계구분도를 보려면 다음과 같이 합니다.

qtm(submap(korpopmap3,c("전라","광주")),"총인구_명")+
    tm_layout(title="호남지역 읍/면/동별 총인구수",fontfamily="AppleGothic")