组件布局
概述
当您在文档中引入交互组件时,您会希望以优化可读性和导航的方式进行布局。
当然,您可以通过多种方式引入交互性,从嵌入长篇文章的可视化到更接近应用程序/仪表板风格的布局。下面我们将涵盖这两种布局场景。
我们将从Observable JS和Shiny交互式文档中使用示例——如果您对某个示例使用的代码/语法不熟悉,只需关注包含布局标记而不是应用程序代码。
输入面板
如果您有多个输入,您可能希望将它们分组在一个输入面板中(带有panel: input
选项的代码块或带有.panel-input
类的div)。例如:
输入被分组在一个面板中,并通过向OJS代码单元格添加panel: input
和layout-ncol: 3
选项以三列布局:
```{ojs}
//| panel: input
//| layout-ncol: 3
viewof ch = checkbox({
title: "护照颜色:",
options: [
{ value: "red", label: "红色" },
{ value: "green", label: "绿色" },
{ value: "blue", label: "蓝色" },
{ value: "black", label: "黑色" }
],
value: ["red", "green", "blue", "black"],
submit: false
})
viewof type = radio({
title: "表示方式:",
options: [
{ label: '护照', value: 'p' },
{ label: '圆形', value: 'c' }
],
value: 'p'
})
viewof k = slider({
title: "符号大小:",
min: 1,
max: 10,
value: 3,
step: 1
})
```
标签页面板
如果您希望允许用户在多个可视化之间切换,请使用标签页(带有.panel-tabset
类的div)。为标签页中的每个标签包含一个标题(例如##
)。
例如,这里有一个图表和数据,每个都在自己的标签中展示:
以下是创建标签页所使用的标记和代码:
::: {.panel-tabset}
## 图表
```{ojs}
Plot.rectY(data,
Plot.stackY(
Plot.binX(
{y: "count"},
{x: "body_mass_g", fill: "species", thresholds: 20})
)
).plot({
facet: {
data,
x: "sex"
},
marks: [Plot.frame()]
})
```
## 数据
```{ojs}
Inputs.table(filtered)
```
:::
全页布局
默认情况下,Quarto文档将其内容居中于文档视口中,并且不超过大约900像素的最大宽度。这种行为是为了优化可读性,但对于应用程序布局,您通常希望占据整个页面。
为此,请添加page-layout: custom
选项。例如:
format:
html:
page-layout: custom
以下是一个占据浏览器全宽的Shiny应用程序示例:
您还会注意到,输入包含在一个侧边栏中——下一节将描述如何创建侧边栏。
侧边栏面板
侧边栏使用带有.panel-sidebar
类的div创建。您可以使用Markdown div容器(如上面用于.panel-input
所示),或者,如果侧边栏的全部内容由单个代码单元格创建,则通过向单元格添加panel: sidebar
选项。
侧边栏面板应始终有一个相邻的带有.panel-fill
或.panel-center
类的面板,它们将并排布局。前者(.panel-fill
)将填充所有可用空间,后者(.panel-center
)将在其内容周围留出一些水平边距。
例如,以下是上面显示的Shiny应用程序的用户界面部分的源代码:
---
title: "鸢尾花K-Means聚类"
format:
html:
page-layout: custom
server: shiny
---
```{r}
#| panel: sidebar
vars <- setdiff(names(iris), "Species")
selectInput('xcol', 'X变量', vars)
selectInput('ycol', 'Y变量', vars, selected = vars[[2]])
numericInput('clusters', '聚类数量', 3, min = 1, max = 9)
```
```{r}
#| panel: fill
plotOutput('plot1')
```
panel: fill
选项被添加到图表输出块中。如果您希望在面板内容周围留出一些水平边距,可以交替使用panel: center
。
向代码块添加panel
选项是向其包含的div添加CSS类的简写(即它等同于用带有类(例如panel-fill
)的div包围代码块)。 以下是使用带有 OJS 输入的侧边栏的示例:
为此,您可以使用以下代码:
```{ojs}
//| panel: sidebar
viewof myage = {
const myage = select({
title: "您想绘制哪个年龄段的图表?",
options: ages,
value: "80etplus"
});
return myage;
}
viewof pctvax = slider({
title: '<br/>疫苗接种目标',
description: '200% 表示每个人接种两剂疫苗',
min: 50,
max: 200,
value: 200,
step: 10,
format: v => v + "%"
})
viewof overlay = radio({
title: "分散圆圈",
options: [{ label: '是', value: 'Y' }, { label: '否', value: 'N' }],
value: 'N'
})
viewof label = radio({
title: "部门编号",
options: [{ label: '显示', value: 'Y' }, { label: '隐藏', value: 'N' }],
value: 'N'
})
```
```{ojs}
//| panel: fill
(疫苗可视化代码)
```
面板布局
您可以使用包含 div 的 layout
属性将多个交互组件排列到面板中。例如,这里我们在第一行有一个主可视化,在第二行有两个辅助可视化:
如 图形 文章中所述,您可以使用 layout
属性以非常灵活的方式排列图形面板。对于上面的示例,我们在以下 div 中包含了三个可视化:
::: {layout="[ [1], [1,1] ]"}
(输出)
:::
请注意,您可以将 layout
属性应用于已经是面板(例如 .panel-fill
)的 div,以指定与侧边栏相邻内容的布局。因此,以下标记也是有效的:
::: {.panel-sidebar}
(输入)
:::
::: {.panel-fill layout="[ [1], [1,1] ]"}
(输出)
:::
layout
属性是一个数组数组,每个数组定义布局的一行。上面我们表示我们希望第一行包含第一个可视化,然后将接下来的两个均等地分布在第二行。
行中的值不需要加起来达到任何特定值(它们在每行内是相对的),因此如果我们更好地呈现数据,我们也可以为第二行指定不同的相对宽度:
::: {layout="[ [1], [3,2] ]"}
(输出)
:::