UK Meteorological & Climate Data

Author

Jo Hardin

Code
library(tidyverse) # ggplot, lubridate, dplyr, stringr, readr...
library(praise)
library(shiny)

The Data

This week we’re exploring historic meteorological data from the UK Met Office.

The UK Met Office is the United Kingdom’s national weather and climate service, providing forecasts, severe weather warnings, and climate science expertise. It helps people, businesses, and governments make informed decisions to stay safe and plan for the future. It was first established in 1854, making it one of the oldest weather services in the world.

Data has been scraped straight from the Met Office website and cleaned in a basic way. The few flags for “estimated” data and changing sunlight monitoring techniques have been removed for simplicity, but are available from the raw data. Also available is simple site metadata which includes the opening date and latitude and longitude of each station.

Monthly Historical information for 37 UK Meteorological Stations. Most go back to the early 1900s, but some go back as far as 1853. Station data files are updated on a rolling monthly basis, around 10 days after the end of the month. No allowances have been made for small site changes and developments in instrumentation.

Code
historic_station_met <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2025/2025-10-21/historic_station_met.csv')
station_meta <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/main/data/2025/2025-10-21/station_meta.csv')

Spiral plot

For each month of each year, we can plot the amount of rain or sun or temperature. Notice that amount of sun hasn’t changed much over the years, but rain and temperature have. That is, the darkest arc for high and low temperature in any piece of pie is toward the later years. Rain is sort of all over the place, it doesn’t really show that rain is necessarily decreasing (or increasing).

High temperature (in Aberporth)

Code
month_length <- c(31, 28, 31, 30, 31, 30,
                  31, 31, 30, 31, 30, 31)

month_breaks <- cumsum(month_length) - 30
base_grey <- "grey28"

year_annotations <- list(
  year = c(1960, 1980, 2000, 2020),
  x = rep(3, 4),
  y = ymd(paste(c(1960, 1980, 2000, 2020), "01", "01", sep = "-"))
)
Code
historic_station_met |> 
  filter(station == "aberporth") |> 
  filter(year >= 2000) |> 
  mutate(date = ymd(paste(year, month, "01", sep = "-")),
         day_of_year = yday(date),
         # Handle December specially - extend to end of year instead of next year
         ymd_month = if_else(month == 12, 
                             ymd(paste(year, "12", "31", sep = "-")),
                             date %m+% months(1)),
         day_month = yday(ymd_month)) |> 
  ggplot() +
  geom_segment(aes(x = day_of_year, xend = day_month, 
                   y = date, yend = ymd_month, color = tmax), linewidth = 2) +
  scale_color_gradient(low = "white", high = "darkgreen") +
  annotate("text", 
           label = paste0(year_annotations$year, "\u2192"), 
           x = year_annotations$x, 
           y = year_annotations$y, 
           family = "Arial",
           size = 2, hjust = c(1.1, 1.2, 1.3, 1.4)) +#, hjust = 0.15) +

  coord_polar() + 
  theme_void() +
  scale_x_continuous(minor_breaks = month_breaks, 
                     breaks = month_breaks[c(3, 6, 9, 12)],
                     labels = c("March", "June", "Sep.", "Dec.")) +
  theme(
    plot.background = element_rect(color = NA, fill = "white"),
    panel.grid.major.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    panel.grid.minor.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    axis.text.x = element_text(color = base_grey, size = 10)
  ) + 
  labs(title = "High temperature (in Aberporth)")

High temperatures recorded for each month and each year since about 2000 in Aberporth. The values are presented in a spiral so that we can see how the temperature changes across year while keeping month constant. There are slighlty higher temperatures in recent years across each month.

Low temperature (in Aberporth)

