Shiny篇(5)------使用R脚本和数据
Shiny篇(1)------欢迎使用shiny - 知乎 (zhihu.com)
Shiny篇(2)------ 建立UI - 知乎 (zhihu.com)
Shiny篇(3)------增加控件 - 知乎 (zhihu.com)
Shiny篇(4)------反馈输出 - 知乎 (zhihu.com)
Shiny篇(5)------使用R脚本和数据 - 知乎 (zhihu.com)
Shiny篇(6)-------使用反馈表达式 - 知乎 (zhihu.com)
Shiny篇(7)------分享App - 知乎 (zhihu.com)
Shinyapps.io 的认证和认证模式 - 知乎 (zhihu.com)
本课内容主要介绍如何在shiny app上加载数据、R脚本文件、R包。在此过程中,将以美国人口数据为案例,制作出一个的功能完善的shiny app。
1.counties.rds #加载数据
counties.rds 是关于美国各个州的人口统计数据集, 在 UScensus2010 R包中. 下载地址:
here
.
如果你已经下载了数据文件,那么进行如下文件操作:
- 建立一个新文件夹 data 在app:census-app文件夹下面
-
将文件counties.rds 放在data 文件夹下面.
操作之后文件关系如下图:
counties.rds
数据集的内容
:
- 美国每个州的名称(第一列name)
- 每个州的人口总数量(第二列total.pop)
-
白人、黑人、西班牙人、亚洲人的百分比(第三,四,五,六列);
加载数据,代码如下:
counties <- readRDS("census-app/data/counties.rds")
head(counties)
name total.pop white black hispanic asian
1 alabama,autauga 54571 77.2 19.3 2.4 0.9
2 alabama,baldwin 182265 83.5 10.9 4.4 0.7
3 alabama,barbour 27457 46.8 47.8 5.1 0.4
4 alabama,bibb 22915 75.0 22.9 1.8 0.1
5 alabama,blount 57322 88.9 2.5 8.1 0.2
6 alabama,bullock 10914 21.9 71.0 7.1 0.2
2.加载R脚本:help.R
helpers.R 是一个帮助我们制作分布图的R脚本文件。如图1所示,能够利用颜色深浅在地图上显示不同区域人口密度的不同(热力图)。在这个案例里,helpers.R 将创建函数 percent_map, 函数作用于数据集counties.rds,形成人口密度与各个州的对应关系图。下载脚本 helpers.R
here
.
helpers.R 会调用 maps 和 mapproj R包,如果你没有安装这两个包,请在制作shiny app之前,安装包,代码如下:
> install.packages(c("maps", "mapproj"))
保存 helpers.R 脚本在 census-app文件夹之下,文件关系如下图:
函数 percent_map 需要5个参数:
参数输入
varthe counties.rds dataset中的一列向量
color 热力图的颜色
legend.title 图例的名称
max 参数的上限,默认最大为100
min 参数的下限,默认最小为0
利用函数percent_map 在命令行 画出数据的人口统计图,代码如下:
library(maps) #加载maps包
library(mapproj) #加载mapproj包
source("census-app/helpers.R") #读R脚本文件
counties <- readRDS("census-app/data/counties.rds") #加载rds数据
percent_map(counties$white, "darkgreen", "% White")
备注: 以上代码假设 census-app 是工作路径的子路径, 工作路径是的 census-app上级路径,在rstiudo改变工作路径的方式: 点击 Session > Set Working Directory > Choose Directory… 函数percent_map 画每个州的人口统计图, 这里会用 深绿色
3.加载文件和文件路径
正如上面代码描述, 为了加载函数 percent_map,我们必须:
首先,使用 source 函数启动 helpers.R脚本,
然后,使用 readRDS 函数加载counties.rds数据集,
再然后,加载 library(maps) 和library(mapproj) 这三部分工作。
那么,为了让Shiny与命令行有相同的结果,在app使用percent_map函数之前,必须让Shiny加载函数percent_map,可是如何能让这些函数能够达到这样的效果 ?
答案是Shiny既需要source 和 readRDS 公用一个文件路径, 同时需要在Shiny app使用同样的路径, 执行起来正如他们在命令行一样。
当我们在Shiny中server.R脚本中运行命令的时候,它将处理所有的文件路径正如所有的路径都开始于相同的 server.R,换句话说. 我们保存server.R的路径就成为新的app的工作路径。
有了这些设置,以上所有代码就简洁了:
因为保存helpers.R 脚本之后,在相同的路径作为server.R,你可以直接用Shiny 加载脚本:
source("helpers.R")
因为保存了数据集 counties.rds 其实server.R和 文件( 名称为data) 存在于同一个工作路径, 你可以直接加载数据集:
counties <- readRDS("data/counties.rds")
可以直接加载 maps and mapproj R包:
library(maps)
library(mapproj)
这两个包本身不需要加载路径。
4.执行代码
Shiny 将执行所有server.R 脚本中的命令,尽管如此 server.R 会决定 代码运行的次数, 进而影响app的呈现。
Shiny 运行 server.R中的某些代码比其他代码的次数多。
当你运行runapp(),Shiny 运行所有的代码脚本, 这促使Shiny 执行shinyServer.shinyServer一次,并且赋予Shiny一些未命名的函数。如下:
Shiny 保存所有未命名的函数,直到给新的用户的到来,每次一个新的用户访问app,Shiny就会运行未命名的函数一次,这个方程帮助Shiny针对不用的用户建立清晰的反馈对象,如下:
当用户改变控件,Shiny将重复运行R表达式赋予行的反馈对象,如果新的用户是活跃的,这些表达式将多次的运行。如下图:
总结::
- 当你运行一次app,server.R脚本运行一次
- 每次用户访问app,在shinyserver中未命名的函数将运行一次。
- 当用户改变多次控件的值,那么,R表达式将会多次运行。
这说明什么?
在加载脚本,加载数据,读取数据作为server.R的开始,在函数shinyServer 之外,Shiny 将运行一次,而其他的代码将R表达式方在shinyserver之内。
定义用户特殊的对象在shinyServer’s的函数内,但是在render*之外的代码,这些对象你可以认为每个用户都有自己私人的代码,例如,如果记录某个用户的对象,那么这些代码每个人执行一次。 session information .
在render*函数之内的代码,一旦空间的某个值改变,那么,Shiny会重新执行render*内的所有代码块。
这样做的目的是为了不让多次执行不必要的代码,拖慢Shiny app的速度,没有必要的不要将代码放在render函数之内。.
作业 1
复制粘贴 ui.R 和 server.R 文件 到 census-app 路径下. 然后增加如下代码到:
source("helpers.R")
counties <- readRDS("data/counties.rds")
library(maps)
library(mapproj)
tserver.R,确定命令行都在有效位置。
备注: 这是完成app两步中的第一步,选择正确的位置放置代码,但是不要执行app,直到后续的有了赋值之后才可以(# some arguments在作业2中进行赋值),否则都会出现错误。
ui.R
# ui.R
shinyUI(fluidPage(
titlePanel("censusVis"),
sidebarLayout(
sidebarPanel(
helpText("Create demographic maps with
information from the 2010 US Census."),
selectInput("var",
label = "Choose a variable to display",
choices = c("Percent White", "Percent Black",
"Percent Hispanic", "Percent Asian"),
selected = "Percent White"),
sliderInput("range",
label = "Range of interest:",
min = 0, max = 100, value = c(0, 100))
mainPanel(plotOutput("map"))
server.R
# server.R
shinyServer(
function(input, output) {
output$map <- renderPlot({
percent_map( # some arguments )
答案 1
因为app只需要加载 helpers.R 和 counties.rds 一次, 这些代码应该放在shinyServer 函数之外,同时也是加载R包代码的好地方。
# server.R
library(maps)
library(mapproj)
source("helpers.R")
counties <- readRDS("data/counties.rds")
shinyServer(
function(input, output) {
output$map <- renderPlot({
percent_map( # some arguments )
你也许想“每个用户都不需要自己的数据和相应函数吗?” (这表明这些代码应该放在shinyServer的未命名函数中。不不不, 每个用户都不需要。.
保持用户的电脑不要运行所有Shinyapp中的的代码,事实上,他们的电脑看不到R代码,你用的电脑作为服务器运行用户的所有代码,它只是将结果以HTML的方式展现在用户面前。
你的服务器依赖数据和函数(counties.rds 和 percent_map)做用户的展现,只需要针对不同的用户拆分出不同的对象。
最后的 app
censusVis app 有交互式对象图“map”,这个图通过map函数进行构造,需要5个参数 :
- 前三个参数 var, color, and legend.title的值来自于选择空间中的值
- 后两个参数, max and min,为滑动条空间的最大值和最小值
如下R脚本服务器展示了一种精巧的方式,通过percent-map函数实现交互式,R的交互式函数能够把在控件选择的值转变你预想,尽管如此,R脚本是不完整的,它没有为 color, legend.title, max, or min提供相应的值, 备注 : 脚本暂时不能执行,必须玩成任务2才能执行
# server.R
library(maps)
library(mapproj)
counties <- readRDS("data/counties.rds")
source("helpers.R")
shinyServer(
function(input, output) {
output$map <- renderPlot({
data <- switch(input$var,
"Percent White" = counties$white,
"Percent Black" = counties$black,
"Percent Hispanic" = counties$hispanic,
"Percent Asian" = counties$asian)
percent_map(var = data, color = ?, legend.title = ?, max = ?, min = ?)
任务2
完成 censusVis app.
当已经配置好了app,保存server.R 和 ui.R files 和 runrunApp("census-app"). 如果一起工作正常,app将会展示给如下图片:
你需要决定:
- 如何给函数percent_map对应的参数值
- 这些创建好的参数放在哪里
切记,当用户改变控件的值应该对应相应的函数值.,当完成,或者你遇到问题,参见如下代码。
Model Answers 2
A simple version of server.R:
# server.R
library(maps)
library(mapproj)
counties <- readRDS("data/counties.rds")
source("helpers.R")
shinyServer(
function(input, output) {
output$map <- renderPlot({
data <- switch(input$var,
"Percent White" = counties$white,
"Percent Black" = counties$black,
"Percent Hispanic" = counties$hispanic,
"Percent Asian" = counties$asian)
color <- switch(input$var,
"Percent White" = "darkgreen",
"Percent Black" = "black",
"Percent Hispanic" = "darkorange",
"Percent Asian" = "darkviolet")
legend <- switch(input$var,
"Percent White" = "% White",
"Percent Black" = "% Black",
"Percent Hispanic" = "% Hispanic",
"Percent Asian" = "% Asian")
percent_map(var = data,
color = color,
legend.title = legend,
max = input$range[2],
min = input$range[1])
A more concise version of server.R:
# server.R
library(maps)
library(mapproj)
counties <- readRDS("data/counties.rds")
source("helpers.R")
shinyServer(
function(input, output) {
output$map <- renderPlot({
args <- switch(input$var,
"Percent White" = list(counties$white, "darkgreen", "% White"),
"Percent Black" = list(counties$black, "black", "% Black"),
"Percent Hispanic" = list(counties$hispanic, "darkorange", "% Hispanic"),
"Percent Asian" = list(counties$asian, "darkviolet", "% Asian"))
args$min <- input$range[1]
args$max <- input$range[2]
do.call(percent_map, args)
and
# ui.R
shinyUI(fluidPage(
titlePanel("censusVis"),
sidebarLayout(
sidebarPanel(
helpText("Create demographic maps with
information from the 2010 US Census."),
selectInput("var",
label = "Choose a variable to display",
choices = c("Percent White", "Percent Black",
"Percent Hispanic", "Percent Asian"),
selected = "Percent White"),
sliderInput("range",
label = "Range of interest:",
min = 0, max = 100, value = c(0, 100))