在Shiny应用程序中的地图中仅选择一个州 [英] Select only one state in a map in a Shiny application

查看:85
本文介绍了在Shiny应用程序中的地图中仅选择一个州的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下数据集:

library(rgdal)
library(leaflet)

tmp <- tempdir()
url <- "http://personal.tcu.edu/kylewalker/data/mexico.zip"
file <- basename(url)
download.file(url, file)
unzip(file, exdir = tmp)
mexico <- readOGR(dsn = tmp, layer = "mexico", encoding = "UTF-8")

pal <- colorQuantile("YlGn", NULL, n = 5)
state_popup <- paste0("<strong>Estado: </strong>", 
                  mexico$name, 
                  "<br><strong>PIB per c?pita, miles de pesos, 2008: </strong>", 
                  mexico$gdp08)

在此数据之上,我构建了以下有光泽的应用程序:

On top of this data I build the following Shiny Application:

# load necessary packages
library(leaflet)    
library(shiny)
library(shinydashboard)


ui <- fluidPage(
  # place the contents inside a box
  shinydashboard::box(
    width = 12
    , title = "Click on the map!"
    # separate the box by a column
    , column(
      width = 2
      , shiny::actionButton( inputId = "clearHighlight"
                             , icon = icon( name = "eraser")
                             , label = "Clear the Map"
                             , style = "color: #fff; background-color: #D75453; border-color: #C73232"
      )
    )
    # separate the box by a column
    , column(
      width = 10
      , leaflet::leafletOutput( outputId = "myMap"
                                , height = 850
      )
    )
  ) # end of the box
) # end of fluid page

# create the server
server <- function( input, output, session ){

  # create foundational map
  foundational.map <- shiny::reactive({
    leaflet() %>%
      #addTiles( urlTemplate = "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png") %>%
      #setView( lng = -87.567215
      #         , lat = 41.822582
      #         , zoom = 11 ) %>%
      addProviderTiles("CartoDB.Positron") %>%
      addPolygons( data = mexico
                   , fillOpacity = 0
                   , opacity = 0.2
                   , color = "#000000"
                   , weight = 2
                   , layerId = mexico$states
                   , group = "click.list"
      )
  })

  output$myMap <- renderLeaflet({

    foundational.map()

  }) 

  click.list <- shiny::reactiveValues( ids = vector() )

  shiny::observeEvent( input$myMap_shape_click, {

    click <- input$myMap_shape_click
    click.list$ids <- c( click.list$ids, click$id )
    lines.of.interest <- mexico[ which( mexico$states %in% click.list$ids ) , ]

    if( is.null( click$id ) ){
      req( click$id )
    } else if( !click$id %in% lines.of.interest@data$id ){
      leaflet::leafletProxy( mapId = "myMap" ) %>%
        addPolylines( data = lines.of.interest
                      , layerId = lines.of.interest@data$id
                      , color = "#6cb5bc"
                      , weight = 5
                      , opacity = 1
        ) 

    } # end of if else statement

  }) # end of shiny::observeEvent({})

  shiny::observeEvent( input$clearHighlight, {

    output$myMap <- leaflet::renderLeaflet({

      click.list$ids <- NULL
      foundational.map()

    }) # end of re-rendering $myMap

  }) # end of clearHighlight action button logic

} # end of server

shiny::shinyApp( ui = ui, server = server)

这给了我一张墨西哥地图,可以在其中选择一个州.这很好.但是现在,如果我选择另一种状态,则会有多种选择.

This gives me a map of Mexico where I can select a state. This works fine. However right now if I select another state I have a multiple selections.

我想拥有的是,当我移至另一种状态时,只会选择另一种状态.

What I would like to have is that when I move to another state the ONLY that other state is selected.

关于如何在上面的代码中实现这一目标的任何想法?

Any thoughts on how to accomplish that in the code above?

推荐答案

下面是一个有效的示例.我有什么改变?