Code
historic_station_met |> 
  filter(station == "aberporth") |> 
  filter(year >= 2000) |> 
  mutate(date = ymd(paste(year, month, "01", sep = "-")),
         day_of_year = yday(date),
         # Handle December specially - extend to end of year instead of next year
         ymd_month = if_else(month == 12, 
                             ymd(paste(year, "12", "31", sep = "-")),
                             date %m+% months(1)),
         day_month = yday(ymd_month)) |> 
  ggplot() +
  geom_segment(aes(x = day_of_year, xend = day_month, 
                   y = date, yend = ymd_month, color = tmin), linewidth = 2) +
  scale_color_gradient(low = "white", high = "maroon") +
  annotate("text", 
           label = paste0(year_annotations$year, "\u2192"), 
           x = year_annotations$x, 
           y = year_annotations$y, 
           family = "Arial",
           size = 2, hjust = c(1.1, 1.2, 1.3, 1.4)) +#, hjust = 0.15) +

  coord_polar() + 
  theme_void() +
  scale_x_continuous(minor_breaks = month_breaks, 
                     breaks = month_breaks[c(3, 6, 9, 12)],
                     labels = c("March", "June", "Sep.", "Dec.")) +
  theme(
    plot.background = element_rect(color = NA, fill = "white"),
    panel.grid.major.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    panel.grid.minor.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    axis.text.x = element_text(color = base_grey, size = 10)
  ) + 
  labs(title = "Low temperature (in Aberporth)")

Rain (in Aberporth)

Code
historic_station_met |> 
  filter(station == "aberporth") |> 
  filter(year >= 2000) |> 
  mutate(date = ymd(paste(year, month, "01", sep = "-")),
         day_of_year = yday(date),
         # Handle December specially - extend to end of year instead of next year
         ymd_month = if_else(month == 12, 
                             ymd(paste(year, "12", "31", sep = "-")),
                             date %m+% months(1)),
         day_month = yday(ymd_month)) |> 
  ggplot() +
  geom_segment(aes(x = day_of_year, xend = day_month, 
                   y = date, yend = ymd_month, color = rain), linewidth = 2) +
  scale_color_gradient(low = "white", high = "darkblue") +
  annotate("text", 
           label = paste0(year_annotations$year, "\u2192"), 
           x = year_annotations$x, 
           y = year_annotations$y, 
           family = "Arial",
           size = 2, hjust = c(1.1, 1.2, 1.3, 1.4)) +#, hjust = 0.15) +

  coord_polar() + 
  theme_void() +
  scale_x_continuous(minor_breaks = month_breaks, 
                     breaks = month_breaks[c(3, 6, 9, 12)],
                     labels = c("March", "June", "Sep.", "Dec.")) +
  theme(
    plot.background = element_rect(color = NA, fill = "white"),
    panel.grid.major.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    panel.grid.minor.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    axis.text.x = element_text(color = base_grey, size = 10)
  ) + 
  labs(title = "Rain (in Aberporth)")

Code
historic_station_met |> 
  filter(station == "aberporth") |> 
  mutate(date = ymd(paste(year, month, "01", sep = "-")),
         day_of_year = yday(date),
         # Handle December specially - extend to end of year instead of next year
         ymd_month = if_else(month == 12, 
                             ymd(paste(year, "12", "31", sep = "-")),
                             date %m+% months(1)),
         day_month = yday(ymd_month)) |> 
  ggplot() +
  geom_segment(aes(x = day_of_year, xend = day_month, 
                   y = date, yend = ymd_month, color = sun), linewidth = 2) +
  scale_color_gradient(low = "yellow", high = "red", na.value = "white") +
  annotate("text", 
           label = paste0(year_annotations$year, "\u2192"), 
           x = year_annotations$x, 
           y = year_annotations$y, 
           family = "Arial",
           size = 2, hjust = c(1.1, 1.2, 1.3, 1.4)) +#, hjust = 0.15) +
  coord_polar() + 
  theme_void() +
  scale_x_continuous(minor_breaks = month_breaks, 
                     breaks = month_breaks[c(3, 6, 9, 12)],
                     labels = c("March", "June", "Sep.", "Dec.")) +
  theme(
    plot.background = element_rect(color = NA, fill = "white"),
    panel.grid.major.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    panel.grid.minor.x = element_line(color = "grey", size = .5, linetype = "dotted"),
    axis.text.x = element_text(color = base_grey, size = 10)
  ) + 
  labs(title = "Sun (in Aberporth)")

Sadly, plotly won’t work with coord_polar(). So we can’t create a pull down menu for the station. We could if we used shiny, but that isn’t in the cards for today.

Code
praise()
[1] "You are riveting!"