Highcharter Cookbook

A cookbook for using the highcharter R package

Overview

What

highcharter is an R implementation of the highcharts javascript library, enabled by R’s htmlwidgets package. Most of the highcharts functionality is implemented through highcharter however the documentation is a little light. This guide will provide examples on how to create and customise various graphs whilst providing some tips on how to think about the package that will help you build and debug your more ambitious charts. I’ll try to show and explain (to the best of my knowledge) the most common graphs and customisation options I use in my day-to-day work. I assume you’re familiar with tidy data, dplyr, and R lists, as well as as simple understanding of the grammar of graphics (ggplot).

highcharts is a commercial product so you can’t add these charts to a commercial product of your own (selling to customers) without purchasing a licence but non commercial use (internal organisation / research) comes under their free license.

Your most important resources should be the highcharter official website, and the highcharts API documentation which you should bookmark in your browser:

Additionally get into styling your charts so a few extra resources you might want bookmarked:

As you become more a more proficient highcharter user and your charting requirements become more complicated you will need to understand more about the complexities of the highcharts API, you might need to write some complex list wrangling code, and you might need to learn a little javascript. This learning curve is actually the best thing about highcharter: most basic charts are as easy to create as ggplot, whilst complex and beautiful charts are still achievable with enough thought and tinkering.

When & Why

highcharter is a perfect compliment for ggplot. Depending on your needs you it might not completely replace your use of that library, but it may. ggplot has a number of functional advantages over highcharter as it has simple implementations of reasonably complex chart types, a huge ecosymstem of satellite packages, and tons of smarts built into the charting functions. However, I’d say I use highcharter for 90% of my day to day plots.

If you’re doing any of the following you might need to stick with ggplot:

  • Semi-complicated facetting
  • Complicated multi chart arrangements
  • Standard statistical layers / geoms like smooths and confidence intervals and error bars etc.
  • Animations (before you get very comfortable with highcharter)
  • Many more

So why would you use highcharter at all then? The answer is that it has a huge number of functional and stylistic advantages over it’s static counterparts. Data analytics & data science outputs are becoming almost exclusively viewable through web browsers so it’s extremely valuable to be able to create charts that are built to be viewed in a web browser. ggvis was supposed to be this solution and a successor to ggplot but it is half built and it’s development has been delayed indefinitely. highcharter is somewhat limited compared with ggplot, however, that’s not an indictment because ggplot is probably the most mature charting library in data analytics history. The most important point to emphasise though is impact. The impact of suprising your stakeholders with interactive, clean, and aesthetically appealing charts is hugely underated and you’re exponentionally more likely to get buy-in on your technical work if you can pair good solid technical analysis with really shiny packaging.

Getting The Data

I’ll be illustrating highcharter functionality with an NBA dataset I’ll get from the nbastatR package.

We’ll use the gamelogs (boxscores) from the most recent complete NBA season 2018-19:

gamelogs = nbastatR::game_logs(seasons = 2019)
## Acquiring NBA basic player game logs for the 2018-19 Regular Season

Basic Charts

Tidy Data

Most (~90%) of your day-to-day charts can be probably written with 2-3 lines of code using the hchart and hcaes functions. These functions allow you to use the extremely powerful grammar of graphics to turn R data into interactive charts - functionality that isn’t implemented natively in R plotly for example. Like ggplot your data needs to be in tidy / long format so you’ll often need to use tidyr for some simple data pivotting before passing it to your highcharter functions.

Let’s compare a simple ggplot call for charting the top 10 scorers in the NBA this year might vs the equivolent call in highcharter.

ggplot

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(ppg = mean(pts)) %>%
  arrange(desc(ppg)) %>%
  slice(1:10) %>%
  ggplot(aes(x = namePlayer, y = ppg)) +
  geom_col()

highcharter

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(ppg = mean(pts)) %>%
  arrange(desc(ppg)) %>%
  slice(1:10) %>%
  hchart("column", hcaes(x = namePlayer, y = ppg))

The ggplot version, let’s be honest here, looks awful. ggplot needs to do a better job of creating pleasing default charts and themes to entice beginners. ggplot has also chosen to alphabetize the players on the x-axis even though I specifically ordered the dataframe in descending points per game order, a reasonbaly challenging workaround is needed for an R beginner. highcharter, on the other hand, creates readable, nice looking default charts that can be presented naturally in a widely used publishing format (a html page).

