The fmt_icon() function

For this first example of generating icons with fmt_icon(), let’s make a simple tibble that has two columns of Font Awesome icon names. We separate multiple icons per cell with commas. By default, the icons are 1 em in height; we’re going to make the icons slightly larger here (so we can see the fine details of them) by setting height = "4em".

dplyr::tibble(
  animals = c(
    "hippo", "fish,spider", "mosquito,locust,frog",
    "dog,cat", "kiwi-bird"
  ),
  foods = c(
    "bowl-rice", "egg,pizza-slice", "burger,lemon,cheese",
    "carrot,hotdog", "bacon"
  )
) |>
  gt() |>
  fmt_icon(height = "4em") |>
  cols_align(align = "center", columns = everything())
animals foods
Hippo Bowl Rice
Fish Spider Egg Pizza Slice
Mosquito Locust Frog Burger Lemon Cheese
Dog Cat Carrot Hotdog
Kiwi Bird Bacon

Let’s take a few rows from the towny dataset and make it so the csd_type column contains Font Awesome icon names (we want only the "city" and "house-chimney" icons here). After using fmt_icon() to format the csd_type column, we get icons that are representative of the two categories of municipality for this subset of data.

towny |>
  dplyr::select(name, csd_type, population_2021) |>
  dplyr::filter(csd_type %in% c("city", "town")) |>
  dplyr::group_by(csd_type) |>
  dplyr::slice_max(population_2021, n = 5) |>
  dplyr::ungroup() |>
  dplyr::mutate(
    csd_type = ifelse(csd_type == "town", "house-chimney", "city")
  ) |>
  gt() |>
  fmt_integer() |>
  fmt_icon(columns = csd_type) |>
  cols_move_to_start(columns = csd_type) |>
  cols_label(
    csd_type = "",
    name = "City/Town",
    population_2021 = "Population"
  )
City/Town Population
City Toronto 2,794,356
City Ottawa 1,017,449
City Mississauga 717,961
City Brampton 656,480
City Hamilton 569,353
House Chimney Oakville 213,759
House Chimney Whitby 138,501
House Chimney Milton 132,979
House Chimney Ajax 126,666
House Chimney Newmarket 87,942

Let’s use a portion of the metro dataset to create a gt table. Depending on which train services are offered at the subset of stations, Font Awesome icon names will be applied to cells where the different services exist (the specific names are "train-subway", "train", and "train-tram"). With tidyr::unite(), those icon names can be converged into a single column (services) with the NA values removed. Since the names correspond to icons and they are in the correct format (separated by commas), they can be formatted as Font Awesome icons with fmt_icon().

metro |>
  dplyr::select(name, lines, connect_rer, connect_tramway, location) |>
  dplyr::slice_tail(n = 10) |>
  dplyr::mutate(lines = "train-subway") |>
  dplyr::mutate(connect_rer = ifelse(!is.na(connect_rer), "train", NA)) |>
  dplyr::mutate(
    connect_tramway = ifelse(!is.na(connect_tramway), "train-tram", NA)
  ) |>
  tidyr::unite(
    col = services,
    lines:connect_tramway,
    sep = ",",
    na.rm = TRUE
  ) |>
  gt() |>
  fmt_icon(
    columns = services,
    a11y = "decorative"
  ) |>
  cols_merge(
    columns = c(name, services),
    pattern = "{1} ({2})"
  ) |>
  cols_label(
    name = "Station",
    location = "Location"
  )
Station Location
Bibliothèque François Mitterrand ( ) Paris 13th
Chevilly-Larue ( ) Chevilly-Larue
Cour Saint-Émilion () Paris 12th
Hôpital Bicêtre () Le Kremlin-Bicêtre
L'Haÿ-les-Roses () L'Haÿ-les-Roses
Olympiades () Paris 13th
Pont Cardinet () Paris 17th
Saint-Denis–Pleyel () Saint-Denis
Saint-Ouen ( ) Clichy, Saint-Ouen-sur-Seine
Thiais–Orly () Thiais

