--- disqus: ahb0222 GA : G-VF9ZT413CG --- # Shinydashboard(儀錶板)手動添加數據繪製風花圖 [![hackmd-github-sync-badge](https://hackmd.io/Kd2uUuldTrmfafDFt_GfCA/badge)](https://hackmd.io/Kd2uUuldTrmfafDFt_GfCA) > [color=#40f1ef][name=LHB阿好伯, 2021/06/13][:earth_africa:](https://www.facebook.com/LHB0222/) ###### tags: `R` `ggplot2` `可視化` [TOC] :::danger 2024/01/20更新 非常可惜的是以前的網站更新了QQ 沒辦法在像之前一樣更改網址爬取資料 目前解決方式只好先分成兩步驟 先使用Python的Selenium下載CSV檔 再用ggplot2畫圖 相關程式碼我就分享出來 拋磚引玉看看有沒有大神能夠將整個程式碼在優化一下 或是有更好用的爬蟲套件能分享一下 不然光Selenium的安裝跟使用就耗費我好多時間XD Chrome的版本太新就是一個大問題chromedriver支援還沒跟上QQ 要想像之前架設一個Shiny能自動爬取跟畫圖看來是有困難QQ [使用Python selenium 爬取codis氣候資料服務系統資料並使用ggplot2繪製風花圖](/LW3Ys5qwQ4a4j6zrOdc8HA) ::: ![](https://i.imgur.com/KFdMCHb.png) ![](https://i.imgur.com/2D75VUT.png) ![](https://i.imgur.com/B7Mn1X5.png) # 程式碼 ```r= #風花圖儀錶板 #https://gtgrthrst.shinyapps.io/Wind_Rose_pro/ #install.packages() library("shiny") #library("jsonlite") library("rvest") library("magrittr") #library("lubridate") library("ggplot2") #library("shinydashboard") library("DataEditR") suppressPackageStartupMessages(library(jsonlite)) suppressPackageStartupMessages(library(lubridate)) suppressPackageStartupMessages(library(shinydashboard)) WRdata1 <- data.frame(WS = c(rep(1, times = 1, length.out = 10)), WD = c(rep("E", times = 1, length.out = 10))) WRdata2 <- data.frame(WS = c(rep(1, times = 1, length.out = 10)), WD = c(seq(from = 1,to = 360,by = 36))) WSbreak <- data.frame(breaks =c(0, 0.3, 1.6, 3.4, 5.5, 8.0,10.8, 13.9, 17.2, 20.8, 24.5, 28.5, 32.7, Inf), labels = c("0~0.2","0.3~1.5", "1.6~3.3", "3.4~5.4", "5.5~7.9", "8.0~10.7", "10.8~13.8", "13.9~17.1", "17.2~20.7", "20.8~24.4","24.5~28.4", "28.5~32.6" , ">32.7","Inf")) windD <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW")) windD2 <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N")) WRplot <- function(WRdata = WRdata1, plottitle = "", WSbreaksdata = WSbreak, lab_max = 100){ #WRdata <- read_csv("C:/R/110Q2.csv") WRdata$Windspeed_N <- cut(as.numeric(WRdata$WS), breaks =as.numeric(WSbreaksdata$breaks), labels =force(WSbreaksdata$labels[-length(WSbreaksdata$labels)]), right = F) windD <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW")) WRdata$WD <- factor(WRdata$WD) p1 <- ggplot(data = na.omit(WRdata), aes(x = WD, fill = Windspeed_N))+ geom_bar(aes(y = (..count..)/sum(..count..)*100 ), position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, limits= windD) + scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)")+ coord_polar(start = -0.2) + annotate("text",x = "NE", y = c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))), label = paste(c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))),"%"))+ xlab("") + ggtitle(plottitle) + ylab("%") + theme(legend.text=element_text(family = "Times New Roman"))+ theme(legend.title=element_text(family = "Times New Roman"))+ theme(axis.title.y = element_text(family = "Times New Roman"))+ theme(title=element_text(family = "DFKai-SB"))+ theme(axis.title=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank()) print(p1) } WRplot2 <- function(WRdata = WRdata1,plottitle = "", WSbreaksdata = WSbreak, lab_max = 25){ #WRdata <- read_csv("C:/R/110Q2.csv") WRdata$Windspeed_N <- cut(as.numeric(WRdata$WS), breaks =as.numeric(WSbreaksdata$breaks), labels =force(WSbreaksdata$labels[-length(WSbreaksdata$labels)]), right = F) windD <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW")) WRdata$WD <- factor(WRdata$WD) p1 <- ggplot(data = na.omit(WRdata), aes(x = WD, fill = Windspeed_N))+ geom_bar( position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, limits= windD) + scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)")+ coord_polar(start = -0.2) + xlab("") + ggtitle(plottitle) + ylab("n") + theme(legend.text=element_text(family = "Times New Roman"))+ theme(legend.title=element_text(family = "Times New Roman"))+ theme(axis.title.y = element_text(family = "Times New Roman"))+ theme(title=element_text(family = "DFKai-SB"))+ theme(axis.title=element_blank()) print(p1) } WRplot3 <- function(WRdata = WRdata2,plottitle = "",WSbreaksdata = WSbreak, lab_max = 25){ #WRdata <- read_csv("C:/R/110Q2.csv") WRdata$Windspeed_N <- cut(as.numeric(WRdata$WS), breaks =as.numeric(WSbreaksdata$breaks), labels =force(WSbreaksdata$labels[-length(WSbreaksdata$labels)]), right = F) WRdata$WD_N <- cut(as.numeric(WRdata$WD), breaks = c(0, 11.26, 33.76, 56.26, 78.76, 101.26, 127.76, 146.26, 168.76, 191.26, 213.76, 236.26, 258.76, 281.26, 303.76, 326.26, 348.75, 360), windD2, include.lowest = TRUE) p1 <- ggplot(data = na.omit(WRdata), aes(x = WD_N, fill = Windspeed_N))+ geom_bar(aes(y = (..count..)/sum(..count..)*100 ), position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, limits= windD) + scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)")+ annotate("text",x = "NE", y = c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))), label = paste(c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))),"%"))+ coord_polar(start = -0.2) + xlab("") + ggtitle(plottitle) + ylab("%") + theme(legend.text=element_text(family = "Times New Roman"))+ theme(legend.title=element_text(family = "Times New Roman"))+ theme(axis.title.y = element_text(family = "Times New Roman"))+ theme(title=element_text(family = "DFKai-SB"))+ theme(axis.title=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank()) print(p1) } WRplot4 <- function(WRdata = WRdata2,plottitle = "",WSbreaksdata = WSbreak, lab_max = 100){ #WRdata <- read_csv("C:/R/110Q2.csv") WRdata$Windspeed_N <- cut(as.numeric(WRdata$WS), breaks =as.numeric(WSbreaksdata$breaks), labels = force(WSbreaksdata$labels[-length(WSbreaksdata$labels)]), right = F) WRdata$WD_N <- cut(as.numeric(WRdata$WD), breaks = c(0, 11.26, 33.76, 56.26, 78.76, 101.26, 127.76, 146.26, 168.76, 191.26, 213.76, 236.26, 258.76, 281.26, 303.76, 326.26, 348.75, 360), windD2, include.lowest = TRUE) p1 <- ggplot(data = na.omit(WRdata), aes(x = WD_N, fill = Windspeed_N))+ geom_bar( position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, limits= windD) + scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)")+ coord_polar(start = -0.2) + xlab("") + ggtitle(plottitle) + ylab("n") + theme(legend.text=element_text(family = "Times New Roman"))+ theme(legend.title=element_text(family = "Times New Roman"))+ theme(axis.title.y = element_text(family = "Times New Roman"))+ theme(title=element_text(family = "DFKai-SB"))+ theme(axis.title=element_blank()) print(p1) } # https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=466910&stname=%25E9%259E%258D%25E9%2583%25A8&datepicker=2021-06-29&altitude=837.6m WindData <- function(station_number,start_date,end_date, lab_max = 25){ url_start <- paste0("https://e-service.cwb.gov.tw/HistoryDataQuery/DayDataController.do?command=viewMain&station=",station_number,"&stname=%25E9%259E%258D%25E9%2583%25A8&datepicker=") start_date <- ymd(start_date) #起始時間 end_date <- ymd(end_date) #終止時間 data1 <- data.frame() data2 <- data.frame() for(d in c(0:(end_date - start_date))){ url <- paste0(url_start,as.character(start_date + d),"&altitude=15m") #時間資料 time_H <- url %>% read_html() %>% html_nodes(xpath='//*[(@id = "MyTable")]//td[(((count(preceding-sibling::*) + 1) = 1) and parent::*)]') %>% html_text(trim = T) %>% as.numeric() #風速資料 Windspeed <- url %>% read_html() %>% html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 7) and parent::*)]') %>% html_text(trim = T) %>% gsub("X","-9999", .) %>% as.numeric() #風向 windDirection<- url %>% read_html() %>% html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 8) and parent::*)]') %>% html_text(trim = T) %>% gsub("X","-9999", .) %>% as.numeric() data1 <- cbind(as.character(start_date + d), time_H, Windspeed,windDirection) #合併資料 data2 <- rbind(data2, data1) } windD <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N")) data3 <- na.omit(data2) #刪除包含NA值的列 data3$windDirection_N <- cut(as.numeric(data3$windDirection), breaks = c(0, 11.26, 33.76, 56.26, 78.76, 101.26, 127.76, 146.26, 168.76, 191.26, 213.76, 236.26, 258.76, 281.26, 303.76, 326.26, 348.75, 360), windD, include.lowest = TRUE) data3$Windspeed_N <- cut(as.numeric(data3$Windspeed), breaks =c(0, 2.1, 4.1, 6.1, Inf), labels = c("0~2", "2.1~4", "4.1~6", ">6.1"), right = F) data3$Windspeed <- as.numeric(data3$Windspeed) p1 <- ggplot(data = data3, aes(x = windDirection_N, fill = Windspeed_N))+ geom_bar( aes(y = (..count..)/sum(..count..)*100 ), position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, labels = windD) + annotate("text",x = "NE", y = c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))), label = paste(c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))),"%"))+ scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)")+ coord_polar(start = -0.2) + xlab("") + ggtitle(paste(station_number,"(",start_date,"~",end_date,")"))+ theme(axis.title=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank()) ggsave("P1.png") p1 } WindData2 <- function(station_number,start_date,end_date, lab_max = 25){ url_start <- paste0("https://e-service.cwb.gov.tw/HistoryDataQuery/MonthDataController.do?command=viewMain&station=",station_number,"&stname=%25E5%2585%25AD%25E8%2585%25B3&datepicker=") start_date <- floor_date(ymd(start_date),unit = "month") #起始時間 end_date <- floor_date(ymd(end_date),unit = "month") #終止時間 int <- interval(start_date, end_date) m1 <- time_length(int, "month") data1 <- data.frame() data2 <- data.frame() for(d in c(0:m1)){ m2 <- start_date + months(d) url <- paste0(url_start,as.character(paste0(year(m2),"-",ifelse(month(m2)>=10, month(m2),paste0(0,month(m2))))),"&altitude=15m") #時間資料 time_d <- url %>% read_html() %>% html_nodes(xpath='//*[(@id = "MyTable")]//td[(((count(preceding-sibling::*) + 1) = 1) and parent::*)]') %>% html_text(trim = T) %>% as.numeric() #風速資料 Windspeed <- url %>% read_html() %>% html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 17) and parent::*)]') %>% html_text(trim = T) %>% gsub("X","-9999", .) %>% as.numeric() #風向 windDirection<- url %>% read_html() %>% html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 18) and parent::*)]') %>% html_text(trim = T) %>% gsub("X","-9999", .) %>% as.numeric() data1 <- cbind(as.character(start_date + months(d)), time_d, Windspeed,windDirection) #合併資料 data2 <- rbind(data2, data1) } data2 windD <- factor(c("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N")) data3 <- na.omit(data2) #刪除包含NA值的列 data3$windDirection_N <- cut(as.numeric(data3$windDirection), breaks = c(0, 11.26, 33.76, 56.26, 78.76, 101.26, 127.76, 146.26, 168.76, 191.26, 213.76, 236.26, 258.76, 281.26, 303.76, 326.26, 348.75, 360), windD, include.lowest = TRUE) data3$Windspeed_N <- cut(as.numeric(data3$Windspeed), breaks =c(0, 2.1, 4.1, 6.1, Inf), labels = c("0~2", "2.1~4", "4.1~6", ">6.1"), right = F) data3$Windspeed <- as.numeric(data3$Windspeed) p2 <- ggplot(data = data3, aes(x = windDirection_N, fill = Windspeed_N))+ geom_bar( aes(y = (..count..)/sum(..count..)*100 ), position = position_stack(reverse = TRUE)) + theme_bw() + scale_x_discrete(drop = FALSE, labels = windD) + scale_fill_discrete(guide = guide_legend(reverse=TRUE), name = "Wind Speed (m/s)") + annotate("text",x = "NE", y = c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))), label = paste(c(scales::extended_breaks(5)(range(0,as.numeric(lab_max)))),"%"))+ coord_polar(start = -0.2) + xlab("") + ggtitle(paste(station_number,"(",paste0(year(start_date),"-",month(start_date)), "~",paste0(year(end_date),"-",month(end_date)),")"))+ theme(axis.title=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank()) ggsave("P2.png") p2 } ui <- dashboardPage( dashboardHeader(title = "Windrose plot by R", dropdownMenu(type = "messages", messageItem( from = "阿好伯製作分享",icon = icon("questiont"), message = "https://www.facebook.com/LHB0222/", time = "2021:06:13" ))), dashboardSidebar( sidebarMenu( menuItem("監測站歷史資料", tabName = "dashboard", icon = icon("dashboard")), menuItem("手動輸入角度", icon = icon("glyphicon glyphicon-pencil"), tabName = "widgets", badgeLabel = "new", badgeColor = "green"), menuItem("手動輸入方位", icon = icon("glyphicon glyphicon-fullscreen" ,lib = "glyphicon"), tabName = "widgets2", badgeLabel = "new", badgeColor = "aqua") ) ), dashboardBody( tabItems( tabItem(tabName = "dashboard", h2("全自動抓資料不費力~"), fluidRow( box( title = "Inputs", status = "warning", #更改外觀1 solidHeader = TRUE, collapsible = TRUE, #更改外觀2 textInput ( "station_number" , " 監測站編號_預設大寮測站", value = "C0V730" ), helpText("測站編號查詢","https://e-service.cwb.gov.tw/HistoryDataQuery/"), radioButtons( "mode", "日/月資料",choices = c("日","月")), dateRangeInput('dateRange', label = 'Date range input: yyyy-mm-dd', start = Sys.Date() -1, end = Sys.Date() -1), textInput ( "xlab1" , "頻率最大值", value = 30 ), submitButton(text = "更新", icon = NULL, width = NULL), downloadButton("downloadData", "Download Plot") )), fluidRow(box( title = "Outputs", status = "info", solidHeader = TRUE, collapsible = TRUE, plotOutput("WindRosePlote"), width = "600px", height = "400px")) ), tabItem(tabName = "widgets", h2("手動輸入好自由~"),#actionButton("done", "Done!"), fluidRow(box( title = "Inputs", status = "warning", solidHeader = TRUE, collapsible = TRUE, textInput ( "plottitle2" , " 圖片標題(中文可能不支援)", value = "Wind Rose" ), radioButtons( "mode2", "相對百分比(%)或計數(n)",choices = c("%","n")), helpText("WS = 風速; WD = 風向角度(0~360)"), dataEditUI("edit-1")), box(title = "breaks", status = "warning", solidHeader = TRUE, collapsible = TRUE, helpText("風速分級"), helpText("預設蒲福氏風級"), helpText("最後一列為'Inf'表示無限大"), helpText("若要新增或刪除請點選右鍵Insert or Remove row"), #submitButton(text = "更新", icon = NULL, width = NULL), dataEditUI("edit-3"))), fluidRow(box(title = "Outputs", status = "info", solidHeader = TRUE, collapsible = TRUE, textInput ( "xlab2" , "頻率最大值", value = 10 ), submitButton(text = "更新", icon = NULL, width = NULL), downloadButton("downloadData2", "Download Plot"), plotOutput("WindRosePlote2"), width = "600px", height = "400px")) ), tabItem(tabName = "widgets2", h2("手動輸入好自由~"),#actionButton("done", "Done!"), fluidRow(box( title = "Inputs", status = "warning", solidHeader = TRUE, collapsible = TRUE, #submitButton(text = "更新", icon = NULL, width = NULL), textInput ( "plottitle3" , " 圖片標題(中文可能不支援)", value = "Wind Rose" ), radioButtons( "mode3", "相對百分比(%)或計數(n)",choices = c("%","n")), #downloadButton("downloadData3", "Download Plot"), helpText("WS = 風速; WD = 風向"), helpText("方向請輸入N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW"), dataEditUI("edit-2")), box(title = "breaks", status = "warning", solidHeader = TRUE, collapsible = TRUE, helpText("風速分級"), helpText("預設蒲福氏風級"), helpText("最後一列為'Inf'表示無限大請勿刪除"), helpText("若要新增或刪除請點選右鍵Insert or Remove row"), #submitButton(text = "更新", icon = NULL, width = NULL), dataEditUI("edit-4")) ), fluidRow(box(title = "Outputs3", status = "info", solidHeader = TRUE, collapsible = TRUE, textInput ( "xlab3" , "頻率最大值", value = 100 ), submitButton(text = "更新", icon = NULL, width = NULL), downloadButton("downloadData3", "Download Plot"), plotOutput("WindRosePlote3"), width = "600px", height = "400px")) ) ) ) ) server <- function(input, output,session) { ##################### #全自動抓資料不費力~# ##################### output$WindRosePlote <- renderPlot( if(input$mode == "日"){ WindData(input$station_number, input$dateRange[1], input$dateRange[2],lab_max=input$xlab1) } else{ WindData2(input$station_number, input$dateRange[1], input$dateRange[2],lab_max=input$xlab1) } ) output$downloadData <- downloadHandler( filename = function(){paste0(input$station_number,"(",input$dateRange[1],"_",input$dateRange[2],")",'.png',sep='')}, content = function(file){ ggsave(file,plot=if(input$mode == "日"){ WindData(input$station_number, input$dateRange[1], input$dateRange[2],lab_max=input$xlab1) } else{ WindData2(input$station_number, input$dateRange[1], input$dateRange[2],lab_max=input$xlab1) }) } ) ########################## # 手動輸入好自由~1 角度 # ########################## data_to_edit <- dataEditServer("edit-1", data = data.frame(WS = c(1.1:10.1), WD = c(seq(from = 1,to = 360,by = 36)))) data_to_edit_3 <- dataEditServer("edit-3", data = data.frame(breaks =c(0, 0.3, 1.6, 3.4, 5.5, 8.0,10.8, 13.9, 17.0, 20.8, 24.5, 28.5, 32.7, Inf), labels = c("0~0.2","0.3~1.5", "1.6~3.3", "3.4~5.4", "5.5~7.9", "8.0~10.7", "10.8~13.8", "13.9~17.1", "17.2~20.7", "20.8~24.4","24.5~28.4", "28.5~32.6" , ">32.7","Inf"))) output$WindRosePlote2 <- renderPlot( if (input$mode2 == "%") { WRplot3(WRdata = data_to_edit(), input$plottitle2, WSbreaksdata = data_to_edit_3(), lab_max= input$xlab2) }else{ WRplot4(WRdata = data_to_edit(), input$plottitle2, WSbreaksdata =data_to_edit_3(), lab_max= input$xlab2) } ) dataOutputServer("output-1", data = data_to_edit) dataOutputServer("output-3", data = data_to_edit_3) output$downloadData2 <- downloadHandler( filename = function(){paste(Sys.time(),'.png',sep='')}, content = function(file){ if (input$mode2 == "%"){ ggsave(file,plot= WRplot3(WRdata = data_to_edit(), input$plottitle2, WSbreaksdata =data_to_edit_3(), lab_max= input$xlab2)) }else{ggsave(file,plot= WRplot4(WRdata = data_to_edit(), input$plottitle2, WSbreaksdata =data_to_edit_3(), lab_max= input$xlab2))} } ) ######################### #手動輸入好自由~2 方位 # ######################### data_to_edit_2 <- dataEditServer("edit-2", data = data.frame(WS = c(1.1:10.1), WD = c(rep("E", times = 1, length.out = 10)))) data_to_edit_4 <- dataEditServer("edit-4", data = data.frame(breaks =c(0, 0.3, 1.6, 3.4, 5.5, 8.0,10.8, 13.9, 17.2, 20.8, 24.5, 28.5, 32.7, Inf), labels = c("0~0.2","0.3~1.5", "1.6~3.3", "3.4~5.4", "5.5~7.9", "8.0~10.7", "10.8~13.8", "13.9~17.1", "17.2~20.7", "20.8~24.4","24.5~28.4", "28.5~32.6" , ">32.7","Inf"))) dataOutputServer("output-4", data = data_to_edit_4) output$WindRosePlote3 <- renderPlot( if (input$mode3 == "%") {WRplot(WRdata = data_to_edit_2(),input$plottitle3, WSbreaksdata =data_to_edit_4(), lab_max= input$xlab3) }else{ WRplot2(WRdata = data_to_edit_2(),input$plottitle3, WSbreaksdata =data_to_edit_4(), lab_max= input$xlab3) } ) dataOutputServer("output-2", data = data_to_edit_2) output$downloadData3 <- downloadHandler( filename = function(){paste(Sys.time(),'.png',sep='')}, content = function(file){ if (input$mode2 == "%"){ ggsave(file,plot= WRplot(WRdata = data_to_edit_2(), input$plottitle3, WSbreaksdata =data_to_edit_4(), lab_max= input$xlab3)) }else{ggsave(file,plot= WRplot2(WRdata = data_to_edit_2(), input$plottitle3, WSbreaksdata =data_to_edit_4(), lab_max= input$xlab3))} } ) } shinyApp(ui, server) ``` # [ :earth_asia: shinydashboard 網址](https://gtgrthrst.shinyapps.io/Wind_Rose_pro/) >參考資料 >https://rstudio.github.io/shinydashboard/ >https://yjtseng.info/shinybook/dashboard # 衍生文章 [使用R擷取觀測資料查詢系統氣象資料並繪製四季風花圖](/sJo4lCwMQZmgTITra_iWYw) 🌟全文可以至下方連結觀看或是補充 https://hackmd.io/@LHB-0222/shinydashboard 全文分享至 https://www.facebook.com/LHB0222/ https://www.instagram.com/ahb0222/ 有疑問想討論的都歡迎於下方留言 喜歡的幫我分享給所有的朋友 \o/ 有所錯誤歡迎指教 # [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings) ![](https://i.imgur.com/47HlvGH.png)