In this vignette, we explain how to customise the visualisation of
tables and plots. The vignette reviews the structure of the
.yml files that define styles, and demonstrates how to
create and apply custom styles. It also shows how to style tables and
plots programmatically, without the need to create a .yml
file.
library(visOmopResults)
library(here)
library(gt)
library(ggplot2)
library(dplyr)
library(officer)
The package currently includes two built-in styles for tables and
plots. Styles are defined using .yml files. To list the
available styles, use:
tableStyle()
#> [1] "darwin" "default"
plotStyle()
#> [1] "darwin" "default"
.ymlThe package contains two built-in styles: "default" and
"darwin". The .yml files for these styles can
be found here.
.yml structureWe use the "darwin" style as an example. The code chunk
below shows the structure of its .yml file:
brand:
color:
palette:
white: '#ffffff'
darwin-blue: '#003399'
background: white
foreground: darwin-blue
typography:
base: Calibri
base-font-size: 11
plot: Calibri
plot-font-size: 11
table: Calibri
table-font-size: 9
plot:
background-color: white
header-color: darwin-blue
header-text-color: white
grid-major-color: '#d9d9d9'
axis-color: '#252525'
border-color: '#595959'
legend-position: right
table:
border-color: darwin-blue
border-width: 1
header:
background-color: darwin-blue
text-bold: yes
align: center
text-color: white
border-color: white
font-size: 11
header-name:
background-color: darwin-blue
text-bold: yes
align: center
text-color: white
border-color: white
font-size: 11
header-level:
background-color: darwin-blue
text-bold: yes
align: center
text-color: white
border-color: white
font-size: 11
column-name:
background-color: darwin-blue
text-bold: yes
align: center
text-color: white
border-color: white
font-size: 11
group-label:
background-color: darwin-blue
text-bold: yes
text-color: white
border-color: white
title:
text-bold: yes
align: center
font-size: 15
subtitle:
text-bold: yes
align: center
font-size: 12
body:
border-width: 0.5
border-color: darwin-blue
The .yml structure can be divided into four main
sections:
background and foreground colors used when a
plot/table section does not override them.border-color and border-width, or
override settings per table section. Table sections include:
header, header-name,
header-level, column-name,
group-label, title, subtitle, and
body. For each section you can set properties such as
background-color, text-color,
text-bold, align, font-size,
border-color, and border-width.Each plot and table element follows a style hierarchy. If a value
isn’t specified at the most specific level, it inherits from
higher-level entries; if none are defined, the default
ggplot2 (for plots) or the default for the specific table
type is used. The table below shows the priority order for common plot
and table options.
| Part | Option 1 | Option 2 | Option 3 |
|---|---|---|---|
| Plot | |||
| Background color | plot:background-color | color:background | - |
| Header (facet) color | plot:header-color | color:foreground | - |
| Header (facet) text color | plot:header-text-color | - | - |
| Border color | plot:border-color | color:foreground | - |
| Grid color | plot:grid-major-color | color:foreground | - |
| Axis color | plot:axis-color | - | - |
| Legend position | plot:legend-position | - | - |
| Font family | typography:plot | typography:base | - |
| Font size | plot:font-size | typography:plot-font-size | typography:base-font-size |
| Table section | |||
| Background color | table:[section_name]:background-color | color:background | - |
| Text bold | table:[section_name]:text-bold | - | - |
| Text color | table:[section_name]:text-color | - | - |
| Text align | table:[section_name]:align | - | - |
| Font size | table:[section_name]:font-size | typography:table-font-size | typography:base-font-size |
| Font family | table:[section_name]:font-family | typography:table | typography:base |
| Border color | table:[section_name]:border-color | table:border-color | - |
| Border width | table:[section_name]:border-width | table:border-width | - |
In the examples above the YML path is represented with colon
separators. For example, plot:background-color refers to
the background-color key inside the plot
section.
The table-formatting functions (visTable(),
visOmopTable(), and formatTable()) and plot
functions accept a style argument. The style
argument can be:
"darwin"), or.yml file that defines a custom
style, or.yml structure
(only tables - see next section).Example: apply the built-in "darwin" style to a
plot:
result <- mockSummarisedResult() |>
filter(variable_name == "age")
barPlot(
result = result,
x = "cohort_name",
y = "mean",
facet = c("age_group", "sex"),
colour = "sex",
style = "darwin"
)
Example: use a custom .yml file (path provided):
barPlot(
result = result,
x = "cohort_name",
y = "mean",
facet = c("age_group", "sex"),
colour = "sex",
style = here("MyStyleFolder", "MyStyle.yml")
)
_brand.ymlIf style = NULL and no global options are provided (via
setGlobalPlotOptions() or
setGlobalTableOptions()), the built-in “default” style is
used. However, if a _brand.yml file is present in the
project directory, that file’s style will be used.
You can customise styles programmatically without creating a
.yml file by passing a named list to the style
argument. The list should follow the same table section structure as the
.yml.
Below is an example that sets table section styles for
gt.
result |>
visOmopTable(
estimateName = c("Mean (SD)" = "<mean> (<sd>)"),
groupColumn = "cohort_name",
header = c("This is an overall header", "sex"),
type = "gt",
style = list(
header = list(
cell_text(weight = "bold"),
cell_fill(color = "red")
),
header_name = list(
cell_text(weight = "bold"),
cell_fill(color = "orange")
),
header_level = list(
cell_text(weight = "bold"),
cell_fill(color = "yellow")
),
column_name = list(
cell_text(weight = "bold")
),
group_label = list(
cell_fill(color = "blue"),
cell_text(color = "white", weight = "bold")
),
title = list(
cell_text(size = 20, weight = "bold")
),
subtitle = list(
cell_text(size = 15)
),
body = list(
cell_text(color = "red")
)
),
.options = list(
title = "My formatted table!",
subtitle = "Created with the `visOmopResults` R package.",
groupAsColumn = FALSE,
groupOrder = c("cohort2", "cohort1")
)
)
| My formatted table! | |||||||
| Created with the `visOmopResults` R package. | |||||||
|
This is an overall header
|
|||||||
|---|---|---|---|---|---|---|---|
| CDM name | Age group | Variable name | Variable level | Estimate name |
Sex
|
||
| overall | Male | Female | |||||
| cohort2 | |||||||
| mock | overall | age | – | Mean (SD) | 38.24 (7.89) | 49.35 (4.78) | 18.62 (8.61) |
| <40 | age | – | Mean (SD) | 82.74 (4.38) | 86.97 (0.23) | 48.21 (7.32) | |
| >=40 | age | – | Mean (SD) | 66.85 (2.45) | 34.03 (4.77) | 59.96 (6.93) | |
| cohort1 | |||||||
| mock | overall | age | – | Mean (SD) | 38.00 (7.94) | 12.56 (6.47) | 26.72 (7.83) |
| <40 | age | – | Mean (SD) | 38.61 (5.53) | 77.74 (1.08) | 21.21 (4.11) | |
| >=40 | age | – | Mean (SD) | 1.34 (5.30) | 93.47 (7.24) | 65.17 (8.21) | |
Note that style objects differ across table engines, so the code must be adapted to the engine you use.
For flextable, styling objects come from the
officer package. The structure is similar, but the style
objects differ:
result |>
visOmopTable(
estimateName = c("Mean (SD)" = "<mean> (<sd>)"),
groupColumn = "cohort_name",
header = c("This is an overall header", "sex"),
type = "flextable",
style = list(
header = list(
cell = fp_cell(background.color = "red"),
text = fp_text(bold = TRUE)
),
header_level = list(
cell = fp_cell(background.color = "orange"),
text = fp_text(bold = TRUE)
),
header_name = list(
cell = fp_cell(background.color = "yellow"),
text = fp_text(bold = TRUE)
),
column_name = list(
text = fp_text(bold = TRUE)
),
group_label = list(
cell = fp_cell(background.color = "blue"),
text = fp_text(bold = TRUE, color = "white")
),
title = list(
text = fp_text(bold = TRUE, font.size = 20)
),
subtitle = list(
text = fp_text(font.size = 15)
),
body = list(
text = fp_text(color = "red")
)
),
.options = list(
title = "My formatted table!",
subtitle = "Created with the `visOmopResults` R package.",
groupAsColumn = FALSE,
groupOrder = c("cohort2", "cohort1")
)
)
My formatted table! | |||||||
|---|---|---|---|---|---|---|---|
Created with the `visOmopResults` R package. | |||||||
CDM name | Age group | Variable name | Variable level | Estimate name | This is an overall header | ||
Sex | |||||||
overall | Male | Female | |||||
cohort2 | |||||||
mock | overall | age | – | Mean (SD) | 38.24 (7.89) | 49.35 (4.78) | 18.62 (8.61) |
<40 | age | – | Mean (SD) | 82.74 (4.38) | 86.97 (0.23) | 48.21 (7.32) | |
>=40 | age | – | Mean (SD) | 66.85 (2.45) | 34.03 (4.77) | 59.96 (6.93) | |
cohort1 | |||||||
mock | overall | age | – | Mean (SD) | 38.00 (7.94) | 12.56 (6.47) | 26.72 (7.83) |
<40 | age | – | Mean (SD) | 38.61 (5.53) | 77.74 (1.08) | 21.21 (4.11) | |
>=40 | age | – | Mean (SD) | 1.34 (5.30) | 93.47 (7.24) | 65.17 (8.21) | |
Plot helpers return ggplot2 objects, so you can further
modify them using + and regular ggplot2
calls:
library(ggplot2)
barPlot(
result = result,
x = "cohort_name",
y = "mean",
facet = c("age_group", "sex"),
colour = "sex"
) +
theme(
strip.background = element_rect(fill = "#ffeb99", colour = "#ffcc00"),
legend.position = "top",
panel.grid.major = element_line(color = "transparent", linewidth = 0.25)
) +
scale_color_manual(values = c("black", "black", "black")) +
scale_fill_manual(values = c("#999999", "#E69F00", "#56B4E9"))
ggplotIf you want to use a font that is not already installed on your system, follow these steps:
.ttf file and
click Install Font. Example Calibri TTF (if not available on
your system): https://www.freefontdownload.org/en/calibri.font.ttf file and
choose Install (or Install for all users).After installing, restart RStudio so the system font registry is updated.
extrafont package
(R)library(extrafont)
# import system fonts (may take several minutes) - just needs to be done when
# a new font is installed
font_import(paths = NULL, prompt = FALSE)
# make fonts available for graphic devices using R
loadfonts(device = "win")
The previous process is embeded in the function
requireExtrafont() from visOmopResults, so the user could
run that single function instead.
Notes: - font_import() scans system font directories. If
you want to import fonts from a custom folder, pass
paths = "path/to/folder".
font_import() can take a long time the first time it
runs.
extrafont::loadfonts() makes fonts available to R’s
graphics devices. For PDFs, call loadfonts(device = "pdf")
before saving plots.
Set the font family in the .yml file, or in
element_text() calls within theme. As an
example we run with “darwin” style, which if “Calibri” is loaded will
use it (otherwise it defaults to “sans”).
barPlot(
result = result,
x = "cohort_name",
y = "mean",
facet = c("age_group", "sex"),
colour = "sex",
style = "darwin"
)
Remember the following:
After installing system fonts, restart R/RStudio so R sees the new fonts.
Use extrafont::font_import() once (or when you add
new fonts) — it populates the extrafont database.
The .yml customisation system allows you to control most
aspects of the visual appearance of your tables and plots. To learn more
about brand.yml and how it interacts with other elements
such as Shiny apps and Quarto/R Markdown documents, refer to https://posit-dev.github.io/brand-yml/.