1

我试图让闪亮在用户单击操作按钮后使用滑动条值进行计算。这些滑动条代表五个维度,用户可以拖动这些维度来设置每个变量的首选权重值。单击操作按钮后,应用程序应显示荷兰地图,其中包含基于这些权重值具有最高“分数”的城市。目前我已经运行了以下代码,但是在单击操作按钮后速度非常慢,因为当反应性滑动条发生变化时它会自动重新执行。是否有人建议让我的代码更快并且操作按钮 eventReactive 以便必须单击它才能让闪亮知道进行新的计算?

因为我想不出一种更简单的方法来共享我的数据(spatialpolygonsdataframe),所以我在主脚本中包含了一个要点链接:https ://gist.github.com/anonymous/602948bce91e61f36fd3eb0c4259d26c

Shiny 应用截图:https ://i.stack.imgur.com/k0Vg9.png

应用程序.R

library(shiny)
library(leaflet)

ui <- fluidPage(
  titlePanel("Quality-of-life-o-meter of The Netherlands"),

  sidebarLayout(
    sidebarPanel(
      h3("Dimensions"),
      h6("Assign a weight value for every dimension and press the 'find!' button"),
      sliderInput("housingslider", 
                  label = h4("Housing"), 
                  min = 1, 
                  max = 5, 
                  value = 1),
      sliderInput("populationslider", 
                  label = h4("Population"), 
                  min = 1, 
                  max = 5, 
                  value = 1),
      sliderInput("provisionsslider", 
                  label = h4("Provisions"), 
                  min = 1, 
                  max = 5, 
                  value = 1),
      sliderInput("safetyslider", 
                  label = h4("Safety"), 
                  min = 1, 
                  max = 5, 
                  value = 1),
      sliderInput("physicalenvslider", 
                  label = h4("Physical Environment"), 
                  min = 1, 
                  max = 5, 
                  value = 1),
      actionButton("action", label = "Find!")
    ),
    mainPanel(
      leafletOutput("mymap", height = "800")
    )
  )
)

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

  output$mymap <-renderLeaflet({
    # Create interactive map of Total Score of Muncipalities in 2016 to display first
    leaflet(data = MunScores2016) %>% addTiles() %>%
      addPolygons(fillColor = ~pal(Total_Score_2016), 
                  fillOpacity = 1, 
                  color = 'white', 
                  weight = 1,
                  popup = popup_dat) %>%
      addLegend("bottomright", # Legend position
                pal=pal, # color palette
                values=~Total_Score_2016, # legend values
                opacity = 0.7,
                title="Percentage difference from national average")
  })  

  observeEvent(input$action,
               output$mymap <-renderLeaflet({
                 Total_Score <- NA
                 Total_Score <- ((input$housingslider * MunScores2016$Housing_Score_2016 +
                                input$populationslider * MunScores2016$Population_Score_2016 +
                                input$provisionsslider * MunScores2016$Provisions_Score_2016 +
                                input$safetyslider * MunScores2016$Safety_Score_2016 +
                                input$physicalenvslider * MunScores2016$PhysicalEnvironment_Score_2016)/
                               (input$housingslider + input$populationslider + input$provisionsslider + input$safetyslider + input$physicalenvslider))
             #Create interactive map
                 leaflet(data = MunScores2016) %>% addTiles() %>%
                   addPolygons(fillColor = ~pal(Total_Score), 
                               fillOpacity = 1, 
                               color = 'white', 
                               weight = 1,
                               popup = paste0("<strong>Municipality:</strong>", 
                                          MunScores2016$Municipality_Name, 
                                          "<br><strong>Quality-of-life-o-meter says: </strong>", 
                                          Total_Score)) %>%
                   addLegend("bottomright", # Legend position
                             pal=pal, # color palette
                             values=~Total_Score_2016, # legend values
                             opacity = 0.7,
                             title="Weighted percentage difference from national average")
               })

  )
}  
shinyApp(ui = ui, server = server)
4

1 回答 1

1

您的代码很慢,因为您在不知情的情况下不断地重新创建所有内容。


刷新

让我先解决您的滑块刷新问题:

observeEvent(实际上只有在按下按钮时才会触发),您将反应环境分配给output$mymap(所有渲染功能都是反应环境)。

renderLeaflet,您可以命名输入参数,在这种情况下,Shiny 会自动将这些输入作为 observables进行跟踪。

因此,一旦单击按钮,您对渲染函数的分配就会发生,但渲染函数本身并不限于此事件,因为反应环境的寿命比分配调用更长。

