2019년 3월 1일 금요일

[R 강의] leaflet heatmap 그림 그리기

해양학과 학생의 요청으로 이 글을 쓰게 되었습니다.

보통 해양학과에서는 한반도와 환경변수를 같이 그릴 때 Surfer라는 프로그램을 이용한다고 합니다. 제가 확인해봐도 R의 기본 그림보다는 훨씬 예쁜 그림이 그려집니다. 문제는 Surfer를 이용해 반복적으로 그림을 그릴 때 직접 클릭을 해야해서 시간이 많이 소요됩니다. R을 이용해 Surfer 만큼 예쁜 그림을 빠르게 그리는 방법을 설명하려고 합니다.

지도 그림은 r shiny에서 자주 이용되는 leaflet을 이용하여 그리겠습니다. leaflet를 이용하면 providers에 저장되어 있는 이름을 이용해 원하는 지도 디자인을 선택할 수 있어 편리합니다. leaflet과 leaflet.extras 패키지를 설치 한 뒤 아래의 코드를 실행해봅시다.

library(leaflet)
library(leaflet.extras)

m<-leaflet(quakes) %>% addProviderTiles(providers$CartoDB) %>%
  setView(lng=179,lat=-20,zoom=4) %>%
  addHeatmap(lng = ~long, lat = ~lat, intensity = ~mag,blur = 20, max = 50, radius = 15)
m
leaflet과 leaflet.extras 패키지를 활성화 한 뒤 leaflet 함수를 이용하여 그림을 그립니다. 처음에 leaflet 안에 그리려는 데이터를 넣습니다. leaflet(데이터)  quakes는 내장되어 있는 데이터 셋으로 지진이 발생한 위도, 경도, 관련 변수들이 포함되어 있습니다.
다음으로 옵션을 추가하기 위해 %>%를 써준 뒤 addProviderTiles(providers$지도 디자인 이름)을 적습니다. 느낌적으로 지도 디자인을 정해주는 함수임을 알 수 있습니다.

그 다음으로 setView 옵션을 하나 더 추가 합니다. setView(lng=경도 값, lat=위도 값,zoom=확대 축소 정도)  setView을 추가하면 그림 파일을 만들었을 때 Viewer 탭에 있는 그림과 다르게 출력되는 것을 방지해줍니다.

마지막으로 addHeatmap은 heatmap을 그리는 함수로 addHeatmap(lng = ~데이터에서 경도 변수 이름, lat = ~데이터에서 위도 변수 이름, intensity = ~데이터에서 그리려는 변수 이름,blur = 숫자값, max = 숫자값, radius = 숫자값)  형식에 맞게 적어줍니다.

설정한 그림을 m이라는 변수에 저장했기 때문에 m을 실행하면 Rstudio Viewer 탭에 그림이 출력되는 것을 확인할 수 있습니다.



그린 그림을 png 파일로 저장해야하는데 기본적인 png 함수로는 Viewer 탭에 있는 그림을 저장할 수가 없습니다. 해결 방법은 Viewer 탭에 있는 그림을 html로 저장한 뒤 html을 다시 읽어 그림 파일로 저장하면 됩니다. 이 과정에 필요한 패키지인 htmlwidgets과 webshot을 설치합시다.

library(htmlwidgets)
library(webshot)

saveWidget(m, "m.html", selfcontained = T)
webshot("m.html", file = "m.png")
htmlwidgets과 webshot 패키지를 활성화 한 뒤 saveWidget 함수를 이용하여 Viewer 탭의 그림을 html 파일로 저장합니다. saveWidget(저장하려는 그림,"파일 경로 및 이름",selfcontained=T)  selfcontained를 F로 하면 html 파일과 관련된 폴더까지 생성되기 때문에 T로 설정합시다.

webshot으로 html 파일을 그림 파일로 생성합니다. webshot("그림 파일로 생성하려는 html 파일 경로 및 이름",file="생성하려는 그림 파일 경로 및 이름")  Viewer 탭에 있는 그림과 똑같은 그림을 얻었습니다!

PhantomJS not found. You can install it with webshot::install_phantomjs(). If it is installed, please make sure the phantomjs executable can be found via the PATH variable.
webshot 함수를 실행했을 때 다음과 같은 에러 메세지가 출력된다면 webshot::install_phantomjs()을 실행해줍니다. 파일을 추가로 다운받은 뒤 실행하면 정상적으로 작동합니다.



거의다 왔습니다. 그림을 반복적으로 생성하는 방법만 배우면 됩니다.
quakes$date<-rep(1:10,each=100)

for(i in c(1:10)){
  
  data_temp<-subset(quakes,quakes$date==i)
  
  m<-leaflet(data_temp) %>% addProviderTiles(providers$CartoDB) %>%
    setView(lng=179,lat=-20,zoom=4) %>%
    addHeatmap(lng = ~long, lat = ~lat, intensity = ~mag,blur = 20, max = 10, radius = 15)
  
  saveWidget(m, "m.html", selfcontained = T)
  
  plot_name<-sprintf("%s.png",i)
  webshot("m.html", file = plot_name)
  
  print(i)
  
}
quakes 데이터에 반복한 숫자를 넣어 date라는 변수를 만들어줍니다. 날짜에 따라 그림을 그리기 위해서 임으로 생성했습니다. 위 코드를 설명하면 아래와 같습니다.

1. Subset 함수를 이용해 날짜가 1일 때 데이터를 생성합니다.
2. 생성한 데이터를 이용해 그림을 그립니다.
3. 생성한 그림을 html 파일로 저장합니다.
4. sprintf 함수를 이용하여 1.png라는 이름을 생성해 plot_name에 저장합니다.
5. webshot 함수를 이용해 1.png 그림을 생성합니다.
6. 이 과정을 날짜가 10일 때까지 반복합니다.

다르게 그려진 10개의 그림을 확인할 수 있습니다. addHeatmap의 blur, max, radius를 변화시키면서 그림을 수정해보시길 바랍니다.


※ 참고문헌
https://rpubs.com/bhaskarvk/leaflet-heatmap
https://gis.stackexchange.com/questions/168886/r-how-to-build-heatmap-with-the-leaflet-package
https://stackoverflow.com/questions/31336898/how-to-save-leaflet-in-r-map-as-png-or-jpg-file
https://www.imsbio.co.jp/RGM/R_rdfile?f=webshot/man/webshot.Rd&d=R_CC

댓글 2개:

  1. 안녕하세요~ 혹시 히트맵의 Legend는 표시하는 방법이 없을까요?

    답글삭제
    답글
    1. https://www.patrick-wied.at/static/heatmapjs/example-legend-tooltip.html 이 링크와 같은 Legend를 원하시는거 같은데 따로 구현이 안되있는 것 같습니다. ㅠㅠ

      삭제