plotly figures in Rijksoverheid style

library(plotly)
## Loading required package: ggplot2
## 
## 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
library(ROvis.plotly) # nolint: missing_package_linter.
library(ROvis.utils)

Introduction

This vignette demonstrates how to create clear, publication-ready visualizations in R using the plotly package, styled according to the Rijksoverheids style The provided functions allow you to quickly apply consistent fonts, colors, grid lines, axes, legends, tooltips, and annotation styling across all your Plotly charts.

Key Function

  • ro_ply_standard()

Code Examples

Column Chart / Grouped Vertical Bar Chart

This example shows how to create a grouped vertical bar chart (column chart) displaying the number of cases by age group and sex.


# We first make some random 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"))
  )


# Then we make the basic plotly plot
theme_rivm <- ro_ply_theme(barmode = "group")
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
kleuren <- c(ro_color("hemelblauw"), ro_color("robijnrood"),  ro_color("paars"))

fig <- plot_ly(
  data = data,
  x = ~`Age group`,
  y = ~`Number of Cases`,
  type = "bar",
  color = ~Sex,
  colors = kleuren,
  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"
)

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "bargraph", 
                      barmode = "group",
                      y_data = data$"Age group", 
                      y_label = "Aantal cases", 
                      title = "COVID-19 cases per leeftijdsgroep en geslacht", 
                      x_label = "Leeftijdsgroepen")
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Bar Graph

This example demonstrates a simple vertical bar chart / bar graph, showing the number of cases per sex, with the default Rijksoverheid / RIVM theme.

# We first make some random data
bar_data <- tibble::tibble(
  Sex = c("Man", "Vrouw"),
  n = c(1234, 1675)
)

# Then we make the basic plotly plot
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood")
)

fig <- plot_ly(
  data = bar_data,
  x = ~Sex,
  y = ~n,
  type = "bar",
  color = ~Sex,
  colors = sex_colors,
  text = ~paste0(
    "Geslacht: <b>", Sex, "</b>",
    "<br>Aantal cases: <b>", 
    format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
  ),
  hoverinfo = "text"
)

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "bargraph",
                      y_data = bar_data$n, 
                      y_label = "Aantal cases", 
                      title = "COVID-19 cases per geslacht",  
                      x_label = "Geslacht")
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Horizontal Bar Chart

This example demonstrates how to create a horizontal bar chart grouped by age group and sex.

# We first make some random data
data <- tibble::tibble(expand.grid(`Age group` = c("A", "B", "C", "D", "E"),
                                   `Sex` = c("Man", "Vrouw")),
                       `Number of Cases` = sample(1:50, 10, TRUE))


# Then we make the basic plotly plot
kleuren <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood")
)

fig <- plot_ly() |>
  plotly::add_trace(data = data,
    x = ~`Number of Cases`,
    y = ~`Age group`,
    color = ~`Sex`,
    colors = kleuren,
    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"
  )

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "barchart",
                      y_data = data$"Age group", 
                      y_label = "Groep", 
                      title = "COVID-19 cases per geslacht en groep", 
                      x_label = "Aantal cases",
                      y_axis_spike = TRUE,
                      x_axis_spike = FALSE,
                      y_axis_showline = TRUE,
                      x_axis_showline = FALSE,
                      y_axis_showgrid = FALSE,
                      x_axis_showgrid = TRUE
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Stacked Bar Graph

This example demonstrates how to create a stacked bar chart displays the number of cases per age group and sex.

The theme uses: theme_rivm <- ro_ply_theme(barmode = "stack") where barmode = "stack" stacks the bars by sex within each age group.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

# We first make some random data
stacked_data <- tibble::tibble(
  Agegroup = rep(c("0-9", "10-19", "20-29", "30-39"), each = 3),
    Sex = factor(rep(c("Man", "Vrouw", "Onbekend"), times = 4), 
               levels = c("Man", "Vrouw", "Onbekend")),
  n = c(10, 14, 2, 15, 17, 1, 23, 18, 0, 9, 11, 3)
)

# Then we make the basic plotly plot
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood"),
  "Onbekend" = ro_color("donkergeel")
)

