Popup
images into filesFilename with the January median rainfall variables in
median_jan_rainfallleaflet to convert the tmap object and add
Popup imagesCreate a map of rainfall in Ireland for the 25 weather stations, colour coding the symbol for each station according to its median rainfall level in January.
This blog will look at how to create a rainfall map in Ireland using
the weather_stations.geojson data set which covers the
period 1850-2014. The process entails the development of an interactive
map using 25 weather stations around Ireland and colour coding them
based on their median rainfall during the month of January.
Alongside the weather_stations.geojson data set, the
counties.geojson data set is also used to help build the
interactive map and its subsequent layers.
How the Map was made 🗺️
We will start by loading in the required packages used in the script below.
library(tidyverse) # sf package uses this
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.1 ✔ stringr 1.5.2
## ✔ ggplot2 4.0.0 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(sf) # The 'sf' package handles geographical data
## Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
library(tmap)
library(leaflet)
library(leafpop)
These packages are crucial to complete the assignment in this blog.
tidyverse is a core package base used for importing and
cleaning data, visualisation and exploration (Wickham et al., 2019). In the context
of this blog, the sf package by Pebesma and Bivand (2023) uses the
tidyverse package to allow us to work with the spatial data
in the data sets described below.
To create the maps for this assignment, we will use both
tmap and leaflet to achieve this (Tennekes, 2018; Cheng et al., 2025).
To embed images into the interactive map, the leafpop
package by Appelhans and Detsch (2021) is
required.
#read in rainfall
rainfall <- st_read('weather_stations.geojson') %>% st_transform(4326)
## Reading layer `weather_stations' from data source
## `/Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversity/GY672[A] — Analysing Spatial and Temporal Data Using R/Class Materials-20250924/weather_stations.geojson'
## using driver `GeoJSON'
## Simple feature collection with 49500 features and 11 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: 46633.44 ymin: 59756.08 xmax: 330201.3 ymax: 457227.9
## Projected CRS: TM65 / Irish Grid
rainfall # looking at our rainfall data using geojson
## Simple feature collection with 49500 features and 11 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -10.23045 ymin: 51.79042 xmax: -5.991011 ymax: 55.35998
## Geodetic CRS: WGS 84
## First 10 features:
## Year Month Rainfall Station Elevation Easting Northing County Abbreviation
## 1 1850 Jan 169.0 Ardara 15 180787.7 394679 Donegal AR
## 2 1851 Jan 236.4 Ardara 15 180787.7 394679 Donegal AR
## 3 1852 Jan 249.7 Ardara 15 180787.7 394679 Donegal AR
## 4 1853 Jan 209.1 Ardara 15 180787.7 394679 Donegal AR
## 5 1854 Jan 188.5 Ardara 15 180787.7 394679 Donegal AR
## 6 1855 Jan 32.3 Ardara 15 180787.7 394679 Donegal AR
## 7 1856 Jan 151.6 Ardara 15 180787.7 394679 Donegal AR
## 8 1857 Jan 179.1 Ardara 15 180787.7 394679 Donegal AR
## 9 1858 Jan 110.1 Ardara 15 180787.7 394679 Donegal AR
## 10 1859 Jan 157.8 Ardara 15 180787.7 394679 Donegal AR
## Source coast_dist geometry
## 1 Briffa 17.36709 POINT (-8.290712 54.79005)
## 2 Briffa 17.36709 POINT (-8.290712 54.79005)
## 3 Briffa 17.36709 POINT (-8.290712 54.79005)
## 4 Briffa 17.36709 POINT (-8.290712 54.79005)
## 5 Briffa 17.36709 POINT (-8.290712 54.79005)
## 6 Briffa 17.36709 POINT (-8.290712 54.79005)
## 7 Briffa 17.36709 POINT (-8.290712 54.79005)
## 8 Briffa 17.36709 POINT (-8.290712 54.79005)
## 9 Briffa 17.36709 POINT (-8.290712 54.79005)
## 10 Briffa 17.36709 POINT (-8.290712 54.79005)
#read in counties
counties <- st_read('counties.geojson') %>% st_transform(4326)
## Reading layer `counties' from data source
## `/Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversity/GY672[A] — Analysing Spatial and Temporal Data Using R/Class Materials-20250924/counties.geojson'
## using driver `GeoJSON'
## Simple feature collection with 40 features and 2 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 17528.59 ymin: 19537.25 xmax: 366403.6 ymax: 466923.2
## Projected CRS: TM65 / Irish Grid
counties # looking at our rainfall data using geojson
## Simple feature collection with 40 features and 2 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: -10.66221 ymin: 51.41943 xmax: -5.432885 ymax: 55.44661
## Geodetic CRS: WGS 84
## First 10 features:
## County mean_rain geometry
## 1 Antrim 77.71545 MULTIPOLYGON (((-6.054397 5...
## 2 Armagh 77.71545 MULTIPOLYGON (((-6.353978 5...
## 3 Carlow County 92.14104 MULTIPOLYGON (((-6.708988 5...
## 4 Cavan County 72.24133 MULTIPOLYGON (((-7.923589 5...
## 5 Clare County 100.73245 MULTIPOLYGON (((-9.090629 5...
## 6 Cork City 100.00000 MULTIPOLYGON (((-8.476869 5...
## 7 Cork County 107.23233 MULTIPOLYGON (((-10.2472 51...
## 8 Donegal County 104.23685 MULTIPOLYGON (((-8.832665 5...
## 9 Down 77.71545 MULTIPOLYGON (((-6.079602 5...
## 10 Dublin City 62.23451 MULTIPOLYGON (((-6.224726 5...
The st_transform function allows us to convert the
geometry points in the data sets to latitude and longitude
co-coordinates. Which will help us manipulate and map the data
later.
Median rainfall for January in each station was filtered and calculated from the data in the period 1850-2014.
rainfall %>% filter(Month == 'Jan') %>% group_by(Station, County) %>%
summarise(median_rain_jan = median(Rainfall, na.rm = TRUE)) -> median_jan_rainfall
## `summarise()` has grouped output by 'Station'. You can override using the
## `.groups` argument.
After this process of data manipulation, visually checking the new
median_jan_rainfall data set is a good way to identify any
irregularities or errors that may have occurred in the previous
step.
head(median_jan_rainfall)
## Simple feature collection with 6 features and 3 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -8.290712 ymin: 52.19037 xmax: -5.991011 ymax: 54.79005
## Geodetic CRS: WGS 84
## # A tibble: 6 × 4
## # Groups: Station [6]
## Station County median_rain_jan geometry
## <chr> <chr> <dbl> <POINT [°]>
## 1 Ardara Donegal 172. (-8.290712 54.79005)
## 2 Armagh Armagh 75 (-6.640924 54.35011)
## 3 Athboy Meath 87.1 (-6.930877 53.6002)
## 4 Belfast Antrim 102. (-5.991011 54.5001)
## 5 Birr Offaly 77.5 (-7.88075 53.08026)
## 6 Cappoquinn Waterford 147. (-7.800753 52.19037)
tail(median_jan_rainfall)
## Simple feature collection with 6 features and 3 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -10.23045 ymin: 51.79042 xmax: -7.090842 ymax: 53.75018
## Geodetic CRS: WGS 84
## # A tibble: 6 × 4
## # Groups: Station [6]
## Station County median_rain_jan geometry
## <chr> <chr> <dbl> <POINT [°]>
## 1 Roches Point Cork 111 (-8.240696 51.79042)
## 2 Shannon Airport Clare 92.9 (-8.920616 52.68031)
## 3 Strokestown Roscommon 102. (-8.100728 53.75018)
## 4 University College Galway Galway 124. (-9.060602 53.27024)
## 5 Valentia Kerry 166 (-10.23045 51.9304)
## 6 Waterford Waterford 103. (-7.090842 52.29037)
Following this, a file name was created for each station. This will
later be added to median_jan_rainfall as this will be used
for the embedded Popup images as part of the finalised
interactive map object. To prevent errors in joining the data sets, we
will ensure that the sf object geometry is
dropped, and only include Station and Filename
variables in the file object. This prevents issues that
arise when joining two data sets which have sf objects in
them, and also where variable names can become duplicated.
# make a filename for each station
median_jan_rainfall %>% st_drop_geometry() %>% mutate(Filename=file.path(getwd(),paste0(Station,'.png'))) %>% select(Station, Filename) -> files
files %>% head
## # A tibble: 6 × 2
## # Groups: Station [6]
## Station Filename
## <chr> <chr>
## 1 Ardara /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
## 2 Armagh /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
## 3 Athboy /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
## 4 Belfast /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
## 5 Birr /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
## 6 Cappoquinn /Users/willryanuni/Library/CloudStorage/OneDrive-MaynoothUniversit…
tmap_mode('view')
## ℹ tmap modes "plot" - "view"
## ℹ toggle with `tmap::ttm()`
tm_start_map <- tm_basemap(leaflet::providers$CartoDB.Positron) + tm_shape(counties) + tm_borders(lwd = 0.5)
tm_start_map
In the loop below, bar chart plots for each station were created so
that they can be assigned to the Filename object created
above (In the Section: Create a filename for each
station). It is designed so that as the loop is going through each
row in the files object, it will identify the current
station and the median rainfall value associated with it.
This allows us to assign a colour that highlights the specific station in the graph for all 25 stations. Enabling us to visually see in the bar chart how the particular station compares to others. As we are using a median rainfall value for each station, and not values across a time series, it is important to find clear way which show the single variable, and how it changes spatially.
# Loop through each station to create a bar chart highlighting the specific weather station
for (i in 1:nrow(files)) {
current_station <- files$Station[i]
# Get rainfall value
current_rainfall <- median_jan_rainfall %>%
filter(Station == current_station) %>%
pull(median_rain_jan)
# Assign fill colour for highlighting
median_jan_rainfall$fill_colour <- ifelse(
median_jan_rainfall$Station == current_station,
"#006778",
"lightgrey"
)
# Open PNG device
png(files$Filename[i], width = 500, height = 300)
# Plot
station_plot <- ggplot(median_jan_rainfall, aes(x = Station, y = median_rain_jan, fill = fill_colour)) +
geom_bar(stat = "identity") +
scale_fill_identity() +
theme_minimal() +
coord_cartesian(ylim = c(0, 200)) +
labs(
title = paste("Median January Rainfall for", current_station,
paste0("(", round(current_rainfall, 2), " mm)")),
x = "Station",
y = "Median Rainfall (mm)"
) +
theme(
plot.title = element_text(size = 13, face = "bold"),
axis.title.x = element_text(size = 13, face = "bold"),
axis.title.y = element_text(size = 13, face = "bold"),
axis.text.x = element_text(angle = 45,size = 10, face = "bold", hjust = 1),
axis.text.y = element_text(size = 10, face = "bold")
)
# Print and save
print(station_plot)
dev.off()
}
Popup images into filesUsing the mutate function, the Popup images
created in the loop above can be linked with their Filename
in the files object.
# add popups
files %>% mutate(Popup=paste0('<img src="',Filename,'">')) -> files
files %>% select(Station,Popup) %>% head
## # A tibble: 6 × 2
## # Groups: Station [6]
## Station Popup
## <chr> <chr>
## 1 Ardara "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
## 2 Armagh "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
## 3 Athboy "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
## 4 Belfast "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
## 5 Birr "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
## 6 Cappoquinn "<img src=\"/Users/willryanuni/Library/CloudStorage/OneDrive-Mayno…
Filename with the January median rainfall
variables in median_jan_rainfallmedian_jan_rainfall %>% left_join(files, by = "Station") %>%
select(Station, median_rain_jan, Filename) -> Station_jan_med_rainfall
leaflet to convert the tmap object and
add Popup imagestmap_leaflet(tm_start_map) %>% addCircleMarkers(data = Station_jan_med_rainfall,
popup=popupImage(Station_jan_med_rainfall$Filename,embed=TRUE))
Now that the Filename, interactive map object and
Popup images have been created, we can bring it all
together in the final interactive map of this blog. Note that
tmap has been overhauled in its newest version (v4), and
uses updated syntax compared to v3. Two useful resources that were
invaluable in overcoming this learning curve were the tmap website on
github and the book Spatial
Data Visualization with tmap . Both are excellent resources, and
highly recommended for working with spatial data in R. I will rely on
them in the future for sure!
tm_start2 <- tm_shape(Station_jan_med_rainfall) +
tm_dots(
fill = "median_rain_jan",
popup.vars = FALSE,
fill.scale = tm_scale(values = "brewer.blues"),
fill.legend = tm_legend(title = "Median January Rainfall: 1850-2014 (mm) ", reverse = TRUE),
size = 0.8
) +
tm_shape(counties) +
tm_borders(lwd = 0.5)
tmap_leaflet(tm_start2) %>%
addCircleMarkers(data=Station_jan_med_rainfall,stroke = NA,
popup=popupImage(Station_jan_med_rainfall$Filename,embed=TRUE))
We can see from the interactive map (Section: [3. Bringing it all
together 📈]) that coastal weather stations experienced higher median
January rainfall levels compared to inland weather stations. The three
stations that recorded the highest median levels for this period were
Killarney (177.7 mm), Ardara (171.6 mm) and
Valentia (166 mm); all of which are located on the west
coast. The image below shows the annual rainfall (mm) in Ireland from Ireland’s
Climate Averages 1991-2020 report. It reveals that the patterns
identified of higher precipitation values in coastal regions, and lower
values inland are reflected by the empirical data. The report also notes
that in addition to the coastal and western location, elevation also
plays a role in increasing rainfall.
This blog shows the process of how to create an interactive map of
median rainfall in Ireland using 25 weather stations. It goes through
the steps on how to manipulate data sets to filter and select particular
variables, how to create file names, Popup images and embed
them successfully into an interactive map object using the updated
tmap package and leaflet. Further work to
improve the map could be to include how the Elevation and
coastal distance (coast_dist) variables in the
weather_stations.geojson data set can further explain the
spatial patterns identified from this blog! Thanks for reading the first
entry for January 2026, maybe the next blog can show how these
observations compare to the rainfall records collected during this
month?
Happy mapping!