I would like to show content of my shiny app depending on the number of selected items of a multiselect input. So far I couldn't figure out what the condition should look like to make this work.
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("select and conditional panel"),
sidebarPanel(
selectInput(inputId = "someSelect", multiple=TRUE, label = "Genes:", choices = colnames(someDataFrame), selected = c("ESR1", "CD44")),
),
mainPanel(
conditionalPanel(
condition="length(input.someSelect.selected) > 2",
tabsetPanel(
...
)
)
)
))
It is probably a matter of taste, but I don't like the conditionalPanel construct, because it enters a javascript logic into an R code. Instead I prefer the uiOutput (and the respective renderUI), that can generate dynamic UI. while the conditionalPanel can handle only rather simple conditions, the dynamic UI approach can create conditional appearance that are based on more complex logic and can take advantage of the power of R.
it is, however, slightly slower to respond to changes.
if you use this approach your ui.r should look something like:
mainPanel(uiOutput("myConditionalPanel"))
and your server.r would look something like:
output$myConditionalPanel = renderUI({
if(length(input$someSelect)>2) {
## some ui definitions here. for example
tabsetPanel(
...
)
} else {
## some alternative definitions here...
}
})
You can't use a R function into the condition of the conditional panel. I think your condition should be : input.someSelect.length > 2
Hopefully this helps someone else having the same issue I had...
Using the above answers I was having issues when trying to make a conditionalPanel only appear when 2 or more items were selected in a selectInput. The uiOutput/renderUi method was buggy and with the condition input.someSelect.length > 1 the conditionalPanel appeared even when nothing was selected in the selectInput.
With the conditionPanel, I needed to include a condition to check whether the selectInput was defined:
"input.someSelect != undefined && input.someSelect.length > 1"
Related
I'm new to Shiny - a lot I don't fully understand yet. I'm working on a Shiny app to display some data. I want to allow for optional filtering of the data before being plotted. In order to construct my criteria, the UI will supply some selectInputs. My plan is that these are initially disabled. I could add, to the UI, buttons to activate each selectInput independently. But I wanted to try and use a checkboxGroupInput for this task. To begin developing this, I tried working on just one of the checkboxGroupInput values enabling/disabling just one of the selectInputs. It works perfectly except for one specific case. If I select the targeted checkboxGroupInput, the targeted selectInput gets enabled. But if I deselect that targeted checkboxGroupInput, the targeted selectInput does not get disabled. However, this behavior only occurs if no other checkboxGroupInput selection is currently selected. If any, or multiple, other checkboxGroupInputs are selected, the target will enable and disable in exactly the way I want and expect based on my (limited) understanding of the code.
Below is (hopefully) a clear and simple piece of code to demonstrate this behavior. I have a checkboxGroupInput with four items, and 4 selectInputs. Checking the third checkboxGroupInput item is supposed to enable the third selectInput. Unchecking (deselecting) the third checkboxGroupInput item is supposed to disable the third selectInput. Again, it behaves in precisely this way - if at least one other checkboxGroupInput is selected. The third selectInput will always be enabled by selecting the third checkboxGroupInput, but deselecting the third checkboxGroupInput item will not disable the third selectInput unless at least one other item is currently selected in the checkboxGroupInput.
I added output of the currently selected checkboxGroupInput contents to try and understand what was happening.
Last thing before the code -- I also first constructed the checkboxGroupInput using choices instead of choiceNames and choiceValues; didn't seem to matter. Also, my first try with the conditional test in the 'if' block was to use is.element instead of %in%; again, no difference in behavior.
library(shiny)
library(shinyjs)
# Let's make lists for the drop boxes
list_1 <- list("a", "b", "c")
list_2 <- list("d", "e", "f")
list_3 <- list("g", "h", "i")
list_4 <- list("j", "k", "l")
# Define UI for application
ui <- fluidPage(
useShinyjs(), # Set up shinyjs
# Application title
titlePanel("What's wrong with this??"),
# Sidebar
sidebarLayout(
sidebarPanel(
checkboxGroupInput("enabled", "Search Filters to Enable:",
choiceNames = list("List_1", "List_2", "List_3", "List_4"),
choiceValues = list("List_1_chosen", "List_2_chosen", "List_3_chosen", "List_4_chosen")),
# Input: Select from the following lists - default behavior is they are all disabled to start
disabled(selectInput("List_1_choice", "Choose from List 1:",
choices = list_1)),
disabled(selectInput("List_2_choice", "Choose from List 2:",
choices = list_2)),
disabled(selectInput("List_3_choice", "Choose from List 3:",
choices = list_3)),
disabled(selectInput("List_4_choice", "Choose from List 4:",
choices = list_4)),
verbatimTextOutput("text_choice")),
# Show a plot
mainPanel(
# empty
)
)
)
# Define server logic
server <- function(input, output) {
# This output is so I can see what's selected in the checkboxGroupInput
output$text_choice <- renderPrint({
return(paste0(input$enabled))})
observeEvent(input$enabled, {
# Here's the problem (I think) -- this 'if' block is not working the way I expect
if("List_3_chosen" %in% input$enabled){
enable("List_3_choice")
}else{
disable("List_3_choice")
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have lot's of workarounds to complete this project, but I would very much like to understand what I'm doing wrong here.
Help! And thanks for your time and attention.
When nothing is selected, checkboxGroupInput returns NULL. You need to explicitly tell the observeEvent to not ignore it:
observeEvent(input$enabled, {
# Here's the problem (I think) -- this 'if' block is not working the way I expect
if("List_3_chosen" %in% input$enabled){
enable("List_3_choice")
}else{
disable("List_3_choice")
}
}, ignoreNULL = FALSE)
My goal is to have a tabsetPanel wrapped in a conditionalPanel whose condition is a global variable being false.
ui.R
mainPanel(
conditionalPanel("searchPage == \"false\"",
tabsetPanel(
tabPanel("Summary",htmlOutput("summary")),
tabPanel("Description", htmlOutput("description"))
))),
global.R
searchPage <- "true"
then in server.R I assign new values to it a few different times, but all like this:
observeEvent(input$openButton,
output$results <- renderUI({
textOutput("")
searchPage <- "false"
}))
No matter what I do, I always get "Uncaught ReferenceError: searchPage is not defined". I've tried changing the global.R to multiple different combinations of using quotes, not using quotes, using <- or <<-, making it this.searchPage, my.searchPage and numerous other things (of course always making server.R and ui.R match too), but haven't had much luck at all.
As mentioned in a comment on the question's post, this is a perfect usecase for the shinyjs toggle()/show()/hide() functions. Whenever you need to conditionally show something where the condition is not a simple javascript expression of an input, it's easy to use these functions instead of a conditionalPanel().
In order to use these functions, you need to have some way to specify the element you want to hide/show (in this case, the mainPanel()). The easist way to do this is to just wrap the entire panel in a div with an id. So define the panel like mainPanel(div(id = "mainpanel", ...)) and voila, there's an id to your panel, and now you can call shinyjs::show("mainpanel") or hide() whenever you want in the server code.
What you are trying to do is not really possible the way you are trying to do it (the server and client are in different environments and don't share variables). You will need to explicitly pass the value from server to client, and there are different approaches to doing that. One way:
library(shiny)
runApp(list(ui = fluidPage(
conditionalPanel(condition='output.bool',
HTML("Hello world")),
actionButton("btn","Press me to toggle")
),
server = function(input, output, session) {
value=TRUE
output$bool <- eventReactive(input$btn,{
value
})
outputOptions(output,"bool",suspendWhenHidden=FALSE)
observeEvent(input$btn,
value <<- !value
)
}))
There are probably better approaches. Hope this helps
I want to use checkboxGroupInput and then, if a certain box is checked, i want a conditionalPanel. A toy example is here:
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
checkboxGroupInput("items","Which Item?",
choices=c("A","B","C","D")),
conditionalPanel( condition = "input.items == 'D'",
numericInput("n","n",value=50,min=0,max=100,step=1)
)
),
mainPanel(
uiOutput("text")
)
)
))
now this works fine if only box 'D' is selected, but not if (as would be normal in my problem) several boxes are selected.
in server.R something like
if("D" %in% input$which)
works fine but that does not seem to work in ui.R. I also tried subsetting ala R, for example
conditionalPanel( condition = "input.items[4] == 'D'",
but that does not work either.
Wolfgang
docendo gave the correct answer: the syntax is
conditionalPanel(condition = "input.items.includes('D')"
Thanks!
somehow it no longer works with shiny v1.1.0. I am using R version 3.5.1 with platform windows. Rather than the includes() solution, the below works well for me (just in case others encounter the same issue):
conditionalPanel(condition = "input.items.indexOf('D') > -1", ...)
I am new to shiny, I have been stuck on this for quite a while and the things I tried and read so far held no fruits. I have a dropdown, where the user will choose a Question, then depending on the question, a drop down will be populated with the response numbers. After the user chooses the response number a map will be plotted. I have gone through the dynamic drop down list, that is done. But I cannot get access to the second user input, the response number, so I can select my data for the map accordingly. I feel like this is really simple I don't know why this does not work. I am getting this error:
Error in .getReactiveEnvironment()$currentContext() : Operation not
allowed without an active reactive context. (You tried to do something
that can only be done from inside a reactive expression or observer.)
My code is as follows, I have tentatively put in special cases and later I will expand to a general case with lists.
library(shiny)
runApp(list(
ui = shinyUI(pageWithSidebar(
headerPanel('Dialect Comparison'),
sidebarPanel(
selectInput('Question', 'Choose The Question', c('100. Do you cut or mow the lawn or grass?'='Q100',
'101. Do you pass in homework or hand in homework?'='Q101')),
uiOutput('C')
),
mainPanel(
plotOutput('plot')
)
)
),
server = function(input, output){
output$C = renderUI({
ques = input$Question
selectInput('Choice', 'Choose The Response', seq(0,max(ling_data[,ques])))
})
##########
#The Data#
##########
#text = renderPrint({'uhu'})
#print(text()) #THIS WORKS
choice_number = renderPrint({input$Choice}) #http://shiny.rstudio.com/gallery/dynamic-ui.html
print(choice_number()) #it fails here
...
})
}
))
Reactive variables, including inputs, can be accessed only in a reactive scope created using one of the following:
shiny::reactive, shiny::eventReactive
shiny::observe, shiny::observeEvent
shiny::render*
or inside shiny::isolate block.
For actions like logging you probably want observe block:
observe({print(choice_number())})
I am trying to display from 1 to 5 tabPanels in a navbarPage in Shiny.
I have 5 plots my code generates, but I'd like a user to be able to select how many they want to have access to -- to be displayed one plot in each tabPanel, naturally.
I've got an external configuration file (config.txt) that via source('config.txt'), I have access to a number_of_pages variable.
For example, number_of_tabPages <- 3
How would I set this up in UI.R?
The number of tabPanels can't be hardcoded at all in the UI file, since it depends on a value that is specified by a user, not using a control.
I've searched around and found that most of the approaches to this kind of thing
involve using uiOutput and renderUI functions, such as this similar problem, but I don't want any special control in the UI to do any selecting.
This is where things get tricky, when we are building the UI depending on values that may change. My brain is trying to wrap itself around the best method for doing this type of thing -- I feel like it isn't exactly in line with how Shiny wants to communicate with itself using a UI <--> server environment.
Any advice is greatly appreciated.
My UI.R is easy to create when it isn't dynamic:
fluidRow(
column(12,
"",
navbarPage("",tabPanel("First Tab",
plotOutput("plot1")),
tabPanel("Second Tab",
plotOutput("plot2")),
tabPanel("Third Tab",
plotOutput("plot3")),
tabPanel("Fourth Tab",
plotOutput("plot4")),
tabPanel("Fifth Tab",
plotOutput("plot5"))
)
)
)
)
Thanks!
If you don't need the user to change the number of tabPanel interactively, but just load varying numbers of them when the app is started you can use the do.call function in the navBarPage:
library(dplyr)
library(shiny)
library(ggvis)
#number of tabs needed
number_of_tabPages <- 10
#make a list of all the arguments you want to pass to the navbarPage function
tabs<-list()
#first element will be the title, empty in your example
tabs[[1]]=""
#add all the tabPanels to the list
for (i in 2:(number_of_tabPages+1)){
tabs[[i]]=tabPanel(paste0("Tab",i-1),plotOutput(paste0("plot",i-1)))
}
#do.call will call the navbarPage function with the arguments in the tabs list
shinyUI(fluidRow(
column(12,
"",
do.call(navbarPage,tabs)
)
)
)