1

I have been using Claus Wilke's great ggtext package for markdown annotations for a while now, and until now it's worked perfectly. In the course of using ggtext to make multiple text annotations (mix of bold face and regular text on multiple lines), either with the ggtext::geom_richtext() or ggtext::geom_textbox(), I found the more geom_richtext()s I added increased the rendering time to the point where it would just churn on end (I gave up after 45 minutes the last time).

Of course, creating and saving the ggplot object with all of the geom_richtext() and element_markdown()s took little time. But when I tried to view the plot or use ggsave to save as a png/jpeg it again churned forever (again, I gave up after 30 minutes).

I've included a sample reprex below.

My questions for ggtext and ggplot2 power users:

  1. Is there an upper limit to the number of ggtext objects you can use in a ggplot2 plot? I'm not well-versed in grid and the underlying mechanics of ggplot.
  2. Are there alternatives to ggtext to mix font weights in annotations in ggplot2? I already tried the plotmath route after seeing this from @aosmith on SO: html - Embolden substring of object passed through geom_text() - Stack Overflow. The problem? atop() only works on one line, not multiple lines of text.

FWIW, the full non-reprex version of my code (and the viz I'm trying to recreate in ggplot2) are at https://github.com/kpivert/wsj/tree/main/01_R/06_cpi_again.

Any recommendations you may have would be greatly appreciated.

Please let me know if you need further clarification or if the reprex doesn't work.

Thanks for your time and consideration.

Kurtis

require(ggthemes)
#> Loading required package: ggthemes
require(ggtext)
#> Loading required package: ggtext
require(tictoc)
#> Loading required package: tictoc
require(tidyverse)
#> Loading required package: tidyverse

df <- data.frame(
  DATE = seq(as.Date("1913-01-01"), as.Date("2020-12-01"), "month")
  ) %>% 
  mutate(
    var = rnorm(n = nrow(.), mean = 0, sd = 0.5)
  )

# Years for X Axis Labels

yr_labs <- seq(as.Date("1915-01-01"), as.Date("2020-01-01"), by = "5 years") %>% 
  str_sub(start = 1, end = 4) 

yr_labs <- case_when(
  yr_labs == "1915" ~ "1915",
  yr_labs == "2020" ~ "2020",
  TRUE ~ str_c("'", str_sub(yr_labs, 3, 4))
)

tic()
ggplot(
  df, 
  aes(
    x = DATE,
    y = var
    )
  ) +
  geom_line(
    lwd = 0.2,
    color = "blue"
  ) +
  scale_x_continuous(
    breaks = seq(as.Date("1915-01-01"), as.Date("2020-01-01"), by = "5 years"), 
    labels = yr_labs
  ) +
  theme_tufte() +
  theme(
    panel.grid.major.y = element_line(size = .1),
    axis.ticks.y = element_blank(),
    axis.text.y = element_text(
      vjust = - 0.8, 
      margin = margin(l = 20, r = -20)
    ),
    plot.title = element_text(size = 16),
    plot.subtitle = element_text(size = 10),
    plot.caption = element_text(hjust = 0)
  ) +
  labs(
    x = "", 
    y = "",
    caption = "Source: Randomness",
    title = "Reprex Title",
    subtitle = "Reprex Subtitle"
  ) +
  # Annotations ----
# 1. WW I ----
geom_segment(
  aes(
    x = as.Date("1914-09-01"), 
    y = 1.25,
    xend = as.Date("1918-11-01"),
    yend = 1.25
  ),
  lwd = 1
) +
  geom_segment(
    aes(
      x = as.Date("1916-08-01"), 
      y = 1.25,
      xend = as.Date("1916-08-01"),
      yend = 1.28
    ),
    linetype = "dotted"
  ) +
geom_richtext(
  x = as.Date("1916-01-01"),
  y = 1.28,
  label = "<b>1914-18</b><br>World<br>War I",
  fill = NA,
  label.color = NA
) 
toc()
#> 20.668 sec elapsed

Created on 2021-12-07 by the reprex package (v2.0.1)

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 4.1.0 (2021-05-18)
#>  os       macOS Big Sur 10.16         
#>  system   x86_64, darwin17.0          
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  ctype    en_US.UTF-8                 
#>  tz       America/New_York            
#>  date     2021-12-07                  
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version date       lib source        
#>  assertthat    0.2.1   2019-03-21 [1] CRAN (R 4.1.0)
#>  backports     1.2.1   2020-12-09 [1] CRAN (R 4.1.0)
#>  broom         0.7.9   2021-07-27 [1] CRAN (R 4.1.0)
#>  cellranger    1.1.0   2016-07-27 [1] CRAN (R 4.1.0)
#>  cli           3.0.1   2021-07-17 [1] CRAN (R 4.1.0)
#>  colorspace    2.0-2   2021-06-24 [1] CRAN (R 4.1.0)
#>  crayon        1.4.1   2021-02-08 [1] CRAN (R 4.1.0)
#>  curl          4.3.2   2021-06-23 [1] CRAN (R 4.1.0)
#>  DBI           1.1.1   2021-01-15 [1] CRAN (R 4.1.0)
#>  dbplyr        2.1.1   2021-04-06 [1] CRAN (R 4.1.0)
#>  digest        0.6.28  2021-09-23 [1] CRAN (R 4.1.0)
#>  dplyr       * 1.0.7   2021-06-18 [1] CRAN (R 4.1.0)
#>  ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.1.0)
#>  evaluate      0.14    2019-05-28 [1] CRAN (R 4.1.0)
#>  fansi         0.5.0   2021-05-25 [1] CRAN (R 4.1.0)
#>  farver        2.1.0   2021-02-28 [1] CRAN (R 4.1.0)
#>  fastmap       1.1.0   2021-01-25 [1] CRAN (R 4.1.0)
#>  forcats     * 0.5.1   2021-01-27 [1] CRAN (R 4.1.0)
#>  fs            1.5.0   2020-07-31 [1] CRAN (R 4.1.0)
#>  generics      0.1.0   2020-10-31 [1] CRAN (R 4.1.0)
#>  ggplot2     * 3.3.5   2021-06-25 [1] CRAN (R 4.1.0)
#>  ggtext      * 0.1.1   2020-12-17 [1] CRAN (R 4.1.0)
#>  ggthemes    * 4.2.4   2021-01-20 [1] CRAN (R 4.1.0)
#>  glue          1.4.2   2020-08-27 [1] CRAN (R 4.1.0)
#>  gridtext      0.1.4   2020-12-10 [1] CRAN (R 4.1.0)
#>  gtable        0.3.0   2019-03-25 [1] CRAN (R 4.1.0)
#>  haven         2.4.3   2021-08-04 [1] CRAN (R 4.1.0)
#>  highr         0.9     2021-04-16 [1] CRAN (R 4.1.0)
#>  hms           1.1.0   2021-05-17 [1] CRAN (R 4.1.0)
#>  htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.1.0)
#>  httr          1.4.2   2020-07-20 [1] CRAN (R 4.1.0)
#>  jsonlite      1.7.2   2020-12-09 [1] CRAN (R 4.1.0)
#>  knitr         1.36    2021-09-29 [1] CRAN (R 4.1.0)
#>  labeling      0.4.2   2020-10-20 [1] CRAN (R 4.1.0)
#>  lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.1.0)
#>  lubridate     1.7.10  2021-02-26 [1] CRAN (R 4.1.0)
#>  magrittr      2.0.1   2020-11-17 [1] CRAN (R 4.1.0)
#>  markdown      1.1     2019-08-07 [1] CRAN (R 4.1.0)
#>  mime          0.12    2021-09-28 [1] CRAN (R 4.1.0)
#>  modelr        0.1.8   2020-05-19 [1] CRAN (R 4.1.0)
#>  munsell       0.5.0   2018-06-12 [1] CRAN (R 4.1.0)
#>  pillar        1.6.3   2021-09-26 [1] CRAN (R 4.1.0)
#>  pkgconfig     2.0.3   2019-09-22 [1] CRAN (R 4.1.0)
#>  purrr       * 0.3.4   2020-04-17 [1] CRAN (R 4.1.0)
#>  R6            2.5.1   2021-08-19 [1] CRAN (R 4.1.0)
#>  Rcpp          1.0.7   2021-07-07 [1] CRAN (R 4.1.0)
#>  readr       * 2.0.1   2021-08-10 [1] CRAN (R 4.1.0)
#>  readxl        1.3.1   2019-03-13 [1] CRAN (R 4.1.0)
#>  reprex        2.0.1   2021-08-05 [1] CRAN (R 4.1.0)
#>  rlang         0.4.11  2021-04-30 [1] CRAN (R 4.1.0)
#>  rmarkdown     2.11    2021-09-14 [1] CRAN (R 4.1.0)
#>  rstudioapi    0.13    2020-11-12 [1] CRAN (R 4.1.0)
#>  rvest         1.0.1   2021-07-26 [1] CRAN (R 4.1.0)
#>  scales        1.1.1   2020-05-11 [1] CRAN (R 4.1.0)
#>  sessioninfo   1.1.1   2018-11-05 [1] CRAN (R 4.1.0)
#>  stringi       1.7.5   2021-10-04 [1] CRAN (R 4.1.0)
#>  stringr     * 1.4.0   2019-02-10 [1] CRAN (R 4.1.0)
#>  styler        1.5.1   2021-07-13 [1] CRAN (R 4.1.0)
#>  tibble      * 3.1.5   2021-09-30 [1] CRAN (R 4.1.0)
#>  tictoc      * 1.0.1   2021-04-19 [1] CRAN (R 4.1.0)
#>  tidyr       * 1.1.3   2021-03-03 [1] CRAN (R 4.1.0)
#>  tidyselect    1.1.1   2021-04-30 [1] CRAN (R 4.1.0)
#>  tidyverse   * 1.3.1   2021-04-15 [1] CRAN (R 4.1.0)
#>  tzdb          0.1.2   2021-07-20 [1] CRAN (R 4.1.0)
#>  utf8          1.2.2   2021-07-24 [1] CRAN (R 4.1.0)
#>  vctrs         0.3.8   2021-04-29 [1] CRAN (R 4.1.0)
#>  withr         2.4.2   2021-04-18 [1] CRAN (R 4.1.0)
#>  xfun          0.26    2021-09-14 [1] CRAN (R 4.1.0)
#>  xml2          1.3.2   2020-04-23 [1] CRAN (R 4.1.0)
#>  yaml          2.2.1   2020-02-01 [1] CRAN (R 4.1.0)
#> 
#> [1] /Library/Frameworks/R.framework/Versions/4.1/Resources/library
kpivert
  • 11
  • 2
  • 1
    Instead of your `geom_segment` and `geom_richtext` layers, try `annotate("segment", x = as.Date("1914-09-01"), y = 1.25, xend = as.Date("1918-11-01"), yend = 1.25, lwd = 1 ) + annotate("richtext", x = as.Date("1916-01-01"), y = 1.28, label = "1914-18
    World
    War I", fill = NA, label.color = NA )`, much faster on my machine. I believe your method is overplotting the segment and text 1,296 times each, once for each row of original data. The `annotate` function lets you add one-off geoms that are not based on the original data.
    – Jon Spring Dec 08 '21 at 00:24
  • For reference, there are other questions on SO that address a similar issue from other directions, if you look for "ggplot2 overplotting" eg: https://stackoverflow.com/questions/11618392/ggplot-text-printed-by-geom-text-is-not-clear/11618663#11618663 or https://stackoverflow.com/a/10953050/6851825 – Jon Spring Dec 08 '21 at 00:37
  • Thanks very much, @JonSpring. Duh, of course it's overplotting. I totally missed the telltale clue in the reprex (the fuzzy text, not shown here because I don't have enough reputation to post the png). However, I wasn't aware of the "richtext" geom in annotate, which of course works like a charm, including with extrafont. Thanks again for your quick reply and help. – kpivert Dec 08 '21 at 15:38

1 Answers1

0

For the record, Jon Spring correctly noted the issue, which was the aesthetic mapping problem in the geom_segment() and geom_richtext() calls. In addition to his solution using annotate(), you can also pass a dataframe and use inherit.aes = FALSE so the text or segment isn't overplotted the same number of times as there are rows in the dataset. For example:

 geom_richtext(
    inherit.aes = FALSE,
    data = tibble(
    x = as.Date("1916-01-01"),
    y = 1.28,
    label = "<b>1914-18</b><br>World<br>War I"),
    aes(
      x = x,
      y = y,
      label = label),
    fill = NA,
    label.color = NA
  )

Kara Woo's great presentation at the 2021 rstudio::global conference addressed this very issue: https://www.rstudio.com/resources/rstudioglobal-2021/always-look-on-the-bright-side-of-plots/.

kpivert
  • 11
  • 2