marquee

library(marquee)
library(grid)
library(ggplot2)

This document will get you up to speed on using marquee for rich text formatting in R graphics. Marquee is collectively a markdown dialect, a parser for the dialect and a grid renderer for text written in the dialect. The package aims to fill the same use cases as gridtext and ggtext by Claus Wilke, but works in a very different and more low-level way.

Requirements

Before we start we should note that marquee has been build for the future. What I mean by this is that it is based on a slew of new features in the R graphics engine putting very hard requirements on what R version it can be used with and which graphics devices it works with. If, for some reason, your setup cannot accommodate these needs you can perhaps get some of the way using gridtext/ggtext. The nuisance of this will likely diminish or completely disappear with time.

An example

md_text <- 
"# Lorem Ipsum
Lorem ipsum dolor sit amet, *consectetur* adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna **aliqua**. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo _consequat_. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla ~pariatur~. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

grob <- marquee_grob(md_text, classic_style())

grid.draw(grob)

From this small example you can see that markdown behaves as you’d expect. We have emphasis, strong, underline, and strikethrough, and stuff like headings etc. In fact, the full markdown (CommonMark) spec is supported and will behave as you’d expect.

Besides the standard grob arguments you’d expect, marquee_grob() takes two main arguments as you can see above. The text, which can be a character vector with multiple separate markdown strings, and a style specification, which again can be a vector of styles or a single style to format everything alike. Marquee ships with classic_style() which is designed to mimic the look of standard HTML rendered markdown. The function itself allows you to modify the final style, and you could also modify it after construction to create a completely new style:

new_style <- classic_style(body_font = "serif", header_font = "mono", hanging = em(1))

new_style <- modify_style(
  new_style, 
  "str", 
  background = "lightgrey", 
  border_radius = 3, 
  padding = trbl(em(0.2))
)

grid.draw(
  marquee_grob(md_text, new_style)
)

Besides standard markdown, marquee also allows you to create custom span classes. These span classes can be styled to anything, but marquee contains a nifty feature where, if the class matches a recognized color name or hex-code, it will be automatically coloured.

md_text_custom <- 
"# Lorem Ipsum
Lorem ipsum dolor {.red sit amet, *consectetur* adipiscing elit, sed do} eiusmod tempor
incididunt ut labore et dolore magna **aliqua**. Ut enim ad minim {#2af veniam}, quis nostrud
exercitation ul lamcolaboris nisi ut aliquip ex ea commodo _consequat_. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla ~pariatur~. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum."

grid.draw(
  marquee_grob(md_text_custom, classic_style())
)

If you provide a styling for the custom class it takes precedence over any matching color name

grid.draw(
  marquee_grob(md_text_custom, modify_style(classic_style(), "red", tracking = 400))
)

Use in ggplot2

Recognizing that most people doesn’t make visualizations directly with grid, marquee also contains the infrastructure to use markdown inside ggplot2 plots. It is expected that these functions will eventually move to ggplot2 proper, but while the package is stress tested they will stay here.

The marquee geom

One way to use marquee with ggplot2 is with geom_marquee(). It supersedes both geom_text() and geom_label() in its capabilities, and even if you don’t need to plot rich text, the styling of geom_marquee() is much more capable:

fancy_font <- classic_style(
  weight = "semibold",
  features = systemfonts::font_feature(
    ligatures = c("standard", "discretionary"),
    letters = c("stylistic", "swash", "historical")
  )
)
ggplot(mtcars, aes(disp, mpg, label = rownames(mtcars))) + 
  geom_marquee(style = fancy_font, size = 2.5, family = "spectral") # You may not have this font

However, the main use will probably be to mix in italicized, bold, or colored fonts in labels, which marquee makes very easy

cars <- sub("(\\w+)", "{.red ***\\1***}", rownames(mtcars))
cars
#>  [1] "{.red ***Mazda***} RX4"           "{.red ***Mazda***} RX4 Wag"      
#>  [3] "{.red ***Datsun***} 710"          "{.red ***Hornet***} 4 Drive"     
#>  [5] "{.red ***Hornet***} Sportabout"   "{.red ***Valiant***}"            
#>  [7] "{.red ***Duster***} 360"          "{.red ***Merc***} 240D"          
#>  [9] "{.red ***Merc***} 230"            "{.red ***Merc***} 280"           
#> [11] "{.red ***Merc***} 280C"           "{.red ***Merc***} 450SE"         
#> [13] "{.red ***Merc***} 450SL"          "{.red ***Merc***} 450SLC"        
#> [15] "{.red ***Cadillac***} Fleetwood"  "{.red ***Lincoln***} Continental"
#> [17] "{.red ***Chrysler***} Imperial"   "{.red ***Fiat***} 128"           
#> [19] "{.red ***Honda***} Civic"         "{.red ***Toyota***} Corolla"     
#> [21] "{.red ***Toyota***} Corona"       "{.red ***Dodge***} Challenger"   
#> [23] "{.red ***AMC***} Javelin"         "{.red ***Camaro***} Z28"         
#> [25] "{.red ***Pontiac***} Firebird"    "{.red ***Fiat***} X1-9"          
#> [27] "{.red ***Porsche***} 914-2"       "{.red ***Lotus***} Europa"       
#> [29] "{.red ***Ford***} Pantera L"      "{.red ***Ferrari***} Dino"       
#> [31] "{.red ***Maserati***} Bora"       "{.red ***Volvo***} 142E"

ggplot(mtcars) + aes(disp, mpg, label = cars) + 
  geom_marquee()

Another use of the geom, where rich text may come more into play, is in annotations. Let’s make a textbox style and add some lorem ipsum to our plot

text_box_style <- modify_style(
  classic_style(base_size = 2),
  "body",
  padding = skip_inherit(trbl(10)),
  border_radius = 3
)

ggplot(mtcars) + aes(disp, mpg, label = cars) + 
  geom_marquee(size = 2) + 
  annotate(GeomMarquee, 
    label = md_text, 
    x = 450, 
    y = 35, 
    style = text_box_style, 
    size = 2, 
    fill = "lightgrey",
    width = 0.3, 
    hjust = "right",
    vjust = "top"
  )