Create cascading/dynamic selectInput() in many steps with dplyr::filter() doesn't work

In my shiny example below I have 3 variables (PEST, DATE_S2 and PROJECT). I would like that when I select Project, the variables DATE_S2 and PEST would only be those contained in the selection made in Project in the input using cascading/dynamic selectInput() with filters, and the same logic is applied to any variable selected. Here is my example (EDIT):


# Packages

library(rgdal)

library(shiny)

library(leaflet)

library(leaflet.providers)

library(ggplot2)

library(shinythemes)

library(sf)

library(lubridate)

library(dplyr)

# get AOI

download.file(

  "https://github.com/Leprechault/trash/raw/main/stands_example.zip",

  zip_path <- tempfile(fileext = ".zip")

)

unzip(zip_path, exdir = tempdir())

# Open the files

setwd(tempdir())

stands_extent <- readOGR(".", "stands_target") # Border

stands_ds <- read.csv("pred_target_stands.csv", sep=";") # Data set

stands_ds <- stands_ds %>%

  mutate(DATA_S2 = ymd(DATA_S2))

# Create the shiny dash

ui <- fluidPage(

  theme = shinytheme("cosmo"),

  titlePanel(title="My Map Dashboard"),  

  sidebarLayout(

    sidebarPanel(

      uiOutput("selectedvariable0"),

      uiOutput("selectedvariable1"),

      uiOutput("selectedvariable2"),

    ),

    mainPanel(

      textOutput("idSaida"),

      fluidRow(

        splitLayout(plotOutput("myplot"))),

      dateInput(inputId = "Dates selection", label = "Time"),

      leafletOutput("map") 

    )

  )

)

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

    

  # Importing data and save it temporary in data variable

  data <- reactive({stands_ds})

  

  currentvariable0 <- reactive({input$selectedvariable0})

  currentvariable1 <- reactive({input$selectedvariable1})

  currentvariable2 <- reactive({input$selectedvariable2})

  currentvariable3 <- reactive({input$selectedvariable3})

  currentvariable4 <- reactive({input$selectedvariable4})

  

  # Creating filters

  output$selectedvariable0 <- renderUI({

    selectInput(inputId = "selectedvariable0", "Type A", choices = var_pest(), selected = TRUE)

  })

  output$selectedvariable1 <- renderUI({

    selectInput(inputId = "selectedvariable1", "Type B", choices = var_moni(), selected = TRUE)

  })

  output$selectedvariable2 <- renderUI({

    selectInput(inputId = "selectedvariable2", "Type C",choices = var_proj(), selected = TRUE)

  })

  

  # Creating reactive function to subset data

  pest_function <- reactive({

    file1 <- data()

    pest <- req(input$selectedvariable0)

    file2 <- file1 %>% dplyr::filter(PEST==pest)

    return (file2)  

  })

  

  var_pest <- reactive({

    file1 <- pest_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$DATA_S2))

  })

  

  moni_function <- reactive({

    file1 <- pest_function()

    moni <- req(input$selectedvariable1)

    file2 <- file1 %>% dplyr::filter(DATA_S2==as.Date(moni))

    return (file2)  

  })

  

  var_moni <- reactive({

    file1 <- moni_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$PROJETO))

  })

  

  proj_function <- reactive({

    file1 <- moni_function()

    proj <- req(input$selectedvariable2)

    file2 <- file1 %>% dplyr::filter(PROJETO==proj)

    return (file2) 

  })

  

  var_proj <- reactive({

    file1 <- proj_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$CD_TALHAO))

  })

    

  output$myplot <- renderPlot({

    

    #Subset stand

    stands_sel <- subset(stands_extent, stands_extent@data$ID_UNIQUE==currentvariable4())

    

    #Subset for input$var and assign this subset to new object, "fbar"

    ds_sel<- stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]

    

    #Create a map

    polys <- st_as_sf(stands_sel)

    ggplot() +

      geom_sf(data=polys) +

      geom_point(data=ds_sel,

                 aes(x=X, y=Y), color="red") +

      xlab("Longitude") + ylab("Latitude") +

      coord_sf() +

      theme_bw() +

      theme(text = element_text(size=10)) 

  })

  

  output$map <- renderLeaflet({

    

    stands_actual<-stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]

    lng <- mean(stands_actual$X)

    lat <- mean(stands_actual$Y)

    

    leaflet() %>%

      setView(lng = lng, lat = lat, zoom=17) %>%

      addProviderTiles(providers$Esri.WorldImagery) %>%                   

      addMarkers(lng=stands_actual$X, lat=stands_actual$Y, popup="Location")

    

  })   

}

shinyApp(ui, server)

##

But not a way to make this work. Please any help for me fix it?

Thanks in advance!!!

It's tricky to debug shiny because you can't set break points or run as a script.

If you're desperate, I have had success saving the intermediate result before an error to an .RData file, letting the shiny app crash. And then taking a look at the variable in the .RData file so I can see if the type and format is what I expect.

