基础 UI
引言
现在,您已经具备了基本的 Shiny 应用程序,我们可以开始详细探索使 Shiny 起作用的内容。正如您在上一章所看到的,Shiny 鼓励将生成用户界面(前端)的代码与驱动应用程序行为的代码(后端)分开。
在本章中,我们将重点关注前端,并向您展示由 Shiny 提供的 HTML 输入和输出的大致情况。这使您能够捕获许多类型的表单数据,并显示许多类型的 R 输出。到目前为止,您可能还没有很多将输入和输出拼接在一起的方法,我们将在第 6 章中回顾这一点。
在这里,我将主要关注 Shiny 自身内置的输入和输出。但是,还有一个丰富而充满活力的社区扩展包,例如 shinyWidgets、colorpicker 和 sorttable。您可以在 https://github.com/nanxstats/awesome-shiny-extensions 找到其他全面且维护良好的包列表,该列表由 Nan Xiao 维护。
与往常一样,我们将从加载 shiny 包开始:
library(shiny)
输入
正如我们在上一章所看到的,您使用诸如 sliderInput()
、 selectInput()
、 textInput()
和 numericInput()
之类的函数将输入控件插入到您的 UI 规范中。现在我们将讨论所有输入函数所共有的常见结构,并为内置在 Shiny 中的输入提供快速概述。
常见结构
所有输入函数都具有相同的第一个参数: inputId
。这是用于将前端与后端连接的标识符:如果您的用户界面具有 ID 为 name
的输入,则 server 函数将使用 input$name
来访问它。
inputId
有两个约束:
它必须是一个简单的字符串,只包含字母、数字和下划线(不允许空格、破折号、句点或其他特殊字符!)以 R 命名变量。
它必须是唯一的。如果它不是唯一的,那么您将无法在 server 函数中引用此控件!
大多数输入函数都有一个称为 label
的第二个参数。这是用于为控件创建一个人类可读的标签。Shiny 对此字符串没有任何限制,但您需要仔细考虑,以确保您的应用程序对人类可用!第三个参数通常是 value
,在可能的情况下,允许您设置默认值。其余参数是控件特有的。
创建输入时,我建议按位置提供 inputId 和 label 参数,并按名称提供所有其他参数:
sliderInput("min", "Limit (minimum)", value = 50, min = 0, max = 100)
以下部分描述了 Shiny 内置的输入,根据它们创建的控制类型松散分组。目标是让您快速了解您的选项,而不是详尽地描述所有参数。下面我将展示每个控件最重要的参数,但您需要阅读文档以获得完整详细信息。
自由文本
使用 textInput()
收集少量文本,使用 passwordInput()
3收集密码,使用 textAreaInput()
收集段落文本。
ui <- fluidPage(
textInput("name", "What's your name?"),
passwordInput("password", "What's your password?"),
textAreaInput("story", "Tell me about yourself", rows = 3)
)
如果你想确保文本具有某些属性,你可以使用 validate()
,我们将在第 8 章中介绍这个函数。
数值输入
要收集数值,请使用 numericInput()
创建一个受约束的文本框,或使用 sliderInput()
创建一个滑块。如果你为 sliderInput () 的默认值提供一个长度为 2 的数值向量,你将获得一个带有两个端点的 “范围” 滑块。
ui <- fluidPage(
numericInput("num", "Number one", value = 0, min = 0, max = 100),
sliderInput("num2", "Number two", value = 50, min = 0, max = 100),
sliderInput("rng", "Range", value = c(10, 20), min = 0, max = 100)
)
一般来说,我只建议在范围较小或者精确数值不太重要的情况下使用滑块。尝试在小的滑块上精确选择一个数字是一件很令人沮丧的事情!
滑块非常可定制,有很多方法可以调整它们的外观。更多细节请参见 ?sliderInput
和 https://shiny.rstudio.com/articles/sliders.html。
日期
使用 dateInput()
收集单个日期,或使用 dateRangeInput()
收集两个日期之间的范围。这些都提供了一个方便的日历选择器,额外的参数如 datesdisabled
和 daysofweekdisabled
允许您限制有效的输入集。
ui <- fluidPage(
dateInput("dob", "When were you born?"),
dateRangeInput("holiday", "When do you want to go on vacation next?")
)
日期格式、语言和一周开始的日期默认采用美国标准。如果您正在为国际用户创建应用程序,请设置格式、语言和一周开始日期,以便日期对您的用户来说是自然的。
有限制的选择
有两种不同的方法允许用户从预设的选项集中进行选择: selectInput()
和 radioButtons()
。
animals <- c("dog", "cat", "mouse", "bird", "other", "I hate animals")
ui <- fluidPage(
selectInput("state", "What's your favourite state?", state.name),
radioButtons("animal", "What's your favourite animal?", animals)
)
单选按钮有两个很好的特点:它们显示所有可能的选项,适合于短列表,并且通过 choiceNames/choiceValues
参数,它们可以显示除普通文本之外的其他选项。 choiceNames
确定向用户显示的内容; choiceValues
确定在您的 server 函数中返回的内容。
ui <- fluidPage(
radioButtons("rb", "Choose one:",
choiceNames = list(
icon("angry"),
icon("smile"),
icon("sad-tear")
),
choiceValues = list("angry", "happy", "sad")
)
)
#> This Font Awesome icon ('angry') does not exist:
#> * if providing a custom `html_dependency` these `name` checks can
#> be deactivated with `verify_fa = FALSE`
#> This Font Awesome icon ('smile') does not exist:
#> * if providing a custom `html_dependency` these `name` checks can
#> be deactivated with `verify_fa = FALSE`
#> This Font Awesome icon ('sad-tear') does not exist:
#> * if providing a custom `html_dependency` these `name` checks can
#> be deactivated with `verify_fa = FALSE`
使用 selectInput()
创建的下拉菜单无论选项数量多少,都占用相同数量的空间,这使得它们更适合于更长的选项。您还可以设置 multiple = TRUE
以允许用户选择多个元素。
ui <- fluidPage(
selectInput(
"state", "What's your favourite state?", state.name,
multiple = TRUE
)
)
如果你有一组非常大的可能选项,你可能想要使用 “server-side” selectInput()
,这样完整的可能选项集不被嵌入到 UI 中(这可能会使加载变慢),而是由服务器按需发送。您可以了解有关此高级主题的更多信息,请访问 https://shiny.rstudio.com/articles/selectize.html#server-side-selectize。
没有方法可以在单选按钮中选择多个值,但有一个概念上类似的替代方案: checkboxGroupInput()
。
ui <- fluidPage(
checkboxGroupInput("animal", "What animals do you like?", animals)
)
如果您想要一个单选框来回答一个 Yes/No
问题,请使用 checkboxInput()
:
ui <- fluidPage(
checkboxInput("cleanup", "Clean up?", value = TRUE),
checkboxInput("shutdown", "Shutdown?")
)
文件上传
允许用户通过 fileInput()
上传文件:
ui <- fluidPage(
fileInput("upload", NULL)
)
fileInput () 需要在 server 端进行特殊处理,并在第 9 章中详细讨论。
动作按钮
使用 actionButton()
或 actionLink()
让用户执行动作。
ui <- fluidPage(
actionButton("click", "Click me!"),
actionButton("drink", "Drink me!", icon = icon("cocktail"))
)
#> This Font Awesome icon ('cocktail') does not exist:
#> * if providing a custom `html_dependency` these `name` checks can
#> be deactivated with `verify_fa = FALSE`
动作链接和按钮最自然地与 server 函数中的 observeEvent()
或 eventReactive()
配对。您还没有学习这些重要的函数,但我们在第 3.5 节中会回到它们。
您可以使用 class
参数来自定义外观,使用 "btn-primary"
, "btn-success"
, "btn-info"
, "btn-warning"
或 "btn-danger"
之一。您还可以使用 "btn-lg"
, "btn-sm"
, "btn-xs"
更改大小。最后,您可以使用 "btn-block"
使按钮跨越其嵌入的元素的整个宽度。
ui <- fluidPage(
fluidRow(
actionButton("click", "Click me!", class = "btn-danger"),
actionButton("drink", "Drink me!", class = "btn-lg btn-success")
),
fluidRow(
actionButton("eat", "Eat me!", class = "btn-block")
)
)
class
参数通过设置底层 HTML 的 class
属性来工作,这会影响元素的样式。要查看其他选项,您可以阅读 Shiny 使用的 CSS 设计系统 Bootstrap 的文档:http://bootstrapdocs.com/v3.3.6/docs/css/#buttons。
练习
2.2.8.1 当空间不足时,使用一个出现在文本输入区域内的占位符来标记文本框很有用。您如何调用 textInput()
生成下面的 UI?
2.2.8.2 认真阅读 sliderInput()
的文档以了解如何创建日期滑块,如下:
2.2.8.3 如何创建日期滑块,使得用户可以在 0 到 100 之间选择日期,滑块上每个可选值的间隔为 5。然后,为输入小部件添加动画,以便当用户按下播放时,输入小部件会自动滚动到该范围。
2.2.8.4 如果您有一个中等长度的 selectInput()
列表,创建子标签是有用的,它可以将列表分成几部分。阅读文档以了解如何操作。(提示:底层 HTML 称为 <optgroup>
。)
输出
用户界面中的输出创建了占位符,稍后将由 server 函数填充。与输入一样,输出需要一个唯一的 ID 作为其第一个参数:如果您的用户界面规范创建了一个 ID 为 plot
的输出,您可以通过 output$plot
在服务器函数中访问它。
前端中的每个输出函数都与后端的渲染函数配对。有三种主要的输出类型,对应于您通常在报告中包含的三件事: 文本
、 表格
和 图形
。以下部分向您展示了前端输出函数的基本知识,以及后端相应的渲染函数。
文本
使用 textOutput()
输出普通文本,使用 verbatimTextOutput()
输出固定代码和控制台输出。
ui <- fluidPage(
textOutput("text"),
verbatimTextOutput("code")
)
server <- function(input, output, session) {
output$text <- renderText({
"Hello friend!"
})
output$code <- renderPrint({
summary(1:10)
})
}
请注意,只有在需要运行多行代码时, {}
才需要在渲染函数中使用。正如您即将了解的那样,您应该在渲染函数中尽可能少地进行计算,这意味着您通常可以省略它们。以下是上述 server 函数更简洁的方式:
server <- function(input, output, session) {
output$text <- renderText("Hello friend!")
output$code <- renderPrint(summary(1:10))
}
注意,有两种渲染函数的行为略有不同:
renderText()
将结果合并成一个字符串,通常与textOutput()
配对renderPrint()
打印结果,就像在 R 控制台中一样,通常与verbatimTextOutput()
配对。
我们可以通过一个玩具应用程序看到这种差异:
ui <- fluidPage(
textOutput("text"),
verbatimTextOutput("print")
)
server <- function(input, output, session) {
output$text <- renderText("hello!")
output$print <- renderPrint("hello!")
}
二者的区别与 R 中的 cat()
and print()
一样。
表格
有三种方法可以在表格中显示数据框:
tableOutput()
和renderTable()
呈现静态数据表,一次显示所有数据。dataTableOutput()
和renderDataTable()
呈现动态数据表,一次显示固定数量的行,同时显示控件以更改可见行。
tableOutput()
最适合小型、固定的摘要(例如模型系数);如果您想向用户展示完整的数据框, dataTableOutput()
最为合适。如果您想更精确地控制 dataTableOutput()
的输出,我强烈推荐 Greg Lin 的 reactable 包。
ui <- fluidPage(
tableOutput("static"),
dataTableOutput("dynamic")
)
server <- function(input, output, session) {
output$static <- renderTable(head(mtcars))
output$dynamic <- renderDataTable(mtcars, options = list(pageLength = 5))
}
图形
您可以使用 plotOutput()
和 renderPlot()
显示任何类型的 R 图形(基础、ggplot2 或其他)。
ui <- fluidPage(
plotOutput("plot", width = "400px")
)
server <- function(input, output, session) {
output$plot <- renderPlot(plot(1:5), res = 96)
}
默认情况下, plotOutput()
将占据其容器的全部宽度(稍后将详细介绍),高度为 400 像素。您可以使用 height
和 width
参数覆盖这些默认值。我们建议始终将 res
设置为 96,这样您的 Shiny 图形就会尽可能与 RStudio 中看到的图形相匹配。
图形是特殊的输出,因为它们也可以作为输入。 plotOutput()
具有许多参数,如 click
、 dblclick
和 hover
。如果您将这些参数传递给字符串,例如 click = "plot_click"
,则它们将创建一个可响应的输入( input$plot_click
),您可以使用它来处理与图形的用户交互,例如单击图形。我们将在第 7 章中再次讨论 Shiny 中的交互式图形。
下载
您可以使用 downloadButton()
或 downloadLink()
让用户下载文件。这些需要在 server 函数中使用新技术,因此我们将在第 9 章中详细介绍。
练习
2.3.5.1 下列哪个应与 textOutput()
和 verbatimTextOutput()
配对?
a. renderPrint(summary(mtcars))
b. renderText("Good morning!")
c. renderPrint(t.test(1:5, 2:6))
d. renderText(str(lm(mpg ~ wt, data = mtcars)))
2.3.5.2 重新创建第 2.3.3 节的 Shiny 应用程序,这次将高度设置为 300 像素,宽度设置为 700 像素。设置图的 “alt” 文本,以便视障用户可以判断其是五个随机数的散点图。
2.3.5.3 更新以下调用 renderDataTable()
的选项,以便仅显示数据,但其他控件均被抑制(即删除搜索、排序和过滤命令)。您需要阅读?renderDataTable 并回顾 https://datatables.net/reference/option/ 中的选项。
ui <- fluidPage(
dataTableOutput("table")
)
server <- function(input, output, session) {
output$table <- renderDataTable(mtcars, options = list(pageLength = 5))
}
2.3.5.4 或者,您可以阅读 reactable 的文档,并将上面的应用程序转换为使用它。
总结
本章向您介绍了 Shiny 应用程序前端的主要输入和输出功能。这是一次大量的信息灌输,因此不要期望在一次阅读后就能记住所有内容。相反,当您需要查找特定组件时,请返回本章:您可以快速浏览图示,然后找到您需要的代码。
下一章我们将介绍 Shiny 应用程序的后端:使您的用户界面生动起来的 R 代码。
练习题答案获取
关注公众号 “生信之巅”,聊天窗口回复 “5369” 获取习题答案。
![]() | ![]() |
敬告:使用文中脚本请引用本文网址,请尊重本人的劳动成果,谢谢!