shiny 初级课程

1. 简介shiny

什么是shiny: Shiny 是一个开源的 R 包,它为使用 R 构建 Web 应用提供了一个优雅有力的 Web 框架 。Shiny 帮助R用户在不需要前端知识的条件下将数据分析的结果转变为可交互的 Web 应用。

shiny能够帮助R用户在没有前端,后端知识的情况下,构建web工程,独立,快速的实现web上数据可视化的工作。 学完本课程,同学们可以实现从数据分析,建模,到最后的分享结果,结果展示。

案例展示

https://liam.shinyapps.io/dashboard/

案例

案例

同学们可以通过这个链接查看我制作的一个shiny案例。 这个案例是一个推荐系统,可以帮助店铺找到某一个商品相似的商品,以及可能对这个商品感兴趣的人。 另外还对商品以及店铺进行了数据分析,并展示

2. shiny app 的基本部分

我们通过几个例子开始

2.1 案例1

我们现来查看一个例子,然后分析其工作原理:

library(shiny)
runExample("01_hello")
example1

example1

这个例子使用的是自带的faithful数据集合,通过改变slider的值调整直方图的bin。

shiny程序包含两个部分:UI部分和server部分,简单的来书,UI部分就是我们需要设定web页面要怎么展示, server 部分就是后台的计算是如何进行。

我们来看一下上面这个程序的源代码:

首先是UI部分:

ui <- fluidPage( 
  
  # App title ----
  titlePanel("Hello Shiny!"),
  
  # 这里指定的是什么布局方式
  sidebarLayout(
    
    # Sidebar panel  
    sidebarPanel(
      
      # 这里是定义一个slider 作为输入
      sliderInput(inputId = "bins",
                  label = "Number of bins:",
                  min = 1,
                  max = 50,
                  value = 30)
      
    ),
    
    # 主页面,这里主页面是一个绘图
    mainPanel(
      
      # Output: Histogram ----
      plotOutput(outputId = "distPlot")
      
    )
  )
)

然后是Server部分

定义我们UI部分展示的结果是如何计算的

server <- function(input, output) {
  

  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")
    
  })
  
}

生成app

shinyApp(ui, server)

简单的修改

我们现在对UI进行一点简单的修改,直接换成一个数值的输入

ui <- fluidPage( 
  
  # App title ----
  titlePanel("Hello Shiny!"),
  
  # 这里指定的是什么布局方式
  sidebarLayout(
    
    # Sidebar panel  
    sidebarPanel(
      
      # 这里是定义一个slider 作为输入
      numericInput(inputId = "bins",
                  label = "Numeric input",value = 10)
      
    ),
    
    # 主页面,这里主页面是一个绘图
    mainPanel(
      
      # Output: Histogram ----
      plotOutput(outputId = "distPlot")
      
    )
  )
)

shinyApp(ui, server)


server <- function(input, output) {
}
shinyApp(ui, server)

大家可以看到,刚才的对应的slider 的位置就变成了一个直接写数字的输入窗口了。 第一个例子大家可能对很对东西都有疑惑,其实这没关系,第一个例子是让大家对 shiny的构建有一个简单的了解。

总结

shiny 程序分为两个部分

  1. UI
  2. Server

2.2 第二个例子

这个例子展示了直接打印R对象,以及使用HTML表格显示数据

library(shiny)
runExample("02_text")
shinyexample2

shinyexample2

第一个例子展示了使用单个数字输入来调整直方图,这个例子包含了两个输入和两种了类型的输出。

如果同学们观察的仔细的话,同学们可以发现shiny程序最重要的属性,就是输入与输出是实施的连接在一起的 这种情况下,这种交互性,是shiny非常重要的一个特性。

我们来查看一下代码:

UI部分

# Define UI for dataset viewer app ----
ui <- fluidPage(
  
  # App title ----
  titlePanel("Shiny Text"), # 标题
  
  # Sidebar layout with a input and output definitions ----
  sidebarLayout(
    
    # Sidebar panel for inputs ----
    sidebarPanel(
      
      # Input: Selector for choosing dataset ----
      selectInput(inputId = "dataset",
                  label = "Choose a dataset:",
                  choices = c("rock", "pressure", "cars")), # 这是一个选择输入
      
      # Input: Numeric entry for number of obs to view ----
      numericInput(inputId = "obs",
                   label = "Number of observations to view:",
                   value = 10) # 这是一个数字输入
    ),
    
    # Main panel for displaying outputs ----
    mainPanel(
      
      # Output: Verbatim text for data summary ----
      verbatimTextOutput("summary"), # 这是一个输入
      
      # Output: HTML table with requested number of observations ----
      tableOutput("view") # 这是一个表格输入
      
    )
  )
)

Server

