2019년 1월 29일 화요일

[R shiny] interactive mapping 그림 legend customizing

 전에 interactive mapping 그림 만들기에 대한 글을 올린적이 있다. legend의 이름과 색깔, label 이름을 바꾸는 방법만 소개하였고 사각형을 다른 모양으로 바꾸는 방법은 설명하지 않아 설명하려한다.

 결론부터 말하자면 legend의 모양을 바꾸기 위해서는 html 코드를 작성하여 R 함수에 넣어야한다. html 코드는 도형 모양 부터 라벨까지 일일이 다 만들어야하고 위치도 각각 설정해야한다.

html 코드를 만드는 함수는 아래와 같다.

# addLegendCustom

addLegendCustom<-function(map,colors,labels,sizes,shapes,borders,ms,ml,mt,opacity = 0.4){

  make_shapes<-function(colors,sizes,borders,shapes,ms) {

    shapes<-gsub("circle", "50%", shapes)

    shapes<-gsub("square", "0%", shapes)

    paste0(colors,"; width:",sizes,"px; height:",sizes,"px; border:1px solid ",borders,"; border-radius:",shapes,";margin-left:",ms,"px",";margin-top: 7px;")

  }

  make_labels<-function(sizes,labels,ml,mt) {

    paste0("<div style='display: inline-block;height: ",sizes,"px;margin-top:",mt,"px;line-height: ",sizes, "px;margin-left:",ml,"px;'>",labels,"</div>")

  }

  legend_colors<-make_shapes(colors, sizes, borders, shapes,ms)
  legend_labels<-make_labels(sizes, labels,ml,mt)

  return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))

}
addLegendCustom 함수는 addLegendCustom(legend를 입력할 지도,도형의 색,도형의 label,도형의 크기,도형의 모양,도형 테두리 색,도형의 왼쪽 마진,label의 왼쪽 마진,label의 위쪽 마진)으로 구성되어있다.

(1) make_shapes
addLegendCustom 함수 안에 있는 make_shapes 함수는 도형을 만들고 위치를 설정하는 함수이다. make_shapes(도형의 색,도형의 크기,도형의 테두리 색,도형의 모양,도형의 왼쪽 마진)으로 구성되어있다.

안의 코드를 살펴보면 gsub 함수를 이용하여 shapes가 circle인 경우 50%, 사각형인 경우 0%으로 바꿔준다. html에서는 'border-radius: 50%' 입력시 원을 표현해준다. 'border-radius: 0%'는 사각형이다. paste0을 살펴보면 'border-radius:' 다음에 shapes 백터를 붙여 html 코드를 만든다.

paste0는 백터 순서대로 값을 붙여주는 함수이다. 예를 들면 아래와 같다.
> paste0(1:12, c("st", "nd", "rd", rep("th", 9)))

 [1] "1st"  "2nd"  "3rd"  "4th"  "5th"  "6th"  "7th"  "8th"  "9th"  "10th" "11th" "12th"
1:12에서 첫 번째 값 1, c("st", "nd", "rd", rep("th", 9))에서 첫 번째 값 'st'를 붙여서 1st를 만든다. 1:12에서 두 번째 값 2, c("st", "nd", "rd", rep("th", 9))에서 두 번째 값 'nd'를 붙여서 2nd를 만든다... 12까지 만들어준다.

paste0 안에 있는 코드를 세분화해서 설명하면 아래와 같다.
여기서 주의 할 점은 width와 height의 크기가 같지 않으면 타원이 표현된다. 위 html 코드를 변형시키면서 원하는 도형의 모양과 위치를 설정하면 된다.

(2) make_labels
make_labels 함수는 label을 만들고 위치를 설정하는 함수이다. paste0 안에 있는 코드를 세분화해서 설명하면 아래와 같다.
마찬가지로 위 html 코드를 변형시키면서 원하는 도형의 모양과 위치를 설정하면 된다.

(3) 마무리
각 변수의 값을 설정했을 때 make_shapes와 make_labels로 생성한 html 코드는 아래와 같음을 확인할 수 있다.

1) make_shapes으로 생성한 html 코드
# addLegendCustom variable
colors <- c("red","blue","blue","blue","white")
labels <- c("1000","100","10","1","1>")
sizes <- (c(log(1000+1),log(100+1),log(10+1),log(1+1),log(0.5+1))+1)*4
shapes <- c("circle","circle","circle","circle","circle")
borders <- c("red","blue","blue","blue","black")
ms<-c(0,5,9,12.5,13)
mt<-c(7,7,8,0,0)
ml<-c(0,9,18,25,23)

