Dependent inputs in Shiny application with R
An example of updateSliderInput
in shiny rmd
---
title: "Dependent Inputs"
runtime: shiny
output:
html_document
---
```{r}
sliderInput("n", "n", min=0, max=100, value=1)
sliderInput("n2", "n2", min=0, max=100, value=1)
observe({
updateSliderInput(session, "n", min=input$n2-1, max=input$n2+1, value=input$n2)
})
```
R Shiny - Dynamically adding dependent inputs using insertUI
Below is a working code. The main problem was your ctn
reactive value initialized to NULL
, because NULL + 1 = numeric(0)
and numeric(0) + 1 = numeric(0)
.
library(shiny)
ui <- fluidPage(
actionButton('add', 'Add'),
div(id = 'placeholder')
)
server <- function(input, output, session) {
ctn <- reactiveVal(0)
Id <- reactive({
function(id){
paste0(id, ctn())
}
})
observeEvent(input$add, {
ctn(ctn() + 1)
insertUI(
selector = '#placeholder',
ui = div(
id = Id()('div'),
selectInput(Id()('letter'), 'Letter:', LETTERS[1:2]),
uiOutput(Id()('input'))
)
)
})
observeEvent(ctn(), {
id <- Id()('input')
selection <- Id()('letter')
output[[id]] <- renderUI({
req(input[[Id()('letter')]])
switch(
input[[selection]],
'A' = textInput(Id()('text'), 'ENTER TEXT', ''),
'B' = numericInput(Id()('numeric'), 'ENTER NUMBER', '')
)
})
}, ignoreInit = TRUE)
}
How to create mutually dependent numeric Input in Shiny?
You need to do two main things:
First let your initial values stable, so either their sum should be 1 (0.333, 0.333, 0.334), or maybe let the initial values be empty, which will only work if you have some type of error escaping mechanism to allow NA or empty string to be an initial value. As I thought there should be in any case some validation that the input is numeric I chose to use the second option, which works well with the validation.
Second one way to get rid of these infinite loops of observing and changing the input, is to change one at a time, meaning:
- if A is changed ---> change B,
- if B is changed ---> change C, and
- if C is changed ---> change A
That being said, note that the order of changing the input makes a difference in this approach, this is most noticeable at the start when you give the input their first set of values.
There might be a better approach to solve this, but this is what I can think of, so here it goes.
The UI:
library(shiny)
ui <- shinyUI(fluidPage(
titlePanel("Mutually Dependent Input Values"),
sidebarLayout(
sidebarPanel(
numericInput("A", "A", NA),
numericInput("B", "B", NA),
numericInput("C", "C", NA)
),
mainPanel(
verbatimTextOutput("result")
)
)
))
The Server:
server <- shinyServer(function(input, output, session) {
sum <- reactive({
validate(
need(is.numeric(input$A), 'A is not a number, only numbers are allowed'),
need(is.numeric(input$B), 'B is not a number, only numbers are allowed'),
need(is.numeric(input$C), 'C is not a number, only numbers are allowed')
)
input$A + input$B + input$C})
observeEvent(input$A,{
newB <- 1 - input$A - input$C
updateNumericInput(session, "B", value = newB)
})
observeEvent(input$B,{
newC <- 1 - input$B - input$A
updateNumericInput(session, "C", value = newC)
})
observeEvent(input$C,{
newA <- 1 - input$C - input$B
updateNumericInput(session, "A", value = newA)
})
output$result <- renderPrint({
print(sprintf("A=%.3f B=%.3f C=%.3f ----> A + B + C = %.0f",
input$A, input$B, input$C, sum()))
})
})
Run:
shinyApp(ui,server)
Dependent filter in shiny inputs
the problem comes from that you have your render UI codependent of the input variables and when one changes the whole UI rerendered including the values of the input variables. Fot this use-case you are better of with the update*Input
functions. Here is a working version for your example
library(shiny)
library(shinydashboard)
library(shinyWidgets)
##
ui <- shinyUI({
sidebarPanel(
htmlOutput("brand_selector"),
htmlOutput("candy_selector"))
})
##
server <- shinyServer(function(input, output,session) {
candyData <- read.table(
text = "Brand Candy
Nestle 100Grand
Netle Butterfinger
Nestle Crunch
Hershey's KitKat
Hershey's Reeses
Hershey's Mounds
Mars Snickers
Mars Twix
Mars M&Ms",
header = TRUE,
stringsAsFactors = FALSE)
observeEvent({
input$candy
},
{
available2 <- candyData
if(NROW(input$candy) > 0 ) available2 <- candyData[candyData$Candy %in% input$candy, ]
updatePickerInput(
session = session,
inputId = "brand",
choices = as.character(unique(available2$Brand)),
selected = input$brand
)
},
ignoreInit = FALSE,
ignoreNULL = FALSE)
output$brand_selector <- renderUI({
pickerInput(
inputId = "brand",
label = "Brand:",
choices = NULL,
multiple = T,options = list(`actions-box` = TRUE))
})
observeEvent({
input$brand
},{
available <- candyData
if(NROW(input$brand > 0)) available <- candyData[candyData$Brand %in% input$brand, ]
updatePickerInput(
session = session,
inputId = "candy",
choices = unique(available$Candy),
selected = input$candy
)
},
ignoreInit = FALSE,
ignoreNULL = FALSE)
output$candy_selector <- renderUI({
pickerInput(
inputId = "candy",
label = "Candy:",
choices = NULL,
multiple = T,options = list(`actions-box` = TRUE))
})
})
##
shinyApp(ui = ui, server = server)
Connect mutually dependent shiny input values
There are a few ways to do this, here is one way:
library(shiny)
u <- shinyUI(fluidPage(
titlePanel("Mutually Dependent Input Values"),
sidebarLayout(
sidebarPanel(
numericInput("X", "X",2000),
numericInput("P", "P",1),
numericInput("C", "C",1000)
),
mainPanel(
verbatimTextOutput("result")
)
)
))
s <- shinyServer(function(input, output,session) {
observeEvent(input$P,{
newX <- input$P*input$C + input$C
updateNumericInput(session, "X", value = newX)
})
observeEvent(input$X,{
newP <- (input$X - input$C)/input$C
updateNumericInput(session, "P", value = newP)
})
output$result<-renderPrint({
val <- input$P*input$C + input$C
print(sprintf("X:%.0f P:%.0f C:%.0f - P*C + C:%.0f",input$X,input$P,input$C,val))
})
})
shinyApp(u,s)
Yielding:
Not sure this is the best way, it occilates if you start out in a state that is inconsistent - need to think about how to suppress this.
Shiny modal that is dependent on fileInput() in shiny app
Perhaps you can try with an if condition.
observeEvent(input$file1, {
if (is.null(input$file1))
# Show a modal when the button is pressed
shinyalert("Oops!", "Something went wrong.", type = "error")
}, ignoreNULL = FALSE)
Shiny: in search of simple selectInput dependency solution
Thanks to Ben for pointing me in the right direction (see link in his comment). I basically needed to change the second selectInput statement in the ui to:
selectInput("countyin", "Select County", choices = NULL)
and then add an observe statement in the server to make the selections reactive:
observe({
updateSelectInput(session, "countyin", "Select County",
choices = usdata[usdata$state == input$statein,]$county)
})
Related Topics
Puzzled by Xlim/Ylim Behavior in R
Error: Package or Namespace Load Failed for 'Car'
Adding a Legend to an Rgl 3D Plot
Find Closest Points (Lat/Lon) from One Data Set to a Second Data Set
Read Column Names as Date Format
Add a Constant Value to All Rows in a Dataframe
Why "Character Is Often Preferred to Factor" in Data.Table for Key
R Shiny: Multiple Use in UI of Same Renderui in Server
Create a Concentric Circle Legend for a Ggplot Bubble Chart
Combining .Sd with Renamed Variable Messes with Names of .Sd Columns
Create a New Column with Non-Null Columns' Names
Understanding Bandwidth Smoothing in Ggplot2
How to Pop Up the Graphics Window from Rscript
Accessing Functions with a Dot in Their Name (Eg. "As.Vector") Using Rpy2
Check Which Elements of a Vector Is Between the Elements of Another One in R