使用按钮单击小册子地图弹出窗口过滤反应数据

时间:2017-12-08 14:12:22

标签: r filter shiny leaflet reactive

我有一个闪亮的应用程序,向用户显示信息。每行代表一个地点,因此您可以使用两个selectInputs来过滤使用特定城市名称和区域的数据。我正在使用reactive()来过滤数据。结果数据显示在下面,信息框和地图显示每个地方的位置。

信息框有一个操作按钮,一旦点击,只显示与该框对应的标记。我正在使用leafletProxy更新我的地图。

另外,在我的地图中,我的制作人员弹出窗口包含一个动作按钮,因此我想点击该按钮,只显示与地图上的地点对应的信息框,而不显示其他信息框。当用户点击地图上的按钮时,我以为我可以再次过滤数据eventReactive,但我似乎无法做到这一点。按钮ID由lapply以动态方式生成,因此我不知道如何在observeEventeventReactive中声明该按钮。有什么建议?

下面的代码示例:

name<-sample(c('a','b','c'),replace=T,5)
area1<-sample(c(0,1),replace=T,5)
area2<-sample(c(0,1),replace=T,5)
area3<-sample(c(0,1),replace=T,5)
LAT<-runif(5,min=-26, max=-22)
LONG<-runif(5,min=-54, max=-48)
data<-data.frame(name,area1,area2,area3,LAT,LONG)

ui <- shinyUI(fluidPage(
selectInput('muni',label='Select city',
             choices=c('Show all',sort(levels(data$name)),selected=NULL)),
selectInput('area',label='Select area',
            choices=c('Show all','area1','area2','area3',selected=NULL)),
HTML('<table border="0"><tr><td style="padding: 8px">
      <a id="reset" href="#" style="text-indent: 0px;" 
      class="action-button shiny-bound-input">
      Reset</a></td></tr></table>'),
htmlOutput('box'),
leafletOutput('map')
))

server <- function (input, output, session) {

data1<-reactive({
  if (input$muni!='Show all') {
    data<-data[which(data$name==input$muni),]
    }
  if (input$area!='Show all') {
    data<-data[data[input$area]!=0,]
  }
  return(data)
})

observeEvent(input$reset, {
   updateSelectInput(session,'muni',selected='Show all')
   updateSelectInput(session,'area',selected='Show all')    
})

output$box <- renderUI({

  data<-data1()
  num<-as.integer(nrow(data))
  func_areas <- function(areas) sub(",\\s+([^,]+)$", " and \\1", 
  toString(areas))

  lapply(1:num, function(i) {
      bt <- paste0('go_btn',i)
      fluidRow(
        HTML(paste0('<div style="border: 1px solid #00000026; 
                      border-radius: 10px; padding: 10px;">
                     <span style="font-size:14px font-weight:bold;">',
                      data$name[i],' - areas: ',
                     func_areas(colnames(data[i,names(data)[2:4]])
                     [which(data[i,names(data)[2:4]]!=0)]),'</span></br>',
        actionButton(bt,'See map',icon=icon('map-marker',lib='font-awesome')),
        HTML('</div></br>')
                    )))
  })
})

output$map<-renderLeaflet({

  data<-data1()
  rownames(data)<-seq(1:nrow(data))
  pop<-paste0('<strong>',data$name,'</strong></br>',
              '<a id="info',rownames(data),'" href="#" style="text-indent: 0px;" 
               class="action-button shiny-bound-input"
              onclick="{Shiny.onInputChange(\'info',rownames(data),'\',
             (Math.random() * 1000) + 1);}">
              <i class="fa fa-info-circle"></i>Show info</a>')

  leaflet(data) %>%
    addProviderTiles("Esri.WorldTopoMap") %>% 
    setView(-51.5,-24.8,zoom=7) %>% 
    addMarkers(lng=~data$LONG,lat=~data$LAT,popup=pop)

})

lapply(1:nrow(data), function(i) {
  bt <- paste0('go_btn',i)
  observeEvent(input[[bt]], {
    data<-data1()
    rownames(data)<-seq(1:nrow(data))

    pop<-paste0('<strong>',data$name[i],'</strong></br>',
                '<a id="info',rownames(data),'" href="#" style="text-indent: 0px;" 
                class="action-button shiny-bound-input"
                onclick="{Shiny.onInputChange(\'info',rownames(data),'\',
               (Math.random() * 1000) + 1);}">
                <i class="fa fa-info-circle"></i>Show info</a>')

    leafletProxy('map',data=data,session=session) %>%
      clearMarkers() %>%
      setView(data$LONG[i],data$LAT[i],zoom=15) %>%
      addMarkers(lng=data$LONG[i],lat=data$LAT[i],popup=pop)
  })
})
}

shinyApp(ui, server)

感谢您的帮助,对不起,如果我写错了,第一次使用stackoverflow。

