3.5 Fonts and Font Sizes
If the most challenging aspects of Venndir were the intricacies of placing labels, surely the next big challenge was ensuring any chosen font rendered correctly.
Particularly for signed count labels, the default output uses Unicode up and down arrows: \(↑\) and \(↓\). These Unicode characters have caused the most heartache, for various reasons related to Unicode font support and computer platform locale.
Most* font rendering issues are handled smoothly by the combination of marquee, systemfonts, and textshaping. These R packages strive to "make it work" by finding each character glyph in the specified font, or by using a suitable font substitution.
Particularly for PDF output, it may be necessary to embed
the font into the PDF file using grDevices::embedFonts()
or
grDevices::embedGlyphs()
. Using cairo_pdf()
should embed
fonts automatically, but has rare exceptions.

Figure 3.30: Most fonts 'just work' thanks to R package marquee, with enough flexibility to keep the focus on effective and artistic choices, and away from any annoyances.
3.5.1 Font Sizes
The default font size used in Venndir is 16
points, and is adjusted
with the argument font_cex
. Default font_cex=c(1, 1, 0.75)
therefore
defines values 16, 16, 12
, which are applied in order as follows:
- Set label
- Count label
- Signed count label(s)
The text is defined with a fixed font size, and is therefore independent of the size of the figure. If the figure itself is drawn on a small graphics device, the font sizes will remain the same, so some care should be taken to select font sizes appropriate for the output figure dimensions.
Ideally, the output device dimensions should be defined with fixed units, such as inches ('in'), or centimeters ('cm'), so that the final figure is clearly defined.
The argument font_cex
has specific behavior based upon the number
of values supplied in the argument:
font_cex
with one value: It is multiplied byc(1, 1, 0.75)
to be an easy adjustment to the typical defaults. Thusfont_cex=2
will double all font sizes.font_cex
with two values: The second value is repeated to make a vector of three values. This vector is multiplied byc(1, 1, 0.75)
, again as convenient way to adjust Set and Count labels proportional to their default values.
font_cex=c(2, 1)
will double the Set label, keeping Count and Signed at their defaults.font_cex
with three values: Three values are used directly.
The adjusted font_cex
is multiplied by 16
to define the font point size.
Several examples are shown in Figure 3.31.




Figure 3.31: Venn diagram showing modifications to font sizes by adjusting the argument font_cex
.
The last example (bottom-right panel) was created using the following code:
3.5.2 Overall Font Family
The overall font typeface used by venndir()
is defined with
the argument fontfamily
, for which the default is fontfamily="Arial"
.
See Available Font Families to review other fonts available.
Figure 3.32 uses the R 'serif' font, with fontfamily='serif'
.
.
setlist <- make_venn_test(n_sets=3, do_signed=TRUE)
v <- venndir(setlist,
main="fontfamily='serif'",
fontfamily="serif")

Figure 3.32: Venn diagram showing two sets, with all labels shown using a serif font, such as 'Times'.
Note that all the labels use 'serif' now, including in the legend.
Similarly, for Venn diagrams which show item labels,
the item font is adjusted with fontfamily
.
This type of plot can be created using venndir()
with argument show_labels="Ni"
, to place set name 'N' outside,
and item labels 'i' inside.
petlist <- list(
Dog=c("Needs walks", "Barks", "Round eyes"),
Cat=c("Free roam", "Meows", "Thin pupils"),
"Dog&Cat"=c("Furry", "Has claws", "Lovable"))
petsetlist <- overlaplist2setlist(petlist)
petv <- venndir(petsetlist,
font_cex=1.5,
item_cex_factor=0.8,
show_labels="Ni",
draw_legend=FALSE,
show_segment=FALSE,
keep_item_order=TRUE,
item_buffer=0, xyratio=2,
fontfamily="Optima")

Figure 3.33: Venn diagram showing Two sets 'Dogs' and 'Cats' with some attributes unique to each, and shared by both. The item labels use the 'Optima' font.
The example above includes some other useful customizations, discussed in detail later in the book. For now, here is a brief description:
font_cex=1.5
enlarges the set name font.draw_legend=FALSE
hides the color legend.show_segment=FALSE
hides the line segments.keep_item_order=TRUE
maintains the original order of item labels, therefore not sorting items alphabetically.item_buffer=0
reduces the buffer zone of each Venn region before determining item label positions.xyratio=2
increases the x:y ratio during item label placement, higher values tend to produce single column output.
Item labels can be displayed using venn_meme()
.
petlist <- list(
Dog=c("Needs walks", "Barks", "Round eyes"),
Cat=c("Free roam", "Meows", "Thin pupils"),
"Dog&Cat"=c("Furry", "Has claws", "Lovable"))
venn_meme(petlist,
font_cex=1.5,
item_cex_factor=0.8,
item_buffer=0, xyratio=1.5,
fontfamily="Optima",
show_labels="Ni")

