基于R语言的shiny网页工具开发基础系列-05

2021-02-03 16:03:50 浏览数 (3)

后起之秀奔涌而至,欢迎大家在《生信技能树》的舞台分享自己的心得体会!

上面是shiny团队的稿件

l5-更复杂的反应app

创建一个更复杂的依赖R脚本和额外数据的有灵魂的(能反应的)app

使用R脚本和数据

此篇旨在展示如何载入数据,R脚本,包,用来构建app。

构建一个复杂的数据,可视化美国的人口普查数据

看起来像下图

counties.rds

counties.rds是一个包含美国每个县人口统计数据的数据集,使用R包UScensus2010收集,也可从这下载

下载文件后

  • 新建一个data文件夹于census-app文件夹中
  • 将counties.rds放入data文件夹

目录结构看起来像这样

这个叫counties.rds的数据集包含以下内容

  • 美国每个县的名字
  • 每个县的总人口
  • 该县白人,黑人,西班牙裔或亚裔居民的百分比
代码语言:javascript复制
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

helpers.R

helpers.R是一个帮助你使用地区分布图的R脚本,就像上面的图。地区分布图使用颜色展示变量的地区差异

此例中,helpers.R 将会创建一个percent_map ,一个设计用于匹配counties.rds数据的函数,下载

脚本将会使用maps和mapproj包,如果未安装请安装

代码语言:javascript复制
install.packages(c("maps", "mapproj"))

helpers.R脚本应存于census-app目录下

helpers.R 脚本中的 percent_map 函数采用五个参数

你可以用percent_map 画各县数据的地区分布图,代码如下

代码语言:javascript复制
library(maps)
library(mapproj)
source("census-app/helpers.R")
counties <- readRDS("census-app/data/counties.rds")
percent_map(counties$white, "darkgreen", "% White")

注意,上面的代码假设census-app 是工作路径的子目录。

percent_map 画县数据到地区分布图中,绿色的深度代表白人种族的百分比

载入文件和文件路径

如上代码,percent_map 的使用,需要先用 source 函数,然后用readRDS载入counties.rds,还载入了两个包library(maps)library(mapproj)

使用shiny也会这样调用这些函数,但是写法略有不同

source和readRDS需要文件路径,文件路径的使用方式在shiny中是不一样的

当shiny运行server中的函数时,会把所有文件路径的起始位置视为server.R所在的路径,换而言之,shiny app会把server.R所在的路径作为工作目录。

因为helpers.R于server.R在同一个路径,可以直接source("helpers.R")

而counties.rds在子目录data文件夹中

counties <- readRDS("data/counties.rds")

载入包可以使用

代码语言:javascript复制
library(maps)
library(mapproj)

执行

你可以把上面的代码放到app.R脚本中,但是放置的位置会决定他们被运行多少次,进而影响app性能,应为app.R中的某些部分会被更频繁的运行。

第一次启动应用,Shiny会运行整个脚本,R会处理server函数

shiny会保存server函数直到下一个用户到达,每次新用户到来都会从新运行server函数。这个每个用户都有自己独特的反应对象。

当用户与小工具交互,并改变他们的值,shiny会重新运行R表达式,分配给每个依赖于被改变的小工具的值的反应对象,如果用户足够活跃,这些表达式会运行很多很多次。

小小节回顾

  • 当启动app,shinyApp 会运行一次
  • server函数会在每个用户访问时跑一次
  • render*函数中的R表达式跑很多次,shiny在用户改变小工具的值时就会运行他们

通过以上信息,思考怎么写出高效的脚本

提高运行效率

source脚本,载入包,读取数据集应该放在app.R的开头,server函数之外。shiny只会运行这些代码一遍,包含了所有你在server函数中的表达式要调用的东西。

在server函数中定义用户特定的对象,当时不包含在render*函数之中,这种对象是每个用户都需要个人副本的。例如,一个对象包含用户的session information。这部分代码会被每个用户跑一次

只把shiny必须重新运行才能构建对象的代码放入render函数,每次在用户改变小工具的时候,Shiny 会返回render包含的所有相关代码,这将是很频繁的。

总之防止把不必要的代码放入render*函数,拖慢app的速度

练习1

尝试将如下代码插入到下面app.R脚本的正确位置

注意,此练习的结果还不是完整的app,所以无法运行,练习二才会完成

代码语言:javascript复制
source("helpers.R")
counties <- readRDS("data/counties.rds")
library(maps)
library(mapproj)
代码语言:javascript复制
# User interface ----
ui <- 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 logic ----
server <- function(input, output) {
  output$map <- renderPlot({
    percent_map( # some arguments )
  })
}

# Run app ----
shinyApp(ui, server)

完成app

人口普查数据可视化软件有一个反应对象,一个名为"map"的图,有percent_map构建,采用五个参数

  • 前三个参数,var, color, 和 legend.title, 取决于选择框小工具的值
  • 后两个参数,max和min,取决于滑块小工具的最大值和最小值

下面的server函数展示了一个percent_map反应参数的框架。R的switch函数能随心所欲转换选择框的输出。但是这个脚本是不完整的,没有为color,legend.title,max或者min提供值

注意,此步的这个脚本还不能运行,将在练习二中完成

代码语言:javascript复制
server <- 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 = ?)
  })
}

练习二

把上面残缺的代码补充完整

当app部署完成后,保存app.R, 运行 runApp("census-app") 命令,如果一切正常,结果将如下图所示

你将要决定

  • 如何为percent_map构建参数值
  • 如何放置这些设置参数的代码

赶紧先自己做做吧

回顾

如今,你已经可以使用R脚本,数据集,包创建复杂的app了

有几个要点

  • 对于shiny app 来说,app.R脚本所在的路径就是工作目录
  • 每次启动,shiny会运行app.R中的代码,server函数之前的部分只会在这个app启动时运行一次
  • server之中的代码会运行多次,可能会拖慢app速度

switch是多选项小工具的实用辅助函数,把小工具的值转换成R表达式

我的答案

代码语言:javascript复制
library(shiny)

source("helpers.R")
counties <- readRDS("data/counties.rds")
library(maps)
library(mapproj)

# User interface ----
ui <- 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 logic ----
server <- 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" = "#5aae61",
                    "Percent Black" = "black",
                    "Percent Hispanic" = "orange",
                    "Percent Asian" = "#762a83")
    title <- switch(input$var,
                    "Percent White" = "White",
                    "Percent Black" = "Black",
                    "Percent Hispanic" = "Orange",
                    "Percent Asian" = "Purper")
    percent_map(var = data, color = color, legend.title = title, max = input$range[2], min = input$range[1])
  })
}

shinyApp(ui = ui,server = server)

参考答案

代码语言:javascript复制
# Load packages ----
library(shiny)
library(maps)
library(mapproj)

# Load data ----
counties <- readRDS("data/counties.rds")

# Source helper functions -----
source("helpers.R")

# User interface ----
ui <- 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 logic ----
server <- 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(data, color, legend, input$range[1], input$range[2])
  })
}

# Run app ----
shinyApp(ui, server)

Reference:

Shiny - Use R scripts and data

0 人点赞