Here comes another treatment of the well-known Tufte weather chart. This time we will use it to demonstrate how to use hc_add_series, a new feature of Highcharter package. This feature makes the more readable by allowing you to add the data argument as numeric, data frame, time series (ts, xts, ohlc) and more.
For this demonstration we will try to replicate the design of the New York Time interactive chart: How Much Warmer Was Your City in 2015, where you can choose among over 3K cities! Let’s start.
DATA
First, let’s download the source data from The New York Times, and the create an extra variable dt to store the date time in a numeric format.
library(printr) library(tidyverse) library(highcharter) library(lubridate) library(stringr) library(forcats) url_base <- "http://graphics8.nytimes.com/newsgraphics/2016/01/01/weather/assets" file <- "new-york_ny.csv" # "san-francisco_ca.csv" url_file
date | month | temp_max | temp_min | temp_rec_max | temp_rec_min | temp_avg_max | temp_avg_min | temp_rec_high | temp_rec_low | precip_value | precip_actual | precip_normal | precip_rec | snow_rec | annual_average_temperature | departure_from_normal | total_precipitation | precipitation_departure_from_normal | dt |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2015-01-01 | 1 | 39 | 27 | 62 | -4 | 39 | 28 | NULL | NULL | 0.00 | 5.23 | 3.65 | NULL | NULL | NA | NA | NA | NA | 1.42e+12 |
2015-01-02 | 1 | 42 | 35 | 68 | 2 | 39 | 28 | NULL | NULL | 0.00 | NA | NA | NULL | NULL | NA | NA | NA | NA | 1.42e+12 |
2015-01-03 | 1 | 42 | 33 | 64 | -4 | 39 | 28 | NULL | NULL | 0.71 | NA | NA | NULL | NA | NA | NA | NA | NA | 1.42e+12 |
2015-01-04 | 1 | 56 | 41 | 66 | -3 | 39 | 27 | NULL | NULL | 1.01 | NA | NA | NULL | NULL | NA | NA | NA | NA | 1.42e+12 |
2015-01-05 | 1 | 49 | 21 | 64 | -4 | 38 | 27 | NULL | NULL | 1.01 | NA | NA | NULL | NULL | NA | NA | NA | NA | 1.42e+12 |
2015-01-06 | 1 | 22 | 19 | 72 | -2 | 38 | 27 | NULL | NULL | 1.06 | NA | NA | NULL | NULL | NA | NA | NA | NA | 1.42e+12 |
SETUP
Next, we’ll create a chart framework using Highcharts library:
hc % hc_xAxis(type = "datetime", showLastLabel = FALSE, dateTimeLabelFormats = list(month = "%B")) %>% hc_tooltip(shared = TRUE, useHTML = TRUE, headerFormat = as.character(tags$small("{point.x: %b %d}", tags$br()))) %>% hc_plotOptions(series = list(borderWidth = 0, pointWidth = 4)) %>% hc_add_theme(hc_theme_smpl()) hc
Move along. Nothing to see here (as the link between the chart framework and the data has yet to be established)!
TEMPERATURE DATA
With the raw data loaded and the chart framework set, we are ready to link the data to the chart framework: I select temperature from the raw data; then, I add the it to the Highcharts object using hc_add_series:
Select temperature data
dtempgather % select(dt, starts_with("temp")) %>% select(-temp_rec_high, -temp_rec_low) %>% rename(temp_actual_max = temp_max, temp_actual_min = temp_min) %>% gather(key, value, -dt) %>% mutate(key = str_replace(key, "temp_", "")) dtempspread % separate(key, c("serie", "type"), sep = "_") %>% spread(type, value) temps % mutate(serie = factor(serie, levels = c("rec", "avg", "actual")), serie = fct_recode(serie, Record = "rec", Normal = "avg", Observed = "actual")) head(temps)
dt | serie | max | min |
---|---|---|---|
1.42e+12 | Observed | 39 | 27 |
1.42e+12 | Normal | 39 | 28 |
1.42e+12 | Record | 62 | -4 |
1.42e+12 | Observed | 42 | 35 |
1.42e+12 | Normal | 39 | 28 |
1.42e+12 | Record | 68 | 2 |
Add temperature data to the chart
hc % hc_add_series(temps, type = "columnrange", hcaes(dt, low = min, high = max, group = serie), color = c("#ECEBE3", "#C8B8B9", "#A90048")) hc
Let’s test the code and check the result:
Great! The chart looks like the one in the New York Times!
Next, let’s add a few features such as temperature records and monthly precipitation.
Temperature records feature
To add this feature, I have to filter the days with temperature records using the columnstemp_rec_high and temp_rec_low. Then, I set some options to show the points such as fill color and longer radius:
records % select(dt, temp_rec_high, temp_rec_low) %>% filter(temp_rec_high != "NULL" | temp_rec_low != "NULL") %>% dmap_if(is.character, str_extract, "\\d+") %>% dmap_if(is.character, as.numeric) %>% gather(type, value, -dt) %>% filter(!is.na(value)) %>% mutate(type = str_replace(type, "temp_rec_", ""), type = paste("This year record", type)) pointsyles
dt | type | value |
---|---|---|
1.44e+12 | This year record high | 95 |
1.44e+12 | This year record high | 97 |
1.45e+12 | This year record high | 74 |
1.45e+12 | This year record high | 67 |
1.45e+12 | This year record high | 67 |
1.45e+12 | This year record high | 68 |
hc % hc_add_series(records, "point", hcaes(x = dt, y = value, group = type), marker = pointsyles) hc
Monthly precipitation feature
This feature is a little bit tricky to set as the t data is on another axis, yet I would like to synchronize it with the main chart. To achieve that, I create a list with two axes using the create_yaxis helper, then I add those axes to the chart:
axis
I also hardcode the titles (I know this can be more elegant) and options.
axis[[1]]$title
Now, the two axes are ready and I need to supply data. I add 12 series; one for each month. But we want to associate one legend for all these 12 series. For this I use the id and linkedTo parameters. The id is a ‘p’ for the first element and NA to the other 11 elements, and here how to link those 11 elements to the first series (id = ‘p’).
precip % hc_add_series(precip, type = "area", hcaes(dt, precip_value, group = month), name = "Precipitation", color = "#008ED0", lineWidth = 1, yAxis = 1, fillColor = "#EBEAE2", id = c("p", rep(NA, 11)), linkedTo = c(NA, rep("p", 11)))
I use the same logic above to add normal precipitations by month.
precipnormal % select(dt, precip_normal, month) %>% group_by(month) %>% filter(row_number() %in% c(1, n())) %>% ungroup() %>% fill(precip_normal) hc % hc_add_series(precipnormal, "line", hcaes(x = dt, y = precip_normal, group = month), name = "Normal Precipitation", color = "#008ED0", yAxis = 1, id = c("np", rep(NA, 11)), linkedTo = c(NA, rep("np", 11)),
Are you curious about what this chart looks like now?
(drumroll!)
Voila!
hc
With R you can create a newspaper-style chart with a little data-wrangling and charting. With a little extra love, one can make the code reusable and make shiny app!
Comments
Leonardo Hermoso | 5 years ago
A lot of code is missing and the code you provide does not work. Can you fix it?
Mustapha Mekhatria | 5 years ago
Hi Leonardo,
The code works fine, please check the jsfiddle demos.
Take care
Want to leave a comment?
Comments are moderated. They will publish only if they add to the discussion in a constructive way. Please be polite.