Сделайте вводимые данные на боковой панели постоянными с помощью вкладок - PullRequest
3 голосов
/ 09 июля 2020

Я хотел бы иметь как постоянную боковую панель (как в макете shinydashboard), так и панель навигации с вкладками (как в макете shiny::navbarPage). Я наткнулся на этот ответ , который, кажется, соответствует тому, что я хочу.

Проблема в том, что входные данные на боковой панели не сохраняются через вкладки, т.е. при переключении вкладок входы на боковой панели больше не отображаются (например, в отличие от shinydashboard боковой панели). Вот пример, который я не могу свести к минимуму, так как большая его часть составляет CSS:

library(shiny)
library(bootstraplib)

# boot dash layout funs ---------------------------------------------------


boot_side_layout <- function(...) {
  div(class = "d-flex wrapper", ...)
}

boot_sidebar <- function(...) {
  div(
    class = "bg-light border-right sidebar-wrapper",
    div(class = "list-group list-group-flush", ...)
  )
}

boot_main <- function(...) {
  div(
    class = "page-content-wrapper",
    div(class = "container-fluid", ...)
  )
}

# css ---------------------------------------------------------------------

css_def <- "
body {
  overflow-x: hidden;
}

.container-fluid, .container-sm, .container-md, .container-lg, .container-xl {
    padding-left: 0px;
}

.sidebar-wrapper {
  min-height: 100vh;
  margin-left: -15rem;
  padding-left: 15px;
  padding-right: 15px;
  -webkit-transition: margin .25s ease-out;
  -moz-transition: margin .25s ease-out;
  -o-transition: margin .25s ease-out;
  transition: margin .25s ease-out;
}


.sidebar-wrapper .list-group {
  width: 15rem;
}

.page-content-wrapper {
  min-width: 100vw;
  padding: 20px;
}

.wrapper.toggled .sidebar-wrapper {
  margin-left: 0;
}

.sidebar-wrapper, .page-content-wrapper {
  padding-top: 20px;
}

.navbar{
  margin-bottom: 0px;
}

.navbar-collapse {
  font-size: 1.1rem
}

@media (max-width: 768px) {
  .sidebar-wrapper {
    padding-right: 0px;
    padding-left: 0px;

  }
}

@media (min-width: 768px) { 
  .sidebar-wrapper {
    margin-left: 0;
    position: fixed;
  }

  .page-content-wrapper {
    min-width: 0;
    width: 100%;
  }

  .wrapper.toggled .sidebar-wrapper {
    margin-left: -15rem;
  }
}

"


# app ---------------------------------------------------------------------
ui <- tagList(
  tags$head(tags$style(HTML(css_def))),
  bootstrap(),
  navbarPage(
    collapsible = TRUE,
    title = "",
    tabPanel(
      "Statistics",
      boot_side_layout(
        boot_sidebar(
          selectInput(
            "variables",
            "Variables",
            NULL
          )
        ),
        boot_main(
          fluidRow(
            dataTableOutput("statistics")
          )
        )
      )
    ),
    
    tabPanel(
      "Plots",
      boot_side_layout(
        boot_sidebar(
          
        ),
        boot_main(
        )
      )
    )
  )
)

server <- function(input, output, session) {
  
  output$statistics <- renderDataTable(mtcars[10, 10])
  
}

shinyApp(ui, server)

Как я могу сделать эти входные данные постоянными через боковую панель? (Если кто-то знает другой простой способ смешать постоянную боковую панель с навигационной панелью, также покажите его).

1 Ответ

1 голос
/ 09 июля 2020

Почему бы не использовать sidebarLayout с navbarPage в mainPanel?

ui <- fluidPage(
  
  sidebarLayout(
    
    sidebarPanel(
      selectInput("select", "Select", c("a", "b", "c"))
    ),
    
    mainPanel(
      navbarPage(
        "App Title",
        tabPanel("Plot"),
        tabPanel("Summary"),
        tabPanel("Table")
      )    
    )
    
  )
)

shinyApp(ui, server)

РЕДАКТИРОВАТЬ

Или что-то вроде этого?

library(shiny)
library(ggplot2)

ui <- fluidPage(
  
  div(
    style = "display: flex; flex-direction: column;",
    div( #~~ Main panel ~~#
      navbarPage(
        "Old Faithful Geyser Data",
        tabPanel(
          "Plot",
          plotOutput("ggplot")
        ),
        tabPanel("Summary"),
        tabPanel("Table")
      )    
    ),
    wellPanel( #~~ Sidebar ~~#
      style = "width: 300px;",
      sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30),
    )
  )
)