fig <- plot_ly(
  data = stacked_data,
  x = ~Agegroup,
  y = ~n,
  type = "bar",
  color = ~Sex,
  colors = sex_colors,
  text = ~paste0(
    "Leeftijdsgroep: <b>", Agegroup, "</b>",
    "<br>Geslacht: <b>", Sex, "</b>",
    "<br>Aantal cases: <b>", 
    format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
  ),
  hovertext = ~paste0(
    "Leeftijdsgroep: <b>", Agegroup, "</b>",
    "<br>Geslacht: <b>", Sex, "</b>",
    "<br>Aantal cases: <b>", 
    format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
  ),
  textposition = "none",
  hoverinfo = "text"
)

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "bargraph", 
                      barmode = "stack",
                      y_data = stacked_data |>  group_by(Agegroup) |>  summarise(n_total = sum(n)) |>  pull(n_total),
                      title = "COVID-19 cases per leeftijdsgroep en geslacht",
                      x_label = "Leeftijdsgroep",
                      y_label = "Aantal cases"
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Proportional Stacked Bar Graph

This example demonstrates how to create aroportional stacked bar chart, displaying the proportion of cases per age group and sex as a horizontal.

library(dplyr)

# We first make some random data
prop_data <- tibble::tibble(
  age_cat = rep(c("0-9", "10-19", "20-29", "30-39"), each = 2),
  Sex = rep(c("Man", "Vrouw"), times = 4),
  n = c(12, 8, 15, 12, 20, 18, 10, 7)
) |> 
  group_by(age_cat) |> 
  mutate(
    total = sum(n),
    prop = n / total,
    prop_label = paste0(round(prop * 100, 1), "%"),
    bar_label = age_cat
  ) |> 
  ungroup()

# Then we make the basic plotly plot
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood")
)

fig <- plot_ly(
  data = prop_data,
  y = ~bar_label,
  x = ~prop,
  color = ~Sex,
  colors = sex_colors,
  type = "bar",
  orientation = "h",
  text = ~paste0(
    "Leeftijdsgroep: <b>", age_cat, "</b><br>",
    "Geslacht: <b>", Sex, "</b><br>",
    "Percentage: <b>", prop_label, "</b>"
  ),
  textposition = "auto",
  hovertemplate = ~paste0(
    "Leeftijdsgroep: <b>", age_cat, "</b><br>",
    "Geslacht: <b>", Sex, "</b><br>",
    "Percentage: <b>", prop_label, "</b>"
  ),
  hoverinfo = "text"
) |> 
  layout(
    xaxis = list(
      range = c(0, 1)
    )
  )

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "bargraph", 
                      barmode = "stack",
                      y_data = prop_data$bar_label,
                      y_label = "Leeftijdsgroep",
                      title = "Percentage COVID-19 cases per leeftijdsgroep en geslacht",
                      x_label = "Percentage",
                      x_axis_tick_format = ".0%",
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Trendline

This example shows a trendline (with points and a moving average) for daily case counts.

library(dplyr)
library(zoo)
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(stringr)