1 Like

I think you haven't been specific about what is not working for you.
Is it an actual error, with a corresponding message, or is it undesirable behaviour? you didnt say.
your code as provided here is probably too big to be a good reprex, but that aside, the explicit error I get is

Warning: Error in var_pest: could not find function "var_pest"
  [No stack trace available]

and thats simple enough to understand, in that you provided no code for var_pest()

1 Like

So sorry Everyone, I make some confusion about my original code and a simple example created in mine post. Now the code is checked below. The problem is that I don't have any error for understand the problem, but in the app created I don't have my variables or my plots, see this image:


# Packages

library(rgdal)

library(shiny)

library(leaflet)

library(leaflet.providers)

library(ggplot2)

library(shinythemes)

library(sf)

library(lubridate)

library(dplyr)

# get AOI

download.file(

  "https://github.com/Leprechault/trash/raw/main/stands_example.zip",

  zip_path <- tempfile(fileext = ".zip")

)

unzip(zip_path, exdir = tempdir())

# Open the files

setwd(tempdir())

stands_extent <- readOGR(".", "stands_target") # Border

stands_ds <- read.csv("pred_target_stands.csv", sep=";") # Data set

stands_ds <- stands_ds %>%

  mutate(DATA_S2 = ymd(DATA_S2))

# Create the shiny dash

ui <- fluidPage(

  theme = shinytheme("cosmo"),

  titlePanel(title="My Map Dashboard"),  

  sidebarLayout(

    sidebarPanel(

      uiOutput("selectedvariable0"),

      uiOutput("selectedvariable1"),

      uiOutput("selectedvariable2"),

    ),

    mainPanel(

      textOutput("idSaida"),

      fluidRow(

        splitLayout(plotOutput("myplot"))),

      dateInput(inputId = "Dates selection", label = "Time"),

      leafletOutput("map") 

    )

  )

)

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

    

  # Importing data and save it temporary in data variable

  data <- reactive({stands_ds})

  

  currentvariable0 <- reactive({input$selectedvariable0})

  currentvariable1 <- reactive({input$selectedvariable1})

  currentvariable2 <- reactive({input$selectedvariable2})

  currentvariable3 <- reactive({input$selectedvariable3})

  currentvariable4 <- reactive({input$selectedvariable4})

  

  # Creating filters

  output$selectedvariable0 <- renderUI({

    selectInput(inputId = "selectedvariable0", "Type A", choices = var_pest(), selected = TRUE)

  })

  output$selectedvariable1 <- renderUI({

    selectInput(inputId = "selectedvariable1", "Type B", choices = var_moni(), selected = TRUE)

  })

  output$selectedvariable2 <- renderUI({

    selectInput(inputId = "selectedvariable2", "Type C",choices = var_proj(), selected = TRUE)

  })

  

  # Creating reactive function to subset data

  pest_function <- reactive({

    file1 <- data()

    pest <- req(input$selectedvariable0)

    file2 <- file1 %>% dplyr::filter(PEST==pest)

    return (file2)  

  })

  

  var_pest <- reactive({

    file1 <- pest_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$DATA_S2))

  })

  

  moni_function <- reactive({

    file1 <- pest_function()

    moni <- req(input$selectedvariable1)

    file2 <- file1 %>% dplyr::filter(DATA_S2==as.Date(moni))

    return (file2)  

  })

  

  var_moni <- reactive({

    file1 <- moni_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$PROJETO))

  })

  

  proj_function <- reactive({

    file1 <- moni_function()

    proj <- req(input$selectedvariable2)

    file2 <- file1 %>% dplyr::filter(PROJETO==proj)

    return (file2) 

  })

  

  var_proj <- reactive({

    file1 <- proj_function()

    if(is.null(file1)){return()}

    as.list(unique(file1$CD_TALHAO))

  })

    

  output$myplot <- renderPlot({

    

    #Subset stand

    stands_sel <- subset(stands_extent, stands_extent@data$ID_UNIQUE==currentvariable4())

    

    #Subset for input$var and assign this subset to new object, "fbar"

    ds_sel<- stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]

    

    #Create a map

    polys <- st_as_sf(stands_sel)

    ggplot() +

      geom_sf(data=polys) +

      geom_point(data=ds_sel,

                 aes(x=X, y=Y), color="red") +

      xlab("Longitude") + ylab("Latitude") +

      coord_sf() +

      theme_bw() +

      theme(text = element_text(size=10)) 

  })

  

  output$map <- renderLeaflet({

    

    stands_actual<-stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]

    lng <- mean(stands_actual$X)

    lat <- mean(stands_actual$Y)

    

    leaflet() %>%

      setView(lng = lng, lat = lat, zoom=17) %>%

      addProviderTiles(providers$Esri.WorldImagery) %>%                   

      addMarkers(lng=stands_actual$X, lat=stands_actual$Y, popup="Location")

    

  })   

}

