How can I create a conditional selectInput widget in R Markdown? - r

The purpose is to choose a county from a state. I first create a selectInput widget for choosing a state. Then I create a selectInput widget for choosing a county from the selected state. In an R Markdown, the code is as follows:
inputPanel(
selectInput(inputId = "State", label = "Choose a state:", choices = state.name),
selectInput(inputId = "County", label = "Choose a county:", choices = input.State)
)
I guess the use of input.State is problematic, but I don't have any other idea.
Thanks for your time!

There are a number of ways to create conditional/dynamic UI in Shiny (see here). The most straightforward is usually renderUI. See below for a possible solution for you. Note that this requires Shiny so if you’re using R Markdown make sure to specify runtime: shiny in the YAML header.
library(shiny)
# I don't have a list of all counties, so creating an example:
county.name = lapply(
1:length(state.name),
function(i) {
sprintf("%s-County-%i",state.abb[i],1:5)
}
)
names(county.name) = state.name
shinyApp(
# --- User Interface --- #
ui = fluidPage(
sidebarPanel(
selectInput(inputId = "state", label = "Choose a state:", choices = state.name),
uiOutput("county")
),
mainPanel(
textOutput("choice")
)
),
# --- Server logic --- #
server = function(input, output) {
output$county = renderUI({
req(input$state) # this makes sure Shiny waits until input$state has been supplied. Avoids nasty error messages
selectInput(
inputId = "county", label = "Choose a county:", choices = county.name[[input$state]] # condition on the state
)
})
output$choice = renderText({
req(input$state, input$county)
sprintf("You've chosen %s in %s",
input$county,
input$state)
})
}
)
Hope this helps!

Related

Show selectInput in rshiny based on condition (conditionalPanel)

I want to create an app that allows you to select one variable based on a condition.
So I have create a switchInput with conditions Yes, and No, and as you can see, a stratify SelectInput should appear in case Yes is marked.
However, no new SelectInput is displayed:
# Shiny
library(shiny)
library(shinyWidgets)
library(shinyjqui)
# Data
library(readxl)
library(dplyr)
# Plots
library(ggplot2)
not_sel <- "Not Selected"
# User interface
ui <- navbarPage(
main_page <- tabPanel(
title = "",
titlePanel(""),
sidebarLayout(
sidebarPanel(
title = "Inputs",
fileInput("xlsx_input", "Select XLSX file to import", accept = c(".xlsx")),
selectInput("num_var_1", "Variable X axis", choices = c(not_sel)),
selectInput("num_var_2", "Variable Y axis", choices = c(not_sel)),
switchInput(
inputId = "Id013",
onLabel = "Yes",
offLabel = "No"
),
conditionalPanel(
condition = "Id013 == 'Yes'", selectInput("Stratify", "Stratify", choices = c(not_sel)), #uiOutput("factor"),
),
actionButton("run_button", "Run Analysis", icon = icon("play"))
),
mainPanel(
tabsetPanel(
tabPanel(
title = "Plot",
br(),
plotOutput("sel_graph")
)
)
)
)
)
)
# Server
server <- function(input, output){
# Dynamic selection of the data. We allow the user to input the data that they want
data_input <- reactive({
#req(input$xlsx_input)
#inFile <- input$xlsx_input
#read_excel(inFile$datapath, 1)
iris
})
}
# Connection for the shinyApp
shinyApp(ui = ui, server = server)
I understand, based on the conditionalPanel function:
Creates a panel that is visible or not, depending on the value of a JavaScript expression. The JS expression is evaluated once at startup and whenever Shiny detects a relevant change in input/output.
That the change on the switchInput value should be enough to generate this changes in the UI interface.
As said in the docs of conditionalPanel():
For example, if you have an input with an id of foo, then you can use input.foo to read its value.
So you need to use input.Id013 instead of Id013 in the condition. Also, even if the labels of the switch are "Yes" or "No", it returns a value TRUE/FALSE (which are written "true" or "false" in Javascript). So the condition you need to use is:
condition = "input.Id013 == true"

fileInput function not responding in r Shiny

