đź’™ Helping others maximise the impact of their expertise
The main aim for today
Create a basic ggplot
See how we can make it better
Colour
Text
Theme
Annotations
Interactivity
The main aim for today
Data from Scottish Environment Protection Agency
https://www2.sepa.org.uk/rainfall/
{ggplot2}
Namespacing
❌ library(dplyr)
✔️ dplyr::mutate
Let’s get some data!
Let’s get some data
rain_data <-read.csv("https://www2.sepa.org.uk/rainfall/api/Month/15201?csv=true",header = T) |> dplyr::mutate(city ="Edinburgh") |> dplyr::bind_rows(read.csv("https://www2.sepa.org.uk/rainfall/api/Month/327234?csv=true",header = T) |> dplyr::mutate(city ="Glasgow")) |># May data is incomplete dplyr::filter(Timestamp !="May 2024") |> tidyr::separate(Timestamp, into =c("month", "year"), remove = F) |># Make the years back into numbers dplyr::mutate(year =as.numeric(as.character(year))) |># Get month factor levels in right order dplyr::mutate(month =factor(month, levels = month.abb))
X Timestamp month year Value city
1 1 Jun 2014 Jun 2014 67.4 Edinburgh
2 2 Jul 2014 Jul 2014 35.2 Edinburgh
3 3 Aug 2014 Aug 2014 90.0 Edinburgh
4 4 Sep 2014 Sep 2014 20.6 Edinburgh
5 5 Oct 2014 Oct 2014 92.4 Edinburgh
6 6 Nov 2014 Nov 2014 9.8 Edinburgh
7 7 Dec 2014 Dec 2014 51.4 Edinburgh
8 8 Jan 2015 Jan 2015 50.2 Edinburgh
9 9 Feb 2015 Feb 2015 27.2 Edinburgh
10 10 Mar 2015 Mar 2015 51.2 Edinburgh
Now for a basic plot…
Now for a basic plot
library(ggplot2)rain_data |> dplyr::group_by(month, city) |> dplyr::summarise(mean_rainfall =mean(Value)) |>ggplot() +geom_bar(aes(x = month, y = mean_rainfall, fill = city),stat ="identity")
Now for a basic plot
library(ggplot2)rain_data |> dplyr::group_by(month, city) |> dplyr::summarise(mean_rainfall =mean(Value)) |>ggplot() +geom_bar(aes(x = month, y = mean_rainfall, fill = city),stat ="identity") +theme_minimal()
Now for a basic plot
library(ggplot2)rain_data |> dplyr::group_by(month, city) |> dplyr::summarise(mean_rainfall =mean(Value)) |>ggplot() +geom_bar(aes(x = month, y = mean_rainfall, fill = city),stat ="identity",position ="dodge") +theme_minimal()
Now for a basic plot
“Wait a minute…” | Check it’s the right type of plot!
rain_data |>ggplot() +geom_point(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city)) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024.") +theme_minimal() +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +theme(axis.title =element_blank(),legend.title =element_blank())
Now for a basic plot
Make the y axis clearer
rain_data |>ggplot() +geom_point(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city)) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024.") +theme_minimal() +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_y_continuous(labels =function(x) paste(x, "mm")) +theme(axis.title =element_blank(),legend.title =element_blank())
#1 Use meaningful colours
#1 Use meaningful colours
Make it easier to remember what’s what
Blend in some brand colours
Check for accessibility
Implement!
#1 Use meaningful colours
Glasgow and Edinburgh
rain_data |> dplyr::group_by(month, city) |> dplyr::summarise(mean_rainfall =mean(Value)) |>ggplot() +geom_bar(aes(x = month, y = mean_rainfall, fill = city),position ="dodge",stat ="identity") +theme_minimal()
rain_data |>ggplot() +geom_jitter(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city),size =5,width =0.05,height =0) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024.") +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none")
#1 Use meaningful colours
Glasgow and Edinburgh over the years
rain_data |>ggplot() +geom_jitter(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year),size =5,width =0.05,height =0) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024.") +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none")
#1 Use meaningful colours
Glasgow and Edinburgh over the years
rain_data |>ggplot() +geom_jitter(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year),size =5,width =0.05,height =0) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none")
#2 Optimise text
#2 Optimise text
Starting point
basic_plot <- rain_data |>ggplot() +geom_jitter(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year),size =5,width =0.05,height =0) +labs(title ="Rainfall in Glasgow and Edinburgh over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none")basic_plot
themed_plot + geomtextpath::geom_labelhline(aes(yintercept =mean(Value),label =paste("Mean (Edinburgh & Glasgow): ", round(mean(Value)), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.9,colour ="#10090E",hjust =0.9) + geomtextpath::geom_labelhline(aes(yintercept =107.5,label =paste("Mean monthly UK rainfall: ", round(107.5), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.8,linetype =2,colour ="#2B2529",hjust =0.9) + ggtext::geom_textbox(data = dplyr::filter(rain_data, Value ==max(Value)),aes(x =as.numeric(month) +0.3, y = Value -20, label =paste0("The wettest month in the dataset was recorded in ", month, " in ", city, " with a total rainfall of ", Value, " mm.")),hjust =0, halign =0,fill =NA, box.colour =NA,colour ="#10090E",family ="Nunito Sans")
#4 Add annotations for context
Highlight interesting observations
themed_plot + geomtextpath::geom_labelhline(aes(yintercept =mean(Value),label =paste("Mean (Edinburgh & Glasgow): ", round(mean(Value)), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.9,colour ="#10090E",hjust =0.9) + geomtextpath::geom_labelhline(aes(yintercept =107.5,label =paste("Mean monthly UK rainfall: ", round(107.5), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.8,linetype =2,colour ="#2B2529",hjust =0.9) + ggtext::geom_textbox(data = dplyr::filter(rain_data, Value ==max(Value)),aes(x =as.numeric(month) +0.3, y = Value -20, label =paste0("The wettest month in the dataset was recorded in ", month, " in ", city, " with a total rainfall of ", Value, " mm.")),hjust =0, halign =0,fill =NA, box.colour =NA,colour ="#10090E",family ="Nunito Sans") +geom_curve(data = dplyr::filter(rain_data, Value ==max(Value)),aes(x =as.numeric(month) +0.3, y = Value -20, xend =as.numeric(month), yend = Value -10),arrow =arrow(length =unit(5, "pt")),curvature =-0.2)
#4 Add annotations for context
Place legend within the title
themed_plot + geomtextpath::geom_labelhline(aes(yintercept =mean(Value),label =paste("Mean (Edinburgh & Glasgow): ", round(mean(Value)), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.9,colour ="#10090E",hjust =0.9) + geomtextpath::geom_labelhline(aes(yintercept =107.5,label =paste("Mean monthly UK rainfall: ", round(107.5), "mm")),fill ="#FEFCF7",family ="Nunito Sans",alpha =0.8,linetype =2,colour ="#2B2529",hjust =0.9) + ggtext::geom_textbox(data = dplyr::filter(rain_data, Value ==max(Value)),aes(x =as.numeric(month) +0.3, y = Value -20, label =paste0("The wettest month in the dataset was recorded in ", month, " in ", city, " with a total rainfall of ", Value, " mm.")),hjust =0, halign =0,fill =NA, box.colour =NA,colour ="#10090E",family ="Nunito Sans") +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years") +geom_curve(data = dplyr::filter(rain_data, Value ==max(Value)),aes(x =as.numeric(month) +0.3, y = Value -20, xend =as.numeric(month), yend = Value -10),arrow =arrow(length =unit(5, "pt")),curvature =-0.2) +theme(plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))
#5 Go interactive!
#5 Go interactive!
rain_data |>ggplot() +geom_jitter(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year),size =5,width =0.05,height =0) +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none") + ophelia::theme_ophelia() +theme(legend.position ="none",axis.title =element_blank(),plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))
#5 Go interactive!
Hello, {ggiraph}!
interactive_version <- rain_data |>ggplot() + ggiraph::geom_jitter_interactive(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year),size =5,width =0.05,height =0) +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none") + ophelia::theme_ophelia() +theme(legend.position ="none",axis.title =element_blank(),plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))ggiraph::girafe(ggobj = interactive_version)
#5 Go interactive!
interactive_version <- rain_data |>ggplot() + ggiraph::geom_jitter_interactive(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year,tooltip =paste0(city, ", ", Timestamp, "<br><b>", Value, "mm</b>")),size =5,width =0.05,height =0) +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none") + ophelia::theme_ophelia() +theme(legend.position ="none",axis.title =element_blank(),plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))ggiraph::girafe(ggobj = interactive_version)
#5 Go interactive!
Style the tooltip…
interactive_version <- rain_data |>ggplot() + ggiraph::geom_jitter_interactive(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year,tooltip =paste0(city, ", ", Timestamp, "<br><b>", Value, "mm</b>")),size =5,width =0.05,height =0) +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none") + ophelia::theme_ophelia() +theme(legend.position ="none",axis.title =element_blank(),plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))ggiraph::girafe(ggobj = interactive_version,option =list(ggiraph::opts_tooltip(css ="background-color:#2B2529;color:#FEFCF7;padding:7.5px;letter-spacing:0.025em;line-height:1.3;border-radius:5px;font-family:Nunito Sans;")))
#5 Go interactive!
… the easier way!
interactive_version <- rain_data |>ggplot() + ggiraph::geom_jitter_interactive(aes(x = dplyr::case_when(city =="Glasgow"~as.numeric(month) -0.1,TRUE~as.numeric(month) +0.1),y = Value,colour = city,alpha = year,tooltip =paste0(city, ", ", Timestamp, "<br><b>", Value, "mm</b>")),size =5,width =0.05,height =0) +labs(title ="Rainfall in <span style='color:#4f3c78'>Glasgow</span> and <span style='color:#7691b1'>Edinburgh</span> over the years",subtitle ="Each dot represents the total rainfall within a given month from 2014 to 2024. The more faded the dot, the further ago the year it represents.") +scale_alpha(range =c(0.3, 1)) +scale_x_continuous(breaks =c(1:12), minor_breaks =NULL,labels = month.abb[1:12]) +scale_colour_manual(values =c("Glasgow"="#4f3c78","Edinburgh"="#7691b1")) +theme_minimal() +theme(axis.title =element_blank(),legend.position ="none") + ophelia::theme_ophelia() +theme(legend.position ="none",axis.title =element_blank(),plot.title = ggtext::element_markdown(family ="Crimson Pro", face ="bold",colour ="#10090E",size =rel(1.6)))ggiraph::girafe(ggobj = interactive_version,option =list(ggiraph::opts_tooltip(css = ophelia::tooltip_css)))