Shiny Part II

在Part I我們學到Shiny底下的UI流動佈局設計概念,由它來接收使用者的input並準備好空箱子output由接下來要進一步介紹的server函數來回填所要視覺資訊,再回傳UI呈現在網頁上。

前情提要

在該課程,我們學到設計UI流動部局fluidPage時,我們可以在裡頭設定頁面大標題titlePanel,同時選擇使用sidebarLayout的方式,來定義UI inputs(即使用者選擇參數)和UI outputs(即回傳圖表格式)。其中,sidebarLayout底下的側邊區塊sidebarPanel是用來定義UI inputs,而主區塊mainPanel則是用來定義UI outputs。

Shiny提供了豐富的UI inputs及UI outputs格式選擇:

下圖為UI對應層狀結構:

image

image

壹:UI流動佈局fluidPage

我們延伸先前的範例,UI inputs格式使用checkboxGroupInput,但和之前不同的是UI outputs格式我們選擇plotlyOutput。此外,

plotlyOutput並不是Shiny套件包含的UI inputs格式函數,而是由plotly套作提供,所以使用前要記得先library(plotly)

下圖為對應前言結構的範例圖,由此程式塊可以得知,在稍後介紹的server函數裡,

我們可以用input$incLevels來取得使用者的選擇結果,依照此結果,server必需產生對應的plotly圖形回存到output$income.selected裡。

讀者有看到“incLevels”及“income.selected”字眼出現的位罝嗎?它們分別是UI input函數及UI output函數的【第一個】定義元素,決定了server要怎麼用input及output變數——相當重要,別忘了定義它們。

ui<-fluidPage(
  # 1.整體網頁佈局設計:大標題
  titlePanel("不同所得家庭水準所面對的物價指數變化"),
  
  sidebarLayout(
    sidebarPanel(
      # 2. Input佈局設計:使用checkboxGroupInput
      checkboxGroupInput("incLevels",
                          label="請選擇所得水準",
                          choices=c("最低20%","中間60%","最高20%"),
                          selected=c("最低20%","中間60%","最高20%"))
      ),   
    mainPanel(
      # 3. Output佈局設計:使用plotlyOutput
      plotlyOutput("income.selected")
      )
  )
)

貳:server函數設計

Plotly Shiny Gallery

由UI output格式選擇,表示我們的依據input$incLevels的內容來使用plotly繪出所要的圖:

1.0.0.1 範例一:

input$incLevels=c("最低20%","中間60%") 畫出對應的plotly圖形

先引入資料

load("./data/cpiByHouseholdIncome.Rda")

查看dataframe

cpiByHouseholdIncome %>% head %>% kable

這裡變數income.level前6筆只有“最低20%”,但其實全部有三種:“最低20%”,“中間60%”,“最高20%”。

貳-1:server情境設計

了解資料內容後,首先要做的是寫一段程式來試試看,在某個input情境下,如何產生對的output要求。我們要先𨤳清:

  • input情境的定義
  • 什麼是對的output要求

範例一(延續):input情境定義

假設在UI inputs下,使用者選了“最低20%”及“中間60%”兩類。依據此情境及【第一節】的UI設計,我們知道它代表了如下的input參數設定:

input<-list() #先宣告一個名為input的串列變數
input$incLevels <- c("最低20%","中間60%") #在input串列裡加一個元素incLevels,並定義情境內容

範例一(延續):對的output要求

由於UI的output格式函數是plotlyOutput,所以我們要寫一段程式:在給定上面的input$incLevels之後,我們要產生一個plotly圖形(因為我們使用了plotlyOutput),這個圖形以上述情況設定必需是“最低20%”及“中間60%”兩類家庭所面對cpi之時間趨勢圖。

【Plotly程式塊】

# 選出資料中符合使用者要求家庭所得水準的資料,存成subset.data
cpiByHouseholdIncome %>%
  filter(income.level %in% input$incLevels)->subset.data

# 從subset.data取出每一所得水準的最後一筆物價指數值(之後要放圖標annotations用)
subset.data %>%
  group_by(income.level) %>%
  summarise(last.cpi=last(cpi)) -> last.y.value

# 使用subset.data繪圖,其中用顏色來區分資料所得水準類別:圖存成p
subset.data %>%
  plot_ly(x=~時間,y=~cpi,color=~income.level) %>%
  add_lines

貳-2:組合出server函數

一旦我們可以在設定情境定畫出對的output要求, 我們只需要依以下程式塊寫法寫下server函數即可:

server <- function(input, output){  
    output$income.selected <- renderPlotly({  
         剪貼前述情境實驗下完成的【Plotly程式塊】  
    })  
}

在剪貼前有幾點要注意:

  • output$ 後面的元素名稱是跟著之前UI函數所使用plotlyOutput的第一個要素名稱(即“income.selected”)而走。
  • renderPlotly是對應UI output style所選用的plotlyOutput而決定。程式設計者如果在UI output style選擇不同的函數,那render的函數名也得對應改變(詳細對應請見之前的UI outputs style) 。

以下是剪貼完成的server函數:

server <- function(input, output){  
    output$income.selected <- renderPlotly({  
         # 選出資料中符合使用者要求家庭所得水準的資料,存成subset.data
        cpiByHouseholdIncome %>%
          filter(income.level %in% input$incLevels)->subset.data
        
        # 從subset.data取出每一所得水準的最後一筆物價指數值(之後要放圖標annotations用)
        subset.data %>%
          group_by(income.level) %>%
          summarise(last.cpi=last(cpi)) -> last.y.value
        
        # 使用subset.data繪圖,其中用顏色來區分資料所得水準類別:圖存成p
        subset.data %>%
          plot_ly(x=~時間,y=~cpi,color=~income.level) %>%
          add_lines  
    })  
}

參:啟動shinyApp

定義完ui及server兩個函數後,我們就可以用shinyApp來啟動了。

shinyApp(ui=ui,server=server)

課後練習

請自政府開放資料平台下載金融機構國內總、分行存款餘額任選幾個存款變數,設計一個基本的Shiny互動圖形網頁,完成後請以此課程檔附加你的名字送出pull request給老師。如果你還不習慣用Plotly繪,你可以用基本的R繪圖函數或ggplot2套件,只要把UI output函數換成plotOutput,server的render函數換成renderPlot即可。

使用Part II HW.Rmd完成練習後上傳到Dropbox作業匣

如果你是ggplot2愛用者,可以參考ggplot2 explorer來設計圖形。