R Reactive values - 唯一添加到列表

时间:2016-09-15 10:15:43

标签: r shiny reactive-programming

对于来自不同编程语言背景的人来说,反应值可能是一种诅咒;) 未来的任务(简化为SO) - 我想在新国家位于地图边界内时下载新文件。在下面的示例中,您需要一个shapefile,例如:http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip UI尽可能简单:

library(leaflet)
library(shiny)
fluidPage(leafletOutput("mymap"))

服务器并不过分复杂(但是;)

library(shiny)
library(DT)
library(leaflet)
library(rgdal)
library(maptools)
library(rgeos)

countries<- readShapeSpatial("TM_WORLD_BORDERS_SIMPL-0.3.shp")

displayed<-c("United Kingdom")

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

 output$mymap <- renderLeaflet({
    leaflet(countries) %>%
      addTiles() %>%
      setView(lng=-0.1294984,lat=51.4992921,zoom=10)

})

pointsInBounds <- reactive({
    if (is.null(input$mymap_bounds))
      return(NULL)
    bounds <- input$mymap_bounds
    N<- bounds$north
    S<-bounds$south
    E<-bounds$east
    W<-bounds$west
    BB = matrix(c(W,E,E,W,W,N,N,S,S,N), nrow=5,ncol=2)
    BB = SpatialPolygons(list(Polygons(list(Polygon(BB)),1)))
    as.vector(countries[which(gIntersects(countries,BB,byid=TRUE)),]$NAME)
  })}

因此pointsinbounds()告诉我哪些国家/地区可见,displayed是已下载内容的列表(以避免重新下载)。 我想要实现的是添加(并保持)pointsinbounds()displayed列表并观察displayed列表是否发生变化(仅在新国家位于边界内时触发下载) 。我设法通过unique(c(displayed,pointsinbounds()))添加到列表中,但它不会永久存储它 - 当我离开法国时,它会从列表中删除法国。同样,只要pointsinbounds()更改,它就会做出反应,而我只想在总列表更改时做出反应,以避免在您移回同一个国家/地区时重新计算。 有什么想法吗?

1 个答案:

答案 0 :(得分:4)

根据您的需要,您可以使用以下两个选项之一。

1)将值存储到reactiveValues()中。在这种情况下,国家/地区列表将在该会话期间保持不变。

2)将值存储在全局值中,并且它在会话之间是持久的,并且可以在会话/用户之间访问(您可以将赋值放在global.R中)。

编辑:在选项2中,添加了用于检测新国家/地区的代码。

注意:在下面的示例中,我添加了一个控件来监控国家/地区列表。

选项1的示例

library(shiny)
library(DT)
library(leaflet)
library(rgdal)
library(maptools)
library(rgeos)


ui <- fluidPage(leafletOutput("mymap") ,
                verbatimTextOutput('myCountries'))

countries <- readShapeSpatial("TM_WORLD_BORDERS_SIMPL-0.3.shp")

displayed <- c("United Kingdom")

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


  observe({
    r$displayed <- unique(c(r$displayed, pointsInBounds())) 
  })

  output$mymap <- renderLeaflet({
    leaflet(countries) %>%
      addTiles() %>%
      setView(lng = -0.1294984,
              lat = 51.4992921,
              zoom = 10)
  })

  output$myCountries <- renderPrint({
    r$displayed 
  })


  pointsInBounds <- reactive({
    if (is.null(input$mymap_bounds)) {
      return(NULL)
    }
    bounds <- input$mymap_bounds
    N <- bounds$north
    S <- bounds$south
    E <- bounds$east
    W <- bounds$west
    BB = matrix(c(W, E, E, W, W, N, N, S, S, N), nrow = 5, ncol = 2)
    BB = SpatialPolygons(list(Polygons(list(Polygon(
      BB
    )), 1)))
    as.vector(countries[which(gIntersects(countries, BB, byid = TRUE)),]$NAME)
  })
} 

shinyApp(ui, server)

选项2的示例

library(shiny)
library(DT)
library(leaflet)
library(rgdal)
library(maptools)
library(rgeos)


ui <- fluidPage(leafletOutput("mymap") ,
                verbatimTextOutput('myCountries'))

countries <- readShapeSpatial("TM_WORLD_BORDERS_SIMPL-0.3.shp")

if (!exists('displayed')){
  displayed <<- c("United Kingdom")
}

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

  observe({   
    current.coutries <- pointsInBounds()
    new.countries    <- current.coutries[ ! (current.coutries %in% displayed) ]
    # DOWNLOAD new.countries
    displayed <<- unique(c(displayed, pointsInBounds()))   
  })

  output$mymap <- renderLeaflet({
    leaflet(countries) %>%
      addTiles() %>%
      setView(lng = -0.1294984,
              lat = 51.4992921,
              zoom = 10)
  })

  output$myCountries <- renderPrint({
    pointsInBounds()

    displayed 
  })

  observeEvent(input$mymap_bounds, {})
  pointsInBounds <- reactive({
    if (is.null(input$mymap_bounds)) {
      return(NULL)
    }
    bounds <- input$mymap_bounds
    N <- bounds$north
    S <- bounds$south
    E <- bounds$east
    W <- bounds$west
    BB = matrix(c(W, E, E, W, W, N, N, S, S, N), nrow = 5, ncol = 2)
    BB = SpatialPolygons(list(Polygons(list(Polygon(
      BB
    )), 1)))
    as.vector(countries[which(gIntersects(countries, BB, byid = TRUE)),]$NAME)
  })
} 

shinyApp(ui, server)