I am new to R and R shiny, and have been working on putting together a statistics application that will allow the user to import files, and then run different statistics programs on the data. The fileData function had been working fine for me until recently, and now whenever I attempt to upload a file, nothing opens. I have tried everything I can think of to get it to run, but it appears the file won't attach to the function. Any help will be very much appreciated!
library(shiny)
library(shinyFiles)
library(dplyr)
library(shinythemes)
ui <- fluidPage(theme = shinytheme("cosmo"),
# Application title
titlePanel("Stats"),
# Sidebar
sidebarLayout(
sidebarPanel(
tabsetPanel(type = "tab",
tabPanel("SCI",
fileInput("file1", "Insert File", multiple = TRUE, accept = c("text/csv", "text/comma-separated-values, text/plain", ".csv")),
selectInput("statChoice", "Choose Stats", c("None" = "None", "ANOVA 0 w/in 1 btw" = "A1btw", "ANOVA 0 w/in 2 btw" = "A2btw")),
conditionalPanel("statChoice == 'A1btw'",
uiOutput("ind1"),
uiOutput("dep1")),
conditionalPanel("statChoice == 'A2btw'",
uiOutput("ind1"),
uiOutput("ind2"),
uiOutput("dep1")),
)
)
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(type = "tab",
tabPanel("Data",
dataTableOutput("fileData")),
tabPanel("Summary Statistics"),
tabPanel("Graphs"))
)
)
)
server <- function(input, output) {
fileData <- eventReactive(input$file1,{
read.csv(input$file1$dataPath, header = TRUE, sep = ",", dec = ".")
})
output$fileData <- renderDataTable(
fileData()
)
vars <- reactive({
names(fileData())
})
output$ind1 <- renderUI({
selectInput("var1", "Independent 1", choices = vars())
})
output$ind2 <- renderUI({
selectInput("var2", "Independent 2", choices = vars())
})
output$dep1 <- renderUI({
selectInput("var3", "Dependent 1", choices = vars())
})
}
shinyApp(ui = ui, server = server)
Tricky because Shiny doesn't give any warning about this :
shiny app will not work if the same "output" is used two times in Ui.R.
Everything looks OK, except the double use of uiOutput("dep1") and uiOutput("ind1") :
conditionalPanel("statChoice == 'A1btw'",
uiOutput("ind1"), # Used once
uiOutput("dep1")), # Used once
conditionalPanel("statChoice == 'A2btw'",
uiOutput("ind1"), # Used twice
uiOutput("ind2"),
uiOutput("dep1")), # Used twice
You should use an output only once.

Use dynamically generated column names in Shiny

I have a Shiny app which contains two dataframes.
The user presses a button which creates new columns in the dataframe
I have a further selectInput box which I want to populate with the names of the dataframe columns as they appear in the Shiny app (ie if the user have pressed the button then the SlectInput box would contain the new column names).
My attempt so far:
---
title: "GUI"
output: html_document
runtime: shiny
---
```{r, echo=FALSE}
library(EndoMineR)
RV <- reactiveValues(data = mtcars)
shinyApp(
ui = fluidPage(
selectInput("variable", "Variable:",
colnames(RV$data)),
tableOutput("data")
),
server = function(input, output) {
observeEvent(input$doExtractor, {
mtcars$cyl2<-mtcars$cyl*10
})
}
)
```
but I get the error:
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.)
besides what MLavoie already mentioned, you want to use updateSelectInput for things like this. Below is working example.
shinyApp(
ui = fluidPage(
column(
width = 3,
selectInput(
inputId = "variable",
label = "Variable:",
choices = colnames(mtcars)),
actionButton(
inputId = "doExtractor",
label = "do Extractor"
)
),
column(
width = 9,
dataTableOutput("data")
)
),
server = function(input, output,session) {
RV <- reactiveValues(data = mtcars)
observeEvent(input$doExtractor, {
browser()
RV$data$cyl2<-mtcars$cyl*10
})
observe(
updateSelectInput(
session = session,
inputId = "variable",
choices = colnames(RV$data),
selected = input$variable # only necessary if you want to keep the selection
)
)
output$data <- renderDataTable({
browser()
DT::datatable(RV$data)
})
}
)
Hope this helps!

R Shiny synchronize filters on multiple tabs