The highcharter chart doesn’t look that nice, but there’s some notable format based advantages to the ggplot version:

  • You can interact with it - hover over it to see a (relatively ugly) tooltip
  • It’s dynamic - reduce the width of your browser window to see the chart react and replot as it tries to estimate the best way to present the data without it looking busy and cluttered

Chart Types

There are many chart types available in higcharts which you can see here however, I’ll go through simple calls for the most common chart types.

Column

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  hchart("column", hcaes(x = namePlayer, y = apg)) %>%
  hc_title(text = "Assists Per Game")

Bar

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  hchart("bar", hcaes(x = namePlayer, y = apg)) %>%
  hc_title(text = "Assists Per Game")

Scatter

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(orebpg = mean(oreb), drebpg = mean(dreb), trebpg = mean(treb)) %>%
  arrange(desc(trebpg)) %>%
  slice(1:30) %>%
  hchart("scatter", hcaes(x = drebpg, y = orebpg)) %>%
  hc_title(text = "Off. Rebounds vs Def. Rebounds")

Bubble

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(orebpg = mean(oreb), drebpg = mean(dreb), trebpg = mean(treb)) %>%
  arrange(desc(trebpg)) %>%
  slice(1:30) %>%
  hchart("scatter", hcaes(x = drebpg, y = orebpg, size = trebpg)) %>%
  hc_title(text = "Off. Rebounds vs Def. Rebounds")

Line

gamelogs %>%
  filter(namePlayer == "Luka Doncic") %>%
  hchart("line", hcaes(x = numberGamePlayerSeason, y = pts)) %>%
  hc_title(text = "Luka Doncic Points")

Spline

Splines have smoothed edges

gamelogs %>%
  filter(namePlayer == "Luka Doncic") %>%
  hchart("spline", hcaes(x = numberGamePlayerSeason, y = pts)) %>%
  hc_title(text = "Luka Doncic Points")

Area

gamelogs %>%
  filter(namePlayer == "Jonathan Isaac") %>%
  hchart("area", hcaes(x = numberGamePlayerSeason, y = blk)) %>%
  hc_title(text = "Jonathan Isaac Blocks")

There is an areaspline (smoothed edges) too.

Treemap

gamelogs %>%
  filter(slugTeam == "TOR") %>%
  group_by(namePlayer) %>%
  summarise(pts = sum(pts), fgpct = sum(fgm) / sum(fga)) %>%
  hchart("treemap", hcaes(name = namePlayer, value = pts, color = fgpct)) %>%
  hc_title(text = "Raptors Scoring") %>%
  hc_subtitle(text = "Shaded by Field Goal %")

Maps

Not yet completed…

Layering Elements

As you can see from the code for some of these charts highcharter is much like ggplot where charts are built with layers. The good thing about highcharter layers is that they are layered with the pipe %>% operator rather than ggplots plus operator +. Layering is an excellent pattern for charting as chart objects can be passed further down scripts and altered / ammended by simply taking the current chart object and piping more layers onto it.

Layering Different Charts (geoms)

Layering series onto the same chart works much like ggplot. It’s a little bet less natural as the data object must be supplied each time which prevents big long data into highcharter chanins. The additional layers, added with hc_add_series() can be added with exactly the same pattern as your initial hchart() call. It’s good practice to name your series. You can specifically add them to the legend with the showInLegend option.

drum = 
  gamelogs %>%
  filter(namePlayer == "Andre Drummond") %>%
  arrange(numberGamePlayerSeason) 

hchart(drum, "column", hcaes(x = numberGamePlayerSeason, y = dreb), name = "Defensive Boards", showInLegend = TRUE) %>%
  hc_add_series(drum, "column", hcaes(x = numberGamePlayerSeason, y = oreb), name = "Offensive Boards", showInLegend = TRUE) %>%
  hc_title(text = "Andre Drummond Rebounds")

Series don’t have to be the same type either obviously

hchart(drum, "column", hcaes(x = numberGamePlayerSeason, y = dreb), name = "Defensive Boards", showInLegend = TRUE) %>%
  hc_add_series(drum, "areaspline", hcaes(x = numberGamePlayerSeason, y = oreb), name = "Offensive Boards", showInLegend = TRUE) %>%
  hc_add_series(drum, "scatter", hcaes(x = numberGamePlayerSeason, y = treb), name = "Total Boards", showInLegend = TRUE) %>%
  hc_title(text = "Andre Drummond Rebounds")

