Cours
Je suis convaincu que la visualisation de données est la meilleure façon de présenter un reporting descriptif et analytique sur un jeu de données. J'adore la dataviz : elle permet souvent de raconter toute une histoire sur un seul écran — selon la complexité des données, bien sûr. Si vous lisez ce tutoriel, vous connaissez sans doute le package ggplot2 dans R, idéal pour produire de superbes graphiques d'analyse, mais qui manque parfois de dynamisme.
Revenons à Highcharter : c'est un wrapper R pour la bibliothèque JavaScript Highcharts et ses modules.
Les principaux atouts de ce package :
- Vous pouvez créer une grande variété de graphiques avec un style homogène : nuage de points, bulles, séries temporelles, cartes de chaleur, treemaps, diagrammes en barres, etc.
- Il prend en charge différents objets R.
- Il prend en charge les graphiques Highstock et les choroplèthes.
- Il propose une syntaxe avec pipes, plébiscitée par les utilisateurs et développeurs R.
- Un large choix de thèmes au rendu soigné.
Passons à la pratique et créons quelques visualisations avec Highcharter en nous appuyant sur ces fonctionnalités :
Créer des graphiques de base avec la fonction hchart
hchart est une fonction générique qui prend un objet en entrée et renvoie un objet highcharter. Plusieurs fonctions se comportent de manière similaire à celles du package ggplot2 :
- hchart fonctionne comme
qplotde ggplot2. - hc_add_series rappelle les fonctions
geom_*de ggplot2. - hcaes s'apparente à
aesde ggplot2.
Choisissons un jeu de données. Nous allons utiliser le dataset Pokémon inclus dans le package Highcharter. Jetons-y un œil.
glimpse(pokemon)
## Observations: 718
## Variables: 20
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,...
## $ pokemon <chr> "bulbasaur", "ivysaur", "venusaur", "charmande...
## $ species_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,...
## $ height <int> 7, 10, 20, 6, 11, 17, 5, 10, 16, 3, 7, 11, 3, ...
## $ weight <int> 69, 130, 1000, 85, 190, 905, 90, 225, 855, 29,...
## $ base_experience <int> 64, 142, 236, 62, 142, 240, 63, 142, 239, 39, ...
## $ type_1 <chr> "grass", "grass", "grass", "fire", "fire", "fi...
## $ type_2 <chr> "poison", "poison", "poison", NA, NA, "flying"...
## $ attack <int> 49, 62, 82, 52, 64, 84, 48, 63, 83, 30, 20, 45...
## $ defense <int> 49, 63, 83, 43, 58, 78, 65, 80, 100, 35, 55, 5...
## $ hp <int> 45, 60, 80, 39, 58, 78, 44, 59, 79, 45, 50, 60...
## $ special_attack <int> 65, 80, 100, 60, 80, 109, 50, 65, 85, 20, 25, ...
## $ special_defense <int> 65, 80, 100, 50, 65, 85, 64, 80, 105, 20, 25, ...
## $ speed <int> 45, 60, 80, 65, 80, 100, 43, 58, 78, 45, 30, 7...
## $ color_1 <chr> "#78C850", "#78C850", "#78C850", "#F08030", "#...
## $ color_2 <chr> "#A040A0", "#A040A0", "#A040A0", NA, NA, "#A89...
## $ color_f <chr> "#81A763", "#81A763", "#81A763", "#F08030", "#...
## $ egg_group_1 <chr> "monster", "monster", "monster", "monster", "m...
## $ egg_group_2 <chr> "plant", "plant", "plant", "dragon", "dragon",...
## $ url_image <chr> "1.png", "2.png", "3.png", "4.png", "5.png", "...
Traçons un diagramme en barres.
pokemon%>%
count(type_1)%>%
arrange(n)%>%
hchart(type = "bar", hcaes(x = type_1, y = n))

Vous obtenez ainsi un diagramme en barres par type_1 de Pokémon.
Si vous préférez un histogramme (colonnes), il suffit de changer le type en column.
pokemon%>%
count(type_1)%>%
arrange(n)%>%
hchart(type = "column", hcaes(x = type_1, y = n))

Treemap
pokemon%>%
count(type_1)%>%
arrange(n)%>%
hchart(type = "treemap", hcaes(x = type_1, value = n, color = n))

On peut aussi utiliser hc_add_series pour tracer le graphique. Cette fonction permet d'ajouter ou de retirer des séries d'un objet highchart.

