11 书签
与大多数网站相比,Shiny应用程序有一个主要的缺点:您无法为应用程序添加书签以便将来返回同一位置,也无法通过电子邮件中的链接与他人分享您的工作。这是因为,默认情况下,Shiny不会在URL中公开应用程序的当前状态。然而,幸运的是,通过一些额外的工作,您可以更改此行为,本章将向您展示如何操作。
1 | library(shiny) |
11.1 基本思路
让我们用一个简单的应用程序来演示如何使其具有书签功能。这个应用程序绘制了利萨茹曲线,这些曲线复制了摆锤的运动。这个应用程序可以生成各种有趣的图案,您可能想要与他人分享。
1 | ui <- fluidPage( |
为了使这个应用程序具有书签功能,我们需要做三件事情:
在用户界面中添加一个bookmarkButton()。这将生成一个按钮,用户点击后生成可书签的URL。
将ui变为一个函数。您需要这样做是因为书签化的应用程序必须重新播放书签化的值:实际上,Shiny会修改每个输入控件的默认
value
。这意味着不再有一个单一的静态用户界面,而是可能有多个依赖于URL中参数的用户界面,因此它必须是一个函数。在shinyApp()调用中添加
enableBookmarking = "url"
。
进行这些更改后,我们得到:
1 | ui <- function(request) { |
1 | shinyApp(ui, server, enableBookmarking = "url") |
您可以在https://hadley.shinyapps.io/ms-bookmark-url尝试一下。如果您在应用程序中操作并书签了一些有趣的状态,您会发现生成的URL看起来像这样:
https://hadley.shinyapps.io/ms-bookmark-url/?_inputs_&damping=1&delta=1&length=100&omega=1
https://hadley.shinyapps.io/ms-bookmark-url/?_inputs_&damping=0.997&delta=1.37&length=500&omega=-0.9
为了理解发生了什么,让我们以第一个URL为例,将其分解成几个部分:
http://
是与应用程序通信时使用的“协议”。这始终是http
或https
。hadley.shinyapps.io/ms-bookmark-url
是应用程序的位置。
问号?
之后的所有内容都是“参数”。每个参数之间用&
分隔,如果将其分解,您可以看到应用程序中每个输入的值:
damping=1
delta=1
length=100
omega=1
因此,“生成书签”意味着在URL的参数中记录输入的当前值。如果您在本地进行操作,URL看起来会略有不同:
http://127.0.0.1:4087/?_inputs_&damping=1&delta=1&length=100&omega=1
http://127.0.0.1:4087/?_inputs_&damping=0.966&delta=1.25&length=100&omega=-0.54
http://127.0.0.1:4087/?_inputs_&damping=0.997&delta=1.37&length=500&omega=-0.9
除了将hadley.shinyapps.io/ms-bookmark-url
替换为类似127.0.0.1:4087
的内容外,大多数部分都是相同的。127.0.0.1
是一个特殊地址,始终指向您自己的计算机,而4087
是一个随机分配的端口。通常,不同的应用程序会获得不同的路径或IP地址,但如果您在自己的计算机上托管多个应用程序,则无法做到这一点。
11.1.1 更新URL
除了提供一个明确的按钮外,另一种选择是自动更新浏览器中的URL。这允许用户在其浏览器中使用用户书签命令,或者从地址栏复制和粘贴URL。
自动更新URL需要在服务器函数中编写一些模板代码:
1 | # Automatically bookmark every time an input changes |
这给我们提供了一个更新后的服务器函数,如下所示:
1 | server <- function(input, output, session) { |
1 | shinyApp(ui, server, enableBookmarking = "url") |
这会产生https://hadley.shinyapps.io/ms-bookmark-auto——由于URL现在会自动更新,您可以从用户界面中删除书签按钮。
11.1.2 存储更丰富的状态
到目前为止,我们使用了enableBookmarking = "url"
,它直接在URL中存储状态。这是一个很好的起点,因为它非常简单,可以在您可能部署Shiny应用的任何地方工作。然而,可以想象,如果您有大量的输入,URL会变得非常长,而且显然无法捕获上传的文件。
对于这些情况,您可能想要使用enableBookmarking = "server"
,它将状态保存到服务器上的.rds
文件。这总是生成一个简短的、不透明的URL,但需要在服务器上额外存储。
1 | shinyApp(ui, server, enableBookmarking = "server") |
目前,shinyapps.io尚不支持服务器端书签,因此您需要在本地尝试。如果您这样做,您会看到书签按钮生成类似以下的URL:
这些URL与您工作目录中匹配的目录配对:
shiny_bookmarks/0d645f1b28f05c97
shiny_bookmarks/87b56383d8a1062c
shiny_bookmarks/c8b0291ba622b69c
服务器端书签的主要缺点是它需要在服务器上保存文件,而且不清楚这些文件需要保留多长时间。如果您正在书签化复杂的状态并且从未删除这些文件,那么随着时间的推移,您的应用将占用越来越多的磁盘空间。如果您删除文件,一些旧书签将停止工作。
11.2 书签挑战
自动书签功能依赖于响应式图表。它使用保存的值初始化输入,然后重新播放所有的响应式表达式和输出,只要您的应用的响应式图表简单明了,就会产生与您看到的相同的应用。本节简要介绍了一些需要特别注意的情况:
如果您的应用使用了随机数,即使所有输入都相同,结果也可能不同。如果确保每次生成相同的数字非常重要,您需要思考如何使随机过程可重复。最简单的方法是使用repeatable()函数;有关更多详细信息,请参阅相关文档。
如果您有选项卡,并希望书签和恢复活动选项卡,请确保在调用tabsetPanel()时提供一个id。
如果有不应被书签记录的输入,例如它们包含不应共享的个人信息,请在服务器函数的某个位置调用setBookmarkExclude()。例如,
setBookmarkExclude(c("secret1", "secret2"))
将确保secret1
和secret2
输入不会被书签记录。如果您在自己的reactiveValues()对象中手动管理响应式状态(我们将在第
16
章中讨论),则需要使用onBookmark()和onRestore()回调来手动保存和加载额外的状态。有关更多详细信息,请参阅高级书签。
11.3 练习
为ambient::noise_simplex()的结果生成可视化应用。您的应用应允许用户控制频率、分形、间隙和增益,并且应支持书签功能。如何确保从书签重新加载时图像看起来完全相同?(考虑seed参数的含义)。
创建一个简单的应用,允许您上传CSV文件,并为其添加书签。上传几个文件,然后查看
shiny_bookmarks
。这些文件是如何与书签对应的?(提示:您可以使用readRDS()来查看Shiny生成的缓存文件的内容)。
11.4 总结
本章介绍了如何为您的应用程序启用书签功能。书签功能对您的用户来说是一个很好的特性,因为它允许他们轻松地将自己的工作与他人分享。接下来,我们将讨论如何在Shiny应用程序中使用整洁评估。整洁评估是许多tidyverse函数的一个特性,如果您希望允许用户在(例如)dplyr管道或ggplot2图形中更改变量,那么您需要了解这个特性。
加关注
敬告:使用文中脚本请引用本文网址,请尊重本人的劳动成果,谢谢!