Below is a working example. What have I changed?

  • 底部有一个observeEvent(),它的主体中也重新创建了一个reactive().这是不好的做法,在这种情况下,最好使用reactiveVal().,所以我添加了名为myMap_revalreactiveVal来容纳我们的地图对象.
  • 我在observeEvent()中添加了一部分,用于为选定的多边形边框着色.现在,它首先检查click.list$ids是否为空.如果是这样,它将首先重置先前选择的多边形边框的颜色.而且,观察者现在将click.list$ids设置为刚选择的值,而不是将其添加到向量中.
  • There was an observeEvent() on the bottom that also recreated a reactive() in its body. That is bad practice, in that case it is better to use a reactiveVal(). So I added the reactiveVal named myMap_reval to hold our map object.
  • I added a part to the observeEvent() that is used to color the selected polygon border. It now first checks if the click.list$ids is empty. If so, it will first reset the color of the previously selected polygon's border. Also, the observer now sets the click.list$ids to just the newly selected value, instead of adding it to a vector.

希望这会有所帮助!

library(rgdal)
library(leaflet)

tmp <- tempdir()
url <- "http://personal.tcu.edu/kylewalker/data/mexico.zip"
file <- basename(url)
download.file(url, file)
unzip(file, exdir = tmp)
mexico <- readOGR(dsn = tmp, layer = "mexico", encoding = "UTF-8")

pal <- colorQuantile("YlGn", NULL, n = 5)
state_popup <- paste0("<strong>Estado: </strong>", 
                      mexico$name, 
                      "<br><strong>PIB per c?pita, miles de pesos, 2008: </strong>", 
                      mexico$gdp08)

# load necessary packages
library(leaflet)    
library(shiny)
library(shinydashboard)


ui <- fluidPage(
  # place the contents inside a box
  shinydashboard::box(
    width = 12
    , title = "Click on the map!"
    # separate the box by a column
    , column(
      width = 2
      , shiny::actionButton( inputId = "clearHighlight"
                             , icon = icon( name = "eraser")
                             , label = "Clear the Map"
                             , style = "color: #fff; background-color: #D75453; border-color: #C73232"
      )
    )
    # separate the box by a column
    , column(
      width = 10
      , leaflet::leafletOutput( outputId = "myMap"
                                , height = 850
      )
    )
  ) # end of the box
) # end of fluid page

# create the server
server <- function( input, output, session ){

  # function to create foundational map
  foundational.map <- function(){
    leaflet() %>%
      #addTiles( urlTemplate = "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png") %>%
      #setView( lng = -87.567215
      #         , lat = 41.822582
      #         , zoom = 11 ) %>%
      addProviderTiles("CartoDB.Positron") %>%
      addPolygons( data = mexico
                   , fillOpacity = 0
                   , opacity = 0.2
                   , color = "#000000"
                   , weight = 2
                   , layerId = mexico$state
                   , group = "click.list")
  }

  # reactiveVal for the map object, and corresponding output object.
  myMap_reval <- reactiveVal(foundational.map())
  output$myMap <- renderLeaflet({
    myMap_reval()
  }) 

  # To hold the selected map region id.
  click.list <- shiny::reactiveValues( ids = vector() )

  shiny::observeEvent( input$myMap_shape_click, ignoreNULL = T,ignoreInit = T, {

    # If already selected, first remove previous selection
    if(length(click.list)>0)
    {
      remove_id = click.list$ids
      lines.of.interest <- mexico[ which( mexico$state %in% remove_id) , ]
      leaflet::leafletProxy( mapId = "myMap" ) %>%
        addPolylines( data = lines.of.interest
                      , layerId = lines.of.interest@data$id
                      , color = "#000000"
                      , weight = 2
                      , opacity = 0.2)
    }

    # add current selection
    click <- input$myMap_shape_click
    click.list$ids <- click$id  # we only store the last click now!
    lines.of.interest <- mexico[ which( mexico$state %in% click.list$ids ) , ]
    print(click)
    if( is.null( click$id ) ){
      req( click$id )
    } else if( !click$id %in% lines.of.interest@data$id ){
      leaflet::leafletProxy( mapId = "myMap" ) %>%
        addPolylines( data = lines.of.interest
                      , layerId = lines.of.interest@data$id
                      , color = "#6cb5bc"
                      , weight = 5
                      , opacity = 1
        ) 
    }

  }) # end of shiny::observeEvent({})

  # oberver for the clearHighlight button.
  shiny::observeEvent( input$clearHighlight, {
    click.list$ids <- NULL
    myMap_reval(foundational.map()) # reset map.
  }) 

} 

shiny::shinyApp( ui = ui, server = server)

这篇关于在Shiny应用程序中的地图中仅选择一个州的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