---
title: "plotly figures in Rijksoverheid style"
format: html
vignette: >
  %\VignetteIndexEntry{plotly figures in Rijksoverheid style}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
---

```{r eval, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, echo = TRUE)
```

```{r setup}
library(plotly)
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](https://plotly.com/r/) 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 Functions

- **`ro_ply_theme()`**  
  Returns a list of theming options (colors, fonts, grid, axis, legend, tooltip styles, etc.) based on the Rijksoverheid visual identity. You can customize many aspects, such as the color palette, fonts, grid lines, and axis formatting.

- **`ro_ply_add_theme()`**  
  Applies the Rijksoverheid / RIVM theme (from `ro_ply_theme()`) to any Plotly figure.

- **`ro_ply_title()`**  
  Adds a custom, left-aligned main title and axis labels as annotations, in line with the Rijksoverheid / RIVM style.

- **`ro_ply_cursor()`**  
  Changes the mouse cursor in interactive Plotly charts from a crosshair to a standard arrow for a friendlier user experience.

- **`ro_ply_legend_theme()`**  
  Enhances the legend styling by adding boxes around legend items.

- **`ro_ply_dim()`**  
  Ensures all charts have the correct dimensions for Rijksoverheid / RIVM reports, and are responsive in Shiny applications.

# Code Examples

## Column chart

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

The Rijksoverheid / RIVM theme is set with:
`theme_rivm <- ro_ply_theme(barmode = "group")`
where `barmode = "group"` ensures grouped bars for each age group.

```{r example column chart}
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"))
  )


theme_rivm <- ro_ply_theme(barmode = "group")
kleuren <- c(theme_rivm$colorway[1], theme_rivm$colorway[3], theme_rivm$colorway[4])

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"
)

fig <- ro_ply_add_theme(fig = fig, theme = theme_rivm)
fig <- ro_ply_title(fig, y_data = data$"Age group", y_label = "cases", title = "fancy title", x_label = "groups")
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)
fig
```


## Bar Graph

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

```{r example bar graph}
# Create example data: counts per group
bar_data <- tibble::tibble(
  Sex = c("Man", "Vrouw"),
  n = c(1234, 1675)
)

# Use the  color function for Rijksoverheid / RIVM colors
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood")
)

# Create plotly bar chart
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"
)

# Apply Rijksoverheid / RIVM theme
fig <- ro_ply_add_theme(fig, ro_ply_theme())

# Add custom title and axis labels
fig <- ro_ply_title(
  fig,
  y_data = bar_data$n,
  y_label = "Aantal cases",
  title = "COVID-19 cases per geslacht",
  x_label = "Geslacht"
)

# Apply cursor and legend theming
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)

fig
```

## Horizontal Bar Chart

This example demonstrates how to create a horizontal bar chart grouped by age group and sex.  
The Rijksoverheid / RIVM theme is customized to:
- show a spike line on the y-axis only,
- show the y-axis line and hide the x-axis line,
- show grid lines only for the x-axis.


```{r example horizontal barchart}
# Generate 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))

theme_rivm <- ro_ply_theme(y_axis_spike = TRUE,
                           x_axis_spike = FALSE,
                           y_axis_showline = TRUE,
                           x_axis_showline = FALSE,
                           y_axis_showgrid = FALSE,
                           x_axis_showgrid = TRUE)
kleuren <- c(theme_rivm$colorway[1], theme_rivm$colorway[3])

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>"
    ),
    hoverinfo = "text"
  )
fig <- ro_ply_add_theme(fig = fig, theme = theme_rivm)
fig <- ro_ply_title(fig, y_data = data$"Age group", y_label = "group", title = "fancy title", x_label = "cases")
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)
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.

```{r example stacked bar graph}
library(dplyr)

# Example data: number of cases per age group and sex
stacked_data <- tibble::tibble(
  Agegroup = rep(c("0-9", "10-19", "20-29", "30-39"), each = 3),
  Sex = rep(c("Man", "Vrouw", "Onbekend"), times = 4),
  n = c(10, 14, 2, 15, 17, 1, 23, 18, 0, 9, 11, 3)
)

# Define color palette using your color function
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood"),
  "Onbekend" = ro_color("donkergeel")
)

# Use ro_ply_theme with barmode = "stack"
theme_rivm <- ro_ply_theme(barmode = "stack")

# Create the plotly stacked bar chart
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>"
  ),
  hoverinfo = "text"
)

fig <- ro_ply_add_theme(fig, theme_rivm)
fig <- ro_ply_title(
  fig,
  y_data = stacked_data |>  group_by(Agegroup) |>  summarise(n_total = sum(n)) |>  pull(n_total),
  y_label = "Aantal cases",
  title = "COVID-19 cases per leeftijdsgroep en geslacht",
  x_label = "Leeftijdsgroep"
)
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)

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.

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

```{r example proportional stacked bar graph}
library(dplyr)

