Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

r - Switch between layouts reactively with shiny

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...