Accessible {highcharter}: Part 4

R
data visualization
accessibility
highcharter
Highcharts

In which we discuss the screen-reader metadata generated by Highcharts’ accessibility module using {highcharter} with {palmerpenguins} data.


Author

Mara Averick

Published

2021-11-15


Back in the first post in this series I mentioned that the impetus for this whole endeavor was Silvia Canelón’s excellent collection of R-specific resources for making data visualizations more accessible (Canelón 2021). I wanted to fill the gap between the possibilities afforded by Highcharts’ accessibility module, and documented examples of module use with the {highcharter} package (Kunst 2021).

Here, we’ll go through the example chart from Silvia’s post (a scatter plot using data from the {palmerpenguins} package (Horst, Hill, and Gorman 2020)), and look at what accessibility features we can enable through {highcharter}.

An accessible penguin plot

First thing’s first, we’ll need both packages loaded in order to get plotting.

library(highcharter)
library(palmerpenguins)

In addition to the ones we’ve used in previous posts (accessibility, export, and export-data), we’ll also attach Highcharts’ annotations module. In the alt-text for Silvia’s initial version of this chart (which is what I’ll use for our caption), she mentioned a specific observation—so, we’ll annotate that point in our re-creation.

The original also specified colours, and we’ll do the same. However, as I note in comments in the code, we’ll do this outside of aesthetic specifications to avoid losing the dual encoding with shapes that Highcharts gives you by default.

View code
highchart() |>
  hc_add_dependency(name = "modules/accessibility.js") |>
  hc_add_dependency(name = "modules/annotations.js") |>
  hc_add_dependency(name = "modules/exporting.js") |>
  hc_add_dependency(name = "modules/export-data.js") |>
  hc_add_series(
    penguins, 
    "scatter", 
    hcaes(x = flipper_length_mm,
          y = bill_length_mm,
          group = species)
  ) |>
  # n.b. by not adding color above, you get "automatic" dual encoding
  # of points with a different shape for the markers for each species
  hc_xAxis(
    title = list(text = "Flipper length (mm)"),
    accessibility = list(
      enabled = TRUE,
      description = "flipper length in millimeters"
    )
  ) |>
  hc_yAxis(
    title = list(text = "Bill length (mm)"),
    accessibility = list(
      enabled = TRUE,
      description = "bill length in millimeters"
    )
  ) |>
  hc_title(
    text = "Flipper length vs. bill length in <b>{palmerpenguins}</b>",
    style = list(useHTML = TRUE)
           ) |>
  hc_subtitle(
    text = "Grouped by species: Adelie, Chinstrap, and Gentoo"
    ) |>
  hc_annotations(
    list(
      labels = list(
        list(
          point = list(x = 201, y = 54.2, xAxis = 0, yAxis = 0),
          text = "Chinstrap<br/>x: {x}<br/>y: {y}",
          shape = "connector" # defaults to 'callout'
        )
      ),
      # below gives you screen-reader descriptions of annotations
      labelOptions = list(
        accessibility = list(
          # wouldn't hard code description here if there was
          # more than one point annotated, need lang options
          description = "A Chinstrap penguin observation mapping to a flipper length of 201mm and bill length of 54.2mm."
      )
    )
  )
  )|>
  hc_caption(text = "Scatterplot of the palmerpenguins dataset showing data points clustered by species (Adelie, Chinstrap, and Gentoo) using the highcharter package making it possible to focus on one cluster and identify the x and y values of a specific data point. In this case the data point is a Chinstrap penguin observation mapping to a flipper length of 201mm and bill length of 54.2mm.") |>
  hc_exporting(
    enabled = TRUE,
    accessibility = list(
      enabled = TRUE
    )
  ) |>
  hc_plotOptions(
    accessibility = list(
      enabled = TRUE,
      keyboardNavigation = list(enabled = TRUE)
    )
  ) |>
  # use the custom colors and keep shape per group if added here
  hc_colors(c("darkorange", "purple", "#057276"))

Looking at the code for this chart, you may be wondering if I lost control of the keyboard when writing the descriptions of the axes, since I didn’t capitalize their first letters. Fear not! It was intentional—I wanted the text to look right in something I’ve mentioned, but not gone through in detail: the screenReaderSection.

The hidden screen-reader <div>

Though it’s hidden from display, you can see how your Highcharts visualization will “look” to a screen reader in the generated HTML. There’s a special <div> with information that comes from a the templated screenReaderSection. In the case of the chart above, the outer HTML is:1

HTML
<div id="highcharts-screen-reader-region-before-0" 
aria-label="Chart screen reader information." role="region" 
aria-hidden="false" style="position: relative;"></div>

ARIA stands for Accessible Rich Internet Applications. aria-hidden="false", in effect, tells a screen reader not to ignore this section even though it’s not visually displayed.

The template for the contents of this section is actually a customizable parameter (screenReadersection.beforeChartFormat), but I used the default format:

HTML
<{headingTagName}>{chartTitle}</{headingTagName}><div>{typeDescription}</div>
<div>{chartSubtitle}</div><div>{chartLongdesc}</div><div>{playAsSoundButton}</div>
<div>{viewTableButton}</div>
<div>{xAxisDescription}</div><div>{yAxisDescription}</div>
<div>{annotationsTitle}{annotationsList}</div>

The information contained is a combination of information we specified manually (e.g. the title and subtitle), and information derived by the annotation module (e.g. the number of groups in our data).

For the chart above, it begins:

HTML
<p>Flipper length vs. bill length in {palmerpenguins}</p>
<div>Scatter chart with 3 data series.</div>
<div>Grouped by species: Adelie, Chinstrap, and Gentoo</div>

Then followed by a <div> containing our chart’s caption. After an option to view the information as a data table rather than a chart, we come to axis descriptions including ranges, which can be automatically calculated or described manually as a rangeDescription.

HTML
<div>The chart has 1 X axis displaying flipper length in millimeters. Range: 171.41 to 231.59.</div>
<div>The chart has 1 Y axis displaying bill length in millimeters. Range: 30 to 70.</div>

And, lastly, we come to “Chart annotations summary”, which contains an unordered list of the annotations. In our case, this contains just one item.

HTML
<li>A Chinstrap penguin observation mapping to a flipper length of 201mm and bill length of 54.2mm.</li>

Fin

There’s one last post to come in this series. There, we’ll re-create an example from Highcharts’ annotation module documentation, and see what it takes to get the screen-reader list of annotations working with more than one item.

Back to top

References

Canelón, Silvia. 2021. “Resources for Data Viz Accessibility.” https://silvia.rbind.io/blog/2021-curated-compilations/01-data-viz-a11y/.
Horst, Allison Marie, Alison Presmanes Hill, and Kristen B Gorman. 2020. Palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data. https://allisonhorst.github.io/palmerpenguins/.
Kunst, Joshua. 2021. Highcharter: A Wrapper for the ’Highcharts’ Library. https://jkunst.com/highcharter.

Footnotes

  1. I’ve added some hard line breaks that aren’t there in the original for ease of reading.↩︎

Reuse

Citation

BibTeX citation:
@online{averick2021,
  author = {Averick, Mara},
  title = {Accessible \{Highcharter\}: {Part} 4},
  date = {2021-11-15},
  url = {https://quartoand.me/blog/2021-11_accessible-highcharter-part-4},
  langid = {en}
}
For attribution, please cite this work as:
Averick, Mara. 2021. “Accessible {Highcharter}: Part 4.” November 15, 2021. https://quartoand.me/blog/2021-11_accessible-highcharter-part-4.