Nuage de points
highchart()%>%
hc_add_series(pokemon, "scatter", hcaes(x = height, y = weight))
La différence majeure entre les fonctions geom_ de ggplot2 et hc_add_series, c'est qu'avec hc_add_series il faut préciser les données et les esthétiques à chaque ajout, alors qu'avec ggplot2 vous pouvez définir ces éléments dans une couche, puis empiler plusieurs geoms qui réutiliseront les mêmes données et esthétiques.
Un exemple parlant ci-dessous avec le dataset diamonds de ggplot2.
data(diamonds, package = "ggplot2")
set.seed(123)
data <- sample_n(diamonds, 300)
modlss <- loess(price ~ carat, data = data)
fit <- arrange(augment(modlss), carat)
highchart() %>%
hc_add_series(data, type = "scatter",
hcaes(x = carat, y = price, size = depth, group = cut)) %>%
hc_add_series(fit, type = "line", hcaes(x = carat, y = .fitted),
name = "Fit", id = "fit") %>%
hc_add_series(fit, type = "arearange",
hcaes(x = carat, low = .fitted - 2*.se.fit,
high = .fitted + 2*.se.fit),
linkedTo = "fit")

Dans cet exemple, le graphique combine trois séries : nuage de points, courbe et zone d'incertitude.
Reproduisons un développement JavaScript Highcharts en R avec hc_add_series.

highchart() %>%
hc_chart(type = "area") %>%
hc_title(text = "Historic and Estimated Worldwide Population Distribution by Region") %>%
hc_subtitle(text = "Source: Wikipedia.org") %>%
hc_xAxis(categories = c("1750", "1800", "1850", "1900", "1950", "1999", "2050"),
tickmarkPlacement = "on",
title = list(enabled = FALSE)) %>%
hc_yAxis(title = list(text = "Percent")) %>%
hc_tooltip(pointFormat = "<span style=\"color:{series.color}\">{series.name}</span>:
<b>{point.percentage:.1f}%</b> ({point.y:,.0f} millions)<br/>",
shared = TRUE) %>%
hc_plotOptions(area = list(
stacking = "percent",
lineColor = "#ffffff",
lineWidth = 1,
marker = list(
lineWidth = 1,
lineColor = "#ffffff"
))
) %>%
hc_add_series(name = "Asia", data = c(502, 635, 809, 947, 1402, 3634, 5268)) %>%
hc_add_series(name = "Africa", data = c(106, 107, 111, 133, 221, 767, 1766)) %>%
hc_add_series(name = "Europe", data = c(163, 203, 276, 408, 547, 729, 628)) %>%
hc_add_series(name = "America", data = c(18, 31, 54, 156, 339, 818, 1201)) %>%
hc_add_series(name = "Oceania", data = c(2, 2, 2, 6, 13, 30, 46))

En comparant, on voit comment chaque bloc de code JavaScript est transposé en fonctions R chaînées. Remarquez par exemple l'argument pointFormat de hctooltip, identique au format utilisé en JavaScript. Pour en savoir plus, consultez cette documentation.
Highstock
Highstock permet de créer des graphiques pour l'analyse financière et des séries temporelles. Il fonctionne très bien avec la bibliothèque quantmod, et il est facile de tracer des symboles, puis d'ajouter d'autres séries via hc_add_series.
x <- getSymbols("GOOG", auto.assign = FALSE)
hchart(x)

Ici, nul besoin de code supplémentaire : hchart gère très bien l'objet xts et offre une vue dynamique des données. Utilisez le zoom pour explorer des segments plus fins et affiner l'analyse.
Utilisons maintenant hc_add_series.
y <- getSymbols("AMZN", auto.assign = FALSE)
highchart(type = "stock") %>%
hc_add_series(x) %>%
hc_add_series(y, type = "ohlc")

Comme vous le voyez, la visualisation s'adapte efficacement à de gros volumes de données.
N'hésitez pas à tester d'autres objets xts.
Highmaps
La façon la plus simple de tracer une carte avec highcharter est d'utiliser la fonction hcmap. Sélectionnez une URL depuis la collection highmaps et utilisez-la comme carte dans hcmap. La carte est alors téléchargée et injectée en argument mapdata.
Traçons la carte de l'Inde.
hcmap("https://code.highcharts.com/mapdata/countries/in/in-all.js")%>%
hc_title(text = "India")

