---
title: "Markdown theme elements"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Markdown theme elements}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 4,
  fig.height = 3.75
)
```


The ggtext package defines two new theme elements, `element_markdown()` and `element_textbox()`/`element_textbox_simple()`, which can be used in place of `element_text()` in ggplot2 themes.

### Simple text labels

Simple text labels are created with `element_markdown()`. To demonstrate typical usage, let's start with a basic plot of a parabola.

```{r message = FALSE}
library(ggplot2)
library(ggtext)

base <- ggplot(data.frame(x = c(-5, 5)), aes(x)) +
  stat_function(fun = ~ .x*.x)

base
```

This plot would benefit from nicer axis labels. In particular, assume we want the x axis label to read "independent variable *x*" and the y axis label to read "dependent variable *y* = *x*<sup>2</sup>". In Markdown, we could write the axis labels as `independent variable *x*` and `dependent variable *y* = *x*<sup>2</sup>`. However, if we do so, we need to tell ggplot2 to interpret the axis labels as Markdown and not as plain text. We do this by setting `axis.title.x` and `axis.title.y` to `element_markdown()`. (Note that both are set to `element_text()` in the default theme.)

```{r}
base +
  labs(
    x = "independent variable *x*",
    y = "dependent variable *y* = *x*<sup>2</sup>"
  ) +
  theme(
    axis.title.x = element_markdown(),
    axis.title.y = element_markdown()
  )
```

The new element `element_markdown()` behaves just like `element_text()`. For example, we can modify the color or the font size.

```{r}
base +
  labs(
    x = "independent variable *x*",
    y = "dependent variable *y* = *x*<sup>2</sup>"
  ) +
  theme(
    axis.title.x = element_markdown(color = "blue"),
    axis.title.y = element_markdown(size = rel(0.8))
  )
```

Inheritance of theme settings also works. For example, we can set both color and font size for `axis.title`, and then both `axis.title.x` and `axis.title.y` inherit the setting.

```{r}
base +
  labs(
    x = "independent variable *x*",
    y = "dependent variable *y* = *x*<sup>2</sup>"
  ) +
  theme(
    axis.title = element_text(color = "blue", size = rel(0.8)),
    axis.title.x = element_markdown(),
    axis.title.y = element_markdown()
  )
```

Note that we used `element_text()` instead of `element_markdown()` for `axis.title` in the above plot.  We could have used `element_markdown()` as well and the result would have been the same. It doesn't matter that we set `axis.title = element_text()`, because the `axis.title` element isn't actually rendered, only the `axis.title.x` and `axis.title.y` elements are. We're setting `axis.title` only for the purpose of providing shared parameter values to `axis.title.x` and `axis.title.y`.

This is important to keep in mind when trying to create more unusual plots, e.g. with the y axis on the right. The naive code fails:

```{r}
base +
  labs(
    x = "independent variable *x*",
    y = "dependent variable *y* = *x*<sup>2</sup>"
  ) +
  scale_y_continuous(position = "right") +
  theme(
    axis.title = element_text(color = "blue", size = rel(0.8)),
    axis.title.x = element_markdown(),
    axis.title.y = element_markdown()
  )
```

This happens because the axis title on the right is actually drawn by `axis.title.y.right`. Therefore, setting that element to `element_markdown()` creates the desired result.

```{r}
base +
  labs(
    x = "independent variable *x*",
    y = "dependent variable *y* = *x*<sup>2</sup>"
  ) +
  scale_y_continuous(position = "right") +
  theme(
    axis.title = element_text(color = "blue", size = rel(0.8)),
    axis.title.x = element_markdown(),
    axis.title.y.right = element_markdown()
  )
```

Additional styling can be applied via inline CSS. The CSS properties `color`, `font-size`, and `font-family` are currently supported. Multi-line labels can be created by placing `<br>` tags where line breaks are desired.

```{r fig.width = 5, message = FALSE}
library(dplyr)

mtcars %>%
  mutate(
    transmission = ifelse(am == 1, "automatic", "manual")
  ) %>%
  ggplot(aes(hp, mpg, color = transmission)) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c(automatic = "#0072B2", manual = "#D55E00"),
    guide = "none"
  ) +
  labs(
    x = "Horse power",
    y = "Miles per gallon (MPG)",
    title = "<span style = 'font-size:14pt; font-family:Helvetica;'>Transmission type impacts fuel efficiency</span><br>
MPG is higher for <span style = 'color:#0072B2;'>automatic</span>
than for <span style = 'color:#D55E00;'>manual</span> transmissions"
  ) +
  theme_bw() +
  theme(
    text = element_text(family = "Times"),
    plot.title.position = "plot",
    plot.title = element_markdown(size = 11, lineheight = 1.2)
  )