server <- function(input, output) {
  output[["ggplot"]] <- renderPlot({
    x    <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
}

shinyApp(ui = ui, server = server)

РЕДАКТИРОВАТЬ

Вот так, чтобы боковая панель была слева:

library(shiny)
library(shinyjs)
library(ggplot2)

CSS <- "
.sidebar {
  min-width: 300px;
  margin-right: 30px;
}
#sidebar {
  width: 300px;
}
"

ui <- fluidPage(
  
  useShinyjs(),
  
  tags$head(tags$style(HTML(CSS))),
  
  div( #~~ Main panel ~~#
    navbarPage(
      "Old Faithful Geyser Data",
      tabPanel(
        "Plot",
        div(
          style = "display: flex;",
          div(class = "sidebar"),
          plotOutput("ggplot")
        )
      ),
      tabPanel(
        "Summary",
        div(
          style = "display: flex;",
          div(class = "sidebar"),
          verbatimTextOutput("summary")
        )
      ),
      tabPanel(
        "Table",
        div(
          style = "display: flex;",
          div(class = "sidebar"),
          tableOutput("table")
        )
      ),
      id = "navbar"
    )    
  ),
  wellPanel( #~~ Sidebar ~~#
    id = "sidebar", 
    sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30),
  )
)

server <- function(input, output) {
  output[["ggplot"]] <- renderPlot({
    x    <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
  output[["summary"]] <- renderPrint({
    list(a = 1:10, b = 1:10)
  })
  output[["table"]] <- renderTable({
    iris[1:10,]
  })
  observeEvent(input[["navbar"]], {
    selector <- 
      sprintf("$('div.tab-pane[data-value=\"%s\"] div.sidebar')", input[["navbar"]])
    runjs(paste0(selector, ".append($('#sidebar'));"))
  })
}

shinyApp(ui = ui, server = server)

РЕДАКТИРОВАТЬ

Вот улучшение описанного выше способа. Я сделал несколько удобных функций tabPanel2 и sidebar, чтобы помочь пользователю. И я использую fluidRow и column вместо display: flex;. Это позволяет иметь ширину боковой панели относительно размера экрана. В приведенном ниже примере также показано, как не включать боковую панель во вкладку (просто используйте tabPanel, а не tabPanel2.

library(shiny)
library(shinyjs)
library(ggplot2)

tabPanel2 <- function(title, ..., value = title, icon = NULL, sidebarWidth = 4){
  tabPanel(
    title = title, 
    fluidRow(
      column(
        width = sidebarWidth,
        class = "sidebar"
      ),
      column(
        width = 12 - sidebarWidth,
        ...
      )
    )
  )
}

sidebar <- function(...){
  div(
    style = "display: none;",
    tags$form(
      class = "well",
      id = "sidebar",
      ...
    )
  )
}

ui <- fluidPage(
  
  useShinyjs(),
  
  div( #~~ Main panel ~~#
    navbarPage(
      "Old Faithful Geyser Data",
      tabPanel2(
        "Plot",
        plotOutput("ggplot")
      ),
      tabPanel2(
        "Summary",
        verbatimTextOutput("summary")
      ),
      tabPanel(
        "Table",
        fluidRow(
          column(
            width = 4,
            wellPanel(
              tags$fieldset(
                tags$legend(h3("About")),
                p("This app is cool")
              )
            )
          ),
          column(
            width = 8,
            tableOutput("table")
          )
        )
      ),
      id = "navbar"
    )    
  ),
  
  sidebar( #~~ Sidebar ~~#
    sliderInput("bins", "Number of bins:", min = 1, max = 50, value = 30)    
  )

)

server <- function(input, output) {
  
  output[["ggplot"]] <- renderPlot({
    x    <- faithful[, 2] 
    bins <- seq(min(x), max(x), length.out = input$bins + 1)
    hist(x, breaks = bins, col = 'darkgray', border = 'white')
  })
  
  output[["summary"]] <- renderPrint({
    list(a = 1:10, b = 1:10)
  })
  
  output[["table"]] <- renderTable({
    iris[1:10,]
  })
  
  observeEvent(input[["navbar"]], {
    selector <- 
      sprintf("$('div.tab-pane[data-value=\"%s\"] div.sidebar')", input[["navbar"]])
    append <- "selector.append($('#sidebar'));"
    js <- sprintf("var selector=%s; if(selector.length){%s;}", selector, append)
    runjs(js)
  })
  
}

shinyApp(ui = ui, server = server)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...