问题
How can I switch between page layouts in Shiny in response to user input? For example, I would like to switch between a sidebar layout to a wellpanel layout in order to have the graphics be able to span the entire page.
What I have so far seems to be on the verge of working, but I think the issue is that I can't reuse interfaces created from renderUI. Here is an example,
library(shiny)
shinyApp(
shinyUI(
fluidPage(
radioButtons('layout', 'Layout:', choices=c('Sidebar', 'WellPanel'), inline=TRUE),
conditionalPanel(
condition = "input.layout == 'Sidebar'",
uiOutput('sidebarUI')
),
conditionalPanel(
condition = "input.layout == 'WellPanel'",
uiOutput('wellUI')
)
)
),
shinyServer(function(input, output) {
output$sidebarUI <- renderUI({
sidebarLayout(
sidebarPanel(
uiOutput('ui')
),
mainPanel(
plotOutput('plot')
)
)
})
output$wellUI <- renderUI({
fluidRow(
column(12, plotOutput('plot')),
column(12, wellPanel(uiOutput('ui')))
)
})
output$ui <- renderUI({
list(
checkboxInput('inp1', 'Some stuff'),
sliderInput('inp2', 'Some more stuff', 0, 10, 5)
)
})
output$plot <- renderPlot({ plot(1) })
})
)
If either one of the conditional panels is commented out, then the other one works, but only one will work with both conditional panels. How is this done?
回答1:
Hi you can't call an output twice (or more) in the ui, that's why this isn't working, instead you can do all the work in the server like this :
library(shiny)
shinyApp(
shinyUI(
fluidPage(
radioButtons('layout', 'Layout:', choices=c('Sidebar', 'WellPanel'), inline=TRUE),
uiOutput('general_ui')
)
),
shinyServer(function(input, output) {
output$general_ui <- renderUI({
if (input$layout == "Sidebar") {
sidebarLayout(
sidebarPanel(
uiOutput('ui')
),
mainPanel(
plotOutput('plot')
)
)
} else if (input$layout == "WellPanel") {
fluidRow(
column(12, plotOutput('plot')),
column(12, wellPanel(uiOutput('ui')))
)
}
})
output$ui <- renderUI({
list(
checkboxInput('inp1', 'Some stuff'),
sliderInput('inp2', 'Some more stuff', 0, 10, 5)
)
})
output$plot <- renderPlot({ plot(1) })
})
)
But there's a catch, when you switch between layout, the input widgets are reinitialized...
But you can fix it with something like this :
output$ui <- renderUI({
list(
checkboxInput('inp1', 'Some stuff'),
if (is.null(input$inp2)) {
sliderInput('inp2', 'Some more stuff', 0, 10, 5)
} else {
sliderInput('inp2', 'Some more stuff', 0, 10, input$inp2)
}
)
})
Before creating your widget, you'll have to check if the value already exists, in a more compact way than above you can do that :
output$ui <- renderUI({
list(
checkboxInput(inputId = "inp1", label = 'Some stuff', value = input$inp1 %||% FALSE),
sliderInput(inputId = "inp2", label = 'Some more stuff', min = 0, max = 10, value = input$inp2 %||% 5)
)
})
With %||% function defined like this :
`%||%` <- function(a, b) {
if (!is.null(a)) a else b
}
来源:https://stackoverflow.com/questions/33137546/switch-between-layouts-reactively-with-shiny