Understanding The API

The most important thing to learn about this package is how the relatively undocumented R functions map onto the actual highcharts javascript library. The way these htmlwidgets packages work is consuming R dataframes and R instructions and turning them into the javascript code, that when embedded into your output html page, will display the particular chart you wanted to create.

Once you understand this concept you’ll no longer be limited by the package documentation, or Josh Kunst’s highcharter showcase website. You’ll be able to build many, many different charts with near unlimited customisation.

To illustrate how to write R highcharter code from just the javascript API documentation we’ll isolate a relatively simple component: a chart’s y axis.

A Simple Example

To customise a highcharter y axis you need to use the hc_yAxis() function. Let’s have a look at the documentation in R for that function.

help(hc_yAxis)

There is some example customisation supplied in the examples which can be very helpful, but is still limited to a few examples.

However, it might not click with you immediately what’s required or valid as an input for the hc_yAxis() function.

  • How do I know what arguments I can use for this function?

The answer is to refer to the API documentation. Let’s check the actual highcharts API documentation for a highcharts y Axis. You can find it yourself here but a screen shot of the page looks like this:

The arguments in the green rectangle (there are more than shown) is an exhaustive list of the customisation options for a highcharts y axis. There are nearly 50 different arguments for a y axis that will change the way your charts looks or works. You can use any of them (provided highcharter stays up to date) in your R function calls.

  • These don’t look like R arguments, how do I write then into my R function?

The highcharts javascript API is expecting a JSON packet to define all y axis options. In other words:

  • Some options are single strings
  • Some are booleans
  • Some are numbers
  • But some are arrays of numbers or strings
  • And and some are yet more self-contained JSON packets

highcharter will make the conversion provided you supply the options as an appropriately structured and named R list. It’s easiest to see this in an example.

Simple Arguments

Starting simply using a couple of the simple boolean chart options we can adjust the gridLineWidth to 10 which will make the major grid lines extremely thick and change the dash style to shortdash. We know we can enter the string shortdash as a possible option for the grid line dash style because when we click on that option in the API documentation it links us to another page which shows us the valid options:

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  hchart("column", hcaes(x = namePlayer, y = apg)) %>%
  hc_title(text = "Assists Per Game") %>%
  hc_yAxis(
    gridLineWidth = 10,
    gridLineDashStyle = "shortdash"
  )

Without going to this page on the documentation we’d be completely in the dark about the valid values for gridLineDashStyle were. That’s why understanding this API documentation / highcharter link is the only way to use this package.

Nested Arguments

Your most common form of axis customisation will be probably be the title and labels on the axis. Here’s the documentation for a Y axis title

Notice the dropdown icons and nested arguments. They tell us that the axis title should be defined by it’s own JSON packet within the broader y axis configuration. Further any styling you want to add to the title should be another JSON packet (we’ll get to this part next). To correctly create this JSON packet in R we use named lists.

When using the documentation all you should think is when I see a nested JSON packet with a dropdown marker / open curly braces I need to start a new R list.

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  hchart("column", hcaes(x = namePlayer, y = apg)) %>%
  hc_title(text = "Assists Per Game") %>%
  hc_yAxis(
    gridLineWidth = 10,
    gridLineDashStyle = "shortdash",
    title = list(
        text = "Assists Per Game", # The actual title text
        align = "high",            # Documentation says options are: low, middle or high
        margin = 10                # Number of pixels between the title and the axis line
    )
  )

It’s as simple as that. Any argument listed in the highcharts API documentation, whether it’s a simple string or number or another nested JSON packet, can be inserted into the appropriate R function call using the right syntax. Failure to name the arguments properly or nest the options appropriately won’t cause a fatal error for your chart (in most instances) the options just won’t be successfully added to the chart (this can be frustrating debugging at times tbh).

Style (CSS)

The style argument is a special case available on many highcharts components. In the documentation for y axis above, only color is listed as an option in the style section but it’s not nearly the only option. If you’ve done a little bit more web coding you’ll know that what it’s referring to is CSS style. Any CSS property can be added to a highcharter component that has this style argument. In this case we’ll be defining the CSS properties to adjust on the chart title. A list of CSS properties can be found here.

