cover

會用 R 做圖表、但不懂網頁、不知道如何做互動視覺化嗎?讓 Shiny 來拯救你吧!Shiny 幫我們打包了網頁的製作細節、提供給我們單一的 R 語言介面,讓我們可以快速的基於 R 製作出互動資料視覺化,一起來看看怎麼使用吧!

R 做為一個專為統計與圖表打造的軟體來說,相當適合做資料分析與處理;比方說,若我們要拆解資料的主要特徵,PCA ( Principal Component Analysis ) 是個不錯的演算法,而相較於一般需要自行撰寫該演算法的程式語言來說,「princomp」這個計算 PCA 的函式便已內建在 R 的環境之中。除了統計的應用外,也有像是 ggplot2 這類的強大圖表函式庫;下圖即為由 R Studio 製作的 ggplot2 指令速查表:

ggplot2-cheat

( ggplot2 cheat sheet by R Studio, CC-BY 4.0. source:  http://www.rstudio.com/wp-content/uploads/2015/12/ggplot2-cheatsheet-2.0.pdf)

然而,R 為一個軟體與程式語言環境,他必須要安裝且執行在自己的電腦中,再加上他做為統計分析工具的本質,使得他在製作互動圖表的這點上相對比較弱;比起像是網路原生的 D3.js 、提供線上嵌入的 Tableau 或其它網路服務來說, R 的圖表不容易做即時更新,也不容易做到互動查詢。

為了克服這幾個弱點, Shiny 出現了 —  專為 R 打造的網路應用框架。

什麼是 Shiny?

雖然我們討論的是圖表,但 Shiny 並不是一個圖表函式庫。 簡單的說, Shiny 讓我們直接用 R 語言撰寫網頁的前後端,並提供圖表接口,讓我們能直接將 R 產生的圖表呈現在網頁上。最基本的 Shiny 專案包含了兩個部份:

  • ui.R — 前端程式碼,描述我們的專案網頁要怎樣呈現與排版
  • server.R — 後端程式碼,負責分析、計算與繪製圖表,並將結果傳遞給前端。

Shiny 並不負責圖表的計算,但他為我們隱藏了網頁互動與設計的細節,並內建了各種表單元件,讓我們可以直接透過 R 的語法來設置元件並利用來達成互動效果。

基本建置

若你沒有用過 R ,那你必須要先安裝 R 。 R 可以在其官方網站「r-projection.org」找到下載連結,或是你也可以點入此連結下載。安裝完成後,執行 R 開啟 R 的開發環境,我們接下來主要會在 R 環境中操作,但由於這篇文章並非 R 的入門教學,我們會將重點放在 Shiny 的使用上。

成功執行 R 以後,我們需要安裝 shiny 套件,並將套件載入到執行環境中,這可以透過執行下列兩行指令完成:

  install.packages("shiny")
  library(shiny)

要確認是否順利將 Shiny 安裝,可以執行 Shiny 的範例程式看看結果是否正確:

  runExample("01_hello")

範例程式將會自動開啟瀏覽器並顯示 Shiny 的互動圖表,結果如下:

example

大家可以玩玩看左方的 Slider ,拖動的同時、右方的圖表也會跟著改變。第一個互動圖表完成!

當然我們不會只想要看看人家的範例程式就過癮囉,接下來就是動手做的時間了。為了要讓我們製作自己的互動圖表,我們要在剛剛我們執行 R 的工作目錄下再建立一個資料夾,並在裡面新增兩個檔案: ui.R 與 server.R 。兩者需要填入的最基本內容如下:

server.R

  shinyServer(function(input, output) { })

ui.R

  library(shiny)
  shinyUI(fluidPage())

接著,我們只要在 R 中執行「runApp(“資料夾名稱”) 」 , Shiny 便會自動啟動瀏覽器並執行這個空白的互動圖表囉!只是空白的圖表並不是我們要的,接著就讓我們來看看 ui.R 與 server.R 要怎麼使用吧!

ui.R — 視覺化前端

ui.R 這隻檔案負責告訴 Shiny 我們的網頁前端要長什麼樣子。一般來說,設計網頁我們會利用 HTML 、 CSS 等技術來實現,但為了讓設計的門檻再降低,Shiny 預先包裝好了許多實用的表單與排版元素,讓我們可以很輕易的在圖表中加入各種控制項。

一個 Shiny ui.R 最基本的程式碼如下:

  library(shiny)
  shinyUI(fluidPage(
  ))

其中 fluidPage 便是我們的互動網頁了,只是現在裡頭是空的。 Shiny 利用階層式的函式呼叫架構來製作版面配置,並預先定義好各種不同用途的版面函式,舉個例子來說,若我們想要呈現一個寫道「大家好」的標題,我們可以這樣寫:

  library(shiny)
  shinyUI(fluidPage(
     titlePanel("大家好")
  ))

若要很多個標題:

  library(shiny)
  shinyUI(fluidPage(
    titlePanel("大家好"),
    titlePanel("大家好"),
    titlePanel("大家好")
  ))

頁面則會如此呈現:

title

當然若要設計複雜的版面,只有「titlePanel」是做不了什麼事的。 Shiny 提供了各種不同的排版函式,比方說:

  • sidebarLayout — 將頁面切成兩塊,包含主內容與 sidebar
  • sidebarPanel — 在 sidebar 內使用的面版
  • mainPanel — 主要呈現資料的面版
  • navlistPanel — 導覽面板
  • tabPanel — 頁籤面板

此外,對於比較複雜的控制項, Shiny 也提供了包裝過後的函式,例如 Slide 或 Radio Button 可以由下列程式碼產生:

  radioButtons("radio", label = "Choices", choices = list("Choice 1" = 1, "Choice 2" = 2)),
  sliderInput("slider1", label = "Slider", min = 0, max = 100, value = 50),

上列兩行程式可產生下圖的兩個控制項:

slider

為了展示板面與控制項的組合運用,我們再示範一次搭配 siderLayout 的組合運用:

  library(shiny)
  shinyUI(fluidPage(
    titlePanel("大家好"),
    sidebarLayout(
      sidebarPanel(
        radioButtons("radio", label = "Choices", choices = list("Choice 1" = 1, "Choice 2" = 2)),
        sliderInput("slider1", label = "Slider", min = 0, max = 100, value = 50)
      ),
      mainPanel("逮給厚,哇喜逮頑歐郎")
    )
  ))

在上例中我們可以看到下列幾個元件:

  1. 使用 titlePanel 設定標題
  2. sidebarLayout 將畫面左右切分
  3. sidebarPanel 設定左方的面板,內含 Radio 與 Slider 控制項
  4. mainPanel 裡面只寫上「逮給厚,哇喜逮頑歐郎」等字。

這樣的設定呈現的結果如下:

layout-sample

Shiny 的控制項其實是基於另一個網路套件「 Bootstrap 」製作出來的,支援的元件數量不少,有興趣的讀者可以參考 Widget Gallery 這個網頁了解更多。裡面除了列出支援的套件,也提供使用的語法,下圖為其中一部份元件範例的截圖:

sample-widgets

到目前為止,我們都只操作到 UI 排版與元件的部份,那我們的圖表要怎麼樣顯示出來呢?

server.R — 計算與繪圖的後端

一般我們在 R 中做視覺化,輸出結果都是由彈出的 R 子視窗來顯示,而這也就是我們想要讓使用者在網頁上看到的部份。為了讓圖表能夠順利的傳到網頁前端, Shiny 提供了程式輸出入介面,我們只要將圖表存到適當的地方, Shiny 便會自動將圖表更新至前端。以下列程式碼為例, Shiny Server 利用函式中「input」與「output」兩個變數做為溝通的管道,而我們的程式則可以讀取 input 中的數值,並將圖表寫入至 output 中:

  shinyServer(function(input, output) {
    output$distPlot <- renderPlot({
      x <- faithful[, 2] # Old Faithful Geyser data
      bins <- seq(min(x), max(x), length.out = 10)
      hist(x, breaks = bins, col = 'blue', border = 'white')
    })
  })

在上例中,我們將 R 內建的「老實忠泉」資料利用「hist」函式製作直方圖,並透過 Shiny 的「renderPlot」函式將圖表回存至 「output$distPlot」 之中,而這個 output$distPlot 便能在 ui.R 之中利用 plotOutput(“distPlot”) 取得。因此,在上面的排版範例之中,我們只要將 mainPanel 修改成下例:

  mainPanel(plotOutput("distPlot"))

重新執行以後我們便可以在網頁中看到直方圖出現了:

 

histogram

為了要「互動」,除了輸出圖表,輸入資料也是必須的;我們在網頁上的元件可以透過「input」變數來讀取其值,例如我們在前面用到的 Slider:

  sliderInput("slider1", label = "Slider", min = 0, max = 100, value = 50)

透過其名稱、也就是第一個參數「slider1」,我們便能取得其值「input$slider」。我們稍稍修改老實忠泉裡設定 bins 數量的部份,改為使用 slider1 的輸入來設定:

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

完成以後重新執行我們的程式,可以看到圖表會隨著我們的輸入變化了!是不是很簡單呢?

adjust bins

小結

在上面的範例中,我們完全看不到 HTML 、 CSS 或 JavaScript 等傳統製作互動網頁圖表時最重要的元素,取而代之的是各式的模板、資料串連與原生的 R 圖表。這個設計邏輯其實簡單的說就是:

「你什麼都不用會,只要會 R ,就可以做互動圖表。」

當然其實在 Shiny UI 的部份,它仍提供了一些像是「h1」、「br」等常見的 HTML 對應元素,但這個主要是為了提高 Shiny UI 的彈性;大部份時候我們其實是可以直接利用現成模版快速兜出一個互動圖表的。

其次,Shiny 本身並不包含圖表生成;上例的直方圖函式「hist」為 R 的內建函式,如果我們要製作其它不同類型的圖表,可以搭配其它套件如「ggplot2」、「quantom」等,這也大大的提升了 Shiny 的可用性,而不會受限於單一套件所支援的圖表類型。

而為了進一步提升 R 圖表的傳播效率, RStudio 甚至架設了「shinyapps.io」網站提供主機服務,我們只要上傳自己的 Shiny app 檔案,就可以把自己的互動圖表分享給任何人看。是不是真的很方便呢?

上述可說是 Shiny 的最大優點,然而缺點也不是沒有的:

  • 需要更複雜客製化的時候, R 語言包裝的 HTML 會是場災難。
  • 無法更即時的互動。圖片永遠由 server 端重新計算後產生。
  • 視覺呈現受制於 R 套件,仍無法利用 D3.js 等更強大的視覺函式庫。

其實,參考 Shiny 的架構,我們也是可以自行開發套件、搭配 Apache 或 Nginx 之類的網頁伺服器將 R 的圖表甚至資料檔餵給前端的 D3.js 程式碼,這樣就可以更彈性的利用 D3.js 與 R 的強大之處;然而網頁前端視覺化還是有其門檻,像 Shiny 這樣將複雜的前端邏輯透過 R 語言包裝,對於不懂網頁的人來說,還是相當方便的!因此,如果下次你有需要透過 R 做資料視覺化,又不具備前端開發的技能時,不妨試試看 Shiny 吧!

 

 


Written by infographics.tw

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *