iT邦幫忙

2

[R語言]資料視覺化S01─shiny

Hi! 大家好,我是Eric,這次要練習R語言中的shiny套件!
shiny是協助我們運用R語言直接作出一個互動式網頁,完成不需要了解網頁語言
/images/emoticon/emoticon15.gif


緣起:農曆春節為臺灣重要習俗,每逢春節時總是造成國道回堵數公里,難免消磨大家出遊的好心情,而據高速公路局2018年2月「春節連假國道重點壅塞路段時段旅行時間倍數表」,我們挑選出旅行時間倍數最高之路段─北上頭城坪林(6倍),並著重在農曆初一及初二期間,運用R語言重要的互動式圖表套件shiny,產生2016-2019年間的互動式圖表。
方法:運用[R語言]的[shiny]套件。
使用資料:交通部高速公路局交通資料庫ETC(Electronic Toll Collection )資料─各類車種通行量統計(TDCS_M03A),2016-2019年。


1. 載入套件。

library(ggplot2)
library(ggthemes)
library(shiny)
library(dplyr)

2. 載入資料與前置處理。

setwd("C:/Users/User/Desktop/Eric/data/2016-2019")    #設定檔案路徑

Y1619<-do.call(rbind,lapply(list.files(path="C:/Users/User/Desktop/Eric/data/2016-2019",pattern="*.csv"),read.table, header=FALSE, sep=","))    #將設定的檔案路徑資料夾中,所有檔名以.csv結尾的檔案載入

names(Y1619)<-c("date time", "o", "NS", "VehicleType", "flow")  #命名欄位名稱
Y1619_TP_31<-Y1619 %>% filter(o=="05F0287N",VehicleType==31)    #篩選出目標路段與目標車種
date<-as.Date(Y1619_TP_31$`date time`)    #自日期時間資料中取出日期部分
Y1619_TP_31<-cbind(Y1619_TP_31,date)      #將取出的日期部分加入到原資料,變成新欄位

3. 產生每30分鐘時間間隔的時間數字,以及依照日期與時間群組取得平均交通量,最後分別篩選出2016-2019年初一及初二資料,並另存成變數。

n1<-seq(100,2400,by=100)   #產生100-2400,以100為間隔
n2<-seq(0030,2330,by=100)  #產生0030-2330,以100為間隔

t<-c()   #產生空向量,用以儲存稍後的時間區間

for (i in 1:48) {
  if(i%%2==0){
    t[i]=n1[i/2]
  }else{
    t[i]=n2[ceiling(i/2)]
  }
}       #由於24小時每30分鐘間隔將產生48個數字,運用for迴圈將n1、n2分別排列至t向量中

t2<-c(0000,rep(t[-48],each=6),rep(t[48],each=5))     #原資料為00:00-23:55,最後30分鐘僅有5項(23:35、23:40、23:45、23:50、23:55),故依此規則產生符合的對照時間

time<-rep(t2,8)  #由於初一及初二各有4年,總共有8個24小時
Y1619_1_TP_31<-cbind(Y1619_TP_31,time)    #將產生的時間數字加入原資料中,形成一個新欄位

ETCdata<-aggregate(flow~date+time,Y1619_1_TP_31,mean)     #依照日期與時間群組,取得平均交通量
ETCdata$date<-as.character(ETCdata$date)          #將日期轉成字串型態

a1<-filter(ETCdata,date=="2016-02-08") 
b1<-filter(ETCdata,date=="2017-01-28")
c1<-filter(ETCdata,date=="2018-02-16")
d1<-filter(ETCdata,date=="2019-02-05")
a2<-filter(ETCdata,date=="2016-02-09")
b2<-filter(ETCdata,date=="2017-01-29")
c2<-filter(ETCdata,date=="2018-02-17")
d2<-filter(ETCdata,date=="2019-02-06")

4. shiny
ui是shiny中定義使用者看到的網頁樣子,fluidPage是表示物件呈現浮動的佈局,較不會因為每個人電腦螢幕的尺寸不同,導致物件錯位:

ui <- fluidPage( 
  
  # shiny的大標題
  titlePanel("ETC data of the first and second day of the Chinese New Year"),
  
  # 將頁面區分為主區塊及側區塊,分別由mainPanel()與sidebarPanel()函數來控制
  sidebarLayout(
    
    # 控制輸入的部分
    sidebarPanel(
      
      # 產生可供勾選的方塊,方塊編號是date;標籤是Date:;可勾選的選項是ETCdata的date欄位的所有資料(不重複計)
      selectInput(inputId = "date",
                  label = "Date:",
                  choices = unique(ETCdata$date))
      
    ),
    
    # 控制輸出的部分
    mainPanel(
    
      # 產生tab的頁面,共有3個子頁面,分別為Plot、Summary及Table
      tabsetPanel(type = "tabs",
                  tabPanel("Plot",plotOutput("ETCPlot")),
                  tabPanel("Summary",verbatimTextOutput("summary")),
                  tabPanel("Table",tableOutput("table"))
      )
      
    )
  )
)