Ceci est une carte simple. Et si on la convertissait en carte choroplèthe ?
Chaque carte téléchargée depuis la collection Highcharts possède des clés pour joindre des données. Deux fonctions permettent d'identifier les régions et les clés de jointure :
- download_map_data : télécharge les données geojson depuis la collection Highcharts.
- get_data_from_map : récupère les propriétés de chaque région de la carte, notamment les clés de jointure.
mapdata <- get_data_from_map(download_map_data("https://code.highcharts.com/mapdata/countries/in/in-all.js"))
glimpse(mapdata)
## Observations: 34
## Variables: 20
## $ `hc-group` <chr> "admin1", "admin1", "admin1", "admin1", "admin1"...
## $ `hc-middle-x` <dbl> 0.65, 0.59, 0.50, 0.56, 0.46, 0.46, 0.51, 0.59, ...
## $ `hc-middle-y` <dbl> 0.81, 0.63, 0.74, 0.38, 0.64, 0.51, 0.34, 0.41, ...
## $ `hc-key` <chr> "in-py", "in-ld", "in-wb", "in-or", "in-br", "in...
## $ `hc-a2` <chr> "PY", "LD", "WB", "OR", "BR", "SK", "CT", "TN", ...
## $ labelrank <chr> "2", "2", "2", "2", "2", "2", "2", "2", "2", "2"...
## $ hasc <chr> "IN.PY", "IN.LD", "IN.WB", "IN.OR", "IN.BR", "IN...
## $ `alt-name` <chr> "Pondicherry|Puduchcheri|Pondichéry", "Ã\u008dl...
## $ `woe-id` <chr> "20070459", "2345748", "2345761", "2345755", "23...
## $ fips <chr> "IN22", "IN14", "IN28", "IN21", "IN34", "IN29", ...
## $ `postal-code` <chr> "PY", "LD", "WB", "OR", "BR", "SK", "CT", "TN", ...
## $ name <chr> "Puducherry", "Lakshadweep", "West Bengal", "Ori...
## $ country <chr> "India", "India", "India", "India", "India", "In...
## $ `type-en` <chr> "Union Territory", "Union Territory", "State", "...
## $ region <chr> "South", "South", "East", "East", "East", "East"...
## $ longitude <chr> "79.7758", "72.7811", "87.7289", "84.4341", "85....
## $ `woe-name` <chr> "Puducherry", "Lakshadweep", "West Bengal", "Ori...
## $ latitude <chr> "10.9224", "11.2249", "23.0523", "20.625", "25.6...
## $ `woe-label` <chr> "Puducherry, IN, India", "Lakshadweep, IN, India...
## $ type <chr> "Union Territor", "Union Territor", "State", "St...
#population state wise
pop = as.data.frame(c(84673556, 1382611, 31169272, 103804637, 1055450, 25540196, 342853, 242911, 18980000, 1457723, 60383628, 25353081, 6864602,
12548926, 32966238, 61130704, 33387677, 64429, 72597565, 112372972, 2721756, 2964007, 1091014, 1980602, 41947358, 1244464,
27704236, 68621012, 607688, 72138958, 3671032, 207281477, 10116752,91347736))
state= mapdata%>%
select(`hc-a2`)%>%
arrange(`hc-a2`)
State_pop = as.data.frame(c(state, pop))
names(State_pop)= c("State", "Population")
hcmap("https://code.highcharts.com/mapdata/countries/in/in-all.js", data = State_pop, value = "Population",
joinBy = c("hc-a2", "State"), name = "Fake data",
dataLabels = list(enabled = TRUE, format = '{point.name}'),
borderColor = "#FAFAFA", borderWidth = 0.1,
tooltip = list(valueDecimals = 0))

Amusez-vous à enrichir les cartes et choroplèthes avec hc_add_series. Pour plus de détails et d'exemples, consultez cette ressource.
Plug-ins
Testons maintenant quelques plug-ins proposés par highcharter : regroupements, drill-down, export, impression des données et de superbes thèmes.
Regroupons les données du dataset mpg. Pour une meilleure lisibilité, nous créons ici une liste qui catégorise les données par constructeur.
data(mpg, package = "ggplot2")
mpgg <- mpg %>%
filter(class %in% c("suv", "compact", "midsize")) %>%
group_by(class, manufacturer) %>%
summarize(count = n())
categories_grouped <- mpgg %>%
group_by(name = class) %>%
do(categories = .$manufacturer) %>%
list_parse()
highchart() %>%
hc_xAxis(categories = categories_grouped) %>%
hc_add_series(data = mpgg, type = "bar", hcaes(y = count, color = manufacturer),
showInLegend = FALSE)

