Global Temperature Change in R & D3 (without the vertigo)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This made the rounds on social media last week:
Spiraling global temperatures from 1850-2016 (full animation) https://t.co/YETC5HkmTr pic.twitter.com/Ypci717AHq
— Ed Hawkins (@ed_hawkins) May 9, 2016
One of the original versions was static and was not nearly as popular, but—as you can see—this one went viral.
Despite the public’s infatuation with circles (I’m lookin’ at you, pie charts), I’m not going to reproduce this polar coordinate visualization in ggplot2. I believe others have already done so (or are doing so) and you can mimic the animation pretty easily with coord_polar()
and @drob’s enhanced ggplot2 animation tools.
NOTE: If you’re more interested in the stats/science than a spirograph or colorful D3 animation (below), Gavin Simpson (@ucfagls) has an awesome post with a detailed view of the HadCRUT data set.
HadCRUT in R
I noticed that the original data source, had 12 fields, two of which (columns 11 & 12) are the lower+upper bounds of the 95% confidence interval of the combined effects of all the uncertainties described in the HadCRUT4 error model (measurement and sampling, bias and coverage uncertainties). The spinning vis of doom may be mesmerizing, but it only shows the median. I thought it might be fun to try to make a good looking visualization using the CI as well (you can pick one of the other pairs to try this at home), both in R and then in D3. I chose D3 for the animated version mostly to play with the new 4.0 main branch, but I think it’s possible to do more with dynamic visualizations in D3 than it is with R (and it doesn’t require stop-motion techniques).
The following code:
- reads in the data set (and saves it locally to be nice to their bandwidth bill)
- does some munging to get fields we need
- saves a version out for use with D3
- uses
geom_segment()
+geom_point()
to do the heavy lifting - colors the segments by year using the
viridis
palette (the Plasma version) - labels the plot by decade using facets and some fun facet margin “tricks” to make it look like the x-axis labels are on top
library(readr) # read_table() / write_csv() library(dplyr) library(zoo) # as.yearmon() library(ggplot2) # devtools::install_github("hadley/ggplot2") library(hrbrmisc) # devtools::install_github("hrbrmstr/hrbrmisc") library(viridis) URL <- "http://www.metoffice.gov.uk/hadobs/hadcrut4/data/current/time_series/HadCRUT.4.4.0.0.monthly_ns_avg.txt" fil <- sprintf("data/%s", basename(URL)) if (!file.exists(fil)) download.file(URL, fil) global_temps <- read_table(fil, col_names=FALSE) global_temps %>% select(year_mon=1, median=2, lower=11, upper=12) %>% mutate(year_mon=as.Date(as.yearmon(year_mon, format="%Y/%m")), year=as.numeric(format(year_mon, "%Y")), decade=(year %/% 10) * 10, month=format(year_mon, "%b")) %>% mutate(month=factor(month, levels=month.abb)) %>% filter(year != 2016) -> global_temps # for D3 vis write_csv(global_temps, "data/temps.csv") #+ hadcrut, fig.retina=2, fig.width=12, fig.height=6 gg <- ggplot(global_temps) gg <- gg + geom_segment(aes(x=year_mon, xend=year_mon, y=lower, yend=upper, color=year), size=0.2) gg <- gg + geom_point(aes(x=year_mon, y=median), color="white", shape=".", size=0.01) gg <- gg + scale_x_date(name="Median in white", expand=c(0,0.5)) gg <- gg + scale_y_continuous(name=NULL, breaks=c(0, 1.5, 2), labels=c("0°C", "1.5°C", "2.0°C"), limits=c(-1.6, 2.25)) gg <- gg + scale_color_viridis(option="C") gg <- gg + facet_wrap(~decade, nrow=1, scales="free_x") gg <- gg + labs(title="Global Temperature Change (1850-2016)", subtitle="Using lower and upper bounds of the 95% confidence interval of the combined effects of all the uncertainties described in the HadCRUT4 error model (measurement and sampling, bias and coverage uncertainties; fields 11 & 12)", caption="HadCRUT4 (http://www.metoffice.gov.uk/hadobs/hadcrut4/index.html)") gg <- gg + theme_hrbrmstr_my(grid="XY") gg <- gg + theme(panel.background=element_rect(fill="black", color="#2b2b2b", size=0.15)) gg <- gg + theme(panel.margin=margin(0,0,0,0)) gg <- gg + theme(panel.grid.major.y=element_line(color="#b2182b", size=0.25)) gg <- gg + theme(strip.text=element_text(hjust=0.5)) gg <- gg + theme(axis.title.x=element_text(hjust=0, margin=margin(t=-10))) gg <- gg + theme(axis.text.x=element_blank()) gg <- gg + theme(axis.text.y=element_text(size=12, color="#b2182b")) gg <- gg + theme(legend.position="none") gg <- gg + theme(plot.margin=margin(10, 10, 10, 10)) gg <- gg + theme(plot.caption=element_text(margin=margin(t=-6))) gg
My theme_hrbrmstr_my()
required the Myriad Pro font, so you’ll need to use one of the other themes in the hrbrmisc
package or fill in some theme()
details on your own.
HadCRUT in D3
While the static visualization is pretty, we can kick it up a bit with some basic animations. Rather than make a multi-file HTML+js+D3+CSS example, this is all self-contained (apart from the data) in a single index.html
file (some folks asked for the next D3 example to be self-contained).
Some nice new features of D3 4.0 (that I ended up using here):
- easier to use
scale
s - less verbose
axis
creation viridis
is now a first-class citizen
Mike Bostock has spent much time refining the API for D3 4.0 and it shows. I’m definitely looking forward to playing with it over the rest of the year.
The vis is below but you can bust the iframe
via https://rud.is/projects/hadcrut4/.
I have it setup as “click to view” out of laziness. It’s not hard to make it trigger on div
scroll visibility, but this way you also get to repeat the visualization animation without it looping incessantly.
If you end up playing with the D3 code, definitely change the width. I had to make it a bit smaller to fit it into the blog theme.
Fin
You can find the source for both the R & D3 visualizations on github.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.