Overall context: I am trying to build a decision tree app in shiny and have never used shiny before. I am trying to have text display when a certain radio button is selected. After trial and error I still can't get anything to display with different inputs. Below is the basic code.
library(shiny)
priceChange <- "Does it change the price?"
zpInfer1 <- "Can zero-price-change be inferred?"
ui <- fluidPage(
radioButtons("exist", "Does it exist?",
c("Yes" = "existYes",
"No" = "existNo"),
textOutput("a")
)
)
server <- function(input, output){
output$a <- renderText({
existAnswer <- switch(input$exist,
existYes = priceChange,
existNo = zpInfer1)
})
}
shinyApp(ui, server)
As #Phil said, this seems to be a simple syntax error. This one should work :
library(shiny)
priceChange <- "Does it change the price?"
zpInfer1 <- "Can zero-price-change be inferred?"
ui <- fluidPage(
radioButtons("exist", "Does it exist?",
c("Yes" = "existYes",
"No" = "existNo")),
textOutput("a")
)
server <- function(input, output){
output$a <- renderText({
existAnswer <- switch(input$exist,
existYes = priceChange,
existNo = zpInfer1)
})
}
shinyApp(ui, server)
Related
In a Shiny app, I would like to be able to use check boxes or radio buttons to toggle on and off the visible output.
Currently, I can achieve this only by creating separate check box ui items and observe conditions for each element I would like to toggle.
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
uiOutput('select1'),
uiOutput('select2'),
div(id='table1',tableOutput('data1')),
div(id='table2',tableOutput('data2'))
)
server <- function(input, output){
data1 <- data.frame(X1=1:5,
X2=6:10)
data2 <- data.frame(Y1=1:5,
Y2=6:10)
output$data1 <- renderTable(data1)
output$data2 <- renderTable(data2)
output$select1 <- renderUI({
checkboxGroupInput('select1', 'Select T1',
choices = 'table1',
selected = 'table1')
})
output$select2 <- renderUI({
checkboxGroupInput('select2', 'Select T2',
choices = 'table2'
)
})
observe({
toggle(id='table1', condition = input$select1)
})
observe({
toggle(id='table2', condition = input$select2)
})
}
shinyApp(ui, server)
Question 1
When the app loads both tables are displayed despite only one being selected. Toggling the second on and then off is required to hide it. Can this be changed so it isn't displayed on first load?
Question 2
I realise my approach is inefficient and it is likely possible to achieve the same with a single checkBoxGroupInput containing the various options and a single observe condition. I'm really inexperienced here and cannot figure it out.
Your help is appreciated.
toggle expects a boolean but input$select returns a character, which might explain the unexpected behaviour.
With a single checkboxGroupInput, using %in% to get booleans:
library(shiny)
library(shinyjs)
ui <- fluidPage(
useShinyjs(),
uiOutput('select'),
div(id='table1',tableOutput('data1')),
div(id='table2',tableOutput('data2'))
)
server <- function(input, output){
data1 <- data.frame(X1=1:5,
X2=6:10)
data2 <- data.frame(Y1=1:5,
Y2=6:10)
output$data1 <- renderTable(data1)
output$data2 <- renderTable(data2)
output$select <- renderUI({
checkboxGroupInput('select', 'Select table',
choices = list('table1','table2'),
selected = 'table1')
})
observe({
toggle(id='table1', condition = "table1" %in% input$select)
toggle(id='table2', condition = "table2" %in% input$select)
})
}
shinyApp(ui, server)
I have a shiny application reading an input from ui and I am unable to follow up with the data from the input in my code. As below:
ui <- fluidPage(
...
selectInput("ISvModels", "Choose:",
choices = c(1000,5000)),
)
server <- function(input, output) {
vModels <- reactive({input$ISvModels})
qtModels <- length(vModels)
qtModels
vtModels <- paste0("M",1:qtModels," n = ",vModels," scenarios")
vtModels
}
And I get:
Warning: Error in as.vector: cannot coerce type 'closure' to vector of type 'character'
I tried all sort of things from observe to renders but nothing works. Seems I'm missing some concepts here, hope you can help. Thanks!
Your server needs an output, some way for what you've calculated to be shown to the user. We can use a textOutput to achieve this.
Below is a minimal example, showing a dropdown box linked to a textbox.
library(shiny)
ui <- fluidPage(
#Dropdown
selectInput("ISvModels", "Choose:", choices = c(1000,5000)),
#Textbox
textOutput("mytext")
)
server <- function(input, output, session) {
#Prepare Textbox Content
output$mytext <- renderText({
qtModels <- length(input$ISvModels)
vtModels <- paste0("M", 1:qtModels, " n = ", input$ISvModels," scenarios")
return(vtModels)
})
}
shinyApp(ui, server)
I'm building an application in which we have 2 fluidPage(). First fluidPage() have a data table with a hyperlink in one column, which gets linked with other fluidPage().
While looking for this scenario, I came upon this solution which links to another tabPanel().
I tried to create two fluidPage() like this
library(shiny)
library(DT)
server <- function(input, output) {
output$iris_type <- DT::renderDataTable({
datatable(data.frame(Species=paste0("<a href='#filtered_data'",
"alt='",unique(iris$Species),"'",
"onclick=\"",
"$('#filtered_data').trigger('change').trigger('shown');",
"Shiny.onInputChange('species', getAttribute('alt'));",
"\">",
unique(iris$Species),
"</a>")),
escape = FALSE)
})
output$filtered_data <- DT::renderDataTable({
if(is.null(input$species)){
datatable(iris)
}else{
datatable(iris[iris$Species %in% input$species, ])
}
})
}
ui <- shinyUI(fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Iris Type", DT::dataTableOutput("iris_type"))
))
),
fluidPage(
mainPanel(
DT::dataTableOutput("filtered_data")
)
)
)
shinyApp(ui = ui, server = server)
I'm getting an error message
Error in shinyUI(fluidPage(mainPanel(tabsetPanel(tabPanel("Iris Type", :
unused argument (fluidPage(mainPanel(DT::dataTableOutput("filtered_data"))))
Can anyone provide a suitable solution where on clicking the specific species, the corresponding table should get displayed on another page rather than being displayed in another tab?
Thanks in advance!!!
I want to render a text to notify the user that a task is going to run, but it seems that shiny executes all code in server first then it moves to UI.
Here is an example:
library(shiny)
ui <- fluidPage(
mainPanel(
textOutput("ptext")
))
server <- function(input, output) {
output$ptext <- renderText("creating a dataframe")
df <- matrix(rnorm(10000),nrow = 10) # a large dataset
output$ptext <- renderText("dataframe created !!")
}
shinyApp(ui = ui, server = server)
In the above example, I never see "creating a dataframe", How to render that text first before executing the rest of the code.
It's not the most beautiful, but if you can use an input for status messages like this, you can relay what's going on ...
library(shiny)
ui <- fluidPage(
mainPanel(
textInput("notice", "Status", "creating a dataframe"),
textOutput("ptext")
)
)
server <- function(input, output, session) {
dat <- reactive({
Sys.sleep(3)
matrix(rnorm(10000), nrow = 10)
})
output$ptext <- renderText({
req(dat())
updateTextInput(session, "notice", value = "dataframe created !!")
return("hello world")
})
}
shinyApp(ui = ui, server = server)
(Note the addition of session to the arguments to server, necessary to use updateTextInput(session, ...).)
You could get more complex by using dynamic UI creation and deletion, or object hiding (perhaps using shinyjs), but that is getting a bit more complex than I think you may want.
Quick question on conditionalPanel for shiny/R.
Using a slightly modified code example from RStudio, consider the following simple shiny app:
n <- 200
# Define the UI
ui <- bootstrapPage(
numericInput('n', 'Number of obs', n),
conditionalPanel(condition = "input.n > 20",
plotOutput('plot') ),
HTML("Bottom")
)
# Define the server code
server <- function(input, output) {
output$plot <- renderPlot({
if (input$n > 50) hist(runif(input$n)) else return(NULL)
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
My objective is to hide the graph and move up the HTML text to avoid a gap. Now, you can see that if the entered value is below 20, the graph is hidden and the text "Bottom" is moved up accordingly. However, if the entered value is larger than 20, but smaller than 50, the chart function returns NULL, and while no chart is shown, the text "Bottom" is not moving up.
Question is: is there a way I can set a conditionalPanel such that it appears/is hidden based on whether or not a plot function returns NULL? The reason I'm asking is because the trigger a bit complex (among other things it depends on the selection of input files, and thus needs to change if a different file is loaded), and I'd like to avoid having to code it on the ui.R file.
Any suggestions welcome,
Philipp
Hi you can create a condition for conditionalPanel in the server like this :
n <- 200
library("shiny")
# Define the UI
ui <- bootstrapPage(
numericInput('n', 'Number of obs', n),
conditionalPanel(condition = "output.cond == true", # here use the condition defined in the server
plotOutput('plot') ),
HTML("Bottom")
)
# Define the server code
server <- function(input, output, session) {
output$plot <- renderPlot({
if (input$n > 50) hist(runif(input$n)) else return(NULL)
})
# create a condition you use in the ui
output$cond <- reactive({
input$n > 50
})
outputOptions(output, "cond", suspendWhenHidden = FALSE)
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
Don't forget to add the session in your server function and the outputOptions call somewhere in that function.