在这一章中,我们将创建一个简单的shiny app。我将要向你展示shiny app所需最简单的组件。然后你将学会如何运行和停止shiny app。接下来,你将学习shiny app的两个最重要的组件:UI部分(用户界面)被人看到的部分、和server部分(让你shiny app在可以稳定运行的部分)。shiny使用的是反应式编程。也就是说shiny会自动的更新输出当输入改变的时候。所以当我们将shiny app的反应表达式学完时,这章就结束了。
如果还没有安装shiny安装包,现在应该安装:
install.packages("shiny")
安装好之后,加载到R的会话里面:
library(shiny)
有很多种方法创建一个shiny app。最简单的是在一个文件夹下,创建一个叫aap.R的文件。这个app.R的文件将告诉shiny。你的shiny是长得什么样,背后运行行为是什么。
试一试创建一个文件夹,在文件夹下添加一个叫app.R的文件,用Rstudio打开这个文件。并将下面的代码写到app.R里面:
library(shiny)
ui <- fluidPage(
"Hello, world!"
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Rstudio 小提示:你可以很轻松的使用Rstudio来创建一个文件夹和一个app.R文件。一步步操作流程如下:“File” 然后 选择”New Project “然后选择“New Directory” 然后选择 “Shiny Web Application"。或者你已经创建一个app.R的文件了,你可以快速的输入“shinyapp"。然后回车(我的win10系统上,输入shinyap的时候就有了,然后回车自动出现shiny app框架,但是原文是按 Shift + tab键。我也不知道为啥)。
运行好之后,会出现和上面的差不多的代码。实际上,我们的app.R做了四件事:
library(shiny)
加载shiny包。hello world!
。server
里面,定义着这个shiny app的行为。但是server
是空的,所以现在这个shiny app啥都做不了。shinyApp(ui, server)
意味着从ui
,server
构建并开始一个shiny app。这里有几个方式运行这个app:
Run App
按钮,在文本编辑窗口的右上角。使用键盘快捷键:Cmd/ctrl + shift + Enter
如果没有使用Rstudio。可以使用source()
函数来加载这个app.R
文件。或者使用shiny::runApp()
来加载app.R
。
随便选择上面的任意一个方式,运行这个shiny app。如果你的运行结果和下面的图一样,那么恭喜你,你的第一个shiny app成功了。
在没有关闭上面这个小窗口的时候,回到Rstudio。看R的console(R的对话界面,或者是控制台)。你也看到这样的一句话(可能具体的数值不一样):
#Listening on http://127.0.0.1:3371
上面这句话说,你可以在你的计算机的3371端口上找到我们正在运行的shiny app。其中127.0.0.1是标准地址,后面的3371是端口(可能每个人运行的端口都不一样,没有关系)将上面的网站链接复制http://127.0.0.1:3371
到浏览器,就可以在浏览器中打开这个shiny app。
如何关闭shiny app。有以下几个方法:
stop
按钮。Esc
按钮(如果用的不是Rstudio软件,使用ctrl + c
结束程序)。我们现在的UI部分太小了,向里面加入输入、输出控件。我们的目的是使用datasets包的内置数据集,来建立一个简单的shiny app。将你的UI代码部分用下面代码替代:
ui <- fluidPage(
selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
verbatimTextOutput("summary"),
tableOutput("table")
)
这里小demo使用下面4个新的函数:
fluidPage()
是一个布局函数,用于设置shiny app的页面,将在章节3.4学到更多。
selectInput()
是一个输入控件,shiny app的按钮提供一个可选择列表,shiny app的使用者可以自己选择。在这个小案例中。在一个小盒子(其实就是一个选择框)里面选择R内置的数据集。关于输入控件,将在章节3.2学到更多。
verbatimTextOutput()
和tableOutput()
是输出控件,是用来告诉shiny将渲染的输出在UI的哪里显示(关于渲染,后面会介绍)。verbatimTextOutput()
显示R的代码。tableOutput()
显示表格。关于这些将在章节3.3学到更多。
布局函数,输入输出函数有着不同的用处。但是本质都是一样的:用来生成HTML。如果在shiny app应用程序之外调用他们中的任意一个。可以在浏览器的控制台看到这些HTML输出。不要害怕有错误,多看看代码和后台运行情况。这些将在章22学到更多。
将上面的代码继续运行,可以看到下面的页面,可以看到有个选择的框(也就是上面说的小盒子)。但是我们只能看到输入,没有看到输出,因为我们还没告诉shiny输入和输出的内在联系。
完整代码如下:
library(shiny)
ui <- fluidPage(
selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
接下来,就是在server
部分定义输出。这样才能将输出展示在UI里面。
shiny使用的是反应式编程。使得shiny app有交互性。反应式编程(reactive programming
)将在章节4有着详细的介绍。但是现在,只需要知道:反应式编程是告诉shiny如何去计算,而不是马上计算(我感觉就是把路给你铺好,你接下来好好的走这条路,但是你现在不用出发)。这个区别就像是给你菜谱和马上做一个三明治一样。
在这里案例里,将告诉shiny。如何填充上面代码里面的summary
和table
这两个输出。我们给输出提供了一个菜谱。将上面的server函数用下面的代码替代:
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- get(input$dataset, "package:datasets")
summary(dataset)
})
output$table <- renderTable({
dataset <- get(input$dataset, "package:datasets")
dataset
})
}
基本上每一个输出,在shiny的server里面写成的形式都是下面这样的:
output$ID <- renderTYPE({
# Expression that generates whatever kind of output
# renderTYPE expects
})
赋值操作<-
的左边是output$ID
。意思要将右边的运算结果赋给output的ID。赋值操作的右边是指定的渲染函数,在渲染函数里面放入你的代码(注意要使用{}将代码包括起来)。在上面的代码中,使用的是renderPrint()
和renderPlot()
渲染你的代码运行结果。
每一个render*
渲染函数都有对应的*output
输出函数。我们使用renderPrint()
来构造和显示定宽文本(普通文本)。使用renderTable()
将数据框用表格来显示。
运行下面的完整代码:
library(shiny)
ui <- fluidPage(
selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
output$summary <- renderPrint({
dataset <- get(input$dataset, "package:datasets")
summary(dataset)
})
output$table <- renderTable({
dataset <- get(input$dataset, "package:datasets")
dataset
})
}
shinyApp(ui, server)
输出结果如下:
值得注意的是,我没有写任何代码来检测shiny app的input$dataset
是否变换了再更新两个输出结果。原因是两个输出都是反应式的:他们自动再计算,当输入部分变化的时候。因为我编写的两个渲染代码都是使用了input$dataset
。只要用户在UI部分选择新的东西,这两个output就会自动在背后计算然后再在UI上呈现出来。
仔细观察上面的这个完整的代码,在server这个函数里面dataset <- get(input$dataset, "package:datasets")
出现了两次。不管在什么编程语言里面,重复的代码都是不明智的:浪费计算资源、调试代码、维护代码成本等,虽然在我们的这个小案例里面没有那么夸张。但是还是要传递一个基本的概念。
在传统的R代码里面,我们使用两种方法处理需要重复计算的部分:将其保存到变量里面、使用函数获得计算结果。具体原因将在18.2中说明。但是这些在shiny的反应式编程里面都不适用。我们需要一个新的机制:反应表达式。
可以使用reactive({})
这个代码块来创建一个反应表达式,并将其赋值给一个变量,然后就可以像是使用函数一样调用这个反应表达式。反应表达式有个特点:一经过运行之后,会将数据缓存,直到更新。
下面的代码和上面的代码基本上没有区别,但是减少了计算量,工作效率更高。因为只用get
这行代码只用运行一次了。
library(shiny)
ui <- fluidPage(
selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
verbatimTextOutput("summary"),
tableOutput("table")
)
server <- function(input, output, session) {
dataset <- reactive({
get(input$dataset, "package:datasets")
})
output$summary <- renderPrint({
summary(dataset())
})
output$table <- renderTable({
dataset()
})
}
shinyApp(ui, server)
我们在以后会更加的介绍反应式编程。到目前为止,虽然我们知道有限的输入、输出、浅显的反应式,但是我们依然可以做出有用的shiny app。
可以看官网链接:https://github.com/rstudio/cheatsheets/raw/master/shiny.pdf
或者看我之前的文章:https://mp.weixin.qq.com/s?__biz=MzU3MDkzNjk1OQ==&mid=2247485297&idx=1&sn=a6e21349a4c93a50111511441e88314a&chksm=fce69c61cb911577f7514e6b4b127dc32cf1123a41b48a9be8b473c4a7acd2e309736bda07b1&token=2015185885&lang=zh_CN#rd
这部分我之前写了,但是我现在还没整理。我打算将这本书翻译完再写,可以查看我的微信公众号:pypi
获得最新的关于这部分的内容
微信扫一扫:
知乎:https://www.zhihu.com/people/fa-fa-1-94
csdn:https://blog.csdn.net/yuanzhoulvpi
我使用的是typora写的md版本,然后导出word和pdf。目前只是版本1。
想要获得更加良好的体验,可以看pdf版本
已经上传到我的github上了:https://github.com/yuanzhoulvpi2017/master_shiny_CN
百度网盘链接:
链接:https://pan.baidu.com/s/18RAJ0A8r3NVzN0Sdo-upUQ
提取码:x5sd
我的QQ群:308463421 (只是用来分享我的资料)
如果想交流R,可以看最大的那个qq群:538911602
如果有错误,欢迎前辈指正。邮箱交流:[email protected]