The highcharter
Package
The highcharter
package link by Joshua Kunst has long been my favorite data visualization package in R. It created a wonderful API to the famous JS Highcharts
library. link. Although Highcharts
is not free for commercial use, but I found many functionality of it is unparalleled with other visualization packages like ploty
or sunburstR
or r2d3
.
For example, you can easily create an interactive scatterplot with ggplot2
like syntax:
data(diamonds, economics_long, mpg, package = "ggplot2")
library(tidyverse)
library(highcharter)
library(widgetframe)
l <- hchart(mpg, "scatter", hcaes(x = displ, y = hwy, group = class))
frameWidget(l, height = '400')
Or to be more flexible, use the API functions to “build” the chart and fine tuning almost any specs of your charts:
hc <- highchart() %>%
hc_xAxis(categories = citytemp$month) %>%
hc_add_series(name = "Tokyo", data = citytemp$tokyo) %>%
hc_add_series(name = "New York", data = citytemp$new_york) %>%
hc_title(text = "This is a title with <i>margin</i> and <b>Strong or bold text</b>",
margin = 20, align = "left",
style = list(color = "#90ed7d", useHTML = TRUE)) %>%
hc_subtitle(text = "And this is a subtitle with more information",
align = "left",
style = list(color = "#2b908f", fontWeight = "bold")) %>%
hc_credits(enabled = TRUE, # add credits
text = "www.link.tomy.site",
href = "http://jkunst.com") %>%
hc_legend(align = "left", verticalAlign = "top",
layout = "vertical", x = 0, y = 100) %>%
hc_tooltip(crosshairs = TRUE, backgroundColor = "#FCFFC5",
shared = TRUE, borderWidth = 5) %>%
hc_exporting(enabled = TRUE)
frameWidget(hc, height = '600')
Here. A light weighted, interactive chart with exporting ability and customized tooltip with less than 20 lines of code.
Sunburst Chart
Let’s take a look at an example of sunburst chart by official Highcharts.org (created in jsfiddle, added to this RMD document using iframe):
Sunburst chart shows hierarchy through a series of rings, that are sliced for each category node. Each ring corresponds to a level in the hierarchy, with the central circle representing the root node and the hierarchy moving outwards from it.
Rings are sliced up and divided based on their hierarchical relationship to the parent slice. The angle of each slice is either divided equally under its parent node or can be made proportional to a value.
Color can be used to highlight hierarchical groupings or specific categories.
Add Wrapper to Existing highcharter
This is very straightforward since the hc_add_series()
function provides an robust interface to Highcharts series API link. Moreover, the data structure required of sunburst chart is actually same as treemap chart.
Assume we have a dataframe with 3 levels(index1, index2 and index3), each observation is also associated with an numeric value:
library(tibble)
data <- tibble(
index0 = "Letter",
index1 = sample(LETTERS[1:5], 500, replace = T),
index2 = sample(LETTERS[6:10], 500, replace = T),
index3 = sample(LETTERS[11:15], 500, replace = T),
value = rpois(500, 5)
)
head(data)
# A tibble: 6 x 5
index0 index1 index2 index3 value
<chr> <chr> <chr> <chr> <int>
1 Letter D F N 1
2 Letter B J M 5
3 Letter A J O 4
4 Letter D J N 8
5 Letter B J M 3
6 Letter D G M 8
and remember we need to parse the data into the format that Highcharts can recognized, which is a nested list:
var data = [{
id: '0.0',
parent: '',
name: 'The World'
}, {
id: '1.3',
parent: '0.0',
name: 'Asia'
}, {
id: '1.1',
parent: '0.0',
name: 'Africa'
}, {
id: '1.2',
parent: '0.0'
},
...
}
Note that every item in the list must have an “id” and “parent”.
In hctreemap2()
function, author parsed the dataframe into list nicely using purrr
and rlang
package from tidyverse. Do not worry if you don’t understand those “Quasiquotations” link. It is just syntax sugar using non-standard evaluation. more reference
group_vars <- c("index0","index1", "index2", "index3")
size_var <- "value"
group_syms <- rlang::syms(group_vars)
size_sym <- rlang::sym(size_var)
if (data %>%
select(!!!group_syms) %>%
map(unique) %>%
unlist() %>%
anyDuplicated()) stop("Sunburst data uses same label at multiple levels.")
data <- data %>% mutate_at(group_vars, as.character)
name_cell <- function(..., depth) paste0(list(...), 1:depth, collapse = "")
data_at_depth <- function(depth) {
data %>%
group_by(!!!group_syms[1:depth]) %>%
summarise(
value = sum(!!size_sym)
) %>%
ungroup() %>%
mutate(
name = !!group_syms[[depth]],
level = depth
) %>%
mutate_at(group_vars, as.character()) %>%
{
if (depth == 1) mutate(., id = paste0(name, 1))
else {
mutate(
.,
parent = pmap_chr(
list(!!!group_syms[1:depth - 1]),
name_cell,
depth = depth - 1),
id = paste0(parent, name, depth)
)
}
}
}
Lets look at the dataframe before we parse it to a list:
sunburst_df <- 1:length(group_vars) %>%
map(data_at_depth) %>%
bind_rows() %>%
arrange(level)
head(sunburst_df)
# A tibble: 6 x 9
index0 value name level id index1 parent index2 index3
<chr> <int> <chr> <int> <chr> <chr> <chr> <chr> <chr>
1 Letter 2496 Letter 1 Letter1 <NA> <NA> <NA> <NA>
2 Letter 440 A 2 Letter1A2 A Letter1 <NA> <NA>
3 Letter 575 B 2 Letter1B2 B Letter1 <NA> <NA>
4 Letter 549 C 2 Letter1C2 C Letter1 <NA> <NA>
5 Letter 477 D 2 Letter1D2 D Letter1 <NA> <NA>
6 Letter 455 E 2 Letter1E2 E Letter1 <NA> <NA>
Let’s take a look at the first couple of items:
data_list <- sunburst_df %>%
highcharter::list_parse() %>%
purrr::map(~.[!is.na(.)])
data_list[1:3]
[[1]]
[[1]]$index0
[1] "Letter"
[[1]]$value
[1] 2496
[[1]]$name
[1] "Letter"
[[1]]$level
[1] 1
[[1]]$id
[1] "Letter1"
[[2]]
[[2]]$index0
[1] "Letter"
[[2]]$value
[1] 440
[[2]]$name
[1] "A"
[[2]]$level
[1] 2
[[2]]$id
[1] "Letter1A2"
[[2]]$index1
[1] "A"
[[2]]$parent
[1] "Letter1"
[[3]]
[[3]]$index0
[1] "Letter"
[[3]]$value
[1] 575
[[3]]$name
[1] "B"
[[3]]$level
[1] 2
[[3]]$id
[1] "Letter1B2"
[[3]]$index1
[1] "B"
[[3]]$parent
[1] "Letter1"
Alright, the data has been parsed into the corresponding format. Now we just need to pass this in to highcharter::hc_add_series()
hc <- highchart() %>%
hc_add_series(data = data_list,
type = "sunburst",
allowDrillToNode = TRUE)
frameWidget(hc, height = '600')
Here we go!
We are able to create the sunburst chart using Highcharts API! link to full code Of course it’s a bit ugly now because we didn’t pass any other parameters to the chart.
More Configurations
Putting everything together,let’s make the center spot transparent by adding color = 'transparent'
arguments and change the sub level coloring by colorVariation = list(key = 'brightness', to = 0.5)
library(tidyverse)
library(highcharter)
library(RColorBrewer)
hc <- tibble(
index0 = "Letter",
index1 = sample(LETTERS[1:5], 500, replace = T),
index2 = sample(LETTERS[6:10], 500, replace = T),
index3 = sample(LETTERS[11:15], 500, replace = T),
value = rpois(500, 5)
) %>%
hcsunburst(
group_vars = c("index0","index1", "index2", "index3"),
size_var = "value",
levels = list(
list(level = 1, color = 'transparent', dataLabels = list(enabled = TRUE)),
list(level = 2, colorByPoint = TRUE, dataLabels = list(enabled = TRUE)),
list(level = 3, colorVariation = list(key = 'brightness', to = 0.5),
dataLabels = list(enabled = TRUE)),
list(level = 4, colorVariation = list(key = 'brightness', to = -0.5),
dataLabels = list(enabled = FALSE))
)
) %>%
hc_tooltip(pointFormat = "<b>{point.name}</b>:<br>
Value: {point.value:,.0f}<br>")
frameWidget(hc, height = '600')
TL;DR — You can start using this function by installing the forked version on my GitHub: devtools::install_github(repo = "wwwjk366/highcharter")
. I have already initiated a pull request and hopefully the maintainer of `highcharter’ can add this function soon.