张金龙的博客分享 http://blog.sciencenet.cn/u/zjlcas 物种适应性、分布与进化

博文

Shiny程序包学习要点

已有 8074 次阅读 2018-6-27 21:57 |个人分类:科研笔记|系统分类:科研笔记|关键词:学者

全文PDF Shiny.pdf



1. 什么是Shiny?

2. Shiny App的基本结构

   2.1 运行Shiny App

   2.2 app.R文件

       2.2.1 ui用户界面

       2.2.2 server函数

       2.2.3 shinyApp

   2.3 运行shiny程序包中的例子

3. 信息的输入与输出

4. 响应式编程与html标签

5. 编写高效的ShinyApp

1. 什么是Shiny?

Shiny 是Rstudio公司开发的R程序包。最早于2012年12月出现在CRAN上。

长期以来,R编写图形界面都不是很方便,Shiny在这方面进行了很大努力。Shiny在R中定义了网页中多种对象,因而可用其制作与R互动的网页。在Shiny生成的网页中,用户可提交数据,调整参数,控制生成的图形,如地图、箱线图等,也可以控制要显示的结果,如表格,模型拟合结果等。

想要在本地运行和调试用Shiny编写的用户界面,就要先安装Shiny及其依赖的程序包。Shiny应用程序可以部署在服务器端, 用户只要访问相应的网址,就可直接对网页中的对象进行操作。安装在服务器上的Shiny Server会收集信息并控制网页如何响应。

例1. 安装 Shiny程序包

install.packages("shiny")

2. Shiny App的基本结构

一个文件夹,加上包含Shiny命令的app.R文件,再加上用到的数据文件和R脚本等, 就称为ShinyApp。

Shiny App总是由三部分组成: 1. 文件夹 2. app.R的脚本 3. 其他数据和R脚本等

文件夹的名字就是shinyApp的名称,因此最好不要有英文或数字以外的字符。

2.1 运行Shiny App

shinyApp需要在导入Shiny程序包之后运行。

## 在本地运行shiny app
setwd("/Users/jinlong/Desktop/")
library(shiny)
runApp("learn_shiny")

2.2 app.R文件

app.R 文件必须包含三部分: 1. ui 设定图形界面 2. server函数 3. 调用shinyApp的命令 shinyApp(ui, server)

# 一个最简单的app.R脚本
library(shiny)# Define UI ----
ui <- fluidPage(

)

# Define server logic ----
server <- function(input, output) {

}

# Run the app ----

shinyApp(ui = ui, server = server)

2.2.1 ui用户界面

其中ui定义网页中对象的展示方式,包括文字的字体,字号,颜色,排列方式,以及各种组件的默认参数,可以选择的参数等。

2.2.2 server函数

server函数读取组件中收集到的数据,计算后,再传递给UI。

2.2.3 shinyApp

shinyApp(ui, server) 分别调用ui和server函数,生成网页。

shiny程序包中内置了十几个例子, 通过以下方式运行:

2.3 运行shiny程序包中的例子

library(shiny)
runExample("01_hello")

用户还可以查看其它Shiny模版, 参见https://rstudio.github.io/shinythemes/

3. 信息的输入与输出

例1