Taking a handful of starred reviews from a popular film review website, we will attempt to format a numerical score (0 to 4) to use the "star" and "star-half" icons. In this case, it is useful to generate the repeating sequence of icon names (separated by commas) in the rating column before introducing the table to gt(). We can make use of the numerical rating values in stars within fmt_icon() with a little help from from_column(). Using that, we can dynamically adjust the icon’s fill_alpha (i.e., opacity) value and accentuate the films with higher scores.

dplyr::tibble(
  film = c(
    "The Passengers of the Night", "Serena", "The Father",
    "Roma", "The Handmaiden", "Violet", "Vice"
  ),
  stars = c(3, 1, 3.5, 4, 4, 2.5, 1.5)
) |>
  dplyr::mutate(rating = dplyr::case_when(
    stars %% 1 == 0 ~ strrep("star,", stars),
    stars %% 1 != 0 ~ paste0(strrep("star,", floor(stars)), "star-half")
  )) |>
  gt() |>
  fmt_icon(
    columns = rating,
    fill_color = "red",
    fill_alpha = from_column("stars", fn = function(x) x / 4)
  ) |>
  cols_hide(columns = stars) |>
  tab_source_note(
    source_note = md(
      "Data obtained from <https://www.rogerebert.com/reviews>."
    )
  )
film rating
The Passengers of the Night Star Star Star
Serena Star
The Father Star Star Star Star Half
Roma Star Star Star Star
The Handmaiden Star Star Star Star
Violet Star Star Star Half
Vice Star Star Half
Data obtained from https://www.rogerebert.com/reviews.

A fairly common thing to do with icons in tables is to indicate whether a quantity is either higher or lower than another. Up and down arrow symbols can serve as good visual indicators for this purpose. We can make use of the "up-arrow" and "down-arrow" icons here. The fmt_icon() function has to find those text values in cells to generate the icons, so, lets generate the text within a new column with cols_add() (an expression is used therein to generate the correct text given the close and open values). Following that, fmt_icon() is used and its fill_color argument is provided with a named vector that indicates which color should be used for each icon.

sp500 |>
  dplyr::slice_head(n = 10) |>
  dplyr::select(date, open, close) |>
  dplyr::arrange(-dplyr::row_number()) |>
  gt(rowname_col = "date") |>
  cols_add(week = date, .after = date) |>
  cols_add(dir = ifelse(close > open, "arrow-up", "arrow-down")) |>
  cols_merge(columns = c(date, week), pattern = "{1} ({2})") |>
  fmt_date(columns = date, date_style = "m_day_year") |>
  fmt_datetime(columns = week, format = "w", pattern = "W{x}") |>
  fmt_currency() |>
  fmt_icon(
    columns = dir,
    fill_color = c("arrow-up" = "green", "arrow-down" = "red")
  ) |>
  cols_label(
    open = "Opening Value",
    close = "Closing Value",
    dir = ""
  ) |>
  opt_stylize(style = 1, color = "gray")
Opening Value Closing Value
Dec 17, 2015 (W51) $2,073.76 $2,041.89 Arrow Down
Dec 18, 2015 (W51) $2,040.81 $2,005.55 Arrow Down
Dec 21, 2015 (W52) $2,010.27 $2,021.15 Arrow Up
Dec 22, 2015 (W52) $2,023.15 $2,038.97 Arrow Up
Dec 23, 2015 (W52) $2,042.20 $2,064.29 Arrow Up
Dec 24, 2015 (W52) $2,063.52 $2,060.99 Arrow Down
Dec 28, 2015 (W53) $2,057.77 $2,056.50 Arrow Down
Dec 29, 2015 (W53) $2,060.54 $2,078.36 Arrow Up
Dec 30, 2015 (W53) $2,077.34 $2,063.36 Arrow Down
Dec 31, 2015 (W53) $2,060.59 $2,043.94 Arrow Down