0
votes

I have two leaflet output with two leafletproxy, each rendering on two different tabpanel inside a tabsetpanel. the problem is that the second leafletproxy doesn't render when I select the second panel, I need to select an input first. My goal is to render the second leaflet proxy when I select the second tab without select an input first.

I have found some solution on the internet but these doesn't suit me :

in the line 83 is this solution : render leaflet markers across tabs on shiny startup

in the line 84 is this solution : https://github.com/rstudio/leaflet/issues/590

the problem with theses solutions is that when you come back and forth to the second panel, the leaflet proxy re-load (see the console). It is not a problem when you have a little amount of data, but that is not my case...

So i would like to render the leafletproxy of the second tab only once, when the shinyApp starts. How can I do that ?

library(shiny)
library(leaflet)
library(RColorBrewer)


ui <- fluidPage(

  tags$style(HTML("
                  #map1 {
                  position: absolute;
                  }
                  #map2 {
                  position: absolute;
                  }
                  ")),

  conditionalPanel(
    condition = "input.tabs=='tabMap1'",
    leafletOutput("map1", width="100%", height = "100%")
    ),

  conditionalPanel(
    condition = "input.tabs=='tabMap2'",
    leafletOutput("map2", width="100%", height = "100%")
  ),

  absolutePanel(
    id = "tabPanel",
    class = "panel panel-default",
    style = "padding : 10px",
    top = "2%", 
    left = "2%",
    right = "78%",
    height= "50%",
    tabsetPanel(id = "tabs", 
      tabPanel("tabMap1",
               selectInput("colors1", "Color Scheme",
                           rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
               )),
      tabPanel("tabMap2",
               selectInput("colors2", "Color Scheme",
                           rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
               )
      )
    )
  )
)

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

  # Leaflet Output Map 1
  output$map1 <- renderLeaflet({
    leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
  })

  colorpal1 <- reactive({
    colorNumeric(input$colors1, quakes$mag)
  })

  # leaflet Proxy Map 1
  observe({
    pal1 <- colorpal1()
    leafletProxy("map1", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal1(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })

  # Leaflet Output Map 2
  output$map2 <- renderLeaflet({
    leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
  })

  colorpal2 <- reactive({
    colorNumeric(input$colors2, quakes$mag)
  })

  # leaflet Proxy Map 2
  observe({
    # input$tabs
    # req(input$tabs == "tabMap2")
    pal2 <- colorpal2()
    leafletProxy("map2", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })
}

shinyApp(ui, server)
2

2 Answers

1
votes

Not the most elegant but I added this:

  # Added for first rendering
  observeEvent(input$tabs, {
    # input$tabs
    # req(input$tabs == "tabMap2")
    pal2 <- colorpal2()
    leafletProxy("map2", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  }, ignoreInit = TRUE, once = TRUE)

Basically, I observe the event of input$tabs, ignoring the initial one for tab 1 with ignoreInit = TRUE and then killing this observeEvent after the next change to tab 2 using once = TRUE. See notes here observeEvent.

Full code below:

library(shiny)
library(leaflet)
library(RColorBrewer)


ui <- fluidPage(

  tags$style(HTML("
                  #map1 {
                  position: absolute;
                  }
                  #map2 {
                  position: absolute;
                  }
                  ")),

  conditionalPanel(
    condition = "input.tabs=='tabMap1'",
    leafletOutput("map1", width="100%", height = "100%")
  ),

  conditionalPanel(
    condition = "input.tabs=='tabMap2'",
    leafletOutput("map2", width="100%", height = "100%")
  ),

  absolutePanel(
    id = "tabPanel",
    class = "panel panel-default",
    style = "padding : 10px",
    top = "2%", 
    left = "2%",
    right = "78%",
    height= "50%",
    tabsetPanel(id = "tabs", 
                tabPanel("tabMap1",
                         selectInput("colors1", "Color Scheme",
                                     rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
                         )),
                tabPanel("tabMap2",
                         selectInput("colors2", "Color Scheme",
                                     rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
                         )
                )
    )
  )
)

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

  # Leaflet Output Map 1
  output$map1 <- renderLeaflet({
    leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
  })

  colorpal1 <- reactive({
    colorNumeric(input$colors1, quakes$mag)
  })

  # leaflet Proxy Map 1
  observe({
    pal1 <- colorpal1()
    leafletProxy("map1", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal1(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })

  # Leaflet Output Map 2
  output$map2 <- renderLeaflet({
    leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
  })

  colorpal2 <- reactive({
    colorNumeric(input$colors2, quakes$mag)
  })

  # leaflet Proxy Map 2
  observe({
    # input$tabs
    # req(input$tabs == "tabMap2")
    pal2 <- colorpal2()
    leafletProxy("map2", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })

  # Added for first rendering
  observeEvent(input$tabs, {
    # input$tabs
    # req(input$tabs == "tabMap2")
    pal2 <- colorpal2()
    leafletProxy("map2", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  }, ignoreInit = TRUE, once = TRUE)

}

shinyApp(ui, server)
1
votes

I managed to find a solution by adding an isolate() on my reactive data and the layer (addCircles) of the leaflet proxy inside the renderLeaflet, it goes like this :

library(shiny)
library(leaflet)
library(RColorBrewer)


ui <- fluidPage(

  tags$style(HTML("
                  #map1 {
                  position: absolute;
                  }
                  #map2 {
                  position: absolute;
                  }
                  ")),

  conditionalPanel(
    condition = "input.tabs=='tabMap1'",
    leafletOutput("map1", width="100%", height = "100%")
  ),

  conditionalPanel(
    condition = "input.tabs=='tabMap2'",
    leafletOutput("map2", width="100%", height = "100%")
  ),

  absolutePanel(
    id = "tabPanel",
    class = "panel panel-default",
    style = "padding : 10px",
    top = "2%", 
    left = "2%",
    right = "78%",
    height= "50%",
    tabsetPanel(id = "tabs", 
                tabPanel("tabMap1",
                         selectInput("colors1", "Color Scheme",
                                     rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
                         )),
                tabPanel("tabMap2",
                         selectInput("colors2", "Color Scheme",
                                     rownames(subset(brewer.pal.info, category %in% c("seq", "div")))
                         )
                )
    )
  )
  )

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

  # Leaflet Output Map 1
  output$map1 <- renderLeaflet({
    print("map1")
    leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))
  })

  colorpal1 <- reactive({
    colorNumeric(input$colors1, quakes$mag)
  })

  # leaflet Proxy Map 1
  observe({
    print("map1")
    pal1 <- colorpal1()
    leafletProxy("map1", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal1(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })

  # Leaflet Output Map 2
  output$map2 <- renderLeaflet({

    foo <- leaflet(quakes) %>% addTiles() %>%
      fitBounds(~min(long), ~min(lat), ~max(long), ~max(lat))

    pal2 <- isolate(colorpal2())
    foo %>% addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                       fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag))
  })

  colorpal2 <- reactive({
    colorNumeric(input$colors2, quakes$mag)
  })

  # leaflet Proxy Map 2
  observe({
    # input$tabs
    #req(input$tabs == "tabMap2")
    pal2 <- colorpal2()
    leafletProxy("map2", data = quakes) %>%
      clearShapes() %>%
      addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
                 fillColor = ~pal2(mag), fillOpacity = 0.7, popup = ~paste(mag)
      )
  })
}

shinyApp(ui, server)