server是背後的程式碼,負責依照輸入執行程式碼,並將輸出回傳:
註:這邊程式碼我寫的比較冗長,應該會有更好的寫法,還是希望能夠有所幫助,這邊我也把程式碼的格式用的比較易讀一點,所以看起來會更冗長

server <- function(input, output) {

  #ETCPlot為前面ui中的ETCPlot,這邊定義他的功能,用if-eles if判斷日期並使用ggplot2製作線圖(ggplot2至作線圖的解釋請參考我的網站另一篇文章,連結在本文最下面)
  output$ETCPlot <- renderPlot({
  
     if(input$date=="2016-02-08"){
      ggplot(a1,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#00CED1")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+
      theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2017-01-28"){
      ggplot(b1,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#2E8B57")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+
      theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2018-02-16"){
      ggplot(c1,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#FFB90F")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+ theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2019-02-05"){
      ggplot(d1,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#EE6363")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+ theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2016-02-09"){
      ggplot(a2,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#FF1493")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+
      theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2017-01-29"){
      ggplot(b2,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#008B8B")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+
      theme(plot.title = element_text(size=15,face = "bold"))
    }else if(input$date=="2018-02-17"){
      ggplot(c2,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#90EE90")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+ 
     theme(axis.text.y = element_text(angle = 360))+ theme(plot.title = element_text(size=15,face = "bold"))
    }else{
      ggplot(d2,aes(x=time,y=flow,group = 1))+
      geom_line(linetype = "solid",size=1.5,color="#008B45")+
      labs(title = paste("Traffic flow in",input$date),x="time",y="flow")+
      theme_stata()+
      theme(axis.title.x = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5))+
      theme(axis.title.y = element_text(size = 15, face = "bold", vjust = 0.5, hjust = 0.5, angle = 360))+
      theme(axis.text.y = element_text(angle = 360))+ theme(plot.title = element_text(size=15,face = "bold"))
    }
  })
  
  #summary為前面ui中的summary,這邊定義他的功能,用if-eles if判斷日期並使用summary()總結當日交通量
  output$summary<-renderPrint({
    if(input$date=="2016-02-08"){
      summary(a1$flow)
    }else if(input$date=="2017-01-28"){
      summary(b1$flow)
    }else if(input$date=="2018-02-16"){
      summary(c1$flow)
    }else if(input$date=="2019-02-05"){
      summary(d1$flow)
    }else if(input$date=="2016-02-09"){
      summary(a2$flow)
    }else if(input$date=="2017-01-29"){
      summary(b2$flow)
    }else if(input$date=="2018-02-17"){
      summary(c2$flow)
    }else if(input$date=="2019-02-06"){
      summary(d2$flow)
    }
  })
  
  #table為前面ui中的table,這邊定義他的功能,用if-eles if判斷日期並輸出交通量資料
  output$table <- renderTable({
    if(input$date=="2016-02-08"){
      a1[-1]
    }else if(input$date=="2017-01-28"){
      b1[-1]
    }else if(input$date=="2018-02-16"){
      c1[-1]
    }else if(input$date=="2019-02-05"){
      d1[-1]
    }else if(input$date=="2016-02-09"){
      a2[-1]
    }else if(input$date=="2017-01-29"){
      b2[-1]
    }else if(input$date=="2018-02-17"){
      c2[-1]
    }else if(input$date=="2019-02-06"){
      d2[-1]
    }
  })
}

啟動shiny應用程式

shinyApp(ui, server)

5. 大功告成

首先這是Plot作圖的部分,可由左邊選擇想看的日期,右邊就會自動更新為當日的線圖。
https://ithelp.ithome.com.tw/upload/images/20190305/20115774WZsdy6qjgs.jpg

再來是Summary的部分,可由右邊圖表上方3個選項(Plot、Summary及Table)選擇資料呈現方式。
https://ithelp.ithome.com.tw/upload/images/20190305/201157742Jsf9Ith9w.jpg

最後是原始資料的呈現,將呈現每日每隔30分鐘的交通量。
https://ithelp.ithome.com.tw/upload/images/20190305/20115774zUa6sEUfIg.jpg

由於這邊只能用靜態的方式呈現,大家可以在自己R語言中互動看看!

6. ggplot2參考資料
[R語言]資料視覺化G01─運用ggplot2完成線圖(line chart)
https://ithelp.ithome.com.tw/articles/10211088


尚未有邦友留言

立即登入留言