> legend_colors
[1] "red; width:31.6350191172609px; height:31.6350191172609px; border:1px solid red; border-radius:50%;margin-left:0px;margin-top: 7px;"    
[2] "blue; width:22.460482067365px; height:22.460482067365px; border:1px solid blue; border-radius:50%;margin-left:5px;margin-top: 7px;"    
[3] "blue; width:13.5915810911935px; height:13.5915810911935px; border:1px solid blue; border-radius:50%;margin-left:9px;margin-top: 7px;"  
[4] "blue; width:6.77258872223978px; height:6.77258872223978px; border:1px solid blue; border-radius:50%;margin-left:12.5px;margin-top: 7px;"
[5] "white; width:5.62186043243266px; height:5.62186043243266px; border:1px solid black; border-radius:50%;margin-left:13px;margin-top: 7px;"
2) make_labels로 생성한 html 코드
> legend_labels
[1] "<div style='display: inline-block;height: 31.6350191172609px;margin-top:7px;line-height: 31.6350191172609px;margin-left:0px;'>1000</div>"
[2] "<div style='display: inline-block;height: 22.460482067365px;margin-top:7px;line-height: 22.460482067365px;margin-left:9px;'>100</div>"  
[3] "<div style='display: inline-block;height: 13.5915810911935px;margin-top:8px;line-height: 13.5915810911935px;margin-left:18px;'>10</div>"
[4] "<div style='display: inline-block;height: 6.77258872223978px;margin-top:0px;line-height: 6.77258872223978px;margin-left:25px;'>1</div>" 
[5] "<div style='display: inline-block;height: 5.62186043243266px;margin-top:0px;line-height: 5.62186043243266px;margin-left:23px;'>1></div>"
마지막으로 addLegend의 colors에 legend_colors, lables에 legend_labels를 입력하고 설정사항을 추가하면 완성이다.
return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))
생성한 함수를 이용하여 맵에 legend를 그리려면 addLegend가 있던 곳에 addLegendCustom 함수를 입력하면 된다.
m <- leaflet(data=data) %>%
     setView(lng=128, lat=37 , zoom=6) %>%
     addProviderTiles(providers$CartoDB.Positron) %>%
     addLegendCustom(colors,labels,sizes,shapes,borders,ms,ml,mt)

최종 코드는 아래와 같다.
1. ui.R
library(shiny)
library(leaflet)

ui <- fluidPage(
  
  leafletOutput("map",height = 800)
  
)
2. server.R
library(shiny)
library(leaflet)

server <- function(input,output, session){
  
  output$map <- renderLeaflet({
    
    # addLegendCustom
    addLegendCustom<-function(map,colors,labels,sizes,shapes,borders,ms,ml,mt,opacity = 0.4){
      
      make_shapes<-function(colors,sizes,borders,shapes,ms) {
        
        shapes<-gsub("circle", "50%", shapes)
        shapes<-gsub("square", "0%", shapes)
        paste0(colors,"; width:",sizes,"px; height:",sizes,"px; border:1px solid ",borders,"; border-radius:",shapes,";margin-left:",ms,"px",";margin-top: 7px;")
        
      }
      
      make_labels<-function(sizes,labels,ml,mt) {
        
        paste0("<div style='display: inline-block;height: ",sizes,"px;margin-top:",mt,"px;line-height: ",sizes, "px;margin-left:",ml,"px;'>",labels,"</div>")
        
      }
      
      legend_colors<-make_shapes(colors, sizes, borders, shapes,ms)
      legend_labels<-make_labels(sizes, labels,ml,mt)
      
      return(addLegend(map, colors = legend_colors, labels = legend_labels, opacity = opacity,position="bottomleft",title="Abundance"))
      
    }
    
    ######################################################################
    
    # addLegendCustom variable
    colors <- c("red","blue","blue","blue","white")
    labels <- c("1000","100","10","1","1>")
    sizes <- (c(log(1000+1),log(100+1),log(10+1),log(1+1),log(0.5+1))+1)*4
    shapes <- c("circle","circle","circle","circle","circle")
    borders <- c("red","blue","blue","blue","black")
    ms<-c(0,5,9,12.5,13)
    mt<-c(7,7,8,0,0)
    ml<-c(0,9,18,25,23)
    
    ######################################################################
    
    m <- leaflet(data=data) %>%
         setView(lng=128, lat=37 , zoom=6) %>%
         addProviderTiles(providers$CartoDB.Positron) %>%
         addLegendCustom(colors,labels,sizes,shapes,borders,ms,ml,mt)
    
  })
  
}

결과를 확인해보면 짜임새 있게 구성된 legend를 확인할 수 있다.










※ 참고문헌
https://stackoverflow.com/questions/52812238/custom-legend-with-r-leaflet-circles-and-squares-in-same-plot-legends
https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
https://www.w3schools.com/css/tryit.asp?filename=trycss_inline-block_span1

0 개의 댓글:

댓글 쓰기