在Shiny (R)应用程序中更新Leaflet地图的问题

3

我正在使用Shiny,并遇到了关于Leaflet的问题。

我的目标: 我的项目的最终目标是选择特定的法国县。当选择这些县时,我会实时创建形状文件(用于在Leaflet上绘制地图所必需的)和包含所有公共数据的数据库(例如人口数量等),这些数据仅对应于这些特定的县。

我的问题: 我知道"合并"操作在Shiny App内完成得很好。但是,我的输出地图无法工作。

详情: 事实上,我在另一个.R脚本上运行了我的“合并和绘图”代码,并且它完美地工作(只定义了我想要绘制的县)。 在我的ShinyApp中,这个选择由input$choix_depa变量决定。

现在,稍微看一下代码。我有三个同时响应的脚本:global.R、ui.R和server.R(这就是Shiny的工作方式)。 对于global.R(我仅展示“有趣”的部分),我加载包含所有县的数据文件(不是形状文件!只是数据)。

setwd('path')
data_BP = read_delim(
  "database-allFrance.csv",
  ",",
  na = "empty",
  quote = "\"",
  locale = locale(encoding = 'windows-1252')
)

在 ui.R(用户界面)中,我有我的县“选择”:

shinydashboard::tabItem(tabName= "Departements", class = 'active',
           shiny::fluidPage(
           shiny::absolutePanel(
           draggable = FALSE,
           fixed = TRUE, 
           top = 60, left = "auto", right = 20, bottom = "auto",
           width = 330, height = "auto",
           wellPanel(
           shiny::h4("Départements"),
           selectizeInput(inputId = "choix_depa", label = "",multiple=TRUE,
           choices = seq(1,95))
            )
            ), textOutput("answ")
            ),

selectizeInput 是一个按钮,允许用户在 seq(1,95) 中选择一个或多个县。

而且在 server.R 文件中(最重要的文件)我有以下内容:

ObserveEvent(input$choix_depa, {
    output$answ<- renderText({
      paste("You choose", input$choix_depa)
    })
    choice=input$choix_depa
    print(choice)
    for (i in input$choix_depa){
      setwd(sprintf("path/county%s",i))

      assign(paste("contouriris",i,sep=""), readOGR(
        dsn = "contours_IRIS_BP.shp",
        layer = "contours_IRIS_BP",
        verbose = FALSE,
        encoding = 'UTF-8'
      ))
      print("modification en cours...")
      assign(paste("data_BP",i,sep=""),subset(data_BP,as.numeric(as.character(data_BP$IRIS))>=as.numeric(i)*10000000&as.numeric(as.character(data_BP$IRIS))<(as.numeric(i)+1)*10000000))

    }

    if (length(input$choix_depa)>=1){
      contours_IRIS  <- get(paste("contouriris",input$choix_depa[1],sep=""))
      data_BPC <- get(paste("data_BP",input$choix_depa[1],sep=""))
    }
    if (length(input$choix_depa)>1){
      for (i in input$choix_depa[-1]){
        contours_IRIS <- rbind(contours_IRIS,get(paste("contouriris",i,sep="")))
        data_BPC <- rbind(data_BPC,get(paste("data_BP",i,sep="")))
      }


    }
    map_WGS84 = spTransform(
      merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
      CRS("+init=epsg:4326")
    ) 
    # Correction of names :
    names(map_WGS84)[names(map_WGS84) == "TYP_IRIS.x"] <- "TYP_IRIS"
  })

您不必理解所有这些代码。在input$choix_depa变量中,您可以选择县。这种类型的变量类似于["4',"87"],如果用户在应用程序内选择了县4和87(例如)。我在计算机上有95个文件夹(每个县一个文件夹)。我使用setwd来进入正确的路径,并在contouririsK中加载“shape file”,其中K是县的编号。在前面的例子中,我们将有contouriris4countouriris87。这些形状文件合并在contours_IRIS中。我对数据文件执行相同的操作,取出与这些县相关联的数据,并将所有文件合并在data_BPC中。(如果我采用之前的例子,我们将在data_BPC中合并data_BPC4data_BPC87)。
此后,我使用两个变量(contours_IRISdata_BPC)创建map_WGS84变量(我将需要此变量进行LeafletOutput)。好的,所以,在选择要在Leaflet地图上绘制的县之后,我必须选择我感兴趣的变量。这是另一个菜单,我不在此处编写所有代码(不必要)。
observeEvent(input$choix_var_pop, {XXXXXXXXX})

用户想要在地图上绘制的变量选择在input$choix_var_pop中。 之后,我创建了我在LeafletMap中需要的特定变量:
label_reac_pop = reactive({as.character(input$choix_var_pop)})
var_reac_pop = reactive({dico$Variable[dico$Label == label_reac_pop()]})
col_reac_pop = reactive({as.character(dico$Couleur[dico$Label == label_reac_pop()])})
type_reac_pop = reactive({as.character(dico$Type[dico$Label == label_reac_pop()])})
unite_reac_pop = reactive({ifelse(as.character(type_reac_pop()) == "Pct", " %", "")})

最后,我绘制了LeafletMap:(为了清晰起见,我已经大大简化了以下代码)
output$Carte_Pop <- renderLeaflet({

      label = label_reac_pop() 
      var = var_reac_pop() 
      col = col_reac_pop() 
      type = type_reac_pop() 
      unite = unite_reac_pop() 
      values_var = map_WGS84@data[,var] 

      leaflet(map_WGS84) %>%
      addProviderTiles("CartoDB.PositronNoLabels") %>% 
      addProviderTiles("CartoDB.PositronOnlyLabels") %>% 
      setView(lng = 2.468738900000062, lat = 49.19316, zoom = 7)  %>% 
      clearShapes() %>%                       
      clearPopups() %>% 
  })

当然,我在ui.R文件中称这个输出为$Carte_Pop,以便绘制它。那么这一系列操作的结果是什么呢?就像我之前提到的那样,当该脚本"单独"运行时,而且没有choix_depa(我手动输入要合并的县,并且它们很好地合并了,地图也很好地绘制了)。但是,当我在ShinyApp上使用我的三个脚本(global.R、ui.R和server.R)时,"地图"的新值未被"保存"。例如:如果在我的alone-script(独立脚本)上选择要合并和绘制4号和87个县,那么(合并部分和绘图部分都可以正常工作)!但是,当我启动我的ShinyApp时,当我选择我想要的县(例如13和91),即使和与对应于13和91的数据成功合并,所以我认为在观察事件后创建的与13和91相符,当我要求绘制特定变量(在之后),绘制的地图不是之前创建的地图,而是旧的地图,其中包含4和87(在"alone-script"中创建的地图)......在启动ShinyApp之前!但我100%确定,在中创建的MAP是正确的。但是,ShinyApp没有"保存"这个MAP的值(而是使用旧地图的值)。那么我的问题是:我该怎么做才能绘制好的新地图(在APP内部创建)?而不是坏的老地图(在APP之前创建)?这个问题有点复杂,如果你有任何问题,请随时问!谢谢!:)
2个回答

3
总结:当您想让某些输出依赖于其他表达式时,应使用eventReactive或将对象存储在reactiveValues中,并从observeEvent中更新该对象。
好的,我已经阅读了您的问题,以下是我的想法:
ObserveEvent(input$choix_depa, {
   output$answ<- renderText({
      paste("You choose", input$choix_depa)
    })

这是不良的实践。观察者应该只用于副作用,而不是用于创建输出。应该改为:

   output$answ<- renderText({
      paste("You choose", input$choix_depa)
    })

ObserveEvent(input$choix_depa, {
....

由于renderText是对input$choix_depa具有响应性的,因此每当input$choix_depa更改时,它也会被触发。因此不需要将其放在observer中。


map_WGS84 = spTransform(
  merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
  CRS("+init=epsg:4326")
) 

什么样的对象是map_WGS84?只有当它是reactiveValue时,这才有效。否则,你不是覆盖全局变量,而是仅在函数observeEvent中覆盖本地变量。一旦observeEvent完成,全局变量map_WGS84没有改变。我想这就是问题所在。
最好的选择可能是将其作为eventReactive,而不是observeEvent,因为你希望它产生可以在其他地方使用的输出。另一个选项是将map_WGS84存储在reactiveValues表达式中,并从observeEvent中覆盖它。

0

感谢Florian提供的帮助,我将精确地描述我如何成功:

 output$answ<- renderText({
      paste("Choix départements:", input$choix_depa)
  })

 observeEvent(input$choix_depa, {
      choice=input$choix_depa
  })
  map_reactive <- eventReactive(input$choix_depa,{
     ... merging and creating contours_IRIS (shape file) 
     and data_BPC given input$choix_depa ...

     map_WGS84 = spTransform(
        merge(contours_IRIS, data_BPC, by.x = 'CODE_IRIS', by.y = 'IRIS'),
        CRS("+init=epsg:4326")
        )

     list(map = map_WGS84) 
   })

observeEvent(input$choix_var_pop, {XXXXXXXXX})

... defining variables... 

output$Carte_Pop <- renderLeaflet({
      compulsive = map_reactive()$map
      label = label_reac_pop() 
      var = var_reac_pop() 
      col = col_reac_pop() 
      type = type_reac_pop() 
      unite = unite_reac_pop() 
      values_var = compulsive@data[,var] 

      leaflet(compulsive) %>%

  })

这里的“重要”之处在于,在eventReactive末尾添加“list”,以便稍后调用“map_reactive$map”。问题解决了!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接