What to watch for here is that CSS properties are often hyphenated words (like font-weight) which won’t play perfectly nicely in R lists so you should define properties in your R lists with camel case version of these property names (eg. fontWeight). As an example we’ll make the chart title bold, slightly larger and the color of the columns like so:

gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  hchart("column", hcaes(x = namePlayer, y = apg)) %>%
  hc_title(text = "Assists Per Game") %>%
  hc_yAxis(
    gridLineWidth = 10,
    gridLineDashStyle = "shortdash",
    title = list(
        text = "Assists Per Game", # The actual title text
        align = "high",            # Documentation says options are: low, middle or high
        margin = 10,               # Number of pixels between the title and the axis line
        style = list(
            fontWeight = "bold",   # Bold
            fontSize = '1.4em',    # 1.4 x tthe size of the default text
            color = "#7cb5ec"      # Hex code for the default blue
        )
    )
  )

Chart Data

Not only are the various chart features understandable and configurable from referencing the javascript API documentation but the data itself (the mapping between R dataframe rows and columns to highcharts data structures you normally just let hchart() do on your behalf) is understandable in the same way.

Building your own nested lists to bypass the normal hchart() approach is a very useful tool to have at your disposal but is overkill for 99% of charts that can be built with a simpler approach. It is, however, helpful to understand and if you want to make highly bespoke charts you’ll probably need to understand how this works.

Columns

Let’s check the API documentation for a column graph. We’ll find the specification for each chart type under the series > sub header.

What we’re interested in is the series > column > data entry which tells us the viable formats to enter the data for a column chart:

The documentation says we can enter the data in 3 different ways:

  1. A simple array of numerical values
  2. A array of arrays with x, y value pairs
  3. An array of objects (JSON packets) with each object defining a single data point

Let’s try to implement the assists chart in each of these 3 ways but without the help of hchart().

Option 1: Simple Array

The first option says data can be presented as a simple array of values. When we see JSON “array” we should generally think of R lists but sometimes an R vector works too.

# Get list of top-10 league leaders in assists
assists = 
  gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast)) %>%
  arrange(desc(apg)) %>%
  slice(1:10)

# Pull out names and assists / game as vectors
apg = assists %>% pull(apg)
namePlayer = assists %>% pull(namePlayer)

# The Assists Per Game Vector
apg
##  [1] 10.739726  8.718750  8.676923  8.254545  8.166667  8.155172  8.061728
##  [8]  7.978261  7.731343  7.721519

To build a highcharter chart without hchart() we need to do it in 2 steps: instantiate a highcharter plot with highchart() and then add data and chart type with hc_add_series().

highchart() %>%
hc_add_series(
  type = "column",
  data = apg
)

So it worked, but given we only passed the chart the assist per game data series it doesn’t know what players the values correspond to. Referencing the option 1 specification abover, we can add the player names to the chart in a second step by specifying axis “categories” manually:

highchart() %>%
hc_add_series(
  type = "column",
  data = apg
) %>%
hc_xAxis(categories = namePlayer)

Option 2: Array of Arrays

So this option suggests you can provide the data as an array of x, y pairs. This isn’t a perfectly natural data structure for R but we can construct a list of x, y pairs from a dataframe with the help of the list_parse2() function exported with highcharter. The reason this function has been created alongside these charting functions is exactly for this purpose. You often need to construct these specific list types if you’re building charts this way.

Hardcode List

It’s helpful to see the R code for each of these lists before we let a blackbox function build them on our behalf so we’ll repeat this pattern for the rest of these chart types. First let’s hardcode an example data series to see what the data looks like in R:

highchart() %>%
 hc_add_series(
   type = "column",
   data = list(
     list("Russell Westbrook",10.5),
     list("John Wall", 8.7),
     list("Kyle Lowry", 8.6)
   )
 )

Notice that the x values (assuming these are x,y pairs) haven’t been placed on the x axis as we’d like but rather appear as the “name” of the column when you hover over it - this is called the series name.

Generate List

Instead of manually hardcoding the list in the right structure we can construct the same structure for the top 10 players using list_parse2(). This function will create a list of length equal to the rows in your dataframe with pairs of values that come from the columns:

# Construct the list in the right format
assistsListXYPairs = 
  assists %>%
  list_parse2()

