# Plots of circular and linear temperature anomalies
# ------------------------------------------------->
library(DescTools)
library(tidyverse)
library(showtext)
library(zoo)
library(RColorBrewer)
font_add_google(name = "Roboto", family = "Roboto")
font <- "Roboto"
comma_delim <- locale(decimal_mark = ",")
# Load and wrangle data
# -------->
# Downloaded daily middle temperature data from https://seklima.met.no/observations/
temp <- read_delim("temp_oslo.txt", delim = "\t", locale = comma_delim) %>%
mutate(
date = dmy(date),
year = year(date),
month = month(date),
day = day(date)
) %>%
filter(!(month(date) == 2 & day(date) == 29))
# Some missing data
date_range <- seq(min(temp$date), max(temp$date), by = "1 day")
# Create a data frame with all dates
all_dates <- data.frame(date = date_range)
temp <- all_dates %>%
left_join(temp) %>%
# Add day, month and year again
mutate(
year = year(date),
month = month(date),
day = day(date)
) %>%
# LOCF (last observation carried forward) for missing values
fill(mid_temp, .direction = "down") %>%
# Make days go up to 365
group_by(year) %>%
mutate(day = as.numeric(date - floor_date(date, "year")) + 1)
# We define the baseline period
baseline_start <- as.Date("1937-02-01")
baseline_end <- as.Date("1959-12-31")
# Calculate the daily mean temperature for each day within the baseline period
baseline_data <- temp %>%
filter(date >= baseline_start & date <= baseline_end) %>%
group_by(day) %>%
summarise(mean_temperature = mean(mid_temp, na.rm = TRUE))
# Left join the baseline data
temp_anom <-
temp %>%
left_join(baseline_data) %>%
mutate(anomaly = mid_temp - mean_temperature)
# Compute 30 day rolling avg
zoo_data <- zoo(temp_anom$anomaly, order.by = temp_anom$date)
moving_avg <- rollapply(zoo_data, width = 90, FUN = mean, align = "right", fill = NA)
temp_anom$rolling_avg_anomaly <- as.vector(moving_avg[temp_anom$date])
cols <- c(
rep("#444444", 33), # 1937 to 1970
rep("#555555", 10), # 1971 to 1980
rep("#666666", 10), # 1981 to 1990
rep("#888888", 10), # 1991 to 2000
rep("#865353", 10), # 2001 to 2010
rep("#c17e7e", 12), # 2011 to 2021
"#e8b1b1", # 2022
"#eccdcd", # 2023
"#eccdcd" # 2024
)
hlines <- tibble(
y = seq(-5, 5, 2.5),
yend = seq(-5, 5, 2.5),
x = -Inf,
xend = Inf
)
hlines2 <- tibble(
y = 0,
yend = 0,
x = -Inf,
xend = Inf
)
# Circular version (coord_polar)
# ----------------------------->
theme_temp_circ <- function() {
theme(
plot.title = element_text(family = font, size = 16, lineheight = 0.3, color = "#e0e0e0", face = "bold"),
plot.subtitle = element_text(family = font, size = 8.5, lineheight = 1.1, color = "#CCCCCC", face = "italic"),
plot.caption = element_text(family = font, size = 7, color = "#666666"),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size = 7, color = "#666666", family = font),
axis.ticks.x = element_blank(),
panel.grid.major.x = element_line(color = "#333333", size = 0.1),
panel.grid.minor.x = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.background = element_rect(color = NA, fill = "#222222"),
plot.background = element_rect(color = NA, fill = "#222222")
)
}
p <-
temp_anom %>%
mutate(lty = case_when(
year < 2021 ~ 0,
year >= 2021 ~ 1
)) %>%
mutate(year = as.factor(year)) %>%
ggplot(aes(x = day, y = rolling_avg_anomaly, color = year, size = lty)) +
# Winter and summer months (optional)
# geom_rect(aes(xmin = 365-31, xmax = 365, ymin = -Inf, ymax = 5), fill = "#333333", color = NA)+
# geom_rect(aes(xmin = 1, xmax = 31+28, ymin = -Inf, ymax = 5), fill = "#333333", color = NA)+
# geom_rect(aes(xmin = 152, xmax = 244, ymin = -Inf, ymax = 5), fill = "#333333", color = NA)+
geom_segment(
data = hlines,
aes(x = x, xend = xend, y = y, yend = yend),
size = 0.1, color = "#555555"
) +
geom_line(aes(group = year)) +
# Add dot for the last day of the data
geom_point(data = temp_anom %>% filter(year == 2024 & day == max(day)), aes(x = day, y = rolling_avg_anomaly), size = 2, color = "#eccdcd", fill = "#222222", shape = 21) +
scale_size(range = c(0.1, 0.25)) +
theme(legend.position = "none") +
scale_color_manual(values = cols) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(limits = c(-11, 6.5), expand = c(0, 0)) +
coord_polar(theta = "x", start = pi * 1.5, clip = "off") +
scale_x_continuous(breaks = c(1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335), labels = c("Jan 01", "Feb 01", "Mar 01", "Apr 01", "May 01", "Jun 01", "Jul 01", "Aug 01", "Sep 01", "Oct 01", "Nov 01", "Dec 01"), expand = c(0, 0), limits = c(1, 365)) +
theme_temp_circ() +
annotate(geom = "text", x = 273, y = 5.5, label = "5.0 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 273, y = 3, label = "2.5 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 272, y = 0.5, label = "0 \u00B0C", family = font, color = "#e0e0e0", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 273, y = -2, label = "-2.5 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 271, y = -4.5, label = "-5.0 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
labs(
title = "Oslo Temperature Anomaly, 1937-2023",
subtitle = "3-month rolling means. Reference period: 1937-1960"
) +
geom_segment(
data = hlines2,
aes(x = x, xend = xend, y = y, yend = yend),
size = 0.3, color = "#e0e0e0", linetype = "dashed"
)
ggsave("temp_oslo_circ.pdf", p, width = 140, height = 140, unit = "mm", dpi = 500, device = cairo_pdf)
# Straight version
# ----------------------------->
theme_temp_lin <- function() {
theme(
plot.title = element_text(family = font, size = 16, lineheight = 0.3, color = "#e0e0e0", face = "bold"),
plot.subtitle = element_text(family = font, size = 8.5, lineheight = 1.1, color = "#CCCCCC", face = "italic"),
plot.caption = element_text(family = font, size = 7, color = "#666666"),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size = 7, color = "#666666", family = font),
axis.ticks.x = element_blank(),
panel.grid.major.x = element_line(color = "#333333", size = 0.1),
panel.grid.minor.x = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
panel.background = element_rect(color = NA, fill = "#222222"),
plot.background = element_rect(color = NA, fill = "#222222"),
plot.margin = unit(c(2, 10, 2, 5), "mm")
)
}
p <-
temp_anom %>%
mutate(lty = case_when(
year < 2020 ~ 0,
year >= 2020 ~ 1
)) %>%
mutate(year = as.factor(year)) %>%
ggplot(aes(x = day, y = rolling_avg_anomaly, color = year, size = lty)) +
geom_segment(
data = hlines,
aes(x = x, xend = xend, y = y, yend = yend),
size = 0.1, color = "#555555"
) +
geom_line(aes(group = year)) +
# Add dot for the last day of the data
geom_point(data = temp_anom %>% filter(year == max(year) & day == max(day)), aes(x = day, y = rolling_avg_anomaly), size = 2, color = "#eccdcd", fill = "#222222", shape = 21) +
scale_size(range = c(0.1, 0.25)) +
theme(legend.position = "none") +
scale_color_manual(values = cols) +
scale_x_continuous(expand = c(0.1, 0.1)) +
scale_y_continuous(limits = c(-6.5, 6.5), expand = c(0, 0)) +
coord_cartesian(clip = "off") +
scale_x_continuous(breaks = c(1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335), labels = c("Jan 01", "Feb 01", "Mar 01", "Apr 01", "May 01", "Jun 01", "Jul 01", "Aug 01", "Sep 01", "Oct 01", "Nov 01", "Dec 01"), expand = c(0, 0), limits = c(1, 365)) +
theme_temp_lin() +
annotate(geom = "text", x = 275, y = 5.3, label = "5.0 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 275, y = 2.8, label = "2.5 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 275, y = 0.3, label = "0 \u00B0C", family = font, color = "#e0e0e0", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 275, y = -2.2, label = "-2.5 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
annotate(geom = "text", x = 275, y = -4.7, label = "-5.0 \u00B0C", family = font, color = "#666666", size = 2.5, hjust = 0) +
labs(
title = "Oslo temperature anomaly, 1937-2023",
subtitle = "3-month rolling means. Reference period: 1937-1960"
) +
geom_segment(
data = hlines2,
aes(x = x, xend = xend, y = y, yend = yend),
size = 0.3, color = "#e0e0e0", linetype = "dashed"
) +
# 2020
annotate(
geom = "text", label = "2020", x = 365,
y = temp_anom %>%
filter(year == 2020 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#c17e7e", hjust = 0, family = font, size = 2
) +
# 2021
annotate(
geom = "text", label = "2021", x = 365,
y = temp_anom %>%
filter(year == 2021 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#c17e7e", hjust = 0, family = font, size = 2
) +
# 2022
annotate(
geom = "text", label = "2022", x = 365,
y = temp_anom %>%
filter(year == 2022 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#e8b1b1", hjust = 0, family = font, size = 2
) +
# 2023
annotate(
geom = "text", label = "2023", x = 365,
y = temp_anom %>%
filter(year == 2023 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#eccdcd", hjust = 0, family = font, size = 2
) +
# 1940
annotate(
geom = "text", label = "1940", x = 365,
y = temp_anom %>%
filter(year == 1940 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#444444", hjust = 0, family = font, size = 1.7
) +
# 1960
annotate(
geom = "text", label = "1960", x = 365,
y = temp_anom %>%
filter(year == 1960 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#444444", hjust = 0, family = font, size = 1.7
) +
# 1980
annotate(
geom = "text", label = "1980", x = 365,
y = temp_anom %>%
filter(year == 1980 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#666666", hjust = 0, family = font, size = 1.7
) +
# 2000
annotate(
geom = "text", label = "2000", x = 365,
y = temp_anom %>%
filter(year == 2000 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#865353", hjust = 0, family = font, size = 1.7
) +
# 2010
annotate(
geom = "text", label = "2010", x = 365,
y = temp_anom %>%
filter(year == 2010 & day == 365) %>%
pull(rolling_avg_anomaly),
color = "#865353", hjust = 0, family = font, size = 1.7
)
ggsave("temp_oslo_lin.pdf", p, width = 160, height = 100, unit = "mm", dpi = 500, device = cairo_pdf)