有两种方法可以将此逻辑从渲染函数中提取出来。

1)isolate在每个输入参考周围使用。(即isolate(input$housingslider))。这样你就可以抑制到输入滑块的反应链接,并且渲染 observable 将不再有更新触发器,只有在你创建它时更新一次。

output$mymap <-renderLeaflet({
  Total_Score <- NA
  # isolate(expr) prevents observables in expr from being subscribed to.
  Total_Score <- isolate(
    (
      input$housingslider * MunScores2016$Housing_Score_2016
      + input$populationslider * MunScores2016$Population_Score_2016  
      + input$provisionsslider * MunScores2016$Provisions_Score_2016 
      + input$safetyslider * MunScores2016$Safety_Score_2016
      + input$physicalenvslider * PhysicalEnvironment_Score_2016
    ) / (
      input$housingslider
      + input$populationslider
      + input$provisionsslider 
      +  input$safetyslider 
      + input$physicalenvslider
    )
  )

  ...
})

2)更好:将您的计算移到函数Total_Score 之外。renderLeaflet这样,输入的 observables 就不会在响应式环境中被命名,也就是说renderLeaflet,它只知道Total_Score它不能订阅的 value。输入的 observables 只属于外部observeEvent的,它将忽略除了操作按钮点击之外的输入变化。

observeEvent(input$action, {
  Total_Score <- NA
  # isolate(expr) prevents observables in expr from being subscribed to.
  Total_Score <- (
    input$housingslider * MunScores2016$Housing_Score_2016
    + input$populationslider * MunScores2016$Population_Score_2016  
    + input$provisionsslider * MunScores2016$Provisions_Score_2016 
    + input$safetyslider * MunScores2016$Safety_Score_2016
    + input$physicalenvslider * PhysicalEnvironment_Score_2016
  ) / (
    input$housingslider
    + input$populationslider
    + input$provisionsslider 
    +  input$safetyslider 
    + input$physicalenvslider
  )

  output$mymap <-renderLeaflet({
    # Use Total_Score here and no input$
    ...
  })
})

重绘

但是现在你应该实现这个的方式:使用leafletProxy!!

每次调用 时renderLeaflet,都会销毁之前使用过的地图对象并创建一个全新的地图对象(并再次创建所有图块,也意味着获取这些资源)。当您看到每次都重置缩放和视图位置时,您就会意识到这一点。

有一种方法可以重用您之前创建的地图。

该功能leafletProxy(<name>)使您可以访问您创建的地图,output$<name> <- renderLeaflet(...)并可以访问常规传单调用的所有功能。

因此,我们将您的代码重写为在开始时只有一个渲染函数,并且没有进一步的重新创建。服务器功能如下:

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

  # Create Map once.
  output$mymap <-renderLeaflet({
    leaflet(data = MunScores2016)
      %>% addTiles()
      %>% addPolygons(
        fillColor = ~pal(Total_Score_2016),
        fill2Opacity = 1, 
        color = 'white', 
        weight = 1,
        popup = popup_dat)
      %>% addLegend(
        "bottomright",
        pal=pal,
        values=~Total_Score_2016,
        opacity = 0.7,
        title="Percentage difference from national average")
  })

  observeEvent(input$action, {
    Total_Score <- NA
    Total_Score <- ((input$housingslider * MunScores2016$Housing_Score_2016 +
      input$populationslider * MunScores2016$Population_Score_2016 +
      input$provisionsslider * MunScores2016$Provisions_Score_2016 +
      input$safetyslider * MunScores2016$Safety_Score_2016 +
      input$physicalenvslider * MunScores2016$PhysicalEnvironment_Score_2016)/
      (input$housingslider + input$populationslider + input$provisionsslider + input$safetyslider + input$physicalenvslider))

    # Just update the existing map
    leafletProxy("mymap")
      # This you have to do now: remove the existing polygons, before you paint new ones.
      %>% clearShapes()
      %>% addPolygons(
        fillColor = ~pal(Total_Score), 
        fillOpacity = 1, 
        color = 'white', 
        weight = 1,
        popup = paste0("<strong>Municipality:</strong>", 
          MunScores2016$Municipality_Name, 
          "<br><strong>Quality-of-life-o-meter says: </strong>", 
          Total_Score))
      # As you can see, no addLegend is needed, since the legend does not change. 
  })
}

使用它,上述所有刷新问题都不会再发生,因为您不会为地图重新创建反应式环境。不过,我认为第一部分在未来可能会有所帮助。

于 2018-01-31T09:14:21.437 回答