# Lets Inspect the first 2 elements
assistsListXYPairs[1:2]
## [[1]]
## [[1]][[1]]
## [1] "Russell Westbrook"
## 
## [[1]][[2]]
## [1] 10.73973
## 
## 
## [[2]]
## [[2]][[1]]
## [1] "John Wall"
## 
## [[2]][[2]]
## [1] 8.71875

That’s exactly what we were looking for, let’s pass it as the value to the data argument and add the names on as categories to finish it off

highchart() %>%
hc_add_series(
  type = "column",
  data = assistsListXYPairs
) %>%
hc_xAxis(categories = namePlayer)

Array of Objects

This is the most general and most frequently viable data specification option for a highcharts series. An array of JSON packets describing all the appropriate properties required (or possible) for the chart. In R this will be a list (array) of named lists.

Hardcode List

Again let’s harcode the named list manually to see what it looks like. We can even pass distinct column colors to illustrate that the named list configures each column independently:

highchart() %>%
 hc_add_series(
   type = "column",
   data = list(
     list(
       name = "Russell Westbrook",
       y = 10.5,
       color = "#5DA271"
      ),
     list(
       name = "John Wall", 
       y = 8.7,
       color = "#7DB58D"
      ),
     list(
       name = "Kyle Lowry", 
       y = 8.6,
       color = "#A4CBAF"
     )
   )
 )

Generate List

To achieve this list structure we use the other list parsing function list_parse() which will do the same thing as list_parse2() but preserve the names on the list. However, we do need the appropriate names inside each point specification so the column names to match up to the graph dimensions. We must first rename the columns. Best way to understand is to inspect a couple of elements:

assistsListConfig = 
  assists %>%
  rename(name = namePlayer, y = apg) %>%
  list_parse()

assistsListConfig[1:2]
## [[1]]
## [[1]]$name
## [1] "Russell Westbrook"
## 
## [[1]]$y
## [1] 10.73973
## 
## 
## [[2]]
## [[2]]$name
## [1] "John Wall"
## 
## [[2]]$y
## [1] 8.71875

Now passing as data for the series

highchart() %>%
hc_add_series(
  type = "column",
  data = assistsListConfig
) %>%
hc_xAxis(categories = namePlayer)

hc_add_series_list()

So we understand the various ways we can construct the data vectors / lists that can be passed to as the data argument in hc_add_series(). The natural extension to this process is that not just the data is defined by a correctly structured nameed list but the entire series specification is input as a named list. That’s what hc_series_add_list() expects - a single named list defining the entire series config.

  • Remember, the data, is just one component of the configuration of a series

Hardcode List

Again let’s start with the manual harcoded list first

highchart() %>%
 hc_add_series_list(
   # Parent list containing a set of N series
   list(
     # An Individual Series Config
     list(
       name = "Assists Per Game",
       type = "column",
       data = list(
         list(
           name = "Russell Westbrook",
           y = 10.5
          ),
         list(
           name = "John Wall", 
           y = 8.7
          ),
         list(
           name = "Kyle Lowry", 
           y = 8.6
         )
       )
     )
   )
 )

Everything about the series (name, type, data) is defined in a named list. This gives us the most flexibility for advanced charts, but the challenge is obviously constructing this deeply nested named list in exactly the right way. Like we’ve seen the package provides as with a number of helpers to make this more feasible however it’s normally overkill for most tasks.

Generate List

Let’s try to do the same chart again.

seriesConfigDF = 
  assists %>%
  rename(name = namePlayer, y = apg) %>%
  nest() %>%
  mutate(data = data %>% map(list_parse)) %>%
  mutate(
    name = "Assists Per Game",
    type = "column"
  )

seriesConfigDF
## # A tibble: 1 x 3
##   data        name             type  
##   <list>      <chr>            <chr> 
## 1 <list [10]> Assists Per Game column

So for us to use list_parse() appropriately here we need a single row which defines our series. On that row at the top level we need the series name, the series type and then a list column which contains the correctly structured list which we saw could be accomplished using the list_parse() function on the renamed dataframe. That’s what we have so now we can use list_parse() again on this dataframe to correctly structure the list and plot that series config list.

seriesConfig = 
  seriesConfigDF %>%
  list_parse()

highchart() %>%
 hc_add_series_list(seriesConfig) %>%
  hc_xAxis(categories = namePlayer)

