Replicating NYT weather App

New York Times Weather in chart

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

 

datemonthtemp_maxtemp_mintemp_rec_maxtemp_rec_mintemp_avg_maxtemp_avg_mintemp_rec_hightemp_rec_lowprecip_valueprecip_actualprecip_normalprecip_recsnow_recannual_average_temperaturedeparture_from_normaltotal_precipitationprecipitation_departure_from_normaldt
2015-01-011392762-43928NULLNULL0.005.233.65NULLNULLNANANANA1.42e+12
2015-01-02142356823928NULLNULL0.00NANANULLNULLNANANANA1.42e+12
2015-01-031423364-43928NULLNULL0.71NANANULLNANANANANA1.42e+12
2015-01-041564166-33927NULLNULL1.01NANANULLNULLNANANANA1.42e+12
2015-01-051492164-43827NULLNULL1.01NANANULLNULLNANANANA1.42e+12
2015-01-061221972-23827NULLNULL1.06NANANULLNULLNANANANA1.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)
dtseriemaxmin
1.42e+12Observed3927
1.42e+12Normal3928
1.42e+12Record62-4
1.42e+12Observed4235
1.42e+12Normal3928
1.42e+12Record682

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 

dttypevalue
1.44e+12This year record high95
1.44e+12This year record high97
1.45e+12This year record high74
1.45e+12This year record high67
1.45e+12This year record high67
1.45e+12This year record high68
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!