Building Pictograms

library(waffle)
library(hrbrthemes)
library(extrafont)
library(dplyr)

Isotype pictograms are kinda like waffle charts but can also convey additional meaning through conveys its meaning through the resemblance to a physical object.

The current iteration of the {waffle} package makes it possible to make isotype pictograms through the use of Font Awesome 5 glyph fonts. Specifically, there is support for the solid and brands Font Awesome 5 variants. (We’ll be abbreviated “Font Awesome 5” as just “FA” from this point forward.)

To use FA fonts you need to install them onto your system and then make them available to R. To make the first step in the process easier the package includes an install_fa_fonts() function which will present the location of the FA TrueType fonts (ttf) that come with the package. Navigate there, install them however you do that on your operating system, them come back to R and run extrafont::font_import(). The {extrafont} package is a dependency of this package so it should have come along for the ride when you installed {waffle}.

To see if that incantation worked, you can do:

extrafont::loadfonts(quiet = TRUE)

extrafont::fonttable() %>% 
  as_tibble() %>% 
  filter(grepl("Awesom", FamilyName)) %>% 
  select(afmfile, FullName, FamilyName, FontName)
## # A tibble: 4 x 4
##   afmfile           FullName           FamilyName          FontName        
##   <chr>             <chr>              <chr>               <chr>           
## 1 fontawesome-webf… FontAwesome        FontAwesome         FontAwesome     
## 2 fa-brands-400.af… Font Awesome 5 Br… Font Awesome 5 Bra… FontAwesome5Bra…
## 3 fa-regular-400.a… Font Awesome 5 Fr… Font Awesome 5 Fre… FontAwesome5Fre…
## 4 fa-solid-900.afm… Font Awesome 5 Fr… Font Awesome 5 Fre… FontAwesome5Fre…

Because it’s 2019 and fonts are still daftly difficult across operating systems you may have different FontName or FamilyName values for each. If so, you won’t be able to use the shortcut names and will have to work some things out on your own or file an issue so I can try to account for your setup in the package itself.

While FA is great and provides a clever way to get glyphs into R charts without too many machinations a major downside is that Unicode values are used to handle the glyph mappings. Typing Unicode values is seriously not fun regardless of context and it’s also not cool that you have to remember the glyph short name and also the Unicode value. We’ve tried to alieviate some of this pain in a few ways.

First, we’ve provided the function fa_list() which presents an htmlwidget with the short name, which type (brand or solid) it is and also a small image of the font itself. Rather than demonstrate that (and put 139 SVG files in the generated Rmd vignette and kill CRAN’s servers) we’ll demonstrate a sibling function — fa_grep() — which lets you do the search before presenting the widget. So, say you wanted to make an isotype pictogram that uses a rocket. You can do something like:

fa_grep("rocket")

which will present a widget with the available choices. Now, you only need to remember 2 things, the “rocket” short name and that it’s in the solid FA font package.

A more practical example may be that you’re trying to show proportions of consumption of three food areas: fruit, sandwiches, and pizza. We can look for available glyphs by paging or guessing some good keywords to grep for:

fa_grep("bread|pizza|apple|pear|peach|lemon|sandwich")

We’ll use apple-alt, bread-slice and pizza-slice. Now, we just need some data.

tibble(
  food_group = factor(
    c("Fruit", "Sandwiches", "Pizza"),
    levels=c("Fruit", "Sandwiches", "Pizza")
  ),
  consumption = c(5, 20, 52)
) -> xdf

xdf
## # A tibble: 3 x 2
##   food_group consumption
##   <fct>            <dbl>
## 1 Fruit                5
## 2 Sandwiches          20
## 3 Pizza               52

Here’s what a traditional waffle chart might look like for that:

ggplot(xdf, aes(fill = food_group, values = consumption)) +
  geom_waffle() +
  coord_equal() +
  theme_ipsum_rc(grid="") +
  theme_enhance_waffle()

Really, you should be making proportional waffle charts since the whole point is to compare parts of a while and we’re pretty good (as humans) of doing that in a 10x10 matrix. The geom_waffle() function can do that for us for free:

ggplot(xdf, aes(fill = food_group, values = consumption)) +
  geom_waffle(n_rows = 10, make_proportional = TRUE) +
  coord_equal() +
  theme_ipsum_rc(grid="") +
  theme_enhance_waffle()

But, this is food and it’s fun to play with our food (as we all learned as kids) so let’s try turning the boring waffle chart into an pictogram. There are two key {ggplot2} components that come with the {waffle} package that we _need to use every time we make a pictogram`!!:

Here’s how we do that (annotated with comments in the code block:

ggplot(xdf, aes(label = food_group, values = consumption)) +
  geom_pictogram(n_rows = 10, make_proportional = TRUE, color = "black") +
  scale_label_pictogram(
    name = NULL,
    values = c(
      Fruit = "apple-alt", 
      Sandwiches = "bread-slice", 
      Pizza = "pizza-slice"
    )
  ) +
  coord_equal() +
  theme_ipsum_rc(grid="") +
  theme_enhance_waffle() +
  theme(legend.key.height = unit(2.25, "line")) +
  theme(legend.text = element_text(size = 10, hjust = 0, vjust = 0.75))

The extra theme() components may be of use to you to help get your output to be decent. Combining these FA glyphs with regular text is a bit tricky and you may need to fiddle with sizing to get the exact look you’re going for.

That pictogram is fine, but it could use some color. Let’s add some in:

ggplot(xdf, aes(label = food_group, values = consumption, color = food_group)) +
  geom_pictogram(n_rows = 10, make_proportional = TRUE) +
  scale_color_manual(
    name = NULL,
    values = c(
      Fruit = "#a40000",
      Sandwiches = "#c68958", 
      Pizza = "#ae6056"
    )
  ) +
  scale_label_pictogram(
    name = NULL,
    values = c(
      Fruit = "apple-alt", 
      Sandwiches = "bread-slice", 
      Pizza = "pizza-slice"
    )
  ) +
  coord_equal() +
  theme_ipsum_rc(grid="") +
  theme_enhance_waffle() +
  theme(legend.key.height = unit(2.25, "line")) +
  theme(legend.text = element_text(size = 10, hjust = 0, vjust = 0.75))

All the same powerful features of geom_waffle() are available to geom_pictogram() (including faceting/etc) but you should use them carefully, sparingly, and wisely. Pictures can help tell a data story but pictures can also distract from the data story.