# We first make some random data
tab_cases_rolling_average <- tibble::tibble(
  Date_statistics = seq(as.Date("2022-11-01"), as.Date("2022-12-31"), by = "day"),
  n = round(seq(100, 400, length.out = 61) + rnorm(61, 0, 20)) # trend + noise
) |> 
  mutate(
    moving_average = zoo::rollmean(n, k = 7, fill = NA, align = "right"),
    text = str_c(
      "Dag: <b>", format(Date_statistics, "%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>"
    )
  )

# Then we make the basic plotly plot
fig <- plot_ly(
  data = tab_cases_rolling_average,
  x = ~Date_statistics
) |> 
  plotly::add_markers(
    y = ~n,
    name = "Aantal cases",
    marker = list(color = ro_color("robijnrood_tint60"), size = 5),
    text = ~text,
    hoverinfo = "text"
  ) |> 
  plotly::add_lines(
    y = ~moving_average,
    name = "7-daags gemiddelde",
    line = list(color = ro_color("robijnrood"), width = 2),
    text = ~text,
    hoverinfo = "text"
  )

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "trendline", 
                      y_data = tab_cases_rolling_average$n,
                      y_label = "Aantal gevallen",
                      title = "COVID-19 gevallen per dag en 7-daags gemiddelde",
                      x_label = "Datum",
                      x_axis_tick_format = "%d %b"
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Grouped Trendline

This example shows a grouped trendline for multiple provinces.

library(dplyr)

# We first make some random data
weeks <- seq(as.Date("2022-11-01"), as.Date("2022-12-31"), by = "week")
tab_cases_week_by_prov <- tibble::tibble(
  week = rep(weeks, 2),
  Province = rep(c("Groningen", "Zeeland"), each = length(weeks)),
  n = c(
    seq(100, 200, length.out = length(weeks)) + rnorm(length(weeks), 0, 10), # Slightly increasing with noise
    seq(100, 200, length.out = length(weeks)) + rnorm(length(weeks), 0, 10) 
  )
)

# Then we make the basic plotly plot
prov_names <- unique(tab_cases_week_by_prov$Province)
prov_colors <- setNames(theme_rivm$colorway[seq_along(prov_names)], prov_names)

fig <- plot_ly()
for (prov in prov_names) {
  prov_data <- filter(tab_cases_week_by_prov, Province == prov)
  fig <- fig |> 
    plotly::add_trace(
      data = prov_data,
      x = ~week,
      y = ~n,
      type = "scatter",
      mode = "lines+markers", 
      name = prov,
      line = list(color = prov_colors[prov], width = 2),
      text = ~paste0(
        "Provincie: <b>", Province, "</b>",
        "<br>Week: <b>", format(week, "%e %b %Y"), "</b>",
        "<br>Aantal cases: <b>", format(round(n, 0), big.mark = ".", decimal.mark = ",", scientific = FALSE), "</b>"
      ),
      hoverinfo = "text"
    )
}


# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "trendline", 
                      y_data = tab_cases_week_by_prov$n,
                      y_label = "Aantal gevallen",
                      title = "COVID-19 gevallen per week voor twee provincies",
                      x_label = "Week",
                      x_axis_tick_format = "%d %b"
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig

Line chart

This example creates a grouped line chart showing cases by year and sex.

library(dplyr)
library(stringr)

# We first make some random data
data <- tibble::tibble(
  expand.grid(Jaar = 2001:2020, Geslacht = c("Man", "Vrouw")),
  value = sample(1:50, 40, TRUE)
)
data_sum <- data |>
  group_by(Jaar) |>
  summarize(value = sum(value), .groups = "drop") |>
  mutate(Geslacht = "Totaal")
data_all <- bind_rows(data, data_sum) |>
  mutate(Geslacht = factor(Geslacht, levels = c("Man", "Vrouw", "Totaal")))

# Then we make the basic plotly plot
kleuren <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood"),
  "Totaal" = ro_color("paars")
)

fig <- plot_ly()
for (geslacht in levels(data_all$Geslacht)) {
  subset <- filter(data_all, Geslacht == geslacht)
  fig <- fig |> 
    plotly::add_trace(
      data = subset,
      x = ~Jaar,
      y = ~value,
      type = "scatter",
      mode = "lines",
      name = geslacht,
      line = list(color = kleuren[geslacht], width = 2),
      text = ~str_c(
        "Geslacht: <b>", Geslacht,
        "</b><br>Jaar: <b>", Jaar,
        "</b><br>Aantal cases: <b>", value
      ),
      hoverinfo = "text"
    )
}

# And apply the Rijksoverheid / RIVM theme, and accesibility features
fig <- ro_ply_standard(fig,
                      type = "linechart", 
                      y_data = data_all$value,
                      y_label = "Aantal cases",
                      title = "COVID-19 cases per geslacht",
                      x_label = "" #For the year, no x-axis title is needed
                      )
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
## ! Can't find the `base_family` = "RijksoverheidSansWebText" in installed fonts,
##   and neither fall-back fonts, "Verdana" and "Arial", are installed.
## ℹ Falling back to "URW Gothic", the first font found on this system. Check
##   installed system fonts with `systemfonts::system_fonts()`.
fig