Créons un graphique avec drill-down vers d'autres graphiques pour une analyse plus fine. Le code sera plus clair si vous êtes à l'aise avec les listes en R.
df <- data_frame(
name = c("Animals", "Fruits", "Cars"),
y = c(5, 2, 4),
drilldown = tolower(name)
)
ds <- list_parse(df)
names(ds) <- NULL
hc <- highchart() %>%
hc_chart(type = "column") %>%
hc_title(text = "Basic drilldown") %>%
hc_xAxis(type = "category") %>%
hc_legend(enabled = FALSE) %>%
hc_plotOptions(
series = list(
boderWidth = 0,
dataLabels = list(enabled = TRUE)
)
) %>%
hc_add_series(
name = "Things",
colorByPoint = TRUE,
data = ds
)
dfan <- data_frame(
name = c("Cats", "Dogs", "Cows", "Sheep", "Pigs"),
value = c(4, 3, 1, 2, 1)
)
dffru <- data_frame(
name = c("Apple", "Organes"),
value = c(4, 2)
)
dfcar <- data_frame(
name = c("Toyota", "Opel", "Volkswage"),
value = c(4, 2, 2)
)
second_el_to_numeric <- function(ls){
map(ls, function(x){
x[[2]] <- as.numeric(x[[2]])
x
})
}
dsan <- second_el_to_numeric(list_parse2(dfan))
dsfru <- second_el_to_numeric(list_parse2(dffru))
dscar <- second_el_to_numeric(list_parse2(dfcar))
hc %>%
hc_drilldown(
allowPointDrilldown = TRUE,
series = list(
list(
id = "animals",
data = dsan
),
list(
id = "fruits",
data = dsfru
),
list(
id = "cars",
data = dscar
)
)
)

Ajoutons du drill-down sur d'autres graphiques.
tm <- pokemon %>%
mutate(type_2 = ifelse(is.na(type_2), paste("only", type_1), type_2),
type_1 = type_1) %>%
group_by(type_1, type_2) %>%
summarise(n = n()) %>%
ungroup() %>%
treemap::treemap(index = c("type_1", "type_2"),
vSize = "n", vColor = "type_1")

tm$tm <- tm$tm %>%
tbl_df() %>%
left_join(pokemon %>% select(type_1, type_2, color_f) %>% distinct(), by = c("type_1", "type_2")) %>%
left_join(pokemon %>% select(type_1, color_1) %>% distinct(), by = c("type_1")) %>%
mutate(type_1 = paste0("Main ", type_1),
color = ifelse(is.na(color_f), color_1, color_f))
highchart() %>%
hc_add_series_treemap(tm, allowDrillToNode = TRUE,
layoutAlgorithm = "squarified")

Ajoutons la fonctionnalité d'export des données.
pokemon%>%
count(type_1)%>%
arrange(n)%>%
hchart(type = "bar", hcaes(x = type_1, y = n, color = type_1))%>%
hc_exporting(enabled = TRUE)
Pour finir, ajoutons quelques thèmes.pokemon%>%
count(type_1)%>%
arrange(n)%>%
hchart(type = "bar", hcaes(x = type_1, y = n, color = type_1))%>%
hc_exporting(enabled = TRUE)%>%
hc_add_theme(hc_theme_chalk())

Vous pouvez en apprendre bien plus ici : c'est une bibliothèque complète pour Highcharter. Je partage aussi l'un de mes graphiques préférés réalisé sur un jeu de données météo. L'argument polar, lorsqu'il est réglé sur TRUE, change totalement la donne.
data("weather")
x <- c("Min", "Mean", "Max")
y <- sprintf("{point.%s}", c("min_temperaturec", "mean_temperaturec", "max_temperaturec"))
tltip <- tooltip_table(x, y)
hchart(weather, type = "columnrange",
hcaes(x = date, low = min_temperaturec, high = max_temperaturec,
color = mean_temperaturec)) %>%
hc_chart(polar = TRUE) %>%
hc_yAxis( max = 30, min = -10, labels = list(format = "{value} C"),
showFirstLabel = FALSE) %>%
hc_xAxis(
title = list(text = ""), gridLineWidth = 0.5,
labels = list(format = "{value: %b}")) %>%
hc_tooltip(useHTML = TRUE, pointFormat = tltip,
headerFormat = as.character(tags$small("{point.x:%d %B, %Y}")))

Pour aller plus loin sur la visualisation de données avec R, suivez le cours Data Visualization with ggplot2 (Part 1) de DataCamp et consultez notre R Formula Tutorial.