shinyApp(ui, server)

##

I can offer you some advice in general.
When building an app of any complexity, one should build ones app incrementally.
That way, between changes, if an error is introduced it can be worked out, before continuing to extend the app.
I would encourage you to think about how you can make a minimal reprex, which zero's in on the technical challenge you have, and assumes that you will succeed with the rest, other parts you are confident with.
I.e. plotting leaflet maps etc.
If you want an example of hierarchical filtering in shiny, there are many that can be found online,
I'll point you to this one in particular as the book its extracted from is excellent, and a great reference to rely on.
Chapter 10 Dynamic UI | Mastering Shiny (mastering-shiny.org)

1 Like

You're code has name collisions.
shiny names should be unique.

 output$selectedvariable0 <- renderUI({
    
    selectInput(inputId = "selectedvariable0", "Type A", choices = var_pest(), selected = TRUE)
    
  })

selectedvariable0 is doing double duty, as the name of a selectInput, and the name of a uiOutput.
This should not be so.

1 Like

Thanks for the tips @nirgrahamuk !!! Problem solved:

# Packages
library(rgdal)
library(shiny)
library(leaflet)
library(leaflet.providers)
library(ggplot2)
library(shinythemes)
library(sf)
library(lubridate)
library(dplyr)


# get AOI
download.file(
  "https://github.com/Leprechault/trash/raw/main/stands_example.zip",
  zip_path <- tempfile(fileext = ".zip")
)
unzip(zip_path, exdir = tempdir())

# Open the files
setwd(tempdir())
stands_extent <- readOGR(".", "stands_target") # Border
stands_ds <- read.csv("pred_target_stands.csv", sep=";") # Data set
stands_ds <- stands_ds %>%
  mutate(DATA_S2 = ymd(DATA_S2))

# Create the shiny dash
ui <- fluidPage(
  theme = shinytheme("cosmo"),
  titlePanel(title="My Map Dashboard"),  
  sidebarLayout(
    sidebarPanel(
      selectInput(inputId = "selectedvariable0", "Type", choices = unique(stands_ds$PEST), selected = TRUE),
      selectInput(inputId = "selectedvariable1", "Date", choices = NULL),
      selectInput(inputId = "selectedvariable2", "Project",choices = NULL),
      selectInput(inputId = "selectedvariable3",
                  label = "Stand", 
                  choices = c(unique(stands_ds$CD_TALHAO)),selected = TRUE),
      selectInput(inputId = "selectedvariable4",
                  label = "Unique ID",                   
                  choices = c(unique(stands_ds$ID_UNIQUE)),selected = TRUE)     
    ),
    mainPanel(
      textOutput("idSaida"),
      fluidRow(
        splitLayout(plotOutput("myplot"))),
      dateInput(inputId = "Dates selection", label = "Time"),
      leafletOutput("map") 
    )
  )
)

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

  currentvariable3 <- reactive({input$selectedvariable3})
  currentvariable4 <- reactive({input$selectedvariable4})  

  selectedvariable0 <- reactive({
    filter(stands_ds, PEST == input$selectedvariable0)
  })
  observeEvent(selectedvariable0(), {
    choices <- unique(selectedvariable0()$DATA_S2)
    updateSelectInput(inputId = "selectedvariable1", choices = choices) 
  })
  
  selectedvariable1 <- reactive({
    req(input$selectedvariable1)
    filter(selectedvariable0(), DATA_S2 == as.Date(input$selectedvariable1))
  })
  observeEvent(selectedvariable1(), {
    choices <- unique(selectedvariable1()$PROJETO)
    updateSelectInput(inputId = "selectedvariable2", choices = choices)
  })
  
  output$myplot <- renderPlot({
    
    #Subset stand
    stands_sel <- subset(stands_extent, stands_extent@data$ID_UNIQUE==currentvariable4())
    
    #Subset for input$var and assign this subset to new object, "fbar"
    ds_sel<- stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]
    
    #Create a map
    polys <- st_as_sf(stands_sel)
    ggplot() +
      geom_sf(data=polys) +
      geom_point(data=ds_sel,
                 aes(x=X, y=Y), color="red") +
      xlab("Longitude") + ylab("Latitude") +
      coord_sf() +
      theme_bw() +
      theme(text = element_text(size=10)) 
  })
  
  output$map <- renderLeaflet({
    
    stands_actual<-stands_ds[stands_ds$ID_UNIQUE==currentvariable4(),]
    lng <- mean(stands_actual$X)
    lat <- mean(stands_actual$Y)
    
    leaflet() %>%
      setView(lng = lng, lat = lat, zoom=17) %>%
      addProviderTiles(providers$Esri.WorldImagery) %>%                   
      addMarkers(lng=stands_actual$X, lat=stands_actual$Y, popup="Location")
    
  })   
}
shinyApp(ui, server)
##

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.