I try to make two mutually dependent input sliders in a shiny app but don't seem to get it to work. I plan to use this kind of situation in a shiny app and for ease illustrate it here with a simplified 'glass half empty / full' example in which one slider should show glass fullness and one emptyness:
library(shiny)
ui =(pageWithSidebar(
headerPanel("Glass fullness"),
sidebarPanel(
sliderInput("Full", "% water", min = 0, max = 1, value = 0.2),
#display dynamic UI
uiOutput("Empty")),
mainPanel()
))
server = function(input, output, session){
# make dynamic slider
output$Empty <- renderUI({
sliderInput("Empty", "% air", min=0, max=1, value=1-input$Full)
})
}
runApp(list(ui = ui, server = server))
I understand the value = 0.2 and value=1-input$Full cause above code only to make the second slider dependent on the first but not the other way around. My problem is that I want to make both dependent on each other. I tried adding an uiOutput("Full") & dynamic slider for Full but did not manage to work around circular coding.
The result of above code looks as follows:
Glass half empty/full screenshot
Any help greatly appreciated!
Hi define your sliders in the UI and updated them in the server when it's needed :
library(shiny)
ui =pageWithSidebar(
headerPanel("Glass fullness"),
sidebarPanel(
sliderInput(inputId = "Full", label = "% water", min = 0, max = 1, value = 0.2),
sliderInput(inputId = "Empty", label = "% air", min = 0, max = 1, value = 1 - 0.2),
uiOutput("Empty")),
mainPanel()
)
server = function(input, output, session){
# when water change, update air
observeEvent(input$Full, {
updateSliderInput(session = session, inputId = "Empty", value = 1 - input$Full)
})
# when air change, update water
observeEvent(input$Empty, {
updateSliderInput(session = session, inputId = "Full", value = 1 - input$Empty)
})
}
shinyApp(ui = ui, server = server)
It is because in the second slider you have:
sliderInput("Empty", "% air", min=0, max=1, value=1-input$Full)
where value is 1-input$Full therefore it does depend on the first one, but in the first slider value is 0.2:
sliderInput("Full", "% water", min = 0, max = 1, value = 0.2),
and due to this 0.2, there is no relation with the second one.
Although, as you mention, you will end up with circular dependency.
Related
I want to perform the Shapiro-Wilk-Test in my Shiny App. Over the two sliders and the numeric input I get the values for rnorm. And because I can change my inputs to rnorm, I made it reactive.
But when running the app it doesn't work - I tried a lot, but it wasn't successful.
How must I change my code that it works? Thanks in advance!
My code:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("slider1", label = h3("Quantity of n"), min = 10, max = 100, value = 50),
sliderInput("slider2", label = h3("Mean of group 1"), min = 0, max = 100, value = 50),
numericInput("num", label = h3("SD of group 1"), value = 1)
),
mainPanel(
textOutput("Text1")
)
)
)
server <- function(input, output) {
group1=reactive({
rnorm(n=input$slider1,mean=input$slider2,sd=input$num)
})
# Shapiro-Wilk-Test
### shapiro.test(....)[[2]][1] shows the p-value
ND_G1=shapiro.test(group1())[[2]][1] # with "rnorm(10,5,2)" instead of group1() it works
output$Text1 <- renderText({paste("The p-value is: ",ND_G1)})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I plot GPS data on a leaflet map using R,
the trip is visualised through an incrementing timeline provided by the sliderInput in animation mode.
sliderInput("animation", "Mesures GPS :",
min = ifelse( !exists("i.data"), 0, min(i.data$sequence)),
max = ifelse( !exists("i.data"), 1, max(i.data$sequence)),
value = 0,
step=20,
animate = animationOptions(interval = 1000, loop = FALSE),
width="100%"))
I can see the GPS points jumping over the map, and now I am looking for the way to have a "next" button ([<<], [>>]) to control more finely local steps. I have not seen any such option in the sliderInput documentation.
This could also be done by adding ad-hoc shiny actionButtons,
any suggestion?
Adapting the code from ?sliderInput:
library(shiny)
shinyApp(
ui = fluidPage(
fluidRow(
div(style = "display: inline-block;vertical-align:center;",
actionButton("left", label = "<<")),
div(style = "display: inline-block;vertical-align:center;",
sliderInput("obs", "Number of observations:",
min = 0, max = 1000, value = 500
)),
div(style = "display: inline-block;vertical-align:center;",
actionButton("right", label = ">>")),
),
plotOutput("distPlot")
),
# Server logic
server = function(input, output, session) {
output$distPlot <- renderPlot({
hist(rnorm(input$obs))
})
observeEvent(input$left, {
updateSliderInput(session, "obs", value = input$obs - 10)
})
observeEvent(input$right, {
updateSliderInput(session, "obs", value = input$obs + 10)
})
}
)
This updates by +/- 10.
I have achieved to define two interconnected or mutually dependent input in my shiny app. Right now, my problem is to set a specific initial value for these slider and numeric inputs. It seems that they always start with the minimum value, even I don't now exactly why. How can I indicate a unique starting point or an initial value for these input parameters?
I have attached a simplified part of my app in order to provide you a reproducible version of my problem here:
"ui.R"
library(shiny)
shinyUI(fluidPage(
uiOutput("Param_s"),
uiOutput("Param_n")
))
and the "server.R"
library(shiny)
shinyServer(
function(input,output) {
# Mutually dependent slider and numeric inputs
output$Param_s = renderUI({
sliderInput(inputId = "param_slide",
label= "My input parameter",
value= input$param_numeric,
min=1,
max=200)
})
output$Param_n = renderUI({
numericInput(inputId = "param_numeric",
label= "My input parameter",
value= input$param_slide,
min=1,
max=200)
})
})
I tried various things to fix the initial value but eventually nothing worked. Any help would be appreciated!!
wow! I got it guys! You should only update the two input objects at the same time and up to the same value. It means adding these two lines solved my problem to set the initial value to 60 for example:
updateSliderInput(session,"param_slide", value = 60)
updateNumericInput(session,"param_numeric", value = 60 )
Therefore the whole "server.R" would be like this:
#
library(shiny)
shinyServer(
function(input,output,session) {
# Mutually dependent slider and numeric inputs
output$Param_s = renderUI({
sliderInput(inputId = "param_slide",
label= "My input parameter",
value= input$param_numeric,
min=1,
max=200)
})
output$Param_n = renderUI({
numericInput(inputId = "param_numeric",
label= "My input parameter",
value= input$param_slide,
min=1,
max=200)
})
updateSliderInput(session,"param_slide", value = 60)
updateNumericInput(session,"param_numeric", value = 60 )
})
You should only be aware of adding these updates with an
observeEvent()
when you have these input objects on the other tabs. In my case which I am using "sidebarMenu" I used a simple line of code as this:
observeEvent(input$sidebar_id =="tab1",{
updateSliderInput(session,"param_slide", value = 60)
updateNumericInput(session,"param_numeric", value = 60 )
})
Coming from here.
You should try to avoid re-rendering (renderUI) if possible.
It's faster to update existing inputs:
library(shiny)
ui <- fluidPage(
sliderInput(
inputId = "param_slide",
label = "My input parameter",
value = 60,
min = 1,
max = 200
),
numericInput(
inputId = "param_numeric",
label = "My input parameter",
value = 60,
min = 1,
max = 200
)
)
server <- function(input, output, session) {
observeEvent(input$param_numeric, {
updateSliderInput(session, "param_slide", value = input$param_numeric)
}, ignoreInit = TRUE)
observeEvent(input$param_slide, {
updateNumericInput(session, "param_numeric", value = input$param_slide)
}, ignoreInit = TRUE)
}
shinyApp(ui, server)
Furthermore, please check this and this.
so I'm trying to make a tax calculation app. In the sidebar I'm using tabsetPanel to display two panels with different inputs relating to the individual and then tax rates.
The mainPanel will also be using tabsetPanel where I plan to plot graphs etc. I have an update button that doesn't seem to be working.
ui.R
Looks like this:
shinyUI(fluidPage(
titlePanel("flatTax"),
sidebarLayout(
sidebarPanel(
h1("Flat Tax Calculator"),
helpText("Input your information below and see how a flat tax could
affect your tax bill."),
#Individual Specific Variables
tabsetPanel(
tabPanel("You",
numericInput(inputId = "incomeNum",
label = "Your annual income:",
value = 0
),
textInput(inputId = "testText",
label = "Test Input"
),
),
tabPanel("Tax Settings",
sliderInput(inputId = "basicIncome",
label = "Choose a monthly basic income",
value = 600, min = 0, max = 1200, step = 50
),
sliderInput(inputId = "taxFree",
label = "Choose a tax free allowance",
value = 10000, min = 0, max = 20000, step = 250
),
sliderInput(inputId = "flatIncomeTax",
label = "Choose a flat tax rate",
value = 50, min = 0, max = 100, step = 1
),
sliderInput(inputId = "flatPropertyTax",
label = "Choose a land value tax rate",
value = 1, min = 0, max = 100, step = 1
)),
# Action Button
actionButton(inputId = "updateButton",
label = "Update"),
plotOutput("text")
)
),
mainPanel(
tabsetPanel(
tabPanel("Summary",
h3("Test Output", textOutput("test"),
h3("Your new income tax bill is:", textOutput("incomeFT")),
h3("Your new property tax bill is:", textOutput("propertyFT")),
textOutput("annualBasicIncome")
)
),
tabPanel("Graphs",
h3("Placeholder"),
h3("Holding the place"),
h3("Plaice holster")
)
)
)
)
))
server.R
Looks like this:
shinyServer(
function(input, output) {
#action button stuff
incomeFT <- eventReactive(input$updateButton, {
((input$incomeNum-input$taxFree)/100*input$flatIncomeTax)
})
output$incomeFT <- renderPrint({
incomeFT()
})
propertyFT <- eventReactive(input$updateButton, {
input$propertyNum/100*input$flatPropertyTax
})
output$propertyFT <- renderPrint({
propertyFT()
})
annualBasicIncome <- eventReactive(input$updateButton, {
switch(as.numeric(input$relStat),
return((input$basicIncome*12)+((input$basicIncome*12)*input$childNum)),
return((2*(input$basicIncome*12))+((input$basicIncome*12)*input$childNum))
)
})
output$annualBasicIncome <- renderPrint({
annualBasicIncome()
})
test <- eventReactive(input$updateButton, {
input$testText
})
output$test <- renderText({
test()
})
})
Without reactivity it seems to work, but the button makes it less distracting to use. I've tried using verbatimTextOutput instead of textOutput but grey bars are sent across the main panel with not outputs in.
Help please?
For some reason, the actionButton does not work inside the tabsetPanel. If you put it outside it (and inside sidebarPanel) it will work. I suggest you try to use one actionButton for each tabPanel. I haven't try it, but I believe it should work. Please, if you try it, let me know the results.
Cheers.
I'm building a shiny app for the Random Forest. The widgets have to define two parameters:
the number of trees, between 1 and 1000
sliderInput("nTree", "Number of trees", min = 1, max = 100, value = 10)
a tree to visualise, between 1 and the number of trees (input$nTree) that depends on the first widget
sliderInput("iTree", "Tree to visualise", min = 1, max = nTree, value = 10)
How can I define nTree inside the second widget? Its value depends on the first widget.
Thanks in advance.
You can make the slider dynamically like so:
library(shiny)
ui =(pageWithSidebar(
headerPanel("Test Shiny App"),
sidebarPanel(
sliderInput("nTree", "Number of trees", min = 1, max = 1000, value = 10),
#display dynamic UI
uiOutput("iTree")),
mainPanel()
))
server = function(input, output, session){
#make dynamic slider
output$iTree <- renderUI({
sliderInput("iTree", "Tree to visualise", min=1, max=input$nTree, value=10)
})
}
runApp(list(ui = ui, server = server))