Shiny篇(5)------使用R脚本和数据

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)

Shiny背景主题 - 知乎 (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))