我们来查看一下Server,这个时候Server也变得有一点复杂:

 #Define server logic to summarize and view selected dataset ----
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 ----
  output$summary <- renderPrint({ # 输出一个summary,这是一个R对象
    dataset <- datasetInput()
    summary(dataset)
  })
  
  # Show the first "n" observations ----
  output$view <- renderTable({ # 另外一个输出
    head(datasetInput(), n = input$obs)
  })
  
}

这里我们接触到了输入与输出是的联动性,在具有交互式用户界面的传统程序中,这可能涉及设置事件处理程序和编写代码以读取值和传输数据,shiny是如何处理的,目前还没有仔细讲解其工作的原理,同学们不要担心,接下来的课程会介绍

2.3 交互性

在之前我们已经了解到shiny 的交互性,使用shiny构建交互程序非常容易,但是为了利用好这一项工具, 需要对其原理有一个简单的了解,在shiny中,有三种对象:

  • Reactive source
  • Reactive conductor
  • Reactive endpoin

分别称为:反应源,中间件,反应端

反应式编程

反应式编程

shiny交互编程最简单的结构就是反应源直接到反应端

简单结构

简单结构

在shiny程序中,反应源通常是通过浏览器界面的用户输入,比如之前的案例,比如输入数值调整直方图的bin。

反应端通常出现用户的浏览器,比如一张图或者一个表。

在一个简单shiny程序中:

  • input 对应的是输入
  • output 对应的是输出
server <- function(input, output) {
  output$distPlot <- renderPlot({
    hist(rnorm(input$obs))
  })
}
案例

案例

另外我们回到前面的案例

datasetInput <- reactive({ # 输入
    switch(input$dataset,
           "rock" = rock, # 对应了不同的数据集合
           "pressure" = pressure,
           "cars" = cars)
  })

大家可能还有注意到reactive函数,这个函数用于封装慢速或计算上昂贵的操作

上面就已经涵盖了很多基本的概念,下一节我们要做一个总结,然后开始从0到1开始构建一个shiny程序

3. shiny 总结

回顾我们课程,我们是如何实现一个shiny的web程序:

  1. 程序分为两个部分,UI和server
  2. UI定义我们的网页是如何展示的,server定义后台是如何运算的
  3. UI中有哪些输出函数
UI部分 server部分
dataTableOutput renderDataTable
imageOutput renderImage
plotOutput renderPlot
verbatimTextOutput renderPrint
tableOutput renderTable
textOutput renderText
uiOutput renderUI
htmloutput renderUI
  1. UI中有哪些输入函数

介绍几个主要的输入:

  1. actionButton

    actionButton(inputId = '按钮',label = '按钮')
  2. checkboxGroupInput

    checkboxGroupInput(inputId = '选择框',label = '选择框',choices = c('a','b','c'))

3. checkboxInput

checkboxInput(inputId = '勾选框',label = '勾选框',value = TRUE)
  1. dateInput

    dateInput(inputId = '时间输入',label = '时间输入')
  1. dateRangeInput

    dateRangeInput(inputId = '时间范围输入',label = '时间范围输入',start = 1,end = 100)
  1. numericInput

    numericInput(inputId = '数字输入',label = '数字输入',value = 100)
  2. textInput

    textInput(inputId = '文本输入',label = '文本输入')

主要的输出:

  1. dataTableOutput

    output$a = renderDataTable({
      head(iris)
    })
    dataTableOutput(outputId = 'a')
  1. plotOutput

    output$b = renderPlot({
      plot(iris$Sepal.Length,iris$Sepal.Width)
    })
    plotOutput(outputId = 'b')

3. 制作一个shiny

3.1 准备工作

打开Rstudio,点击file,创建一个shiny app

使用的数据数据是,ggplot里面自带的数据diamonds,绘制不同的直方图:


#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
# Find out more about building applications with Shiny here:
#
#    http://shiny.rstudio.com/
#

library(shiny)
library(ggplot2)
# Define UI for application that draws a histogram
ui <- fluidPage(
   
   # Application title
   titlePanel("Diamond data"),
   
   # Sidebar with a slider input for number of bins 
   sidebarLayout(
      sidebarPanel(
        selectInput(inputId = "x",label = 'x',choices = names(diamonds)[c(1,5,6,7,8,9,10)],
                    selected = T),
        selectInput(inputId = "y",label = 'y',choices = names(diamonds)[c(1,5,6,7,8,9,10)],
                    selected = T)
      ),
      
      
      # Show a plot of the generated distribution
      mainPanel(
         plotOutput("diamondplot")
      )
   )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
   
   output$diamondplot <- renderPlot({
      # generate bins based on input$bins from ui.R
    plot(x = diamonds[[input$x]],y = diamonds[[input$y]],xlab = 'x',ylab = 'y')
     
   })
}

# Run the application 
shinyApp(ui = ui, server = server)

需要联系我可以添加我的微信