I have two pickerInput values in the app. In the first, geography, the user can select to view either state (default) or county data. If the user selects county, I'd like to require that they pick a state from the second pickerInput, which is just a list of states. It is not required that the user pick a state when input$geography == "state".
I have considered putting this inside of a modalDialogue but it wasn't working. I also tried an updatePickerInput which didn't work either.
What is the best way of conditionally requiring the user to select a value from a pickerInput?
Thank you.
Here is a solution with shinyjs :
library(shiny)
library(shinyWidgets)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
pickerInput("pick_1", choices = c("state","county"), multiple = FALSE, selected = "state"),
shinyjs::hidden(
pickerInput("pick_2", choices = state.name, multiple = TRUE)
)
)
server <- function(input, output, session) {
observe({
toggleElement("pick_2", condition = input$pick_1 == "state")
})
}
shinyApp(ui, server)
Related
I'm using observe() to change a value of a selectInput after a user selects TRUE/FALSE in the Categorical drop down list. In the first tab of my program if you set Categorical to TRUE then Impute gets updated to mode and mean otherwise. I'm then able to change the Impute value as desired without it reverting to the value that appears when TRUE/FALSE is selected.
In the second tab I have a multiple selectInput list with a similar interface as the first tab; the interface is created for every value selected in Select covariates. In this section I also used observe() to update each selected covariates' Impute drop down list accordingly to the logic of the first tab (i.e. if TRUE is selected then Impute gets updated to mode and mean otherwise). However, the value in Impute appers to be locked in the sense that I'm not able to switch between values as I did in the first tab.
I don't know how to correct this issue and I was wondering if anyone out there has encountered this similar problem and has been able to fix it. Any advice or help would be greatly appreciated.
The code to my app can be seen below and can be ran in a single file.
library(shiny)
library(shinyjs)
ui <- shinyUI(fluidPage(
shinyjs::useShinyjs(),
navbarPage("Test",id="navbarPage",
tabPanel("First tab", id = "first_tab",
sidebarLayout(
sidebarPanel(
selectInput('covariate.L.categorical', 'Categorical', c("",TRUE,FALSE)),
selectInput('covariate.L.impute', "Impute", c("","default","mean","mode","median"))
),
mainPanel()
)
),
tabPanel("Second tab", id = "second_tab",
sidebarLayout(
sidebarPanel(
selectInput('covariates', 'Select covariates', choices = c("age","sex","race","bmi"), multiple=TRUE, selectize=TRUE),
tags$hr(),
uiOutput("covariateop")
),
mainPanel()
)
))
))
server <- shinyServer(function(input, output, session) {
rv <- reactiveValues(cov.selected = NULL)
observe({
updateSelectInput(session, "covariate.L.impute", selected = ifelse(input$covariate.L.categorical,"mode","mean"))
})
output$covariateop <- renderUI({
lapply(input$covariates, function(x){
tags$div(id = paste0("extra_criteria_for_", x),
h4(x),
selectInput(paste0(x,"_categorical"), "Categorical",
choices = c("",TRUE,FALSE)),
selectInput(paste0(x,"_impute"), "Impute",
choices = c("","default","mean","mode","median")),
textInput(paste0(x,"_impute_default_level"), "Impute default level"),
tags$hr()
)
})
})
observe({
lapply(input$covariates, function(x){
updateSelectInput(session, paste0(x,"_impute"), selected = ifelse(as.logical(reactiveValuesToList(input)[[paste0(x,"_categorical")]])==TRUE,"mode","mean"))
})
})
})
# Run the application
shinyApp(ui = ui, server = server)
In your observe in the second tab, you use reactiveValuesToList(input)[[paste0(x,"_categorical")]]. This means that this observe is reactive to any changes in any input element, so also if you change the "Imputation" input. You can just use input[[paste0(x,"_categorical")]] instead to get rid of this behaviour.
Note that the implementation of dynamic UI with lapply leads to the deletion and anew rendering of already existing input selections when an additional variable is selected. Maybe you can have a look at insertUI/removeUI to get a bit nicer UI.
I'm attempting to use InsertUI and updateSelectizeInput methods in the server function as part of my app, primarily since my list of choices is so large.
library(shiny)
baby_names <- babynames::babynames %>%
distinct(name) %>%
.[["name"]] %>%
sort()
ui <- fluidPage(
tags$div(id = 'placeholder')
)
server <- function(input, output, session) {
id = "babies"
insertUI(selector = '#placeholder',
ui = tags$div(list(
selectizeInput("babynames", label = "Baby Names!", multiple = TRUE, choices = NULL, width = '400px',
options = list(placeholder = 'Type a baby name.'))
),
immediate = TRUE,
id = id))
updateSelectizeInput(
session, inputId = "babynames",
choices = baby_names,
server = TRUE)
}
shinyApp(ui, server)
I'm not getting much success out of this, as the selectizeInput is displayed but the dropdown options are not shown. How should I address this issue? Thanks!
This is explained in the documentation of insertUI:
This function allows you to dynamically add an arbitrarily large UI object into your app, whenever you want, as many times as you want. Unlike renderUI(), the UI generated with insertUI is not updatable as a whole: once it's created, it stays there. Each new call to insertUI creates more UI objects, in addition to the ones already there (all independent from one another). To update a part of the UI (ex: an input object), you must use the appropriate render function or a customized reactive function
(I added the bold font)
Therefore, you should use renderUI instead.
I have a shiny application with many tabs and many widgets on each tab. It is a data-driven application so the data is tied to every tab.
I can save the application using image.save() and create a .RData file for later use.
The issue I am having how can I get the state restored for the widgets?
If the user has checked boxes, selected radio buttons and specified base line values in list boxes can I set those within a load() step?
I have found libraries such as shinyURL and shinystore but is there a direct way to set the environment back to when the write.image was done?
I am not sure where to even start so I can't post code.
edit: this is a cross-post from the Shiny Google Group where other solutions have been suggested
This is a bit hacky, but it works. It uses an "internal" function (session$sendInputMessage) which is not meant to be called explicitly, so there is no guarantee this will always work.
You want to save all the values of the input object. I'm getting all the widgets using reactiveValuesToList(input) (note that this will also save the state of buttons, which doesn't entirely make sense). An alternative approach would be to enumerate exactly which widgets to save, but that solution would be less generic and you'd have to update it every time you add/remove an input. In the code below I simply save the values to a list called values, you can save that to file however you'd like (RDS/text file/whatever). Then the load button looks at that list and updates every input based on the value in the list.
There is a similar idea in this thread
library(shiny)
shinyApp(
ui = fluidPage(
textInput("text", "text", ""),
selectInput("select", "select", 1:5),
uiOutput("ui"),
actionButton("save", "Save"),
actionButton("load", "Load")
),
server = function(input, output, session) {
output$ui <- renderUI({
tagList(
numericInput("num", "num", 7),
checkboxGroupInput("chk", "chk", 1:5, c(2,4))
)
})
observeEvent(input$save, {
values <<- lapply(reactiveValuesToList(input), unclass)
})
observeEvent(input$load, {
if (exists("values")) {
lapply(names(values),
function(x) session$sendInputMessage(x, list(value = values[[x]]))
)
}
})
}
)
Now with bookmarking is possible to save the state of your shinyapp. You have to put the bookmarkButton on your app and also the enableBookmarking.
The above example may not work if shiny UI involves date. Here is a minor change for date handling.
library(shiny)
shinyApp(
ui = fluidPage(
dateInput("date", "date", "2012-01-01"),
selectInput("select", "select", 1:5),
uiOutput("ui"),
actionButton("save", "Save"),
actionButton("load", "Load")
),
server = function(input, output, session) {
output$ui <- renderUI({
tagList(
numericInput("num", "num", 7),
checkboxGroupInput("chk", "chk", 1:5, c(2,4))
)
})
observeEvent(input$save, {
values <<- lapply(reactiveValuesToList(input), unclass)
})
observeEvent(input$load, {
if (exists("values")) {
lapply(names(values),
function(x) session$sendInputMessage(x, list(value = values[[x]]))
)
temp=as.character(as.Date(values$date, origin = "1970-01-01"))
updateDateInput(session, inputId="date", label ="date", value = temp)
}
})
}
)
I am facing a problem with submitButton usage in my Shiny application (which I use as some time-consuming rendering is done with the data supplied by the app-user). I also use some radioButtons with conditionalPanel to define the variables group of which user may choose the parameters. Please see the attached image to get the idea (user is selecting a list type, and - based on his list choice - a particular list appears (conditionalPanel is working) from which the user is selecting a parameter), or run a reprodicible example supplied below.
Of course, only the parameter is a value that is using in rendering an output, and I would like to force a submitButton to pass only the parameter in an automatic way. The problem is that submitButton affects also the radioButtons element, which unables the use to choose the desired value (as the values list are not switching).
QUESTION: Is there any way to define which UI elements are to be stop-from-automatic-update by submitButton so as to solve my problem? Thank you for any help!
UI:
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Problem with submit button"),
sidebarPanel(
radioButtons("selectionway", "Choose list type", c(number='number', letter='letter')),
conditionalPanel(
condition = "input.selectionway == 'number'",
selectInput("numberlist", "Choose NUMBER:", choices = c("11111", "22222", "33333"))
),
conditionalPanel(
condition = "input.selectionway == 'letter'",
selectInput("letterlist", "Choose LETTER:", choices = c("A", "B", "C"))
),
submitButton("submitButton")
),
mainPanel(
verbatimTextOutput("list"),
verbatimTextOutput("value")
)
))
SERVER:
library(shiny)
shinyServer(function(input, output) {
selected.value <- reactive({
if(input$selectionway=="letter"){
return(input$letterlist)
} else {
return(input$numberlist)
}
})
output$list <- renderText({
input$selectionway
})
output$value <- renderText({
selected.value()
})
})
Originally I create this shiny interface that takes in a parameter "company id" and "date", but here we have a problem: most people dont know the companies we work with by their id, only their name, i.e. (McDonalds, Radioshack).
So I want to ideally create a search function like this
My current idea is to pass in a table including a list of all our partner companies and their ids to global.R. Then pass in the textInput as the search variables and perform the search on server side. However, I get lost on how to pass searchResults back into the UI on a selectInput panel?
My current code:
ui.R
library(shiny)
shinyUI(pageWithSidebar(
sidebarPanel(
textInput("nameSearch", "Or, Search for company name", 'McDonald'),
selectInput("partnerName", "Select your choice", list( "searchResults" ),
br(),
submitButton("Update View"),
br(),
),
server.R
shinyServer(function(input, output) {
#subTable
searchResult<- reactive({
subset(partners, grepl(input$nameSearch, partners$name))
})
output$searchResults <- renderTable({
searchResult[,1]
})
global.R
partners<- read.csv("partnersList.csv", fill=TRUE)
partnersList is just in this format
name id
------------------
McDonalds 1
Wendy's 2
Bestbuy 3
You need to make the UI reactive. I haven't tested this (miss data for it too) but should work I think. In server.R add:
output$selectUI <- renderUI({
selectInput("partnerName", "Select your choice", searchResult()[,1] ),
})
And in ui.R replace the selectInput with:
htmlOutput("selectUI")
In Shiny version 0.8 (where I have tested it), in server.R add the following:
shinyServer(function(input, output, session) {
observe({
# This will change the value of input$partnerName to searchResult()[,1]
updateTextInput(session, "partnerName",
label = "Select your choice",
value = searchResult()[,1])
})
})
Now the function within shinyServer has additional argument session.
You can skip the label if you don't need to change it.
You don't need to change anything in ui.R.
Reply from Rstudio's JC:
Sure, just use a textInput for the search string, and use
renderUI/uiOutput to make a dynamic selectInput. Then the rest of
your code can depend on the selectInput's value. (Make sure to check
for NULL or whatever when reading the selectInput value, because it
will start out with no value.)
If I understand the question correcly, all you need to do is display to the user company names and have company ids passed to the server.
I suppose this feature was not available back in the days (and you had to work around as suggested above) but nowadays the argument choices in selectInput function accepts named lists exactly for this need. Hopefully example below clarifies the situation.
library(shiny)
library(tidyverse)
companies <- tribble(
~name, ~id,
"McDonalds", 1,
"Wendy's", 2,
"Bestbuy", 3
)
ui <- fluidPage(
uiOutput("select_company_ui"),
textOutput("value")
)
server <- function(input, output) {
output$select_company_ui <- renderUI({
selectInput("select_company", "Select company", choices = deframe(companies))
})
output$value <- renderText(paste0("Value of the company filter is ", input$select_company))
}
# Run the application
shinyApp(ui = ui, server = server)
Here you can see the resulting app:
Side note: I use function deframe from package tibble to turn a tibble into a named list just for convenience, you could do without it by writing
choices = c("McDonalds" = 1, "Wendy's" = 2, "Bestbuy" = 3)