Now, you might be thinking that’s a lott of work and complexity to plot this simple chart. Let’s show the power of this approach by extending this aprroach to multiple series. Notice the reasonably involved R required to build the right named list, but after that’s achieved there’s no highcharter configuration required. Hopefully this simple example will help you when you’re building your own deeply nested named lists for advanced attempts

seriesConfig = 
  gamelogs %>%
  group_by(namePlayer) %>%
  summarise(apg = mean(ast), pts = mean(pts)) %>%
  arrange(desc(apg)) %>%
  slice(1:10) %>%
  pivot_longer(-namePlayer, names_to = "stat", values_to = "y") %>%
  rename(name = namePlayer) %>%
  group_by(stat) %>%
  nest() %>%
  mutate(data = data %>% map(list_parse)) %>%
  rename(name = stat) %>%
  mutate(
    type = case_when(
      name == "apg" ~ "column",
      TRUE ~ "line"
    )
  ) %>%
  list_parse()

highchart() %>%
 hc_add_series_list(seriesConfig) %>%
 hc_xAxis(categories = namePlayer)

Conclusion

Hopefully what you should understand after these examples is that highcharts on the javascript side are just giant JSON configuration objects. Even the data is nested within the series > data slot in the appropriately structured format. On the R side a set of functions and helpers enable you to create this JSON often with only 1 or 2 lines of code. Most of the time you simply pass hchart() a tidy dataframe and let it convert your data into the JSON that will be placed inside the series config. Every now and then, though, and when you need to venture into more complicated chart types (animated charts is an example) the data specification won’t be simple and easy to construct with hchart() and you’ll need to build the raw data specification list yourself. To do so you need to know how to wrangle lists, likely with purrr, but most importantly: you need to understand the structure the javascript API needs expects. Knowing that you just fiddle around with purrr and tidyr functions till your output list looks exactly right.

Pre-Baked hchart() for different R classes

One of the awesome features Josh Kunst has built into highcharter is that, with some black box magic, hchart() supports charting of various standard R objects / classes out of the box.

The github page currently says this function current supports:

  • numeric
  • histogram
  • character
  • density
  • factors
  • ts
  • mts
  • xts
  • stl
  • ohlc
  • acf
  • forecast
  • mforecast
  • ets
  • igraph
  • dist
  • dendrogram
  • survfit

To see how this works lets have a look at a few examples of the functionality that i use regularly. This gamelog dataset doesn’t lend itself to some of these classes so I won’t show them all.

Histograms

I want to view histograms or density plots of numeric vectors very regularly. This is a simple one liner in highcharter

gamelogs %>% pull(pts) %>% hchart()

hchart() has been passed a simple numeric vector here (the points scored by players in all 19-20 NBA games), and decided that the appropriate plot is a histogram. Like other highcharts it is a highcharts object that supports the normal layering and customisation so we can add a few lines to makes the chart more readable:

gamelogs %>% pull(pts) %>% 
  hchart(name = "Player Points") %>%
  hc_xAxis(title = list(text = "Points Scored")) %>%
  hc_yAxis(title = list(text = "# times acheived")) %>%
  hc_title(text = "19-20 Box Score Points")

Densities

Similarly if we were interested in this plot but in a density form (smoothed & proportion of total cases) we can simply pass hchart() a density object created by the base density() function

gamelogs %>% 
  pull(pf) %>% 
  density() %>%
  hchart(name = "Player Fouls") %>%
  hc_xAxis(title = list(text = "Fouls")) %>%
  hc_yAxis(title = list(text = "% of time acheived")) %>%
  hc_title(text = "19-20 Box Score Fouls")

Character / Factor Counts

Like the numeric vector example suppling hchart() with a character vector or factor vector will create a plot of the value counts within the vector.

gamelogs %>% pull(slugTeamWinner) %>% hchart(name="Total Winning Games Per Player")

Forecast

To show a more elaborate implementation a forecast created with the forecast package is plotted automatically as follows

gamelogs %>%
  filter(namePlayer == "Al Horford") %>%
  select(pts) %>%
  slice(1:60) %>%
  ts() %>%
  forecast() %>%
  hchart()

Correlation Matrix

Plotting a correlation matrix from a base R correlation analysis is also simple and easy. Notice the huge presentation and clutter advantage of interactivity for a chart type like this.

