# data input
library(readr)
library(readxl)
# data organization
library(tidyr)
library(dplyr)
library(stringi)
library(magrittr)
library(lubridate)
library(zoo)
# website organization
library(htmltools)
library(htmlwidgets)
# plotting
library(ggformula)
library(gridExtra)
library(RColorBrewer)
Motivated by empirical observations from myself and other runners, as
well as a Reddit
post:
“What is up with this summer?”
“Maybe it’s recency bias, maybe it’s short term memory but I’ve lived here for 30 years and I can’t remember a summer this freaking humid. Every day feels like high 80s with 70-80% humidity making outside just feel muggy and nasty. I know Wisconsin has hot summers but I remember a dry heat breezes etc not this swamp. I legit feel like iam in the south half the time with how i step straight into humidity the minute my door opens. Has anyone else noticed this?”
Data are pulled from the NOAA’s Local Climatological Data, from January 1985 - July 2024. Measured at the weather station at Chippewa Valley Regional Airport.
Climate_1985_1994 <- read.csv("ChipAirport1985to1994.csv")
Climate_1995_2004 <- read.csv("ChipAirport1995to2004.csv")
Climate_2005_2014 <- read.csv("ChipAirport2005to2014.csv")
Climate_2015_2024 <- read.csv("ChipAirport2015to2024.csv")
LocalClimate_40years = rbind(Climate_1985_1994,
Climate_1995_2004,
Climate_2005_2014,
Climate_2015_2024)
dim(LocalClimate_40years)
## [1] 470772 124
nhours <- dim(LocalClimate_40years)[1]
Inital Plots:
head(select(LocalClimate_40years,
DATE, DailyAverageWetBulbTemperature, HourlyWetBulbTemperature))
## DATE DailyAverageWetBulbTemperature HourlyWetBulbTemperature
## 1 1985-01-01T00:00:00 NA 12
## 2 1985-01-01T01:00:00 NA 11
## 3 1985-01-01T02:00:00 NA 11
## 4 1985-01-01T03:00:00 NA 11
## 5 1985-01-01T04:00:00 NA 11
## 6 1985-01-01T05:00:00 NA 11
plot( LocalClimate_40years$HourlyWetBulbTemperature , type="l")
## Warning in xy.coords(x, y, xlabel, ylabel, log): NAs introduced by coercion
plot( LocalClimate_40years$HourlyRelativeHumidity , type="l")
## Warning in xy.coords(x, y, xlabel, ylabel, log): NAs introduced by coercion
There is a lot of missing wet bulb temp information. Let’s try a direct calculation:
Td_C = 20; RH = 50
Td_C*atan(0.151977*sqrt(RH+8.313659) ) + atan(Td_C + RH) - atan(RH - 1.676331) + 0.00391838*(RH^(3/2))*atan(0.023101*RH) - 4.686035
## [1] 13.69934
LocalClimate_40years <- mutate(LocalClimate_40years, Td_F = as.numeric(HourlyDryBulbTemperature),
Td_C = round((Td_F-32)*(5/9),2),
RH = as.numeric(HourlyRelativeHumidity),
Tw_C = round(Td_C*atan(0.151977*sqrt(RH+8.313659) ) + atan(Td_C + RH) - atan(RH - 1.676331) + 0.00391838*(RH^(3/2))*atan(0.023101*RH) - 4.686035,2),
Tw_F = (9/5)*Tw_C + 32,
T_dewp_F = as.numeric(HourlyDewPointTemperature),
T_dewp_C = round((T_dewp_F-32)*(5/9),2))
## Warning: There were 3 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `Td_F = as.numeric(HourlyDryBulbTemperature)`.
## Caused by warning:
## ! NAs introduced by coercion
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 2 remaining warnings.
gf_point(Tw_F ~ as.numeric(HourlyWetBulbTemperature), data=LocalClimate_40years)
## Warning in FUN(X[[i]], ...): NAs introduced by coercion
## Warning: Removed 117571 rows containing missing values or values outside the scale range
## (`geom_point()`).
colSums(is.na(LocalClimate_40years[,c(125:131)]))
## Td_F Td_C RH Tw_C Tw_F T_dewp_F T_dewp_C
## 53945 53945 54048 54101 54101 54086 54086
And voila, we have managed to regain about half the missing data via direct computation!
splitdate = strsplit(LocalClimate_40years$DATE, "T")
matrixdate = matrix(unlist(splitdate), ncol = 2, byrow = TRUE)
LocalClimate_40years <- mutate(LocalClimate_40years,
DateUsable=as.Date(format(as.Date(matrixdate[,1]), "%Y-%m-%d")),
DateFormatted=format(as.Date(matrixdate[,1]), format = "%B %d %Y"),
Time=hms(matrixdate[,2])
)
LocalClimate_40years$DateUsable[1:10]
## [1] "1985-01-01" "1985-01-01" "1985-01-01" "1985-01-01" "1985-01-01"
## [6] "1985-01-01" "1985-01-01" "1985-01-01" "1985-01-01" "1985-01-01"
LocalClimate_40years$DateFormatted[1:10]
## [1] "January 01 1985" "January 01 1985" "January 01 1985" "January 01 1985"
## [5] "January 01 1985" "January 01 1985" "January 01 1985" "January 01 1985"
## [9] "January 01 1985" "January 01 1985"
LocalHumidity_40years <- select(LocalClimate_40years,125:134)
length(unique(LocalHumidity_40years$DateUsable))
## [1] 14455
names(LocalHumidity_40years)
## [1] "Td_F" "Td_C" "RH" "Tw_C"
## [5] "Tw_F" "T_dewp_F" "T_dewp_C" "DateUsable"
## [9] "DateFormatted" "Time"
LocalHumidity_Daily <- group_by(LocalHumidity_40years, DateUsable) |>
summarize(meanTd = mean(Td_F, na.rm=T), maxTd = max(Td_F, na.rm=T), minTd = min(Td_F, na.rm=T),
meanTw = mean(Tw_F, na.rm=T), maxTw = max(Tw_F, na.rm=T), minTw = min(Tw_F, na.rm=T),
meanRH = mean(RH, na.rm=T), maxRH = max(RH, na.rm=T), minRH = min(RH, na.rm=T)
) |>
mutate(meanTd7day = round(rollmean(meanTd, 7, fill=NA,align="center"),1),
maxTd7day = round(rollmean(maxTd, 7, fill=NA,align="center"),1),
minTd7day = round(rollmean(minTd, 7, fill=NA,align="center"),1),
meanTw7day = round(rollmean(meanTw, 7, fill=NA,align="center"),1),
maxTw7day = round(rollmean(maxTw, 7, fill=NA,align="center"),1),
minTw7day = round(rollmean(minTw, 7, fill=NA,align="center"),1),
meanRH7day = round(rollmean(meanRH, 7, fill=NA,align="center"),1),
maxRH7day = round(rollmean(maxRH, 7, fill=NA,align="center"),1),
minRH7day = round(rollmean(minRH, 7, fill=NA,align="center"),1),
meanTd28day = round(rollmean(meanTd, 28, fill=NA,align="center"),1),
maxTd28day = round(rollmean(maxTd, 28, fill=NA,align="center"),1),
minTd28day = round(rollmean(minTd, 28, fill=NA,align="center"),1),
meanTw28day = round(rollmean(meanTw, 28, fill=NA,align="center"),1),
maxTw28day = round(rollmean(maxTw, 28, fill=NA,align="center"),1),
minTw28day = round(rollmean(minTw, 28, fill=NA,align="center"),1),
meanRH28day = round(rollmean(meanRH, 28, fill=NA,align="center"),1),
maxRH28day = round(rollmean(maxRH, 28, fill=NA,align="center"),1),
minRH28day = round(rollmean(minRH, 28, fill=NA,align="center"),1),
DateFormatted=format(DateUsable, format = "%B %d %Y")) |>
arrange(DateUsable)
head(LocalHumidity_Daily)
## # A tibble: 6 × 29
## DateUsable meanTd maxTd minTd meanTw maxTw minTw meanRH maxRH minRH
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1985-01-01 9.71 15 -3 7.32 12.4 -4.68 74.4 88 56
## 2 1985-01-02 -7.04 4 -14 -8.19 1.81 -13.9 58.8 75 37
## 3 1985-01-03 3.71 25 -15 1.36 19.9 -15.8 65.4 83 51
## 4 1985-01-04 23.9 36 11 20.8 31.6 9.46 77.0 92 61
## 5 1985-01-05 28.9 35 23 26.2 31.3 20.9 81.4 96 70
## 6 1985-01-06 26.6 30 17 25.0 28.2 15.3 89.9 96 81
## # ℹ 19 more variables: meanTd7day <dbl>, maxTd7day <dbl>, minTd7day <dbl>,
## # meanTw7day <dbl>, maxTw7day <dbl>, minTw7day <dbl>, meanRH7day <dbl>,
## # maxRH7day <dbl>, minRH7day <dbl>, meanTd28day <dbl>, maxTd28day <dbl>,
## # minTd28day <dbl>, meanTw28day <dbl>, maxTw28day <dbl>, minTw28day <dbl>,
## # meanRH28day <dbl>, maxRH28day <dbl>, minRH28day <dbl>, DateFormatted <chr>
## Warning: Removed 18 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 81 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 18 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 81 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 18 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 81 rows containing missing values or values outside the scale range
## (`geom_line()`).