R shiny passing reactive to selectInput choices
You need to use renderUI
on the server side for dynamic UIs. Here is a minimal example. Note that the second drop-down menu is reactive and adjusts to the dataset you choose in the first one. The code should be self-explanatory if you have dealt with shiny before.
runApp(list(
ui = bootstrapPage(
selectInput('dataset', 'Choose Dataset', c('mtcars', 'iris')),
uiOutput('columns')
),
server = function(input, output){
output$columns = renderUI({
mydata = get(input$dataset)
selectInput('columns2', 'Columns', names(mydata))
})
}
))
EDIT. Another Solution using updateSelectInput
runApp(list(
ui = bootstrapPage(
selectInput('dataset', 'Choose Dataset', c('mtcars', 'iris')),
selectInput('columns', 'Columns', "")
),
server = function(input, output, session){
outVar = reactive({
mydata = get(input$dataset)
names(mydata)
})
observe({
updateSelectInput(session, "columns",
choices = outVar()
)})
}
))
EDIT2: Modified Example using parse
. In this app, the text formula entered is used to dynamically populate the dropdown menu below with the list of variables.
library(shiny)
runApp(list(
ui = bootstrapPage(
textInput("text", "Enter Formula", "a=b+c"),
uiOutput('variables')
),
server = function(input, output){
outVar <- reactive({
vars <- all.vars(parse(text = input$text))
vars <- as.list(vars)
return(vars)
})
output$variables = renderUI({
selectInput('variables2', 'Variables', outVar())
})
}
))
r - Output from Shiny server to reactive selectInput(choices = ) in ui
Hi I think your first solution was closer but you should split the APIData
in to two functions at least like this
APIdata <- reactive({
# Initial fetch of data from eBird API, with conditionals to reject errant input
a <- try(api2(regionCode = as.character(input$region_in),
back = as.numeric(input$slider_in)))
if(class(a) == "try-error" ||length(a) == 0){return(NULL)}
a
})
filteredData <- reactive({
a <- APIdata()
## resrt of your code here
})
at the moment you are collecting the data from the api everytime some input changes and that is quite redundant.
After that you can use something like this to set the selectInput
observeEvent({APIdata()},{
updateSelectInput(session, "species_in",
choices = unique(APIdata()[["comName"]]), # fixed
selected = input$species_in
))})
hope this helps!
Shiny - Changing the number of choices in selectInput()
Instead of case_when
, try to use switch
. Also, renderUI
might be useful. Try this
library(shiny)
ui <- fluidPage(
tabPanel("tbls",
selectInput("tab1",label="Pick a table:",choices=c("a","b","c")),
uiOutput("myselect")
#selectInput("cht1",label="Pick a time series:",choices=c("d","e","f"))
)
)
server <- function(input,output,session) {
Nchoices <- reactive({
switch(input$tab1,
"a" = c("d","e","f"),
"b" = c("g","h"),
"c" = c("j","k","l","m") # adding one more choice breaks the code
)
})
output$myselect <- renderUI({
req(input$tab1)
selectInput("cht1",label="Pick a time series:",choices=Nchoices())
})
observe(print(Nchoices()))
}
shinyApp(ui, server)
Please note that in case_when
All RHS values need to be of the same type. Inconsistent types will throw an error.
R Shiny - How to update a dependent reactive selectInput before updating dependent reactive plot
You can try using the freezReactiveValue()
function, as Hadley Wickham recommend in mastering shiny. link: Freezing reactive inputs
library(shiny)
library(ggplot2)
library(dplyr)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Reactivity Test"),
# Sidebar with two input widgets
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Input #1 - Dataset",
choices = c("mtcars", "iris")),
selectInput(inputId = "variable",
label = "Input #2 - Variable",
choices = NULL)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
input_dataset <- reactive({
if(input$dataset == "mtcars") {
return(mtcars)
} else {
return(iris)
}
})
observeEvent(input$dataset, {
freezeReactiveValue(input, "variable")
updateSelectInput(session = session, inputId = "variable", choices = names(input_dataset()))
})
output$distPlot <- renderPlot({
ggplot(input_dataset(), aes(x = .data[[input$variable]])) +
geom_histogram()
})
}
# Run the application
shinyApp(ui = ui, server = server)
Shiny reactive selectInput in R
Here is a way. It uses the selectize plugin disable_options.
Download the plugin here. Save it under the name selectize-disable-options.js in the www subfolder of the app folder.
Then here is the app:
library(shiny)
library(ggplot2)
CSS <- "
.selectize-dropdown [data-selectable].option-disabled {
color: #aaa;
cursor: default;
}"
type <- as.character(c('summer','summer','summer','summer','winter','winter','winter','winter'))
country <- as.character(c('A','A','B','B','A','A','B','B'))
year <- c(2011,2012,2013,2014,2011,2012,2013,2014)
col1 <- c(33,7,NA,NA,5,11,NA,NA)
col2 <- c(10,3,NA,NA,8,15,NA,NA)
col3 <- c(NA,NA,10,15,NA,NA,20,25)
col4 <- c(NA,NA,8,5,NA,NA,22,16)
TD <- data.frame(type,country,year,col1,col2,col3,col4,stringsAsFactors=FALSE)
ui <- fluidPage(
tags$head(
tags$script(src = "selectize-disable-options.js"),
tags$style(HTML(CSS))
),
titlePanel("Test App"),
sidebarLayout(
sidebarPanel(
selectInput("type","Choose a type", choices = c("All",unique(TD$type))),
selectInput("country","Choose an country", choices = c("All",unique(TD$country))),
selectizeInput("yaxis", "Choose a y variable", choices = colnames(TD[,3:7])),
selectInput("xaxis", "Choose a x variable", choices = colnames(TD[,3:7])),
actionButton("goButton", "Update")
),
mainPanel(
tabsetPanel(
tabPanel('Plot', plotOutput("plot1"))
)
)
)
)
server <- function(input, output, session){
data1 <- reactive({
if(input$type == "All"){
TD
}else{
TD[TD$type == input$type,]
}
})
data2 <- reactive({
if(input$country == "All"){
TD
}else{
TD[TD$country == input$country,]
}
})
observe({
if(input$type != "All"){
selected_country <- isolate(input$country)
countries <- unique(data1()$country)
updateSelectInput(
session, "country",
choices = c("All", countries),
selected = ifelse(selected_country %in% countries, selected_country, "All")
)
}else if(input$country != 'All'){
selected_type <- isolate(input$type)
types <- unique(data2()$type)
updateSelectInput(
session, "type",
choices = c('All', types),
selected = ifelse(selected_type %in% types, selected_type, "All")
)
}else if(input$type == "All" && input$country == "All"){
updateSelectInput(
session, "country",
choices = c('All', unique(TD$country))
)
updateSelectInput(
session, "type",
choices = c('All', unique(TD$type))
)
}
})
data3 <- reactive({
if(input$country == "All"){
data1()
}else if(input$type == "All"){
data2()
}else if(input$country == "All" && input$type == "All"){
TD
}else{
TD[which(TD$country== input$country & TD$type == input$type),]
}
})
observeEvent(data3(), {
emptyColumns <- sapply(data3()[,3:7], function(x){
all(is.na(x))
})
choices <- colnames(TD[,3:7])
choices[emptyColumns] <- paste(choices[emptyColumns], "(no data)")
updateSelectizeInput(
session, "yaxis", choices = choices,
options = list(
plugins = list(
disable_options = list(
disableOptions = as.list(choices[emptyColumns])
)
)
)
)
})
data4 <- eventReactive(input$goButton, {
data3()
})
x_var<- eventReactive(input$goButton, {
input$xaxis
})
y_var <- eventReactive(input$goButton,{
input$yaxis
})
output$plot1 <- renderPlot({
x <- x_var()
y <- y_var()
p <- ggplot(data4(), aes_string(x=x, y=y)) + geom_line() + geom_point()
p + labs(x = x, y = y) + theme(plot.title = element_text(hjust = 0.5, size=20))
})
}
shinyApp(ui,server)
The empty columns are disabled in the select input:
How to make selectInput choices reactive?
You should avoid renderUI
where possible and use update*
functions instead - updating is faster than re-rendering:
library(shiny)
library(data.table)
DT <- data.table(
ID = c(1, 1, 1, 2, 2, 2, 3, 3, 3),
Period = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
Values = c(5, 10, 15, 0, 2, 4, 3, 6, 9)
)
all_choices <- unique(DT$Period)
ui <- fluidPage(
tableOutput("data"),
selectizeInput(
inputId = "fromPeriod",
label = "From period:",
choices = setdiff(all_choices, last(all_choices)),
selected = 1
),
selectizeInput(
inputId = "toPeriod",
label = "To period:",
choices = setdiff(all_choices, first(all_choices)),
selected = 2
),
tableOutput("dataSelect")
)
server <- function(input, output, session) {
output$data <- renderTable({
DT
})
observeEvent(input$fromPeriod, {
freezeReactiveValue(input, "toPeriod")
updateSelectizeInput(
session,
inputId = "toPeriod",
choices = all_choices[all_choices > input$fromPeriod],
selected = max(all_choices[all_choices > input$fromPeriod])
)
}, ignoreInit = TRUE)
output$dataSelect <- renderTable({
# in one line, however you seem to need part1 / part2 for your custom function
# setorder(DT[Period %in% c(input$fromPeriod, input$toPeriod)], Period)
part1 <- DT[Period == input$fromPeriod]
part2 <- DT[Period == input$toPeriod]
rbindlist(list(part1, part2))
}, rownames = TRUE)
}
shinyApp(ui, server)
To avoid triggering reactives or outputs unnecessarily you should almost alway use freezeReactiveValue
when using a update*
function in shiny. Please see this related chapter from Mastering Shiny.
Shiny: selectInput based on previous selectInput resetting the selected value
That's because your observer is inside the renderPlot
. It has nothing to do here.
server <- function(input, output, session) {
# Make drop-down choice of sel_2 dependent upon user input of sel_1
observeEvent(input$sel_1, {
updateSelectInput(session,
"sel_2",
choices = sort(unique(mtcars[[input$sel_1]]))
)
})
output$plot_out <- renderPlot({
# Assign inputs
sel_1 <- input$sel_1
sel_2 <- input$sel_2
# Data to plot
my_data <- mtcars %>%
filter(.data[[sel_1]] == sel_2)
# Plot
ggplot(my_data, aes(x = factor(.data[[sel_1]]), y = hp)) + geom_point()
})
}
Here the observeEvent
instead of observe
is not necessary, since input$sel_1
is the only reactive value inside the observer, but I find that observeEvent
is more readable.
Also, avoid to load tidyverse. That loads a ton of packages you don't need. Here dplyr and ggplot2 are enough
Could I get the choices of a SelectInput in the ui from a reactive function in server? (RShiny)
Generate the selectInput
on the server side.
library(shiny)
ui <- fluidPage(
titlePanel("Old Faithful Geyser Data"),
sidebarLayout(
sidebarPanel(
uiOutput('selectUI')
),
mainPanel(
verbatimTextOutput("print")
)
)
)
server <- function(input, output) {
cars <- reactive({
data("mtcars")
cars <- rownames(mtcars)
return(cars)
})
output$selectUI <- renderUI({
selectInput(inputId = 'options', "Select one", choices = cars())
})
output$print <- renderPrint(cars())
}
# Run the application
shinyApp(ui = ui, server = server)
Related Topics
Plot Multiple Lines in One Graph
How to Subtract/Add Days From/To a Date
What's Wrong With My Function to Load Multiple .Csv Files into Single Dataframe in R Using Rbind
Create New Variables With Mutate_At While Keeping the Original Ones
Formatting Dates on X Axis in Ggplot2
Convert Hour:Minute:Second (Hh:Mm:Ss) String to Proper Time Class
How to Get a Vertical Geom_Vline to an X-Axis of Class Date
How to Read a CSV File in R With Different Number of Columns
Windows 7, Update.Packages Problem: "Unable to Move Temporary Installation"
How to Display Only Integer Values on an Axis Using Ggplot2
Dplyr: How to Use Group_By Inside a Function
Rolling Mean (Moving Average) by Group/Id With Dplyr
Remove Extra Legends in Ggplot2
How to Convert Posix Date to Day of Year
Figure Position in Markdown When Converting to Pdf With Knitr and Pandoc
Getting Warning: " 'Newdata' Had 1 Row But Variables Found Have 32 Rows" on Predict.Lm