开发一个Rshiny应用(基础)

Introduction

Shiny 是一个 R 包,可轻松地直接从 R 构建交互式 Web 应用程序。还可以在网页上托管独立应用程序或将它们嵌入 R Markdown 文档或构建仪表板,还可以使用 CSS 主题、html 小部件和 JavaScript 操作扩展您的 Shiny 应用程序。

#first app
library(shiny)
ui <- fluidPage(
  "Hello, world!"
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

整个app可分为两个部分,ui与sever,可以认为是前端与后端的关系,Rshiny提供了很多内置的小组件帮我们将前后端联系起来,非常方便好用。只需要有一点点的HTML/CSS/Javascript的知识就可以设计出更好看的界面和更多有趣的交互。

这里是shiny的记忆手册,浓缩了大部分的操作。

Methods

UI设计

Layout

最基础的布局就是sidebarLayout,可以分成sidebarPanel,mainPanel两个部分。

ui <- fluidPage(
  titlePanel("title panel"),

  sidebarLayout(
    sidebarPanel("sidebar panel"),
    mainPanel("main panel")
  )
)

可以通过将内容放在 *Panel 函数中来向Shiny 应用程序添加内容,shiny提供了R代码方便插入HTML (Table 1),更多标签可以查看tag-glossary

Table 1: shiny function HTML5 equivalent creates
shiny function HTML5 equivalent creates
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
HTML NA Directly passes a character string as HTML code
Control widgets

这些是常用shiny内置的小控件,提供一种向 Shiny serve发送消息的方式。

Table 2: standard Shiny widgets
function widget
actionButton Action Button
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

可以想想怎么获取更多控件,比如一个color panel等等。

更多:

使用 textInput() 收集少量文本,使用 passwordInput()3 收集密码,使用 textAreaInput() 收集文本段落。

要收集数值,请使用 numericInput() 创建一个受约束的文本框或使用 sliderInput() 创建一个滑块。如果您为 sliderInput() 的默认值提供一个长度为 2 的数值向量,您将得到一个具有两端的“范围”滑块。

使用 dateInput() 收集一天或使用 dateRangeInput() 收集两天的范围。这些提供了一个方便的日历选择器,并且诸如 datesdisabled 和 daysofweekdisabled 之类的附加参数允许您限制有效输入的集合。

有两种不同的方法允许用户从一组预先指定的选项中进行选择:selectInput()(还可以设置 multiple = TRUE 以允许用户选择多个元素)和 radioButtons(); 可以使用checkboxGroupInput()形成多选。

ui <- fluidPage(
  textInput("name", "What's your name?"),
  passwordInput("password", "What's your password?"),
  textAreaInput("story", "Tell me about yourself", rows = 3)
)

ui <- fluidPage(
  numericInput("num", "Number one", value = 0, min = 0, max = 100),
  sliderInput("num2", "Number two", value = 50, min = 0, max = 100),
  sliderInput("rng", "Range", value = c(10, 20), min = 0, max = 100)
)

ui <- fluidPage(
  dateInput("dob", "When were you born?"),
  dateRangeInput("holiday", "When do you want to go on vacation next?")
)

animals <- c("dog", "cat", "mouse", "bird", "other", "I hate animals")
ui <- fluidPage(
  selectInput("state", "What's your favourite state?", state.name),
  radioButtons("animal", "What's your favourite animal?", animals),
  checkboxGroupInput("animal", "What animals do you like?", animals)
)

让用户使用 actionButton() 或 actionLink() 执行操作,可以使用“btn-primary”、“btn-success”、“btn-info”、“btn-warning”或“btn-danger”之一使用类参数自定义外观,使用“btn-lg”、“btn-sm”、“btn-xs”更改大小,可以使用“btn-block”使按钮跨越它们嵌入的元素的整个宽度。

ui <- fluidPage(
  fluidRow(
    actionButton("click", "Click me!", class = "btn-danger"),
    actionButton("drink", "Drink me!", class = "btn-lg btn-success")
  ),
  fluidRow(
    actionButton("eat", "Eat me!", class = "btn-block")
  )
)

连接sever

general
  1. 添加输出对象在ui中

Shiny 提供了一系列函数,可以将 R 对象转换为用户界面的输出。每个函数创建特定类型的输出。

Table 3: output R objects family
Output function Creates
dataTableOutput DataTable
htmlOutput raw HTML
imageOutput image
plotOutput plot
tableOutput table
textOutput text
uiOutput raw HTML
verbatimTextOutput text
  1. 编写构建R对象的代码在serve中
Table 4: render R objects family
render function creates
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
  1. 使用input,output连接

以下代码就可以将selectInput选择的值var通过input$var的形式传递到renderText(),再render成output$selected_var的形式,最后通过textOutput()输出到ui界面。

library(shiny)

ui <- fluidPage(
  titlePanel("censusVis"),
  
  sidebarLayout(
    sidebarPanel(
      
      selectInput("var", 
                  label = "Choose a variable to display",
                  choices = c("Percent White", 
                              "Percent Black",
                              "Percent Hispanic", 
                              "Percent Asian"),
                  selected = "Percent White")
    ),
    
    mainPanel(
      textOutput("selected_var")
    )
  )
)

server <- function(input, output) {
  output$selected_var <- renderText({ 
    paste("You have selected", input$var)
  })
}

shinyApp(ui, server)

更多:

使用 textOutput() 输出常规文本,使用 verbatimTextOutput() 输出固定代码和控制台输出。
renderText() 将结果组合成一个字符串,通常与 textOutput() 配对
renderPrint() 打印结果,就像您在 R 控制台中一样,并且通常与 verbatimTextOutput() 配对。

tableOutput() 和 renderTable() 呈现静态数据表,同时显示所有数据。
dataTableOutput() 和 renderDataTable() 呈现一个动态表,显示固定数量的行以及用于更改哪些行可见的控件。
tableOutput() 对于小型、固定的摘要(例如模型系数)最有用;如果您想向用户公开完整的数据框,则 dataTableOutput() 是最合适的。

默认情况下,plotOutput() 将占据其容器的整个宽度(稍后会详细介绍),并且高度为 400 像素。您可以使用高度和宽度参数覆盖这些默认值。我们建议始终设置 res = 96,因为这将使您的 Shiny 图与您在 RStudio 中看到的尽可能接近。

reactive expressions

This difference between commands and recipes is one of the key differences between two important styles of programming:

In imperative programming, you issue a specific command and it’s carried out immediately. This is the style of programming you’re used to in your analysis scripts: you command R to load your data, transform it, visualise it, and save the results to disk.

In declarative programming, you express higher-level goals or describe important constraints, and rely on someone else to decide how and/or when to translate that into action. This is the style of programming you use in Shiny.

Shiny 中声明式编程的优势之一是它允许应用程序非常懒惰。 Shiny 应用程序只会执行更新您当前可以看到的输出控件所需的最少工作量,优点是快速,缺点是如果你不运行所有代码,可能不会发现错误。

反应式表达式比常规 R 函数更聪明。它们缓存值并知道它们的值何时会变。第一次运行反应式表达式时,表达式会将其结果保存在计算机的内存中。下次调用反应式表达式时,它可以返回保存的结果而不进行任何计算(这将使您的应用程序更快)。

如果反应式表达式知道结果是最新的,它只会返回保存的结果。如果反应式表达式得知结果已过时(因为小部件已更改),则表达式将重新计算结果。然后它返回新结果并保存一个新副本。反应式表达式将使用这个新副本,直到它也变得过时为止。
让我们总结一下这种行为:

  1. 反应式表达式会在您第一次运行时保存其结果。

  2. 下次调用反应式表达式时,它会检查保存的值是否已过时(即,它所依赖的小部件是否已更改)。

  3. 如果该值已过期,反应对象将重新计算它(然后保存新结果)。

  4. 如果该值是最新的,反应式表达式将返回保存的值而不进行任何计算。

建议把文件导入等不需要每次更新的代码放在reactive里。

在 Shiny 中,应该考虑一个规则:每当复制和粘贴一次东西时,就应该考虑将重复的代码提取到一个反应表达式中,因为反应式表达式不仅让人类更容易理解代码,它们还提高了 Shiny 高效重新运行代码的能力。

考虑以下代码,reactive()确保只有在改变n或lambda时才会重新计算:

library(ggplot2)

freqpoly <- function(x1, x2, binwidth = 0.1, xlim = c(-3, 3)) {
    df <- data.frame(
        x = c(x1, x2),
        g = c(rep("x1", length(x1)), rep("x2", length(x2)))
    )
    
    ggplot(df, aes(x, colour = g)) +
        geom_freqpoly(binwidth = binwidth, size = 1) +
        coord_cartesian(xlim = xlim)
}

ui <- fluidPage(
    fluidRow(
        column(3, 
               numericInput("lambda1", label = "lambda1", value = 3),
               numericInput("lambda2", label = "lambda2", value = 5),
               numericInput("n", label = "n", value = 1e4, min = 0)
        ),
        column(9, plotOutput("hist"))
    )
)
server <- function(input, output, session) {
    x1 <- reactive(rpois(input$n, input$lambda1))
    x2 <- reactive(rpois(input$n, input$lambda2))
    output$hist <- renderPlot({
        freqpoly(x1(), x2(), binwidth = 1, xlim = c(0, 40))
    }, res = 96)
}

shinyApp(ui,server)

控制reactive行为:

  1. 计时器
    reactiveTimer() 是一个响应式表达式,它依赖于隐藏的输入:当前时间。
    将server里的reactive修改成下列形式可以让图形每500ms刷新一次。
server <- function(input, output, session) {
  timer <- reactiveTimer(500)
  
  x1 <- reactive({
    timer()
    rpois(input$n, input$lambda1)
  })
  x2 <- reactive({
    timer()
    rpois(input$n, input$lambda2)
  })
  
  output$hist <- renderPlot({
    freqpoly(x1(), x2(), binwidth = 1, xlim = c(0, 40))
  }, res = 96)
}
  1. 点击刷新
    当你的serve运行一次需要庞大计算和时间时,可能希望要求用户通过单击按钮来选择执行昂贵的计算。这是 actionButton() 的一个很好的用例:

并且我们需要 eventReactive(),它有两个参数:第一个参数指定依赖什么,第二个参数指定计算什么。

修改ui和serve,添加了按键,用户点击按键即可出现新的模拟结果。

ui <- fluidPage(
  fluidRow(
    column(3, 
      numericInput("lambda1", label = "lambda1", value = 3),
      numericInput("lambda2", label = "lambda2", value = 5),
      numericInput("n", label = "n", value = 1e4, min = 0),
      actionButton("simulate", "Simulate!")
    ),
    column(9, plotOutput("hist"))
  )
)
server <- function(input, output, session) {
  x1 <- eventReactive(input$simulate, {
    rpois(input$n, input$lambda1)
  })
  x2 <- eventReactive(input$simulate, {
    rpois(input$n, input$lambda2)
  })

  output$hist <- renderPlot({
    freqpoly(x1(), x2(), binwidth = 1, xlim = c(0, 40))
  }, res = 96)
}

observeEvent() 与 eventReactive() 非常相似。它有两个重要的参数:eventExpr 和 handlerExpr。第一个参数是要依赖的输入或表达式;第二个参数是将要运行的代码。例如,对 server() 的以下修改意味着每次更新该名称时,都会向控制台发送一条消息:

ui <- fluidPage(
  textInput("name", "What's your name?"),
  textOutput("greeting")
)

server <- function(input, output, session) {
  string <- reactive(paste0("Hello ", input$name, "!"))
  
  output$greeting <- renderText(string())
  observeEvent(input$name, {
    message("Greeting performed")
  })
}
file up/download

使用fileInput在ui中上传文件后,得到的input是一个列表,其中的datapath是文件上传后的路径,需要使用read.csv等函数读取file$datapath。

ui <- fluidPage(
    sidebarLayout(
        sidebarPanel(
            fileInput("file1", "Choose CSV File", accept = ".csv"),
            checkboxInput("header", "Header", TRUE)
        ),
        mainPanel(
            tableOutput("contents")
        )
    )
)

server <- function(input, output) {
    output$contents <- renderTable({
        file <- input$file1
        ext <- tools::file_ext(file$datapath)
        
        req(file)
        validate(need(ext == "csv", "Please upload a csv file"))
        
        read.csv(file$datapath, header = input$header)
    })
}

shinyApp(ui, server)

您可以让用户使用 downloadButton() 或 downloadLink() 下载文件。这些都需要服务器功能中的新技术,因此我们将在第 9 章中回过头来讨论。

Share

文件形式

任何拥有 R 的人都可以运行Shiny 应用程序,分享你的app.R 文件副本,以及您的应用程序中使用的任何补充材料(例如,www 文件夹或 helpers.R 文件)即可,最好写上代码运行的依赖包安装代码。

  • runUrl() will download and launch a Shiny app straight from a weblink.
  • runGitHub( "<your repository name>", "<your user name>")

网页形式

上述方法要求用户在他们的计算机上安装 R 和 Shiny。但如果我们自己搭建好了服务器,也可以直接用浏览器使用我们的APP。

  1. Shinyapps.io

将 Shiny 应用程序转换为网页的最简单方法是使用 shinyapps.io,这是 RStudio 为 Shiny 应用程序提供的托管服务。
2. Shiny Server

  1. RStudio Connect

Reference

官方教程:Shiny Learning Resources

参考书:Mastering Shiny

关注公众号,获取最新推送

关注公众号 ‘bio llbug’,获取最新推送。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dynamic chart是一种在R Shiny中使用的一种功能强大的图表类型。它可以根据输入数据的变化而动态更新,并自动调整图表的显示。 R Shiny是一种用于创建交互式Web应用程序的R语言包。借助R Shiny,我们可以使用R语言来设计和开发具有图形用户界面(GUI)的应用程序。动态图表是R Shiny应用程序中的一个重要组成部分,它通过反映输入数据的变化来提供更加直观和可交互的数据可视化体验。 使用R Shiny的dynamic chart可以轻松地将动态图表添加到应用程序中。您可以使用R语言中强大的绘图功能,例如ggplot2包,来创建丰富多样的图形。然后,通过使用Shiny的reactive programming和reactive expressions功能,您可以将图表与应用程序的其他组件和数据进行交互。 当输入数据发生改变时,dynamic chart会自动更新并显示新的图表。例如,当用户通过应用程序的用户界面选择不同的数据集时,dynamic chart将根据选定的数据集生成相应的图表。这种自动刷新的功能使得R Shiny应用程序中的图表保持与数据的同步,并根据数据的变化提供最新的可视化效果。 在R Shiny应用程序中使用dynamic chart可以为用户提供更加灵活和交互性的数据探索方式。用户可以通过选择不同的数据集、变量或过滤器来动态更改图表的内容和外观。这种交互性允许用户快速探索数据,并根据需要进行分析和展示。 综上所述,dynamic chart是R Shiny中一种功能强大且灵活的图表类型。它可以根据输入数据的变化而动态更新,并可以与应用程序的其他组件和数据进行交互。使用dynamic chart,用户可以通过交互式和可视化的方式来探索和分析数据,提高数据分析的效率和效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值