gamelogs %>%
  select(pts, minutes, treb, dreb, oreb) %>%
  cor() %>%
  hchart()

Components + Style

Adding the right components and style to charts is my #1 rule for data visualisation. It’s your job as the visualiser to make a chart that is clear, easy to understand, and purposeful. Too many charts are presented without labels, descriptions, units or fail to convey a clear message or conclusion and it’s a crime (not a real crime I suppose, but a chart crime). Making your chart clean and aesthetically appealing is also a hugely underated job and has huge impact on how much effort your viewer will spend trying to absorb your chart’s insight.

This is where highcharter really shines over some of it’s htmlwidget & static competitors. highcharter is brimming with options to customise and highcharter allows natural component and option layering through the pipe operator making highcharter charts flexible and extensible.

Grids + Facetting

This is an area highcharter is genuinely much inferior to ggplot. In ggplot, facetting is natural, logical and easy. Supplmentary ggplot packages like cowplot and Thomas Pedersen’s new patchwork package enhance this process even further. Assembling a grid of highcharts split by some variable or combination of variables requires a fair bit more code. Like most things in highcharter, though, it is largely possible.

Splitting charts vertically is easy with the concept of multiple axes. Axes can be assembled with different heights / sizes to make vertical grids within charts plotting different series. You use the hc_yAxis_multiples() function instead of the single hc_yAxis() function to do this.

You can either specify the options for each y axis with named R lists like the following. When creating the initial series or adding additional series you also need to define which axis you want to chart the data against. You do this with a y axis index, obsersving that javascript is a language where indicies start at 0.

2 Axes:

harden = 
  gamelogs %>%
  filter(namePlayer == "James Harden") %>%
  select(numberGameTeamSeason, pts, treb, ast) 

hchart(harden, "column", hcaes(x = numberGameTeamSeason, y = pts), yAxis = 0) %>%
  hc_yAxis_multiples(
    list(title = list(text = "Points"), top = "0%", height = "50%"),                    # specify details of axis 1 (0 index)
    list(title = list(text = "Assists"), top = "50%", height = "50%", opposite = TRUE)  # specify details of axis 2 (1 index)
    # ... could add more axes
  ) %>%
  hc_add_series(harden, "column", hcaes(x = numberGameTeamSeason, y = ast), yAxis = 1)

With 3 axes we need to specify the top of the axis (the % of the way down the plot area) and how tall we want the axis to be. If we want 3 equal rows then each axis should be 33% (roughly) of the plot area and their starting points should be 0% (top) 33% the way down and 66% of the way down.

hchart(harden, "column", hcaes(x = numberGameTeamSeason, y = pts), yAxis = 0) %>%
  hc_yAxis_multiples(
    list(title = list(text = "Points"), top = "0%", height = "33%"),                     # specify details of axis 1 (0 index)
    list(title = list(text = "Assists"), top = "33%", height = "33%", opposite = TRUE),  # specify details of axis 2 (1 index)
    list(title = list(text = "Rebounds"), top = "66%", height = "33%")                   # specify details of axis 3 (2 index)
  ) %>%
  hc_add_series(harden, "column", hcaes(x = numberGameTeamSeason, y = ast), yAxis = 1) %>%
  hc_add_series(harden, "column", hcaes(x = numberGameTeamSeason, y = treb), yAxis = 2)

However, you’ll notice some weird spacing issues on the 3rd axis, that’s due to some little fidgety stuff about the heights and sizes of each axis. The helper function create_yaxis can create these axis specifications for you with a more simple function call. You could create the same chart like:

hchart(harden, "column", hcaes(x = numberGameTeamSeason, y = pts), yAxis = 0) %>%
  hc_yAxis_multiples(
    create_yaxis(
      naxis = 3,                                                       # 3 different y axes
      heights = c(1,1,1),                                              # All equal
      turnopposite = TRUE,                                             # Alternate left-right sides of the axes
      title = map(c("Points", "Asissts", "Rebounds"), ~list(text = .)) # Needs a list like: list(list(text = 'Points'), list(text = 'Assists'),...)
    )
  ) %>%
  hc_add_series(harden, "column", hcaes(x = numberGameTeamSeason, y = ast), yAxis = 1) %>%
  hc_add_series(harden, "column", hcaes(x = numberGameTeamSeason, y = treb), yAxis = 2)