原文:https://shiny.rstudio.com/articles/layout-guide.html[1]
概览
Shiny 包含了许多用于布局应用程序组件的工具。本指南描述了以下应用程序布局功能特性:
sidebarLayout()
:用于放置存放输入的sidebarPanel()
和存放输出的mainPanel()
。- 使用 Shiny 的自定义网格布局系统进行自定义布局(即
fluidRow()
&column()
)。 - 使用
tabsetPanel()
和navlistPanel()
函数进行分段布局。 - 使用
navbarPage()
函数创建带多个顶层组件的应用。
All these features are made available via Bootstrap[2], an extremely popular HTML/CSS framework (though no prior experience with Bootstrap is assumed). Shiny currently defaults to Bootstrap 3. To upgrade to a more recent version and/or implement custom Bootstrap themes, check out the application themes article[3].
侧边栏布局
侧边栏布局是许多应用非常有用的起点。该布局提供了一个侧边栏用于放置输入控件和一个大的主区域放置输出控件。
这是创建该布局的代码:
代码语言:javascript复制ui <- fluidPage(
titlePanel("Hello Shiny!"),
sidebarLayout(
sidebarPanel(
sliderInput(
"bins", label = "Number of bins:",
min = 1, value = 30, max = 50
)
),
mainPanel(
plotOutput("distPlot")
)
)
)
注意这个侧边栏左右放置都是可以的(默认在左边),修改位置的代码如下:
代码语言:javascript复制sidebarLayout(position = "right",
sidebarPanel(
# Inputs excluded for brevity
),
mainPanel(
# Outputs excluded for brevity
)
)
网格布局
上面使用的侧边栏布局使用了 Shiny 低级的网格布局函数。该布局使用 fluidRow()
创建行,使用column()
在行中创建列。列宽基于 Bootstrap 总宽为 12 的网格系统,因此 fluidRow()
容积的宽度总和永远是 12。
为了展示这一点,下面的代码通过网格布局实现了侧边栏布局:
代码语言:javascript复制ui <- fluidPage(
titlePanel("Hello Shiny!"),
fluidRow(
column(4,
wellPanel(
sliderInput(
"bins", label = "Number of bins:",
min = 1, value = 30, max = 50
)
)
),
column(8,
plotOutput("distPlot")
)
)
)
column()
中的 offset
可以用来设置位移量,更好地控制布局。
下面是一个例子:界面顶部是一个图形,而底部是控制图像输出的 3 列控件。
下面是代码:
代码语言:javascript复制library(shiny)
library(ggplot2)
dataset <- diamonds
ui <- fluidPage(
title = "Diamonds Explorer",
plotOutput('plot'),
hr(),
fluidRow(
column(3,
h4("Diamonds Explorer"),
sliderInput('sampleSize', 'Sample Size',
min=1, max=nrow(dataset), value=min(1000, nrow(dataset)),
step=500, round=0),
br(),
checkboxInput('jitter', 'Jitter'),
checkboxInput('smooth', 'Smooth')
),
column(4, offset = 1,
selectInput('x', 'X', names(dataset)),
selectInput('y', 'Y', names(dataset), names(dataset)[[2]]),
selectInput('color', 'Color', c('None', names(dataset)))
),
column(4,
selectInput('facet_row', 'Facet Row', c(None='.', names(dataset))),
selectInput('facet_col', 'Facet Column', c(None='.', names(dataset)))
)
)
)
这里有一些需要注意的事项:
- 底部的 3 列输入控件有不同宽度。The inputs are at the bottom and broken into three columns of varying widths.
offset
用来自定义第 1 列和第 2 列输入空间的中间距离。- 页面没有包含
titlePanel()
,因此通过title
参数显式指定。
网格布局可以在 fluidPage()
任何地方使用,而且支持嵌套。你可以在下方的章节获取更多的内容介绍。
标签(选项)集
通常应用需要将用户界面划分为几个独立的部分。这可以通过使用 tabsetPanel()
函数完成。例如:
下面是实现该 UI 的代码:
代码语言:javascript复制ui <- fluidPage(
titlePanel("Tabsets"),
sidebarLayout(
sidebarPanel(
# Inputs excluded for brevity
),
mainPanel(
tabsetPanel(
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
)
)
)
选项卡可以位于选项卡内容的上方(默认)、下方、左侧或右侧。例如,要在标签内容下面放置标签,你可以使用以下代码:
代码语言:javascript复制tabsetPanel(position = "below",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Table", tableOutput("table"))
)
导航列表
当你有很多 tabPanel 时,navlistPanel()
可能是 tabsetPanel()
很好的替代品。一个导航列表将诸多组件展示为侧边栏而不是使用标签。而且它还支持节标题以及长列表分隔符。下面是一个例子:
实现这一点所需的代码如下(注意,tabPanels是空的,以保持示例整洁,通常他们会包括额外的UI元素):
代码语言:javascript复制ui <- fluidPage(
titlePanel("Application Title"),
navlistPanel(
"Header A",
tabPanel("Component 1"),
tabPanel("Component 2"),
"Header B",
tabPanel("Component 3"),
tabPanel("Component 4"),
"-----",
tabPanel("Component 5")
)
)
导航条页面
您可能希望创建这样一个 Shiny 的应用程序:它由多个不同的子组件组成(每个组件都有自己的侧边栏、选项卡或其他布局结构)。函数的作用是:创建一个顶部带有标准引导导航条的应用程序。例如:
代码语言:javascript复制ui <- navbarPage("My Application",
tabPanel("Component 1"),
tabPanel("Component 2"),
tabPanel("Component 3")
)
注意 tabPanel()
用于指定可以导航的组件。
二级导航
可以使用 navbarMenu()
函数向页面添加第二级导航。这为顶级导航栏添加了一个菜单,可以参考其他的选项卡面板。
ui <- navbarPage("My Application",
tabPanel("Component 1"),
tabPanel("Component 2"),
navbarMenu("More",
tabPanel("Sub-Component A"),
tabPanel("Sub-Component B"))
)
其他选项
navbarPage()
还有其他几个参数提供了额外的定制措施:
参数 | 描述 |
---|---|
header | 标签列表的标签显示为一个共同的标题以上的所有标签面板。 |
footer | 标签或标签列表显示为一个通用的页脚下面的所有标签面板。 |
inverse | “TRUE”表示导航栏使用深色背景和浅色文本。 |
collapsable | 当浏览器的宽度小于940像素(对于在较小的触摸屏设备上查看很有用)时,自动将导航元素折叠为菜单。 |
网格布局进阶
有两种类型的 Bootstrap 网格,fluid 的和 fixed 的。到目前为止,这些例子只使用了 fluid 的网格系统,这也是大多数应用程序所推荐的系统(默认的 Shiny 功能,如 navbarPage()
和 sidebarLayout()
)。
两种网格系统都使用灵活的可细分的12列网格进行布局。fluid 系统总是占据网页的全部宽度,并随着页面大小的变化动态地调整其组件的大小。固定系统默认占用940像素的固定宽度,当引导响应式布局启动时(例如在平板电脑上),可能会假定其他宽度。
以下部分是官方Bootstrap 3网格系统文档的翻译,其中HTML代码被 R 代码取代。
Fluid 网格系统
Bootstrap网格系统采用12列,可以灵活地细分为行和列。要基于 fluid 系统创建布局,请使用fluidPage()
函数。要在网格中创建行,请使用 fluidRow()
函数;要在行中创建列,可以使用column()
函数。
例如,考虑这个高层次的页面布局(列宽和为 12):
要在一个 Shiny 的应用程序中创建这种布局,你需要使用以下代码(注意,fluidRow 中的列宽总和为12):
代码语言:javascript复制ui <- fluidPage(
fluidRow(
column(2,
"sidebar"
),
column(10,
"main"
)
)
)
列偏移
还可以偏移列的位置,以实现对UI元素位置的更精确控制。通过向column()
函数添加offset
参数将列向右移动。每增加一个单位的偏移量,就增加一列的左距。考虑一下这个布局:
要在一个 Shiny 的应用程序中创建这种布局,你需要使用以下代码:
代码语言:javascript复制ui <- fluidPage(
fluidRow(
column(4,
"4"
),
column(4, offset = 4,
"4 offset 4"
)
),
fluidRow(
column(3, offset = 3,
"3 offset 3"
),
column(3, offset = 3,
"3 offset 3"
)
)
)
列嵌套
在 fluid 网格内嵌套列时,每个嵌套的列级别应加起来为12。这是因为 fluid 网格使用百分比,而不是像素来设置宽度。考虑以下页面布局:
要在一个 Shiny 的应用程序中创建这种布局,你需要使用以下代码:
代码语言:javascript复制ui <- fluidPage(
fluidRow(
column(12,
"Fluid 12",
fluidRow(
column(6,
"Fluid 6",
fluidRow(
column(6,
"Fluid 6"),
column(6,
"Fluid 6")
)
),
column(width = 6,
"Fluid 6")
)
)
)
)
注意,每次引入fluidRow()
时,行内的列数加起来为12。
固定网格系统
固定网格系统也使用12列,并在默认情况下保持940像素的固定宽度。如果启动响应特性是启用的(它们在 Shiny 中是默认情况),那么网格也将适应为724px或1170px宽,这取决于你的视窗(例如,当在平板电脑上)。
固定网格的主要好处是,它提供了更强的保证,让用户能够看到UI布局的各种元素(这是因为它不是根据浏览器的宽度动态布局的)。它的主要缺点是使用起来有点复杂。一般来说,我们建议使用 fluid 网格,除非您绝对需要由固定网格提供的低层布局控制。
使用固定网格
在 Shiny 中使用固定网格与 fluid 网格的效果几乎相同。以下是需要记住的区别:
- 你使用
fixedPage()
和fixedRow()
函数构建网格。 - 行可以嵌套,但应始终包括一组列,这些列加起来等于其父列的列数(而不是像在流动网格中那样,在每个嵌套级别上重置为12)。
下面是前面简单的侧边栏布局的固定网格版本的代码:
代码语言:javascript复制ui <- fixedPage(
fixedRow(
column(2,
"sidebar"
),
column(10,
"main"
)
)
)
列嵌套
在固定网格中,每个嵌套列的宽度必须与其父列的数量相加。下面是一个fixedRow()
,它的列宽度为9,其中包含另外两列,宽度分别为6和3:
要在一个 Shiny 的应用程序中创建这种布局,你需要使用以下代码:
代码语言:javascript复制fixedRow(
column(9,
"Level 1 column",
fixedRow(
column(6,
"Level 2"
),
column(3,
"Level 2"
)
)
)
)
注意,嵌套列的总大小是9,与它们的父列相同。
响应布局
Bootstrap 网格系统支持响应式CSS,它使您的应用程序能够自动调整其布局,以在不同大小的设备上查看。响应式布局包括以下内容:
- 修改网格列宽。
- 在必要之处堆砌而不是浮动组件。
- 调整标题和文本的大小以更适合设备。
响应式布局默认为所有 Shiny 的页面类型启用。要禁用响应式布局,您应该将 response = FALSE
传递给 fluidPage()
或 fixedPage()
函数。
支持的设备
响应布局启用时 Bootstrap 网格系统会自动适应多种设备:
布局宽度 | 列宽 | Gutter 宽度 | |
---|---|---|---|
大型显示 | 1200px and up | 70px | 30px |
Default | 980px and up | 60px | 20px |
竖屏平板电脑 | 768px and above | 42px | 20px |
手机或平板 | 767px and below | Fluid (no fixed widths) | Fluid (no fixed widths) |
手机 | 480px and below | Fluid (no fixed widths) | Fluid (no fixed widths) |
请注意,在较小的屏幕尺寸上,即使页面使用固定的网格布局,fluid 列宽也会自动使用。
参考资料
[1]
https://shiny.rstudio.com/articles/layout-guide.html: https://shiny.rstudio.com/articles/layout-guide.html
[2]
Bootstrap: https://getbootstrap.com/
[3]
application themes article: https://shiny.rstudio.com/articles/themes.html