library(ROvis.plotly) # nolint: missing_package_linter.
ggplotly and plotly keyboard accessibility
Source:vignettes/ggplotly-and-plotly-keyboard-accessibility.qmd
Introduction
This vignette demonstrates the use of accessibility functions for interactive plotly and ggplotly plots. These functions are designed to improve keyboard and screen reader accessibility for various types of interactive charts.
Note: The example plots in this vignette are for demonstration only and do not themselves comply with the Rijksoverheid style requirements.
Key Accessibility Features
- Keyboard navigation: Users can focus bars, points, and legend items using Tab and Arrow keys.
- Accessible tooltips: Tooltip content is made available for screen readers and keyboard navigation.
- Screen reader support: Meaningful ARIA labels are provided for plot elements.
- Legend accessibility: Legends can be reached and toggled via keyboard.
- Toolbar control: The plotly modebar (toolbar) can be disabled for improved accessibility.
The functions covered in this vignette are:
- ro_ply_keyboard_nav_barchart()
- ro_ply_keyboard_nav_bargraph()
- ro_ply_keyboard_nav_trendline()
- ro_ply_keyboard_nav_linechart()
- ro_ply_keyboard_nav_legend()
- ro_ply_disable_toolbar()
Keyboard accessibility - ggplotly and plotly plots
Each section below demonstrates how to add accessibility to a ggplotly or plotly graph using the functions from this package. For each plot type, you will see an example with and without accessibility enhancements.
Horizontal Barchart
This section demonstrates how to make a horizontal bar chart created with ggplotly or plotly keyboard accessible. The example shows how to use ro_ply_keyboard_nav_barchart() to enable keyboard navigation and accessible tooltips for all bars.
Example data
data <- tidyr::tibble(
expand.grid(`Age group` = c("A", "B", "C", "D", "E"), `Sex` = c("Man", "Vrouw")),
`Number of Cases` = sample(1:50, 10, TRUE)
) ggplotly - Horizontal Barchart
library(ggplot2)
library(plotly)
#>
#> Attaching package: 'plotly'
#> The following object is masked from 'package:ggplot2':
#>
#> last_plot
#> The following object is masked from 'package:stats':
#>
#> filter
#> The following object is masked from 'package:graphics':
#>
#> layout
p <- ggplot(data, aes(
x = `Number of Cases`,
y = `Age group`,
fill = Sex,
text = paste0(
"Leeftijdsgroep: <b>", `Age group`, "</b><br>",
"Geslacht: <b>", Sex, "</b><br>",
"Aantal cases: <b>", `Number of Cases`, "</b>"
)
)) +
geom_col(position = "dodge") +
labs(
x = "Aantal cases",
y = "Leeftijdsgroep",
fill = "Geslacht"
)
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_barchart(fig)
figplotly - Horizontal Barchart
library(plotly)
fig <- plot_ly(data = data,
x = ~`Number of Cases`,
y = ~`Age group`,
color = ~`Sex`,
type = "bar",
orientation = "h", # horizontal bars
hovertext = ~paste0(
"Leeftijdsgroep: <b>", `Age group`, "</b><br>",
"Geslacht: <b>", `Sex`, "</b><br>",
"Aantal cases: <b>", `Number of Cases`, "</b>"
),
text = ~paste0(
"Leeftijdsgroep: <b>", `Age group`, "</b><br>",
"Geslacht: <b>", `Sex`, "</b><br>",
"Aantal cases: <b>", `Number of Cases`, "</b>"
),
textposition = "none",
hoverinfo = "text"
)
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_barchart(fig)
figGrouped Bar Graph / Column Chart
This section demonstrates how to make a column chart created with ggplotly or plotly keyboard accessible. The example shows how to use ro_ply_keyboard_nav_barchart() to enable keyboard navigation and accessible tooltips for all bars.
Example data
age_levels <- c(
"0", "1-9", "10-19", "20-29",
"30-39", "40-49", "50-59",
"60-69", "70-79", "80-89", "90+"
)
base_data <- tidyr::expand_grid(
`Age group` = age_levels,
Sex = c("Men", "Women")
) |>
dplyr::mutate(
`Number of Cases` = sample(1:50, length(age_levels) * 2, TRUE)
)
summary_data <- base_data |>
dplyr::summarize(
`Number of Cases` = sum(`Number of Cases`),
.by = `Age group`
) |>
dplyr::mutate(Sex = "Total")
data <- dplyr::bind_rows(base_data, summary_data) |>
dplyr::mutate(
`Age group` = factor(`Age group`, levels = age_levels),
Sex = factor(Sex, levels = c("Men", "Women", "Total"))
) ggplotly Grouped Bar Graph / Column Chart
p <- ggplot(data, aes(
x = `Age group`,
y = `Number of Cases`,
fill = Sex,
text = paste0(
"Geslacht: <b>", Sex, "</b>",
"<br>Leeftijdsgroep: <b>", `Age group`,
"</b><br>Aantal cases: <b>",
format(round(`Number of Cases`, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
)
)) +
geom_col(position = position_dodge(width = 0.7), width = 0.7) +
labs(x = "Leeftijdsgroep", y = "Aantal cases", fill = "Geslacht")
# Convert to interactive plotly plot
fig <- ggplotly(p, tooltip = "text")
fig <- ro_ply_keyboard_nav_bargraph(fig)
figplotly Grouped Bar Graph / Column Chart
fig <- plot_ly(
data = data,
x = ~`Age group`,
y = ~`Number of Cases`,
type = "bar",
color = ~Sex,
text = ~paste0(
"Geslacht: <b>", Sex, "</b>",
"<br>Leeftijdsgroep: <b>", `Age group`,
"</b><br>Aantal cases: <b>",
format(round(`Number of Cases`, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
),
textposition = "none",
hoverinfo = "text"
) |>
layout(barmode = "group")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_bargraph(fig)
figBar Graph
This section demonstrates how to make a bar graph created with ggplotly or plotly keyboard accessible. The example shows how to use ro_ply_keyboard_nav_barchart() to enable keyboard navigation and accessible tooltips for all bars.
Example data
ggplotly Bar Graph
library(ggplot2) library(plotly)
p <- ggplot(data, aes(x = Sex, y = n, fill = Sex,
text = paste0(
"Geslacht: <b>", Sex, "</b>",
"</b><br>Aantal cases: <b>",
format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
))) +
geom_col(width = 0.6) +
labs(x = "Geslacht", y = "Aantal cases") +
theme_minimal()
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_bargraph(fig)
figplotly Bar Graph
fig <- plot_ly(
data = data,
x = ~Sex,
y = ~n,
type = "bar",
color = ~Sex,
text = ~paste0(
"Geslacht: <b>", Sex, "</b>",
"</b><br>Aantal cases: <b>",
format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
),
hoverinfo = "text",
width = 0.6
)
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_bargraph(fig)
figStacked Bar Graph
This section demonstrates how to make a stacked bar graph created with ggplotly or plotly keyboard accessible. The example shows how to use ro_ply_keyboard_nav_barchart() to enable keyboard navigation and accessible tooltips for all bars.
Example data
agegroups <- c("0-9", "10-19", "20-29", "30-39", "40-49", "50-59", "60-69", "70-79", "80-89", "90+")
sex <- c("Vrouw", "Man", "Onbekend")
data <- expand.grid(
Agegroup = agegroups,
Sex = sex,
stringsAsFactors = FALSE
) |>
tibble::as_tibble() |>
dplyr::rowwise() |>
dplyr::mutate(
n = if (Sex == "Onbekend") sample(200:3000, 1) else sample(200000:700000, 1)
) |>
dplyr::ungroup() |>
dplyr::mutate(Sex = factor(Sex, levels = c("Vrouw", "Man", "Onbekend")))ggplotly Stacked Bar Graph
library(ggplot2)
library(plotly)
p <- ggplot(data, aes(x = Agegroup, y = n, fill = Sex,
text = paste0(
"Aantal cases: <b>", format(n, big.mark = ".", decimal.mark = ",", scientific = FALSE),
"</b><br>Leeftijdsgroep: <b>", Agegroup,
"</b><br>Geslacht: <b>", Sex
))) +
geom_col(width = 0.7, position = "stack") +
labs(x = "Leeftijdsgroep", y = "Aantal cases", fill = "Geslacht")
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_bargraph(fig)
figplotly Stacked Bar Graph
library(plotly)
fig <- plot_ly(
data = data, # your tibble
x = ~Agegroup,
y = ~n,
color = ~Sex,
type = "bar",
text = ~paste0(
"Aantal cases: <b>", format(n, big.mark = ".", decimal.mark = ",", scientific = FALSE),
"</b><br>Leeftijdsgroep: <b>", Agegroup,
"</b><br>Geslacht: <b>", Sex
),
textposition = "none",
hoverinfo = "text"
) |>
layout(barmode = "stack")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_bargraph(fig)
figProportional Stacked Bar Graph
This section demonstrates how to make a proportional stacked bar graph created with plotly keyboard accessible. The example shows how to use ro_ply_keyboard_nav_barchart() to enable keyboard navigation and accessible tooltips for all bars.
Note: Proportional stacked bar graphs are not supported via ggplotly, only via plotly.
Example data
age_cat <- c("0-19", "20-39", "40-59", "60+")
sex <- c("Vrouw", "Man")
period <- c("Na", "Voor")
data <- expand.grid(
age_cat = age_cat,
omicron_period = period,
stringsAsFactors = FALSE
) |>
tibble::as_tibble() |>
dplyr::rowwise() |>
dplyr::mutate(
# Simuleer totaal aantal cases per groep
total_n = sample(50000:1200000, 1),
# Simuleer random verhouding tussen vrouw/man
vrouw_prop = runif(1, 0.45, 0.55),
man_prop = 1 - vrouw_prop,
n_vrouw = as.integer(total_n * vrouw_prop),
n_man = total_n - n_vrouw
) |>
dplyr::ungroup() |>
# Zet weer om naar long format per sex
tidyr::pivot_longer(
cols = c(n_vrouw, n_man),
names_to = "Sex",
values_to = "n",
names_prefix = "n_"
) |>
dplyr::group_by(age_cat, omicron_period) |>
dplyr::mutate(
prop = n / sum(n),
bar_label = paste0(age_cat, " (", omicron_period, ")"),
prop_label = paste0(format(round(prop * 100, 1), decimal.mark = ","), "%")
) |>
dplyr::ungroup() |>
dplyr::select(age_cat, Sex, omicron_period, n, prop, bar_label, prop_label)
# Order the labels
data <- data |>
dplyr::mutate(
Sex = dplyr::recode(Sex, "vrouw" = "Vrouw", "man" = "Man")
)
bar_label_levels <- as.vector(outer(age_cat, period, function(a, p) paste0(a, " (", p, ")")))
data <- data |>
dplyr::mutate(
bar_label = factor(bar_label, levels = bar_label_levels),
Sex = factor(Sex, levels = c("Vrouw", "Man"))
) |>
dplyr::arrange(bar_label, Sex) |>
dplyr::select(age_cat, Sex, omicron_period, n, prop, bar_label, prop_label)
# Show the structure of the data
str(data)
#> tibble [16 × 7] (S3: tbl_df/tbl/data.frame)
#> $ age_cat : chr [1:16] "0-19" "0-19" "20-39" "20-39" ...
#> $ Sex : Factor w/ 2 levels "Vrouw","Man": 1 2 1 2 1 2 1 2 1 2 ...
#> $ omicron_period: chr [1:16] "Na" "Na" "Na" "Na" ...
#> $ n : int [1:16] 36809 31361 472320 563589 369395 385471 157434 187827 513213 464731 ...
#> $ prop : num [1:16] 0.54 0.46 0.456 0.544 0.489 ...
#> $ bar_label : Factor w/ 8 levels "0-19 (Na)","20-39 (Na)",..: 1 1 2 2 3 3 4 4 5 5 ...
#> $ prop_label : chr [1:16] "54%" "46%" "45,6%" "54,4%" ...plotly Proportional Stacked Bar Graph
library(plotly)
fig <- plot_ly(
data = data,
y = ~bar_label,
x = ~prop,
color = ~Sex,
orientation = "h",
type = "bar",
text = ~paste0(
"Leeftijdsgroep: <b>", age_cat, "<br></b>",
"Omicron periode: <b>", omicron_period, "<br></b>",
"Geslacht: <b>", Sex, "<br></b>",
"Percentage: <b>", prop_label, "<br></b>"
),
textposition = "auto",
hovertemplate = ~paste0(
"Leeftijdsgroep: <b>", age_cat, "<br></b>",
"Omicron periode: <b>", omicron_period, "<br></b>",
"Geslacht: <b>", Sex, "<br></b>",
"Percentage: <b>", prop_label, "<br></b>"
),
hoverinfo = "text"
) |> layout(barmode = "stack")
fig <- ro_ply_keyboard_nav_barchart(fig)
figTrendline
This section demonstrates how to make a trendline created with ggplotly or plotly keyboard accessible. The ro_ply_keyboard_nav_trendline() function allows users to focus on individual points (not lines), with tooltips and ARIA labels for screen readers.
Example data
dates <- seq(as.Date("2021-10-04"), by = "day", length.out = 100)
n <- round(2500 + 700 * sin(seq_along(dates) / 25) + seq_along(dates) * 3 + rnorm(length(dates), 0, 150))
moving_average <- stats::filter(n, rep(1 / 7, 7), sides = 2)
text <- paste0(
"Dag: <b>", format(dates, "%d-%m-%Y"), "</b><br>",
"Aantal cases: <b>", format(n, big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b><br>",
"7-daags gemiddelde: <b>", format(round(moving_average, 0),
big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
)
data <- tibble::tibble(
Date_statistics = dates,
n = n,
moving_average = as.numeric(moving_average),
text = text
)ggplotly Trendline
p <- ggplot(data, aes(x = Date_statistics, y = n, text = text, group = 1)) +
geom_line() +
geom_point()
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_trendline(fig)
figplotly Trendline
library(plotly)
fig <- plot_ly()
fig <- fig |>
plotly::add_trace(
data = data,
x = ~Date_statistics,
y = ~n,
type = "scatter",
mode = "markers",
name = "Aantal cases",
text = ~text,
hoverinfo = "text"
)
# Add line for moving average
fig <- fig |>
plotly::add_trace(
data = data,
x = ~Date_statistics,
y = ~moving_average,
type = "scatter",
mode = "lines",
name = "7-daags gemiddelde",
text = ~text,
hoverinfo = "text"
)
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_trendline(fig)
figGrouped Trendline
This section demonstrates how to make a grouped trendline created with ggplotly or plotly keyboard accessible. The ro_ply_keyboard_nav_trendline() function allows users to focus on individual points (not lines), with tooltips and ARIA labels for screen readers.
Example data
categories <- LETTERS[1:5] # "A", "B", "C", "D", "E"
weeks <- seq(as.Date("2023-01-02"), as.Date("2023-05-29"), by = "week")
data <- tidyr::expand_grid(
week = weeks,
Category = categories
) |>
dplyr::mutate(
n = dplyr::case_when(
Category == "A" ~ round(100 + 10 * as.numeric(week - min(week)) / 7 + stats::rnorm(dplyr::n(), 0, 15)),
Category == "B" ~ round(50 + 2 * as.numeric(week - min(week)) / 7 + stats::rnorm(dplyr::n(), 0, 7)),
Category == "C" ~ round(80 + 5 * sin(dplyr::row_number() / 4) + stats::rnorm(dplyr::n(), 0, 10)),
Category == "D" ~ round(200 - 5 * as.numeric(week - min(week)) / 7 + stats::rnorm(dplyr::n(), 0, 18)),
Category == "E" ~ round(70 + 8 * cos(dplyr::row_number() / 5) + stats::rnorm(dplyr::n(), 0, 12))
)
)
data <- data |>
dplyr::mutate(
text = paste0(
"Week: <b>", format(week, "%d-%m-%Y"), "</b><br>",
"Categorie: <b>", Category, "</b><br>",
"Aantal cases: <b>", format(n, big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
)
)
cat_names <- unique(data$Category)ggplotly Grouped Trendline
library(ggplot2)
library(plotly)
p <- ggplot(data, aes(x = week, y = n, color = Category, group = Category, text = text)) +
geom_line() +
geom_point()
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_trendline(fig)
figplotly Grouped Trendline
library(plotly)
fig <- plot_ly()
for (cat in cat_names) {
subset <- data[data$Category == cat, ]
fig <- fig |>
plotly::add_trace(
data = subset,
x = ~week,
y = ~n,
type = "scatter",
mode = "lines+markers",
name = cat,
text = ~text,
hoverinfo = "text"
)
}
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_trendline(fig)
figLine Chart
This section demonstrates how to make a line chart created with ggplotly or plotly keyboard accessible. The ro_ply_keyboard_nav_linechart() adds keyboard focus to lines, and shows a focus-point.
Example data
base_data <- tidyr::tibble(expand.grid(
Jaar = 2001:2020,
Geslacht = c("Man", "Vrouw")
)) |>
dplyr::mutate(value = sample(1:50, dplyr::n(), TRUE))
total_data <- base_data |>
dplyr::group_by(Jaar) |>
dplyr::summarize(value = sum(value), .groups = "drop") |>
dplyr::mutate(Geslacht = "Totaal")
data <- dplyr::bind_rows(base_data, total_data) |>
dplyr::mutate(Geslacht = factor(Geslacht, levels = c("Man", "Vrouw", "Totaal")))ggplotly Line Chart
ro_ply_keyboard_nav_linechart
library(ggplot2)
library(plotly)
p <- ggplot(data, aes(x = Jaar, y = value, color = Geslacht, group = Geslacht,
text = paste0(
"Geslacht: <b>", Geslacht,
"</b><br>Jaar: <b>", Jaar,
"</b><br>Aantal cases: <b>", value
))) +
geom_line()
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_linechart(fig)
figplotly Line Chart
library(plotly)
fig <- plot_ly()
for (geslacht in levels(data$Geslacht)) {
subset <- data |> filter(Geslacht == geslacht)
fig <- fig |>
add_trace(
data = subset,
x = ~Jaar,
y = ~value,
type = "scatter",
mode = "lines",
name = geslacht,
text = paste0(
"Geslacht: <b>", subset$Geslacht,
"</b><br>Jaar: <b>", subset$Jaar,
"</b><br>Aantal cases: <b>", subset$value
),
hoverinfo = "text"
)
}
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_linechart(fig)
figKeyboard accessibility - ggplotly and plotly legends
By default, plotly legends are not keyboard accessible. The ro_ply_keyboard_nav_legend() function makes it possible to reach and toggle legend items using the keyboard, with visual focus indication and ARIA attributes for screen readers.
Note: For stacked bar graphs for ggplot, it is advised to disable the legend filtering (also with the mouse) altogether, as the image is not re-rendered after filtering, which can lead to ‘floating’ bars.
Example data and plot (horizontal barchart from above)
The example data is used from the horizontal barchart as shown above.
data <- tidyr::tibble(
expand.grid(`Age group` = c("A", "B", "C", "D", "E"), `Sex` = c("Man", "Vrouw")),
`Number of Cases` = sample(1:50, 10, TRUE)
)
library(ggplot2)
library(plotly)
p <- ggplot(data, aes(
x = `Number of Cases`,
y = `Age group`,
fill = Sex,
text = paste0(
"Leeftijdsgroep: <b>", `Age group`, "</b><br>",
"Geslacht: <b>", Sex, "</b><br>",
"Aantal cases: <b>", `Number of Cases`, "</b>"
)
)) +
geom_col(position = "dodge") +
labs(
x = "Aantal cases",
y = "Leeftijdsgroep",
fill = "Geslacht"
)
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_barchart(fig)After the figure is made, the legend can be made accessible.
# Add the keyboard accessibility to the legend
fig <- ro_ply_keyboard_nav_legend(fig)
figggplotly and plotly disable toolbar
The plotly modebar / toolbar can be distracting or inaccessible for keyboard users.
The ro_ply_disable_toolbar() function removes the toolbar and disables legend popup further improving accessibility.
Example data and plot
The example data is used from the horizontal barchart as shown above.
data <- tidyr::tibble(
expand.grid(`Age group` = c("A", "B", "C", "D", "E"), `Sex` = c("Man", "Vrouw")),
`Number of Cases` = sample(1:50, 10, TRUE)
)
library(ggplot2)
library(plotly)
p <- ggplot(data, aes(
x = `Number of Cases`,
y = `Age group`,
fill = Sex,
text = paste0(
"Leeftijdsgroep: <b>", `Age group`, "</b><br>",
"Geslacht: <b>", Sex, "</b><br>",
"Aantal cases: <b>", `Number of Cases`, "</b>"
)
)) +
geom_col(position = "dodge") +
labs(
x = "Aantal cases",
y = "Leeftijdsgroep",
fill = "Geslacht"
)
# Convert to plotly and add accessibility
fig <- ggplotly(p, tooltip = "text")
# Add the keyboard accessibility in the plot
fig <- ro_ply_keyboard_nav_barchart(fig)
# Add keyboard accessibility to the legend
fig <- ro_ply_keyboard_nav_legend(fig)Then the toolbar / modbar can be disabled, and the pop-up on filtering can be disabled as well, as this not accessible with the keyboard
# Disable the modbar and filtering pop-up
fig <- ro_ply_disable_toolbar(fig)
fig