# Define UI for app that draws a histogram ----
# ui为user interface的缩写,ui是基本组件之一。此处定义ui,用于生成频度直方图
ui <- fluidPage(  
# App title ----
  # 添加标题
  titlePanel("Hello Shiny!"),  
  # Sidebar layout with input and output definitions ----
  # 添加侧面的导航栏, 同时定义输入input和输出的显示模式
  sidebarLayout(    
  # Sidebar panel for inputs ----
    # 输入数据用的导航栏
    sidebarPanel(      
    # Input: Slider for the number of bins ----
      # Input: 定义直方图的数量
      sliderInput(inputId = "bins",
                  label = "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
    ),    
    # Main panel for displaying outputs ----
    # 网页的主要板块用于输出结果
    mainPanel(      
    # Output: Histogram ----
      # 输出结果:频度直方图
      plotOutput(outputId = "distPlot")
    )
  )
)
# 定义server函数,绘制频度直方图
server <- function(input, output) {  
# server函数同时包括input和output两个参数
  # 输出结果要保存在output参数中

  # output中,用来保存绘图结果
  # 返回给putput中的对象,是经过 renderPlot转换过的R脚本
  # renderPlot本身是一个函数, 内部却直接放花括号
  # 花括号内的R脚本, 与普通R脚本无异
  output$distPlot <- renderPlot({

    x    <- faithful$waiting
    bins <- seq(min(x), max(x), length.out = input$bins + 1)

    hist(x, breaks = bins, col = "#75AADB", border = "white",
         xlab = "Waiting time to next eruption (in mins)",
         main = "Histogram of waiting times")

    })

}
# 脚本必须以shinyApp(ui, server)结束。shinyApp(ui, server)

要点

  • shiny application 包括 UI 和 Server以及shinyApp(ui, server)三部分。

  • UI负责收集数据和展示数据。fluidPage中的参数,titlePanelsidebarLayoutmainPanel用“,”分隔。

  • 收集数据的一般在 SidePanel 中进行

  • 展示数据在MainPanel中进行

  • 所有网页内容要放在fluidPage当中

  • UI中对象的命名习惯是,首字母小写,第二个单词的首字母大写,中间无任何间隔符号 (例如下划线_),这与javaScript的命名习惯相同

  • titlePanel用来给整个程序命名

  • sidebarLayout主要用来控制Sidebar独立为一列

  • 任何要输入的内容一般都放在sidebarPanel

  • 要输出的内容放在mainPanel

  • 输出的内容需要放在plotOutput中,以生成动态图形

  • 输入的内容需要用 outputId 指定

  • server 必须为一个函数,参数为input和output

  • 所有server函数要输出的内容,都必须作为output的组件,创建output组件用$指明即可

  • 所有从ui界面的数据获取,计算,绘图等都需要在renderPlot中处理

  • renderPlot的调用方法, 看似一个函数, 但是在小括号内放花括号,可放置多行R代码。

  • 从UI提取的数据,是input的参数的组件,用input$xxx提取

  • shinyApp结尾, 必须用shinyApp()`` 指明ui和server。格式为shinyApp(ui = ui, server = server)`

例2

library(shiny)
# Define UI for dataset viewer app ----
# 定义图形界面,用于查看数据
ui <- fluidPage(  # App title ----
  # 添加标题
  titlePanel("Shiny Text"),  
  # Sidebar layout with a input and output definitions ----
  # 添加导航栏,并定义input和output
  sidebarLayout(    
  # Sidebar panel for inputs ----
    # 用于输入数据的导航栏
    sidebarPanel(      
    # Input: Selector for choosing dataset ----
      # Input: 输入数据选择器
      selectInput(inputId = "dataset",
                  label = "Choose a dataset:",
                  choices = c("rock", "pressure", "cars")),      
                  # Input: Numeric entry for number of obs to view ----
      # Input:输入要查看的记录条数
      numericInput(inputId = "obs",
                   label = "Number of observations to view:",
                   value = 10)
    ),    # Main panel for displaying outputs ----
    # 主显示版
    mainPanel(      
    # Output: Verbatim text for data summary ----
      # Output: 直接显示数据概要
      verbatimTextOutput("summary"),      
      # Output: HTML table with requested number of observations ----
      # Output: 显示指定行数的表格
      tableOutput("view")

    )
  )
)

# Define server logic to summarize and view selected dataset ----
# 定义server函数,用于汇总和查看所选择数据
server <- function(input, output) {  
# Return the requested dataset ----
  # 返回所请求的数据
  datasetInput <- reactive({    
  switch(input$dataset,           
  "rock" = rock,           
  "pressure" = pressure,           
  "cars" = cars)
  })  
  # Generate a summary of the dataset ----
  # 创建数据汇总summary
  output$summary <- renderPrint({
    dataset <- datasetInput()
    summary(dataset)
  })  
  # Show the first "n" observations ----
  # 显示前n个观测值
  output$view <- renderTable({
    head(datasetInput(), n = input$obs)
  })

}

# Create Shiny app ----
# 创建ShinyAppshinyApp(ui = ui, server = server)

要点

  • 每一个形为*Input的组件,如 selectInputnumericInput 都是R函数,可以在帮助文件查询到各参数的要求。

  • 在ui中,输入数据可以用selectInput组件建立,此时用inputId参数识别输入的数据。

  • 输入数据可以用numericInput组件建立,此时用inputId识别输入的数据


  • selectInputnumericInput组件在输入数据时, 都有inputId, label以及value三个选项

  • 直接输出要打印的数据,可以用verbarimTextOutput("")

  • 其中“”中放要显示的对象名称,这个对象是由server中的output参数返回的,如“summary”

  • 要输出表格, 用tableOutput("view")

  • server函数中,通过reactive提取input$dataset中的数据

  • reactive面对的是selectInput组件,则需要用switch对UI中相应的操作做出响应

  • reactive的结果保存为一个对象, 也是在括号内放花括号, 以保证读取多行

  • 要输出的结果, 都必须保存到output对象中, 保存结果的操作符为 操作符为$

  • 要输出的结果分别用renderPrint, 或者renderTable转换为Print或者Table相应的类型。即使是一行,也需要用花括号将要打印的值或者表格包

  • datasetInputreactive返回的对象,但是也是一个函数,用来获取UI界面获取的值, 所以调用时, 都用datasetInput(), 与调用函数时一样

  • server文件中, 输入的数值, 可以直接用input$obs 的方式提取。

  • 所有要输出的内容, 都是作为output的一部分, 用$指定并赋值。这是响应式编程的基本要求。

4. 响应式编程与html标签

例3

# Define UI for dataset viewer app ----
# 定义ui, 该app用于查看数据
ui <- fluidPage(  
# App title ----
  # App标题
  titlePanel("Reactivity"),  
  # Sidebar layout with input and output definitions ----
  # 导航栏
  sidebarLayout(    
  # Sidebar panel for inputs ----
    # 输入数据的导航栏
    sidebarPanel(      
    # Input: Text for providing a caption ----
      # Note: Changes made to the caption in the textInput control
      # are updated in the output area immediately as you type

      # Input: 选择的标题会马上显示在右侧的结果显示区域中

      textInput(inputId = "caption",
                label = "Caption:",
                value = "Data Summary"),      
                # Input: Selector for choosing dataset ----
      # Input: 输入数据选择器
      selectInput(inputId = "dataset",
                  label = "Choose a dataset:",
                  choices = c("rock", "pressure", "cars")),      
      # Input: Numeric entry for number of obs to view ----
      # Input:设定要查看的记录条数
      numericInput(inputId = "obs",
                   label = "Number of observations to view:",
                   value = 10)

    ),    # Main panel for displaying outputs ----
    # 显示输出结果的主要面板

    mainPanel(      
    # Output: Formatted text for caption ----
      # Output: 修改标题格式
      h3(textOutput("caption", container = span)),      
      # Output: Verbatim text for data summary ----
      # Output: 打印data summary
      verbatimTextOutput("summary"),      
      # Output: HTML table with requested number of observations ----
      # Output: 生成HTML表格,以显示指定数量的观测值
      tableOutput("view")

    )
  )
)

要点

  • shiny中,可以直接使用html5标签

  • h3 为 第三级标题的html标签

  • tableOutput 直接生成表格

例4

library(shiny)

# Define UI for dataset viewer app ----
ui <- fluidPage(  
# App title ----
  titlePanel("More Widgets"),  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(    
  # Sidebar panel for inputs ----
    # 导航栏
    sidebarPanel(      
      # Input: Select a dataset ----
      # Input: 选择数据
      selectInput("dataset", "Choose a dataset:",
                  choices = c("rock", "pressure", "cars")),      
      
      # Input: Specify the number of observations to view ----
      # Input: 查看多少条记录
      numericInput("obs", "Number of observations to view:", 10),      
      # Include clarifying text ----
      # 帮助
      helpText("Note: while the data view will show only the specified",               
      "number of observations, the summary will still be based",               
      "on the full dataset."), 
           
      # Input: actionButton() to defer the rendering of output ----
      # until the user explicitly clicks the button (rather than
      # doing it immediately when inputs change). This is useful if
      # the computations required to render output are inordinately
      # time-consuming.
      # 当获得结果所需时间较长, 是否运行脚本需要由用户决定, 此时用本按钮。
      
      actionButton("update", "Update View")

    ),    
    
    # Main panel for displaying outputs ----
    # 主面板
    mainPanel(      
      # Output: Header + summary of distribution ----
      # 输出
      h4("Summary"),
      verbatimTextOutput("summary"),      
      # Output: Header + table of distribution ----
      # 输出
      h4("Observations"),
      tableOutput("view")
    )

  )
)# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {  
# Return the requested dataset ----
  # Note that we use eventReactive() here, which depends on
  # input$update (the action button), so that the output is only
  # updated when the user clicks the button
  datasetInput <- eventReactive(input$update, {    
  switch(input$dataset,           
  "rock" = rock,           
  "pressure" = pressure,           
  "cars" = cars)
  }, ignoreNULL = FALSE)  
  
  # Generate a summary of the dataset ----
  output$summary <- renderPrint({
    dataset <- datasetInput()
    summary(dataset)
  })  
  
  # Show the first "n" observations ----
  # The use of isolate() is necessary because we don't want the table
  # to update whenever input$obs changes (only when the user clicks
  # the action button)
  
  output$view <- renderTable({
    head(datasetInput(), n = isolate(input$obs))
  })

}# Create Shiny app ----shinyApp(ui, server)

要点

  • helpText 用来显示SideBarPanel中的帮助文本

  • actionButton("update", "Update View") 是按钮, 前一个参数是动作, 后一个参数是按钮上的标签。

  • 使用eventReactive 捕获UI按钮中的动作。

  • 使用Widgets时, 需要指定名称以及标签, 名称用于访问,标签用于显示。名称一般全部小写。标签一般首字母大写。Widgets标签也是可以直接用html5的tag的。 无论是 chekboxGroupInput 还是 radioButtonsselectInput, 都涉及到choices参数, 输入的都是list()

  • helpText()用以显示灰色帮助文字

server 函数有两个参数,inputoutput, output表示运算的结果, input表示从Widget收集到的数据。

输入数据,在UI中, 使用*Output系列函数。

Shiny中可以直接使用html5的标签, 包括:

Shiny函数html标签说明
p<p>A paragraph of text
h1<h1>A first level header
h2<h2>A second level header
h3<h3>A third level header
h4<h4>A fourth level header
h5<h5>A fifth level header
h6<h6>A sixth level header
a<a>A hyper link
br<br>A line break (e.g. a blank line)
div<div>A division of text with a uniform style
span<span>An in-line division of text with a uniform style
pre<pre>Text ‘as is’ in a fixed width font
code<code>A formatted block of code
img<img>An image
strong<strong>Bold text
em<em>Italicized text


UI中可放入如下Widgets

按钮功能
checkboxGroupInputA group of check boxes
checkboxInputA single check box
dateInputA calendar to aid date selection
dateRangeInputA pair of calendars for selecting a date range
fileInputA file upload control wizard
helpTextHelp text that can be added to an input form
numericInputA field to enter numbers
radioButtonsA set of radio buttons
selectInputA box with choices to select from
sliderInputA slider bar
submitButtonA submit button
textInputA field to enter text

Shiny输出的对象类型, 函数名称及其返回的对象

Shiny输入的对象Shiny返回的对象
dataTableOutputDataTable
htmlOutputraw HTML
imageOutputimage
plotOutputplot
tableOutputtable
textOutputtext
uiOutputraw HTML
verbatimTextOutputtext
  • \*Output可以放在 sidebarPanel 或 mainPanel 中。在server中,任何一个widget都需要有自己的名字,这个名字用来从server函数内的input对象访问widget。 Output系列函数,用来直接读取server 函数中, output对方中保存的内容。

  • server 函数返回的是output对象。

  • widget 显示出的结果, 都作为output的子对象保存。 可以返回的类型

  • server函数中,要显示的内容,都是通过render* 函数输出的。包括以下类型s

render 函数生成的对象
renderDataTableDataTable
renderImageimages (saved as a link to a source file)
renderPlotplots
renderPrintany printed output
renderTabledata frame, matrix, other table like structures
renderTextcharacter strings
renderUIa Shiny tag object or HTML

每一个render*函数,输入的参数都是用花括号包裹的。可以包含一行至多行代码。 数据文件放入data子文件夹。


5. 编写高效的ShinyApp

一般来说,运行ShinyApp是,ShinyApp本身只运行一次; Server函数,每一个用户访问时,都会运行一次; render* 函数里面的内容,用户一旦改变内容, 就会重新运行一次。

因此,为了Shiny程序能够高效运行, 一般有以下建议:

在server函数一开头,就要加载所有函数,程序包以及读取数据;

server函数中, 尽量在render* 函数意外建立新对象; 

render* 函数中, 只放不可或缺的对象。 

需要从网络下载的数据,一般放入 reactive({})环境中。 

当数据发生变化时,R会自动更新。

reactive({}) 返回的也是函数, 其返回值要用render\* 显示时,后面要跟括号()。

注意: 只能在render\*系列中调用reactive expressions。


参考网址




https://m.sciencenet.cn/blog-255662-1121166.html

上一篇:《R语言编程概述》讲座前言
下一篇:诗一首:吐露港的午夜

0

该博文允许注册用户评论 请点击登录 评论 (1 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-3-29 23:47

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部