基础UI
引言
现在,您已经具备了基本的Shiny应用程序,我们可以开始详细探索使Shiny起作用的内容。正如您在上一章所看到的,Shiny鼓励将生成用户界面(前端)的代码与驱动应用程序行为的代码(后端)分开。
在本章中,我们将重点关注前端,并向您展示由Shiny提供的HTML输入和输出的大致情况。这使您能够捕获许多类型的表单数据,并显示许多类型的R输出。到目前为止,您可能还没有很多将输入和输出拼接在一起的方法,我们将在第6章中回顾这一点。
在这里,我将主要关注Shiny自身内置的输入和输出。但是,还有一个丰富而充满活力的社区扩展包,例如shinyWidgets、colorpicker和sorttable。您可以在https://github.com/nanxstats/awesome-shiny-extensions找到其他全面且维护良好的包列表,该列表由Nan Xiao维护。
与往常一样,我们将从加载shiny包开始:
1 | library(shiny) |
输入
正如我们在上一章所看到的,您使用诸如sliderInput()
、selectInput()
、textInput()
和numericInput()
之类的函数将输入控件插入到您的UI规范中。现在我们将讨论所有输入函数所共有的常见结构,并为内置在Shiny中的输入提供快速概述。
常见结构
所有输入函数都具有相同的第一个参数:inputId
。这是用于将前端与后端连接的标识符:如果您的用户界面具有ID为name
的输入,则server函数将使用input$name
来访问它。
inputId
有两个约束:
它必须是一个简单的字符串,只包含字母、数字和下划线(不允许空格、破折号、句点或其他特殊字符!)以R命名变量。
它必须是唯一的。如果它不是唯一的,那么您将无法在server函数中引用此控件!
大多数输入函数都有一个称为label
的第二个参数。这是用于为控件创建一个人类可读的标签。Shiny对此字符串没有任何限制,但您需要仔细考虑,以确保您的应用程序对人类可用!第三个参数通常是value
,在可能的情况下,允许您设置默认值。其余参数是控件特有的。
创建输入时,我建议按位置提供inputId和label参数,并按名称提供所有其他参数:
1 | sliderInput("min", "Limit (minimum)", value = 50, min = 0, max = 100) |
以下部分描述了Shiny内置的输入,根据它们创建的控制类型松散分组。目标是让您快速了解您的选项,而不是详尽地描述所有参数。下面我将展示每个控件最重要的参数,但您需要阅读文档以获得完整详细信息。
自由文本
使用textInput()
收集少量文本,使用passwordInput()
3收集密码,使用textAreaInput()
收集段落文本。
1 | ui <- fluidPage( |
如果你想确保文本具有某些属性,你可以使用validate()
,我们将在第8章中介绍这个函数。
数值输入
要收集数值,请使用numericInput()
创建一个受约束的文本框,或使用sliderInput()
创建一个滑块。如果你为sliderInput()的默认值提供一个长度为2的数值向量,你将获得一个带有两个端点的“范围”滑块。
1 | ui <- fluidPage( |
一般来说,我只建议在范围较小或者精确数值不太重要的情况下使用滑块。尝试在小的滑块上精确选择一个数字是一件很令人沮丧的事情!
滑块非常可定制,有很多方法可以调整它们的外观。更多细节请参见?sliderInput
和https://shiny.rstudio.com/articles/sliders.html。
日期
使用dateInput()
收集单个日期,或使用dateRangeInput()
收集两个日期之间的范围。这些都提供了一个方便的日历选择器,额外的参数如datesdisabled
和daysofweekdisabled
允许您限制有效的输入集。
1 | ui <- fluidPage( |
日期格式、语言和一周开始的日期默认采用美国标准。如果您正在为国际用户创建应用程序,请设置格式、语言和一周开始日期,以便日期对您的用户来说是自然的。
有限制的选择
有两种不同的方法允许用户从预设的选项集中进行选择:selectInput()
和radioButtons()
。
1 | animals <- c("dog", "cat", "mouse", "bird", "other", "I hate animals") |
单选按钮有两个很好的特点:它们显示所有可能的选项,适合于短列表,并且通过choiceNames/choiceValues
参数,它们可以显示除普通文本之外的其他选项。choiceNames
确定向用户显示的内容;choiceValues
确定在您的server函数中返回的内容。
1 | ui <- fluidPage( |
使用selectInput()
创建的下拉菜单无论选项数量多少,都占用相同数量的空间,这使得它们更适合于更长的选项。您还可以设置multiple = TRUE
以允许用户选择多个元素。
1 | ui <- fluidPage( |
如果你有一组非常大的可能选项,你可能想要使用“server-side”selectInput()
,这样完整的可能选项集不被嵌入到UI中(这可能会使加载变慢),而是由服务器按需发送。您可以了解有关此高级主题的更多信息,请访问https://shiny.rstudio.com/articles/selectize.html#server-side-selectize。
没有方法可以在单选按钮中选择多个值,但有一个概念上类似的替代方案:checkboxGroupInput()
。
1 | ui <- fluidPage( |
如果您想要一个单选框来回答一个Yes/No
问题,请使用checkboxInput()
:
1 | ui <- fluidPage( |
文件上传
允许用户通过 fileInput()
上传文件:
1 | ui <- fluidPage( |
fileInput()需要在server端进行特殊处理,并在第9章中详细讨论。
动作按钮
使用actionButton()
或actionLink()
让用户执行动作。
1 | ui <- fluidPage( |
动作链接和按钮最自然地与server函数中的observeEvent()
或eventReactive()
配对。您还没有学习这些重要的函数,但我们在第3.5节中会回到它们。
您可以使用class
参数来自定义外观,使用"btn-primary"
,"btn-success"
,"btn-info"
,"btn-warning"
或"btn-danger"
之一。您还可以使用"btn-lg"
,"btn-sm"
,"btn-xs"
更改大小。最后,您可以使用"btn-block"
使按钮跨越其嵌入的元素的整个宽度。
1 | ui <- fluidPage( |
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()
输出固定代码和控制台输出。
1 | ui <- fluidPage( |
请注意,只有在需要运行多行代码时,{}
才需要在渲染函数中使用。正如您即将了解的那样,您应该在渲染函数中尽可能少地进行计算,这意味着您通常可以省略它们。以下是上述server函数更简洁的方式:
1 | server <- function(input, output, session) { |
注意,有两种渲染函数的行为略有不同:
renderText()
将结果合并成一个字符串,通常与textOutput()
配对renderPrint()
打印结果,就像在R控制台中一样,通常与verbatimTextOutput()
配对。
我们可以通过一个玩具应用程序看到这种差异:
1 | ui <- fluidPage( |
二者的区别与R中的 cat()
and print()
一样。
表格
有三种方法可以在表格中显示数据框:
tableOutput()
和renderTable()
呈现静态数据表,一次显示所有数据。dataTableOutput()
和renderDataTable()
呈现动态数据表,一次显示固定数量的行,同时显示控件以更改可见行。
tableOutput()
最适合小型、固定的摘要(例如模型系数);如果您想向用户展示完整的数据框,dataTableOutput()
最为合适。如果您想更精确地控制dataTableOutput()
的输出,我强烈推荐Greg Lin的reactable包。
1 | ui <- fluidPage( |
图形
您可以使用plotOutput()
和renderPlot()
显示任何类型的R图形(基础、ggplot2或其他)。
1 | ui <- fluidPage( |
默认情况下,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/中的选项。
1 | ui <- fluidPage( |
2.3.5.4 或者,您可以阅读reactable的文档,并将上面的应用程序转换为使用它。
总结
本章向您介绍了Shiny应用程序前端的主要输入和输出功能。这是一次大量的信息灌输,因此不要期望在一次阅读后就能记住所有内容。相反,当您需要查找特定组件时,请返回本章:您可以快速浏览图示,然后找到您需要的代码。
下一章我们将介绍Shiny应用程序的后端:使您的用户界面生动起来的R代码。
练习题答案获取
关注公众号“生信之巅”,聊天窗口回复“5369”获取习题答案。
敬告:使用文中脚本请引用本文网址,请尊重本人的劳动成果,谢谢!