I built a R Shiny application with multiple tabs, which have some filters in common. Right now, all filters are stand-alone and do not synchronize across multiple tabs. Hence, when I change selectInput1 from value "a" to value "b", I have to repeat this handling on the next tab which contains selectInput2 with the same options/meaning.
I thought about making the filters dynamic, hence rendering them using the server side of R Shiny. Then of course, I can always make selectInput2 equal to selectInput1. But what if the user changes selectInput2 rather than selectInput1? It creates kind of a loop in the logic.
I spent quite some time finding a solution for this problem, and somehow I'm sure I'm not the first one encountering this problem. Suggestions or useful links would be really helpful!
Example:
## UI.R
shinyUI(
dashboardPage("Dashboard",
# Create tabs
tabPanel("Start",
p("This is the frontpage")
),
tabPanel("tab1",
uiOutput("selectInput1")
),
tabPanel("tab2",
uiOutput("selectInput2")
)
)
)
and:
## Server.R
library(shiny)
shinyServer(function(input, output,session){
output$selectInput1 <- renderUI({
selectInput(inputId = "id1",
label = "select",
choices = c("a","b","c"),
selected = "a")
})
output$selectInput2 <- renderUI({
selectInput(inputId = "id2",
label = "select",
choices = c("a","b","c"),
selected = "a")
})
})
I would personally use a single input control to control the different tab panels. One way is to include that single input under your tabs:
shinyApp(
fluidPage(
fluidRow(
tabsetPanel(
tabPanel("Tab1",
verbatimTextOutput("choice1")),
tabPanel("Tab2",
verbatimTextOutput("choice2"))
)
),
fluidRow(
selectInput("id1", "Pick something",
choices = c("a","b","c"),
selected = "a")
)
),
function(input, output, session){
output$choice1 <- renderPrint(input$id1)
output$choice2 <- renderPrint({
paste("The choice is:", input$id1)
})
}
)
Or, as you use a shinydashboard, you could actually add that control in the sidebar, possibly again in its own row under a set of tabs if you must.
I can't think of a reason to have multiple inputs who automatigically select the same thing. Other than slowing down your app, I can't see any gain. But if you insist, you make the selected choice a reactive value using reactiveVal and you use eg observeEvent() to update that reactive value. A small example using shinydashboard:
library(shinydashboard)
library(shiny)
ui <- shinyUI(
dashboardPage(title = "Dashboard",
dashboardHeader(),
dashboardSidebar(
tabsetPanel(
tabPanel("tab1",
uiOutput("selectInput1")
),
tabPanel("tab2",
uiOutput("selectInput2")
)
)),
dashboardBody(
verbatimTextOutput("selected")
)
)
)
server <- shinyServer(function(input, output,session){
thechoice <- reactiveVal("a")
output$selectInput1 <- renderUI({
selectInput(inputId = "id1",
label = "select",
choices = c("a","b","c"),
selected = thechoice())
})
output$selectInput2 <- renderUI({
selectInput(inputId = "id2",
label = "select",
choices = c("a","b","c"),
selected = thechoice())
})
observeEvent(input$id2,{
thechoice(input$id2)
})
observeEvent(input$id1,{
thechoice(input$id1)
})
output$selected <- renderPrint({
c(input$id1, input$id2)
})
})
shinyApp(ui, server)

Creating R-shiny app, want to use the names of people in CSV file as choices in selectInput

Not sure if this has been asked before. I am very new to working with RShiny apps, and I would like to use the values from a particular column of a particular CSV file for the choices in my selectInput() select box. Here is my code without the CSV, using some dummy variables.
ui <- shinyUI(fluidPage(
titlePanel(title = h4("PLAYER SELF-CENTERED RATING (PSCR)", align = "center")),
sidebarLayout(
sidebarPanel(
selectInput("selectplayer",
label = h3("Select box"),
choices = list("Choice 1" = 3,
"Choice 2" = 4,
"Choice 3" = 5),
selected = 3)
),
mainPanel(
plotOutput('radarPlot', width = "100%")
)
)
))
quite frankly, I'm fairly lost w.r.t where to begin on this. I also will need to use data from the CSV file to create another dataframe that is plotted in a renderPlot() call in shinyServer, so will need to find a way to get the CSV data into both server and ui. Is this a simple task, or something difficult? any help appreciated!
You can display uiOutput in ui and dynamically generate the ui in server. The code below should give you a hint.
library(shiny)
server <- function(input, session, output) {
# read csv here
datin <- read.table(text = 'Name,Age,Weight
John,10,40
Hary,20,70
Mike,30,80',
header = TRUE, sep =",", stringsAsFactors = FALSE)
output$select_1 = renderUI({
selectInput("select_input","select", choices = datin['Name'])
})
}
ui <- fluidPage(
uiOutput("select_1")
)
shinyApp(ui = ui, server = server)
You can generate dynamic output using uiOutput in the sidebar as shown in the following code:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "R-shiny app"),
dashboardSidebar(
uiOutput("columnNames") # Dynamic generate UI element
),
dashboardBody(
fluidRow(
column(10,
dataTableOutput('dataview')) #Display data in the tabular form
),
fluidRow(column(3, verbatimTextOutput("column_value"))),
hr()
)
)
server <- function(input, output) {
# Read data from .csv file
data=iris # (for understanding I am using iris dataset)
output$column_value <- renderPrint({
output$columnNames <- renderUI({
selectInput("datacolumn", h4("Select Data Column"), colnames(data)) # Dynamically set selectInput
})
output$dataview <- renderDataTable(data,options = list(pageLength = 10)) # Display the iris dataset
})
}
shinyApp(ui, server)

Resources