# Example data: Age group, Sex, and number of cases
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()

# Define color palette using your color function
sex_colors <- c(
  "Man" = ro_color("hemelblauw"),
  "Vrouw" = ro_color("robijnrood")
)

# Use ro_ply_theme with barmode = "stack"
theme_rivm <- ro_ply_theme(barmode = "stack")

# Create the proportional stacked bar chart (horizontal)
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"
)

fig <- ro_ply_add_theme(fig, theme_rivm)
fig <- ro_ply_title(
  fig,
  y_data = prop_data$bar_label,
  y_label = "Leeftijdsgroep",
  title = "Percentage COVID-19 cases per leeftijdsgroep en geslacht",
  x_label = "Percentage"
)
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)

# Format x-axis as percentage
fig <- fig |> 
  layout(
    xaxis = list(
      tickformat = ".0%",
      range = c(0, 1),
      title = "Percentage"
    )
  )

fig

```

## Trendline

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

Here, the x-axis is formatted to display as "day month" for better readability:
`theme_rivm <- ro_ply_theme(x_axis_tick_format = "%d %b")` where x_axis_tick_format customizes the date format on the x-axis.

```{r example trendline}
library(dplyr)
library(zoo)
library(stringr)

# Example data: daily cases with a 7-day rolling average
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>"
    )
  )

theme_rivm <- ro_ply_theme(x_axis_tick_format = "%d %b")

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"
  )

fig <- ro_ply_add_theme(fig, theme_rivm)
fig <- ro_ply_title(
  fig,
  y_data = tab_cases_rolling_average$n,
  y_label = "Aantal gevallen",
  title = "COVID-19 gevallen per dag en 7-daags gemiddelde",
  x_label = "Datum"
)
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)

fig

```

## Grouped Trendline
This example shows a grouped trendline for multiple provinces.

Here, the x-axis is formatted to display as "day month" for better readability:
`theme_rivm <- ro_ply_theme(x_axis_tick_format = "%d %b")` where x_axis_tick_format customizes the date format on the x-axis.

```{r example grouped trendline}
library(dplyr)

# Example: Simulated COVID-19 cases per week for 2 provinces
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) 
  )
)

theme_rivm <- ro_ply_theme(x_axis_tick_format = "%d %b")
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", # Or use mode = "lines+markers" for lines and points
      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"
    )
}
fig <- ro_ply_add_theme(fig, theme_rivm)
fig <- ro_ply_title(
  fig,
  y_data = tab_cases_week_by_prov$n,
  y_label = "Aantal gevallen",
  title = "COVID-19 gevallen per week voor 5 provincies",
  x_label = "Week"
)
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)
fig
```

## Line chart

This example creates a grouped line chart showing cases by year and sex.
The theme is set to display the x-axis as a plain number (year), without the default thousand separator:
`theme_rivm <- ro_ply_theme(x_axis_tick_format = ".0f")`
so years appear as 2001, 2002, etc.

```{r example line chart}
library(dplyr)
library(stringr)

# Generate 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")))

# Use Rijksoverheid / RIVM theme and color palette
theme_rivm <- ro_ply_theme(x_axis_tick_format = ".0f") # No thousand seperator for the x-axis
kleuren <- c(
  "Man" = theme_rivm$colorway[1],
  "Vrouw" = theme_rivm$colorway[3],
  "Totaal" = theme_rivm$colorway[4]
)

# Create the plotly line chart
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"
    )
}

fig <- ro_ply_add_theme(fig, theme = theme_rivm)
fig <- ro_ply_title(
  fig,
  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
)
fig <- ro_ply_cursor(fig)
fig <- ro_ply_legend_theme(fig)
fig <- ro_ply_dim(fig)
fig
```

