library(ROvis.plotly) # nolint: missing_package_linter.library(ROvis.plotly) # nolint: missing_package_linter.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
The functions covered in this vignette are:
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.
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.
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)
#>
#> 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)
figlibrary(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)
figThis 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.
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"))
) 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)
figfig <- 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)
figThis 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.
data <- tidyr::tibble(
Sex = factor(c("Vrouw", "Man"), levels = c("Vrouw", "Man")),
n = sample(1e6:5e6, 2)
)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)
figfig <- 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)
figThis 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.
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")))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)
figlibrary(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)
figThis 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.
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] 377825 426895 175689 185337 475958 552204 374982 361982 138322 122726 ...
#> $ prop : num [1:16] 0.47 0.53 0.487 0.513 0.463 ...
#> $ 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] "47%" "53%" "48,7%" "51,3%" ...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)
figThis 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.
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
)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)
figlibrary(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)
figThis 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.
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)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)
figlibrary(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)
figThis 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.
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")))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)
figlibrary(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)
figBy 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.
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)
figThe 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.
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