Figure 3.34: Venn diagram showing Two sets 'Dogs' and 'Cats', this time created using venn_meme()
. The item labels use the 'Optima' font.
3.5.3 Individual Font Families
For more control over specific fonts, use argument fontfamilies
.
This argument expects a list
with these elements:
- overlap - fontfamily to use for set or overlap labels
- count - fontfamily to use for main count labels
- signed - fontfamily to use for signed count labels
Any value not customized will use the default fontfamily
value.
This example shows distinct fonts for each element, in fact it shows two fonts for "count" which corresponds to the main counts, and the percentage of counts, in order.
setlist <- make_venn_test(do_signed=TRUE)
venndir(setlist,
show_labels="Ncps",
main="Main Title (Times New Roman)",
fontfamily="Times New Roman",
y_inset=grid::unit(1, "lines"),
expand_fraction=c(0.15, 0, 0, 0),
fontfamilies=list(overlap="Optima",
count=c("Arial Black", "Times"),
signed="Arial Narrow"))

Figure 3.35: Venn diagram showing distinct font families used for each type of label: overlap, count, and signed.
The arguments to assemble_venndir_label()
also include fontfaces
which
may also be customized to control whether each font is 'plain', 'bold',
'italic', or 'bold.italic' for example. These customizations are rather
advanced, and are discussed in more detail later.
3.5.4 Available Font Families
Before getting into details with fonts, some useful terminology should be defined. Thomas Pederson wrote an excellent overview of font terms specific to R in Typography and R, as part of the systemfonts (Pedersen, Ooms, and Govett 2025) package.
To paraphrase, the commonly used term "font" typically refers to a 'typeface', for example 'Arial' and 'Helvetica' are each typefaces. The typeface may have several variations that may include width (normal, bold, or thin), and style (normal, italic, or oblique). Each variation represents its own "font" within the typeface. Some typefaces such as 'Helvetica Neue' may have 18 or more individual fonts!
With these terms in mind, R refers to a typeface with either the term
'fontfamily'
or 'family'
, and this convention is followed
in Venndir.
The systemfonts R package (Pedersen, Ooms, and Govett 2025) is used by Venndir, by way of the marquee R package (Pedersen and Mitáš 2025).
A function subset_systemfonts()
may be helpful to browse the available
fonts on the system running R. The following example demonstrates how
to summarize available fonts for 'Helvetica Neue', shown in
Table 3.5.
name | family | style | weight |
---|---|---|---|
HelveticaNeue-UltraLight | Helvetica Neue | UltraLight | thin |
HelveticaNeue-Thin | Helvetica Neue | Thin | ultralight |
HelveticaNeue-Light | Helvetica Neue | Light | light |
HelveticaNeue | Helvetica Neue | Regular | normal |
HelveticaNeue-Medium | Helvetica Neue | Medium | medium |
HelveticaNeue-Bold | Helvetica Neue | Bold | bold |
HelveticaNeue-CondensedBold | Helvetica Neue | Condensed Bold | bold |
HelveticaNeue-CondensedBlack | Helvetica Neue | Condensed Black | heavy |
HelveticaNeue-UltraLightItalic | Helvetica Neue | UltraLight Italic | thin |
HelveticaNeue-ThinItalic | Helvetica Neue | Thin Italic | ultralight |
HelveticaNeue-LightItalic | Helvetica Neue | Light Italic | light |
HelveticaNeue-Italic | Helvetica Neue | Italic | normal |
HelveticaNeue-MediumItalic | Helvetica Neue | Medium Italic | medium |
HelveticaNeue-BoldItalic | Helvetica Neue | Bold Italic | bold |
Note that it uses grepl()
on the column 'family'
to subset the
set of all available fonts. To list all fonts, use: subset_systemfonts()
.
3.5.4.1 Font family visualization
The results can be plotted by adding do_plot=TRUE
, as a
basic way of viewing the resulting fonts. Note that there are no provisions
to prevent overlapping labels, so this approach is considered as a
"quick check" to view only a few fonts.

Figure 3.36: Quick check of available fonts where the family name contains 'Helvetica'.
3.5.4.2 Automatic font substitution
Another helpful feature of systemfonts
is that it will substitute
a font, or a glyph within a font, when it cannot otherwise be found.
In Venndir, this approach helps ensure suitable Unicode characters
are used by default for example.
For example, the font family 'sans'
is replaced with the
appropriate corresponding font, which is important because it
differs on Windows, Mac, and linux architectures.
The typical defaults, for example:
'Arial' on Windows; 'Helvetica' on MacOS; 'DejaVu Sans' on Linux.
Similarly, when trying to use 'Arial' on a machine which lacks 'Arial',
systemfonts
will substitute a suitable replacement,
for example 'DejaVu Sans' or 'Helvetica'.
The font substitutions can be pre-defined, see systemfonts::font_fallback()
.
To review the font substitution, one can use systemfonts::font_info()
in the simple example below, however there is much more capability
described in the systemfonts documentation.
path | index | family | style | italic | bold | monospace | weight | width |
---|---|---|---|---|---|---|---|---|
/System/Library/Fonts/Helvetica.ttc | 0 | Helvetica | Regular | FALSE | FALSE | FALSE | normal | normal |