Setup
Advantages of ob_label
over ob_latex
The ob_label
function uses ggtext::geom_richtext
to create labels. It’s primary advantage is that it is simple and renders quickly. Wherever possible, it is the recommended way to create labels. It understands some markdown formatting (e.g., italics and bolding) and some HTML tags (e.g., span
, sub
, sup
, img
, and style
).
Advantages of ob_latex
over ob_label
If something more elaborate is needed than italics, bolding, subscripts, and superscripts, we can use LaTeX instead. The ob_latex
function can place an image of a LaTeX equation in a ggplot diagram.
For example, suppose I want to label a latent variable’s variance with the symbol . This symbol would be difficult to render in HTML, so we can render it in LaTeX instead.
ggdiagram(font_family = "Roboto Condensed") +
{l <- ob_circle(label = ob_label("*e*", size = 48))} +
{lv <- ob_variance(l)} +
ob_latex(tex = "\\sigma_e^2",
center = lv@midpoint(),
width = .4)
If we want the symbol to be in the same font as the rest of the figure, we can trick LaTeX into giving us any font we have installed on our system. I often use Roboto Condensed:
ggdiagram(font_family = "Roboto Condensed") +
{l <- ob_circle(label = ob_label("*e*", size = 48))} +
{lv <- ob_variance(l)} +
ob_latex(tex = r"(\text{\emph{σ}}_{\text{\emph{e}}}^{\text{2}})",
center = lv@midpoint(),
width = .4,
family = "Roboto Condensed")
If you need an equation in a plot that requires something other than a 1:1 aspect ratio, you can set the aspect ratio of the equation to be the same as the aspect ratio as the plot.
ggplot() +
coord_fixed(ratio = 1000) +
theme_classic() +
stat_function(
fun = \(x) dnorm(x, mean = 50, sd = 10),
geom = "area",
n = 1000,
fill = "dodgerblue",
alpha = .5
) +
scale_x_continuous(breaks = seq(10,90,10), limits = c(10, 90)) +
scale_y_continuous(NULL, breaks = NULL, limits = c(0, dnorm(50,50,10))) +
ob_latex(
r"(f(x) =
\frac{1}{\sigma\sqrt{2\pi}}
e^{-\frac{1}{2}
\left(\frac{x-\mu}{\sigma}\right)^2})",
width = 30,
aspect_ratio = 1000,
border = 1,
filename = "zscore",
density = 600) %>%
place(ob_point(57, dnorm(57, 50, 10)),
where = "right",
sep = 3)
Image quality
The default density for ob_latex
images is 300 dots per inch. If a small expression is displayed as a large image, it will appear pixelated.
Setting the density to a higher value will usually create a better image.
Higher densities are not always better. In addition to using more memory and rendering more slowly, images with very high densities will sometimes appear blurry or pixelated.
How does ob_latex
work?
The ob_latex
function works through these steps:
- Create a .tex file with content based on the LaTeX standalone package.
- Create a .pdf file via the
tinytex::xelatex
function, if tinytex is available. Otherwise, use xelatex via a shell command. - Import the .pdf file as raster bitmap via the
magick::image_read_pdf
function. - Store raster bitmap in the
ob_latex@image
slot.
When rendered in ggplot2, the bitmap is displayed via ggplot2::annotation_raster
.