```

We set the `lineheight` property to 1.2 because the default lineheight is too small for multi-line text labels rendered with `element_markdown()`.

### Text boxes

Text boxes can be created with `element_textbox()` or `element_textbox_simple()`. Text boxes differ from labels created with `element_markdown()` in that they tend to have a specific width and wrap their contents so it fits that width. The height of a textbox is normally calculated automatically so it matches the content height, but explicitly setting the height is also possible. Finally, while markdown labels can be displayed at any angle, textboxes have only four possible orientations, upright, left-rotated, right-rotated, and inverted.

In practice, setting a theme element to `element_textbox()` in a ggplot2 theme will frequently not have the desired result, because textboxes require many additional parameters that are not set by the parent text elements present in standard themes. To work around this issue, you can use `element_textbox_simple()`. It sets reasonable defaults for the additional parameters and thus can be used more readily. You will usually be able to use `element_textbox_simple()` as is, with only a few parameter adjustments required. 

The following example adds both a title and a subtitle to the plot by drawing one single text box.

```{r fig.width = 5, message = FALSE}
base <- mtcars %>%
  mutate(
    transmission = ifelse(am == 1, "automatic", "manual")
  ) %>%
  ggplot(aes(hp, mpg, color = transmission)) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c(automatic = "#0072B2", manual = "#D55E00"),
    guide = "none"
  ) +
  labs(
    x = "Horse power",
    y = "Miles per gallon (MPG)",
    title = "Transmission type impacts fuel efficiency<br>
<span style = 'font-size:10pt;'>Miles per gallon (MPG) is on average higher for cars
with <span style = 'color:#0072B2;'>automatic transmission</span> than for cars with
<span style = 'color:#D55E00;'>manual transmission.</span> However, MPG generally
declines with increasing horse power.</span>"
  ) +
  theme_bw() + theme(plot.title.position = "plot")

base +
  theme(
    plot.title = element_textbox_simple(
      size = 14, lineheight = 1, padding = margin(0, 0, 5, 0)
    )
  )
```

Text boxes can have a background color and a border, and they have internal padding and external margins.

```{r fig.width = 5, message = FALSE}
base +
  theme(
    plot.title = element_textbox_simple(
      size = 14, lineheight = 1,
      linetype = 1, # turn on border
      box.color = "#748696", # border color
      fill = "#F0F7FF", # background fill color
      r = grid::unit(3, "pt"), # radius for rounded corners
      padding = margin(5, 5, 5, 5), # padding around text inside the box
      margin = margin(0, 0, 10, 0) # margin outside the box
    )
  )
```

We can explicitly restrict the width of the box, and we can align the box relative to the enclosing space (with `hjust` and `vjust`) and the box content relative to the box edges (with `halign` and `valign`, not shown).

```{r fig.width = 5, message = FALSE}
base +
  theme(
    plot.title = element_textbox_simple(
      size = 14, lineheight = 1, 
      width = grid::unit(4, "in"), # fixed width
      hjust = 1, # alignment of box relative to plot
      linetype = 1, # turn on border
      box.color = "#748696", # border color
      fill = "#F0F7FF", # background fill color
      r = grid::unit(3, "pt"), # radius for rounded corners
      padding = margin(5, 5, 5, 5), # padding around text inside the box
      margin = margin(0, 0, 10, 0) # margin outside the box
    )
  )
```

If we want a box to be rotated, we can use the `orientation` parameter.

```{r}
mtcars %>%
  mutate(
    transmission = ifelse(am == 1, "automatic", "manual")
  ) %>%
  ggplot(aes(hp, mpg, color = transmission)) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c(automatic = "#0072B2", manual = "#D55E00"),
    guide = "none"
  ) +
  labs(
    x = "Horse power",
    y = "Miles per gallon (MPG) is on average higher for cars with <span style =
'color:#0072B2;'>automatic transmission</span> than for cars with <span style =
'color:#D55E00;'>manual transmission.</span>",
    title = "Transmission type impacts fuel efficiency"
  ) +
  theme_bw() + 
  theme(
    plot.title.position = "plot",
    axis.title.y = element_textbox_simple(
      orientation = "left-rotated",
      width = grid::unit(2.5, "in"),
      hjust = 0, fill = "#F0F7FF",  
      padding = margin(5, 5, 5, 5),
      margin = margin(0, 0, 10, 0)
    )
  )
```
