||
全文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
Shiny 是Rstudio公司开发的R程序包。最早于2012年12月出现在CRAN上。
长期以来,R编写图形界面都不是很方便,Shiny在这方面进行了很大努力。Shiny在R中定义了网页中多种对象,因而可用其制作与R互动的网页。在Shiny生成的网页中,用户可提交数据,调整参数,控制生成的图形,如地图、箱线图等,也可以控制要显示的结果,如表格,模型拟合结果等。
想要在本地运行和调试用Shiny编写的用户界面,就要先安装Shiny及其依赖的程序包。Shiny应用程序可以部署在服务器端, 用户只要访问相应的网址,就可直接对网页中的对象进行操作。安装在服务器上的Shiny Server会收集信息并控制网页如何响应。
例1. 安装 Shiny程序包
install.packages("shiny")
一个文件夹,加上包含Shiny命令的app.R文件,再加上用到的数据文件和R脚本等, 就称为ShinyApp。
Shiny App总是由三部分组成: 1. 文件夹 2. app.R的脚本 3. 其他数据和R脚本等
文件夹的名字就是shinyApp的名称,因此最好不要有英文或数字以外的字符。
shinyApp需要在导入Shiny程序包之后运行。
## 在本地运行shiny app setwd("/Users/jinlong/Desktop/") library(shiny) runApp("learn_shiny")
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)
其中ui定义网页中对象的展示方式,包括文字的字体,字号,颜色,排列方式,以及各种组件的默认参数,可以选择的参数等。
server函数读取组件中收集到的数据,计算后,再传递给UI。
shinyApp(ui, server)
分别调用ui和server函数,生成网页。
shiny程序包中内置了十几个例子, 通过以下方式运行:
library(shiny) runExample("01_hello")
用户还可以查看其它Shiny模版, 参见https://rstudio.github.io/shinythemes/
# 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
中的参数,titlePanel
, sidebarLayout
, mainPanel
用“,”分隔。
收集数据的一般在 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)`
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
的组件,如 selectInput
,numericInput
都是R函数,可以在帮助文件查询到各参数的要求。
在ui中,输入数据可以用selectInput
组件建立,此时用inputId参数识别输入的数据。
输入数据可以用numericInput
组件建立,此时用inputId识别输入的数据
selectInput
和numericInput
组件在输入数据时, 都有inputId, label以及value三个选项
直接输出要打印的数据,可以用verbarimTextOutput("")
其中“”中放要显示的对象名称,这个对象是由server
中的output
参数返回的,如“summary”
要输出表格, 用tableOutput("view")
在server
函数中,通过reactive
提取input$dataset
中的数据
若reactive
面对的是selectInput
组件,则需要用switch
对UI中相应的操作做出响应
reactive
的结果保存为一个对象, 也是在括号内放花括号, 以保证读取多行
要输出的结果, 都必须保存到output
对象中, 保存结果的操作符为 操作符为$
要输出的结果分别用renderPrint
, 或者renderTable
转换为Print
或者Table
相应的类型。即使是一行,也需要用花括号将要打印的值或者表格包
datasetInput
为reactive
返回的对象,但是也是一个函数,用来获取UI界面获取的值, 所以调用时, 都用datasetInput()
, 与调用函数时一样
在server
文件中, 输入的数值, 可以直接用input$obs
的方式提取。
所有要输出的内容, 都是作为output
的一部分, 用$指定并赋值。这是响应式编程的基本要求。
# 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
直接生成表格
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
还是 radioButtons
, selectInput
, 都涉及到choices
参数, 输入的都是list()
。
helpText()
用以显示灰色帮助文字
server
函数有两个参数,input
和output
, 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
按钮 | 功能 |
---|---|
checkboxGroupInput | A group of check boxes |
checkboxInput | A single check box |
dateInput | A calendar to aid date selection |
dateRangeInput | A pair of calendars for selecting a date range |
fileInput | A file upload control wizard |
helpText | Help text that can be added to an input form |
numericInput | A field to enter numbers |
radioButtons | A set of radio buttons |
selectInput | A box with choices to select from |
sliderInput | A slider bar |
submitButton | A submit button |
textInput | A field to enter text |
Shiny输出的对象类型, 函数名称及其返回的对象
Shiny输入的对象 | Shiny返回的对象 |
---|---|
dataTableOutput | DataTable |
htmlOutput | raw HTML |
imageOutput | image |
plotOutput | plot |
tableOutput | table |
textOutput | text |
uiOutput | raw HTML |
verbatimTextOutput | text |
\*Output
可以放在 sidebarPanel
或 mainPanel
中。在server
中,任何一个widget都需要有自己的名字,这个名字用来从server函数内的input对象访问widget。 Output系列函数,用来直接读取server
函数中, output对方中保存的内容。
server
函数返回的是output
对象。
widget
显示出的结果, 都作为output
的子对象保存。 可以返回的类型
server
函数中,要显示的内容,都是通过render*
函数输出的。包括以下类型s
render 函数 | 生成的对象 |
---|---|
renderDataTable | DataTable |
renderImage | images (saved as a link to a source file) |
renderPlot | plots |
renderPrint | any printed output |
renderTable | data frame, matrix, other table like structures |
renderText | character strings |
renderUI | a Shiny tag object or HTML |
每一个render*
函数,输入的参数都是用花括号包裹的。可以包含一行至多行代码。 数据文件放入data子文件夹。
一般来说,运行ShinyApp是,ShinyApp本身只运行一次; Server函数,每一个用户访问时,都会运行一次; render*
函数里面的内容,用户一旦改变内容, 就会重新运行一次。
因此,为了Shiny程序能够高效运行, 一般有以下建议:
在server函数一开头,就要加载所有函数,程序包以及读取数据;
server
函数中, 尽量在render*
函数意外建立新对象;
render*
函数中, 只放不可或缺的对象。
需要从网络下载的数据,一般放入 reactive({})
环境中。
当数据发生变化时,R会自动更新。
reactive({})
返回的也是函数, 其返回值要用render\*
显示时,后面要跟括号()。
注意: 只能在render\*
系列中调用reactive expressions。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-12-23 00:49
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社