1 个答案:

答案 0 :(得分:0)

好吧,我并不是100%确定这是理想的行为,但我认为这足以让你有所作为,所以你可以达到你想要的效果。

我为您创建的div添加了一个ID,然后使用lapply为每个按钮创建一个单独的observeEvent。然后,observeEvent会从相应div上的show包中触发hideshinyjs

我在添加或修改的行之上添加了#added by Florianmodified by Florian,因为代码很长。我希望这有帮助!如果出现任何其他问题,请告诉我。

# Added by Florian
library(shinyjs)

name<-sample(c('a','b','c'),replace=T,5)
area1<-sample(c(0,1),replace=T,5)
area2<-sample(c(0,1),replace=T,5)
area3<-sample(c(0,1),replace=T,5)
LAT<-runif(5,min=-26, max=-22)
LONG<-runif(5,min=-54, max=-48)
data<-data.frame(name,area1,area2,area3,LAT,LONG)

ui <- shinyUI(fluidPage(
  # Added by Florian
  useShinyjs(),
  selectInput('muni',label='Select city',
              choices=c('Show all',sort(levels(data$name)),selected=NULL)),
  selectInput('area',label='Select area',
              choices=c('Show all','area1','area2','area3',selected=NULL)),
  HTML('<table border="0"><tr><td style="padding: 8px">
       <a id="reset" href="#" style="text-indent: 0px;" 
       class="action-button shiny-bound-input">
       Reset</a></td></tr></table>'),
  htmlOutput('box'),
  leafletOutput('map')
  ))

server <- function (input, output, session) {

  data1<-reactive({
    if (input$muni!='Show all') {
      data<-data[which(data$name==input$muni),]
    }
    if (input$area!='Show all') {
      data<-data[data[input$area]!=0,]
    }
    return(data)
  })

  observeEvent(input$reset, {
    updateSelectInput(session,'muni',selected='Show all')
    updateSelectInput(session,'area',selected='Show all') 

    # Added by Florian
    for (i in 1:as.integer(nrow(data)))
    {
        shinyjs::show(paste0('mydiv_',i))
    }

  })

  output$box <- renderUI({

    data<-data1()
    num<-as.integer(nrow(data))
    func_areas <- function(areas) sub(",\\s+([^,]+)$", " and \\1", 
                                      toString(areas))
    #modified by Florian: added div id
    lapply(1:num, function(i) {
      bt <- paste0('go_btn',i)
      fluidRow(
        HTML(paste0('<div id="mydiv_',i,'"; style="border: 1px solid #00000026; 
                    border-radius: 10px; padding: 10px;">
                    <span style="font-size:14px font-weight:bold;">',
                    data$name[i],' - areas: ',
                    func_areas(colnames(data[i,names(data)[2:4]])
                               [which(data[i,names(data)[2:4]]!=0)]),'</span></br>',
                    actionButton(bt,'See map',icon=icon('map-marker',lib='font-awesome')),
                    HTML('</div></br>')
        )))
    })
  })

  # Added by Florian
  lapply(1:as.integer(nrow(data)),function(x)
  {
    observeEvent(input[[paste0('go_btn',x)]], {
      logjs('Click!')
      shinyjs::show(paste0('mydiv_',x))
      for (i in 1:as.integer(nrow(data)))
      {
        if(i!=x)
        {
          shinyjs::hide(paste0('mydiv_',i))
        }
      }

    } )

  })


  output$map<-renderLeaflet({

    data<-data1()
    pop<-paste0('<strong>',data$name,'</strong></br>',
                '<a id="info" href="#" style="text-indent: 0px;" 
                class="action-button shiny-bound-input"
                onclick="{Shiny.onInputChange(\'info\', (Math.random() * 1000) + 1);}">
                <i class="fa fa-info-circle"></i>Show info</a>')

    leaflet(data) %>%
      addProviderTiles("Esri.WorldTopoMap") %>% 
      setView(-51.5,-24.8,zoom=7) %>% 
      addMarkers(lng=~data$LONG,lat=~data$LAT,popup=pop)

  })

  lapply(1:nrow(data), function(i) {
    bt <- paste0('go_btn',i)
    observeEvent(input[[bt]], {
      data<-data1()

      pop<-paste0('<strong>',data$name[i],'</strong></br>',
                  '<a id="info" href="#" style="text-indent: 0px;" 
                  class="action-button shiny-bound-input"
                  onclick="{Shiny.onInputChange(\'info\', (Math.random() * 1000) + 1);}">
                  <i class="fa fa-info-circle"></i>Show info</a>')

      leafletProxy('map',data=data,session=session) %>%
        clearMarkers() %>%
        setView(data$LONG[i],data$LAT[i],zoom=15) %>%
        addMarkers(lng=data$LONG[i],lat=data$LAT[i],popup=pop)
    })
  })
}

shinyApp(ui, server)