This made the rounds on social media last week:
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.
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
geom_point()to do the heavy lifting
- colors the segments by year using the
viridispalette (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.220.127.116.11.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
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
- less verbose
viridisis 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.
You can find the source for both the R & D3 visualizations on github.