---
image:https://i.imgur.com/C360j5T.png
---
# 用R做氣候圖
###### tags: `用R做`, `學習筆記`
氣候圖(climograph)是一種用來呈現某地長時間氣候的圖表,主要內容就是該地的氣溫與降水狀況,一般會呈現月均溫和各月雨量的分布。透過氣候圖,我們可以更直觀地了解一個地方的氣候型態。
除了單純的氣候圖之外,也有一種在植群生態學中使用的生態氣候圖(climate diagram),藉由特定的氣溫與降水量比例(莽原氣候 $10^{\circ}C=30mm$、地中海型氣候 $10^{\circ}C=20mm$),可以在氣候圖中呈現降水量與蒸散量的關係(若該月降水量超過 100mm 則為重濕),以及水的型態可否為植物所利用(是否低於 $0^{\circ}C$)等等。不過比較常看到的還是普通的氣候圖。
---
以下以中央氣象局香山觀測站(編號 C0D570,目前已撤銷)為例,用 R 的幾個套件從測站觀測資訊網把觀測資料抓下來,再繪製成氣候圖。
先來抓資料,把香山測站自設站到撤銷的所有完整年度資料抓下來:
(這部分的程式碼修改自[阿好伯用來抓取風速風向資料的程式碼](https://hackmd.io/@LHB-0222/Wind_Rose),感謝阿好伯。)
```java!
packages <- c("dplyr","jsonlite", "rvest", "magrittr", "lubridate","ggplot2")
invisible(lapply(packages, library, character.only = TRUE))
#載入資料,網址隨各站不同
url_start <- "https://e-service.cwb.gov.tw/HistoryDataQuery/YearDataController.do?command=viewMain&station=C0D570&stname=%25E9%25A6%2599%25E5%25B1%25B1&datepicker="
climatecrawler <-
function(x,y){
begin_year <- x
end_year <- y
data1 <- data.frame()
data2 <- data.frame()
for(r in c(0:(end_year - begin_year))){
url <- paste0(url_start,as.character(begin_year + r),"&altitude=15m") #要記得加上測站海拔
#時間資料
month <- url %>%
read_html() %>%
html_nodes(xpath='//*[(@id = "MyTable")]//td[(((count(preceding-sibling::*) + 1) = 1) and parent::*)]') %>%
html_text(trim = T) %>%
as.numeric()
#均溫資料
avgtemp <- url %>%
read_html() %>%
html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 8) and parent::*)]') %>%
html_text(trim = T) %>%
gsub("X","-9999", .) %>%
as.numeric()
#高溫資料
hightemp <- url %>%
read_html() %>%
html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 9) and parent::*)]') %>%
html_text(trim = T) %>%
gsub("X","-9999", .) %>%
as.numeric()
#低溫資料
lowtemp <- url %>%
read_html() %>%
html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 11) and parent::*)]') %>%
html_text(trim = T) %>%
gsub("X","-9999", .) %>%
as.numeric()
#降水量
precip <- url %>%
read_html() %>%
html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 19) and parent::*)]') %>%
html_text(trim = T) %>%
gsub("X","-9999", .) %>%
as.numeric()
#日照時數
sunshine <- url %>%
read_html() %>%
html_nodes(xpath='//td[(((count(preceding-sibling::*) + 1) = 30) and parent::*)]') %>%
html_text(trim = T) %>%
gsub("X","-9999", .) %>%
as.numeric()
#合併資料
data1 <- cbind(year = as.character(begin_year + r), month, avgtemp, hightemp, lowtemp, precip, sunshine)
data2 <- rbind(data2, data1[-1,])
data3 <- data2[order(as.numeric(data2$month)),]
}
return(data3)
}
SSweather <- climatecrawler(2008, 2021)
write.csv(SSweather, "香山測站2008_2021觀測資料.csv")
```
接著,用抓到的資料作圖:
```java!
library(dplyr)
weather <- read.csv("香山測站2008_2021觀測資料.csv", header = T)
total <- as.data.frame(weather %>%
group_by(month) %>%
summarise(
temp = mean(avgtemp, na.rm = T),
hightemp = mean(hightemp, na.rm = T),
lowtemp = mean(lowtemp, na.rm = T),
precip = mean(precip, na.rm = T)
)
)
library(scales)
library(ggpubr)
library(ggthemes)
windowsFonts(GJ = windowsFont("Gen Jyuu Gothic P Medium"))
TempPrecp <- ggplot(total) +
geom_bar(aes(y = precip *20/300, x = month), stat="identity", fill = "#19B4C5", colour = "#19B4C5") +
geom_line(mapping = aes(y = temp, x = month), size = 1.5, color = "#F9BD21") +
geom_point(mapping = aes(y = temp, x = month), size = 4, color = "#F9BD21") +
#geom_ribbon(aes(x = month, y = temp,
# ymin = hightemp,
# ymax = lowtemp,
# fill = "#F9BD21"), alpha = 0.2) +
scale_x_continuous(name = "月份", breaks = 1:12) +
#scale_y_continuous(name = "月均溫 (℃) \n", breaks = seq(0, 30, by = 5),
# sec.axis = sec_axis(~. *300/30, name = "降水量(mm) \n")) +
scale_y_continuous(name = "月均溫 (℃) ", limit = c(0, 35), breaks = c(10, 20, 30),
sec.axis = sec_axis(~. *300/20, name = "降水量(mm) \n")) +
theme_few() +
ggtitle("香山氣象站氣候圖(2008–2021年)") +
theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 32),
plot.margin = unit(c(1,2.5,1,1),'cm'),
legend.position="none") +
font("xy.text", size = 18)
ggpar(TempPrecp, font.family = "GJ", font.x = c(28, "azure4"), font.y = c(28, "azure4"))
```
最後輸出如下:
<center>
<img src = "https://i.imgur.com/C360j5T.png" width = 80%>
繪製出的氣候圖。
</center>
兩側的 Y 軸單位與數字不同,用來繪圖的溫度和雨量數字大小也不同,因此需要乘以最高月均溫與最大月降水量的比值。
此處繪圖順序是將降水量作為第 2 個 Y 軸,因此畫長條圖時要乘以 $(\frac {最高月均溫}{最大月降水量})$,而在繪製軸線刻度時則相反,要將主軸線刻度(記為 ~.)乘以 $(\frac {最大月降水量}{最高月均溫})$。
除了氣候圖之外,當然也可以只畫溫度或雨量圖:
```java!
total2 <- as.data.frame(weather %>%
group_by(year) %>%
summarise(
temp = mean(avgtemp, na.rm = T),
hightemp = mean(hightemp, na.rm = T),
lowtemp = mean(lowtemp, na.rm = T),
precip = sum(precip, na.rm = T)
)
)
tem <- ggline(total2, "year", "temp", size = 1, point.size = 1.5, color = "#7F1084") +
labs(x = "\n 年度", y = "年均溫 (℃) \n", title = "香山氣象站 2008–2021年均溫變化") +
scale_x_continuous(breaks = seq(2008, 2021, by = 1)) +
scale_y_continuous(limits = c(22, 23.5), breaks = c(22.0, 22.25, 22.5, 22.75, 23.0, 23.25, 23.5)) +
theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 32),
plot.margin = unit(c(1,2.5,1,1),'cm')) +
font("xy.text", size = 18) +
theme_hc()
ggpar(tem, font.family = "GJ", font.x = c(28, "azure4"), font.y = c(28, "azure4")) +
geom_hline(yintercept = 22.6583, lty = 5, color = "black")
```
<center>
<img src = "https://i.imgur.com/01mLU5b.png" width = 80%>
繪製出的年均溫變化圖。
</center>
可以看到香山氣象站這 14 年來的的年均溫趨勢往上,真是讓人擔心啊。
而最開頭提到的生態氣候圖,可以參考嘉義大學[林政道老師的程式碼](https://gist.github.com/mutolisp/3cc9c337c271fbfd12ec6e15a05f8d23)。
<span style="font-size:30px">🐕🦺</span> 2022.10.06