The cols_nanoplot() function

Let’s make some nanoplots with the illness dataset. The columns beginning with ‘day’ all contain ordered measurement values, comprising seven individual daily results. Using cols_nanoplot() we create a new column to hold the nanoplots (with new_col_name = "nanoplots"), referencing the columns containing the data (with columns = starts_with("day")). It’s also possible to define a column label here using the new_col_label argument.

illness |>
  dplyr::slice_head(n = 10) |>
  gt(rowname_col = "test") |>
  tab_header("Partial summary of daily tests performed on YF patient") |>
  tab_stubhead(label = md("**Test**")) |>
  cols_hide(columns = starts_with("norm")) |>
  fmt_units(columns = units) |>
  cols_nanoplot(
    columns = starts_with("day"),
    new_col_name = "nanoplots",
    new_col_label = md("*Progression*")
  ) |>
  cols_align(align = "center", columns = nanoplots) |>
  cols_merge(columns = c(test, units), pattern = "{1} ({2})") |>
  tab_footnote(
    footnote = "Measurements from Day 3 through to Day 8.",
    locations = cells_column_labels(columns = nanoplots)
  )
Partial summary of daily tests performed on YF patient
Test Progression1
Viral load (copies per mL)
12.0K 250 12.0K 4.20K 1.60K 830 760 520 250
WBC (×109/L)
30.3 4.26 5.26 4.26 9.92 10.5 24.8 30.3 19.0
Neutrophils (×109/L)
27.2 4.72 4.87 4.72 7.92 18.2 22.1 27.2 16.6
RBC (×1012/L)
5.98 2.68 5.72 5.98 4.23 4.83 4.12 2.68 3.32
Hb (g/L)
153 75 153 135 126 115 75 87 95
PLT (×109/L)
74.1 25.6 67.0 38.6 27.4 26.2 74.1 36.2 25.6
ALT (U/L)
12.8K 512 12.8K 12.6K 6.43K 4.26K 1.62K 673 512
AST (U/L)
23.7K 782 23.7K 21.4K 14.7K 8.69K 2.19K 1.14K 782
TBIL (µmol/L)
163 105 117 144 137 158 127 105 163
DBIL (µmol/L)
144 71.4 71.4 105 94.6 144 118 83.6 126
1 Measurements from Day 3 through to Day 8.

The previous table showed us some line-based nanoplots. We can also make very small bar plots with cols_nanoplot(). Let’s take the pizzaplace dataset and make a small summary table showing daily pizza sales by type (there are four types). This will be limited to the first ten days of pizza sales in 2015, so, there will be ten rows in total. We can use plot_type = "bar" to make bar plots from the daily sales counts in the chicken, classic, supreme, and veggie columns. Because we know there will always be four bars (one for each type of pizza) we can be a little creative and apply colors to each of the bars through use of the data_bar_fill_color argument in nanoplot_options().

pizzaplace |>
  dplyr::count(type, date) |>
  tidyr::pivot_wider(names_from = type, values_from = n) |>
  dplyr::slice_head(n = 10) |>
  gt(rowname_col = "date") |>
  tab_header(
    title = md("First Ten Days of Pizza Sales in 2015")
  ) |>
  cols_nanoplot(
    columns = c(chicken, classic, supreme, veggie),
    plot_type = "bar",
    autohide = FALSE,
    new_col_name = "pizzas_sold",
    new_col_label = "Sales by Type",
    options = nanoplot_options(
      show_data_line = FALSE,
      show_data_area = FALSE,
      data_bar_stroke_color = "transparent",
      data_bar_fill_color = c("brown", "gold", "purple", "green")
    )
  ) |>
  cols_width(pizzas_sold ~ px(150)) |>
  cols_align(columns = -date, align = "center") |>
  fmt_date(columns = date, date_style = "yMMMEd") |>
  opt_all_caps()
First Ten Days of Pizza Sales in 2015
chicken classic supreme veggie Sales by Type
Thu, Jan 1, 2015 36 46 39 41
46 0 36 46 39 41
Fri, Jan 2, 2015 32 57 45 31
57 0 32 57 45 31
Sat, Jan 3, 2015 42 47 32 37
47 0 42 47 32 37
Sun, Jan 4, 2015 28 26 28 24
28 0 28 26 28 24
Mon, Jan 5, 2015 31 37 28 29
37 0 31 37 28 29
Tue, Jan 6, 2015 31 48 31 37
48 0 31 48 31 37
Wed, Jan 7, 2015 28 45 33 32
45 0 28 45 33 32
Thu, Jan 8, 2015 31 47 46 49
49 0 31 47 46 49
Fri, Jan 9, 2015 21 40 34 32
40 0 21 40 34 32
Sat, Jan 10, 2015 27 37 40 42
42 0 27 37 40 42

Now we’ll make another table that contains two columns of nanoplots. Starting from the towny dataset, we first reduce it down to a subset of columns and rows. All of the columns related to either population or density will be used as input data for the two nanoplots. Both nanoplots will use a reference line that is generated from the median of the input data. And by naming the new nanoplot-laden columns in a similar manner as the input data columns, we can take advantage of select helpers (e.g., when using tab_spanner()). Many of the input data columns are now redundant because of the plots, so we’ll elect to hide most of those with cols_hide().

towny |>
  dplyr::select(name, starts_with("population"), starts_with("density")) |>
  dplyr::filter(population_2021 > 200000) |>
  dplyr::arrange(desc(population_2021)) |>
  gt() |>
  fmt_integer(columns = starts_with("population")) |>
  fmt_number(columns = starts_with("density"), decimals = 1) |>
  cols_nanoplot(
    columns = starts_with("population"),
    reference_line = "median",
    autohide = FALSE,
    new_col_name = "population_plot",
    new_col_label = md("*Change*")
  ) |>
  cols_nanoplot(
    columns = starts_with("density"),
    plot_type = "bar",
    autohide = FALSE,
    new_col_name = "density_plot",
    new_col_label = md("*Change*")
  ) |>
  cols_hide(columns = matches("2001|2006|2011|2016")) |>
  tab_spanner(
    label = "Population",
    columns = starts_with("population")
  ) |>
  tab_spanner(
    label = "Density ({{*persons* km^-2}})",
    columns = starts_with("density")
  ) |>
  cols_label_with(
    columns = -matches("plot"),
    fn = function(x) gsub("[^0-9]+", "", x)
  ) |>
  cols_align(align = "center", columns = matches("plot")) |>
  cols_width(
    name ~ px(140),
    everything() ~ px(100)
  ) |>
  opt_horizontal_padding(scale = 2)
Population
Density (persons km−2)
1996 2021 Change 1996 2021 Change
Toronto 2,385,421 2,794,356
2.56M 2.79M 2.39M 2.39M 2.48M 2.50M 2.62M 2.73M 2.79M
3,779.8 4,427.8
4.43K 0 3.78K 3.93K 3.97K 4.14K 4.33K 4.43K
Ottawa 721,136 1,017,449
848K 1.02M 721K 721K 774K 812K 883K 934K 1.02M
258.6 364.9
365 0 259 278 291 317 335 365
Mississauga 544,382 717,961
691K 722K 544K 544K 613K 669K 713K 722K 718K
1,859.6 2,452.6
2.46K 0 1.86K 2.09K 2.28K 2.44K 2.46K 2.45K
Brampton 268,251 656,480
479K 656K 268K 268K 325K 434K 524K 594K 656K
1,008.9 2,469.0
2.47K 0 1.01K 1.22K 1.63K 1.97K 2.23K 2.47K
Hamilton 467,799 569,353
512K 569K 468K 468K 490K 505K 520K 537K 569K
418.3 509.1
509 0 418 438 451 465 480 509
London 325,699 422,324
359K 422K 326K 326K 336K 352K 366K 384K 422K
774.5 1,004.3
1.00K 0 775 800 838 871 913 1.00K
Markham 173,383 338,503
282K 339K 173K 173K 209K 262K 302K 329K 339K
822.0 1,604.8
1.60K 0 822 989 1.24K 1.43K 1.56K 1.60K
Vaughan 132,549 323,103
264K 323K 133K 133K 182K 239K 288K 306K 323K
486.5 1,186.0
1.19K 0 487 668 877 1.06K 1.12K 1.19K
Kitchener 178,420 256,885
212K 257K 178K 178K 190K 205K 219K 233K 257K
1,304.1 1,877.7
1.88K 0 1.30K 1.39K 1.50K 1.60K 1.70K 1.88K
Windsor 197,694 229,660
214K 230K 198K 198K 208K 216K 211K 217K 230K
1,353.9 1,572.8
1.57K 0 1.35K 1.43K 1.48K 1.44K 1.49K 1.57K
Oakville 128,405 213,759
174K 214K 128K 128K 145K 166K 183K 194K 214K
924.2 1,538.5
1.54K 0 924 1.04K 1.19K 1.31K 1.40K 1.54K
Richmond Hill 101,725 202,022
174K 202K 102K 102K 132K 163K 186K 195K 202K
1,009.3 2,004.4
2.00K 0 1.01K 1.31K 1.61K 1.84K 1.93K 2.00K

The sza dataset can, with just some use of dplyr and tidyr, give us a wide table full of nanoplottable values. We’ll transform the solar zenith angles to solar altitude angles and create a column of nanoplots using the newly calculated values. There are a few NA values during periods where the sun hasn’t risen (usually before 06:30 in the winter months) and those values will be replaced with 0 using missing_vals = "zero". We’ll also elect to create bar plots using the plot_type = "bar" option. The height of the plots will be bumped up to "2.5em" from the default of "2em". Finally, we will use nanoplot_options() to modify the coloring of the data bars.

sza |>
  dplyr::filter(latitude == 20 & tst <= "1200") |>
  dplyr::select(-latitude) |>
  dplyr::filter(!is.na(sza)) |>
  dplyr::mutate(saa = 90 - sza) |>
  dplyr::select(-sza) |>
  tidyr::pivot_wider(
    names_from = tst,
    values_from = saa,
    names_sort = TRUE
  ) |>
  gt(rowname_col = "month") |>
  tab_header(
    title = "Solar Altitude Angles",
    subtitle = "Average values every half hour from 05:30 to 12:00"
  ) |>
  cols_nanoplot(
    columns = matches("0"),
    plot_type = "bar",
    missing_vals = "zero",
    new_col_name = "saa",
    plot_height = "2.5em",
    options = nanoplot_options(
      data_bar_stroke_color = "GoldenRod",
      data_bar_fill_color = "DarkOrange"
    )
  ) |>
  tab_options(
    table.width = px(400),
    column_labels.hidden = TRUE
  ) |>
  cols_align(
    align = "center",
    columns = everything()
  ) |>
  tab_source_note(
    source_note = "The solar altitude angle is the complement to
    the solar zenith angle. TMYK."
  )
Solar Altitude Angles
Average values every half hour from 05:30 to 12:00
jan
47 0 0 0 0 5.10 11.3 17.3 23.9 28.5 33.5 37.9 41.7 44.5 46.4 47.0
feb
52.8 0 0 0 1.10 7.50 14.2 20.4 26.7 32.3 37.8 42.6 46.9 50.0 52.2 52.8
mar
62.3 0 0 0 4.30 11.2 18.0 24.8 31.4 37.7 43.8 49.5 54.5 58.6 61.4 62.3
apr
74.5 0 0 1.50 8.50 15.6 22.6 29.7 36.6 43.5 50.3 56.8 63.1 68.7 72.8 74.5
may
85 0 0 5.00 11.8 18.8 25.7 32.8 39.8 46.8 53.9 60.9 63.9 74.8 81.2 85.0
jun
88 0 0.80 7.30 14.0 20.7 27.5 34.3 41.2 48.1 55.0 61.9 68.9 75.8 82.7 88.0
jul
86.9 0 1.20 7.70 14.3 20.9 27.7 34.5 41.3 48.2 55.0 61.9 68.8 75.7 82.3 86.9
aug
88.1 0 0 6.20 12.9 19.8 26.7 33.6 40.6 47.6 54.6 61.7 68.7 75.7 82.7 88.1
sep
78.4 0 0 2.80 9.80 16.8 23.9 30.9 37.9 44.9 51.9 58.7 65.3 71.4 76.3 78.4
oct
66.9 0 0 0 5.90 12.9 19.8 26.7 33.5 40.1 46.5 52.5 58.0 62.6 65.7 66.9
nov
55.6 0 0 0 2.20 8.70 15.5 21.7 28.2 34.0 39.8 44.7 49.3 52.6 54.9 55.6
dec
48.2 0 0 0 0 5.70 12.0 18.2 23.9 29.5 34.4 39.1 42.8 45.8 47.6 48.2
The solar altitude angle is the complement to the solar zenith angle. TMYK.

You can use number and time streams as data for nanoplots. Let’s demonstrate how we can make use of them with some creative transformation of the pizzaplace dataset. A value stream is really a string with delimited numeric values, like this: "7.24,84.2,14". A value stream can also contain dates and/or datetimes, and here’s an example of that: "2020-06-02 13:05:13,2020-06-02 14:24:05,2020-06-02 18:51:37". Having data in this form can often be more convenient since different nanoplots might have varying amounts of data (and holding different amounts of data in a fixed number of columns is cumbersome). There are date and time columns in this dataset and we’ll use that to get x values denoting high-resolution time instants: the second of the day that a pizza was sold (this is true pizza analytics). We also have the sell price for a pizza, and that’ll serve as the y values. The pizzas belong to four different groups (in the type column) and we’ll group by that and create value streams with paste(..., collapse = ",") inside the dplyr::summarize() call. With two value streams in each row (having the same number of values) we can now make a gt table with nanoplots.

pizzaplace |>
  dplyr::filter(date == "2015-01-01") |>
  dplyr::mutate(date_time = paste(date, time)) |>
  dplyr::select(type, date_time, price) |>
  dplyr::group_by(type) |>
  dplyr::summarize(
    date_time = paste(date_time, collapse = ","),
    sold = paste(price, collapse = ",")
  ) |>
  gt(rowname_col = "type") |>
  tab_header(
    title = md("Pizzas sold on **January 1, 2015**"),
    subtitle = "Between the opening hours of 11:30 to 22:30"
  ) |>
  cols_nanoplot(
    columns = sold,
    columns_x_vals = date_time,
    expand_x = c("2015-01-01 11:30", "2015-01-01 22:30"),
    reference_line = "median",
    new_col_name = "pizzas_sold",
    new_col_label = "Pizzas Sold",
    options = nanoplot_options(
      show_data_line = FALSE,
      show_data_area = FALSE,
      currency = "USD"
    )
  ) |>
  cols_width(pizzas_sold ~ px(200)) |>
  cols_align(columns = pizzas_sold, align = "center") |>
  opt_all_caps()
Pizzas sold on January 1, 2015
Between the opening hours of 11:30 to 22:30
Pizzas Sold
chicken
$20.75 $20.75 $12.75 $20.75 $12.75 $20.75 $20.75 $16.75 $20.75 $12.75 $20.75 $20.75 $20.75 $20.75 $20.75 $12.75 $16.75 $20.75 $20.75 $12.75 $20.75 $20.75 $20.75 $16.75 $12.75 $16.75 $16.75 $16.75 $20.75 $20.75 $16.75 $20.75 $20.75 $16.75 $20.75 $16.75 $16.75 $20.75 $20.75
classic
$14.88 $25.50 $9.75 $13.25 $16.00 $12.00 $20.50 $12.00 $15.25 $12.00 $12.00 $12.00 $12.00 $20.50 $20.50 $12.00 $20.50 $16.00 $16.00 $12.50 $12.00 $16.00 $9.75 $20.50 $12.00 $12.00 $12.50 $17.50 $16.00 $20.50 $10.50 $12.00 $10.50 $20.50 $25.50 $17.50 $16.50 $11.00 $16.00 $16.00 $12.50 $11.00 $15.25 $14.50 $12.00 $11.00 $16.00 $16.00 $16.00
supreme
$16.50 $20.75 $12.25 $20.75 $20.75 $16.50 $16.50 $16.50 $12.50 $12.50 $20.75 $20.75 $12.50 $16.50 $20.75 $16.50 $16.25 $12.50 $20.25 $12.50 $16.25 $16.50 $20.75 $20.75 $16.50 $16.50 $20.75 $20.75 $20.75 $20.25 $20.75 $16.50 $16.50 $12.50 $20.75 $20.75 $16.50 $16.50 $12.25 $12.50 $20.75 $16.50
veggie
$17.95 $20.75 $12.00 $16.00 $18.50 $12.00 $20.75 $12.00 $12.00 $20.25 $20.25 $18.50 $17.95 $16.00 $20.25 $14.75 $20.25 $16.00 $18.50 $12.75 $18.50 $18.50 $20.25 $20.25 $12.00 $16.00 $20.25 $12.00 $16.00 $20.25 $17.95 $12.00 $14.75 $18.50 $20.25 $12.50 $17.95 $12.00 $12.00 $20.25 $20.25 $18.50 $12.75 $14.75

Notice that the columns containing the value streams are hid due to the default argument autohide = TRUE because, while useful, they don’t need to be displayed to anybody viewing a table. Since we have a lot of data points and a connecting line is not as valuable here, we also set show_data_line = FALSE in nanoplot_options(). It’s more interesting to see the clusters of the differently priced pizzas over the entire day. Specifying a currency in nanoplot_options() is a nice touch since the y values are sale prices in U.S. Dollars (hovering over data points gives correctly formatted values). Finally, having a reference line based on the median gives pretty useful information. Seems like customers preferred getting the "chicken"-type pizzas in large size!

Using the gibraltar dataset, let’s make a series of nanoplots across the meteorological parameters of temperature, humidity, and wind speed. We’ll want to customize the appearance of the plots across three columns and we can make this somewhat simpler by assigning a common set of options through nanoplot_options(). In this table we want to make comparisons across nanoplots in a particular column easier, so, we’ll set autoscale = TRUE so that there is a common y-axis scale for each of the parameters (based on the extents of the data).

nanoplot_options_list <-
  nanoplot_options(
    data_point_radius = px(4),
    data_point_stroke_width = px(2),
    data_point_stroke_color = "black",
    data_point_fill_color = "white",
    data_line_stroke_width = px(4),
    data_line_stroke_color = "gray",
    show_data_line = TRUE,
    show_data_points = TRUE,
    show_data_area = FALSE,
  )

gibraltar |>
  dplyr::filter(date <= "2023-05-14") |>
  dplyr::mutate(time = as.numeric(hms::as_hms(paste0(time, ":00")))) |>
  dplyr::mutate(humidity = humidity * 100) |>
  dplyr::select(date, time, temp, humidity, wind_speed) |>
  dplyr::group_by(date) |>
  dplyr::summarize(
    time = paste(time, collapse = ","),
    temp = paste(temp, collapse = ","),
    humidity = paste(humidity, collapse = ","),
    wind_speed = paste(wind_speed, collapse = ","),
  ) |>
  dplyr::mutate(is_satsun = lubridate::wday(date) %in% c(1, 7)) |>
  gt(rowname_col = "date") |>
  tab_header(
    title = "Meteorological Summary of Gibraltar Station",
    subtitle = "Data taken from May 1-14, 2023."
  ) |>
  fmt_date(columns = stub(), date_style = "wd_m_day_year") |>
  cols_nanoplot(
    columns = temp,
    columns_x_vals = time,
    expand_x = c(0, 86400),
    autoscale = TRUE,
    new_col_name = "temperature_nano",
    new_col_label = "Temperature",
    options = nanoplot_options_list
  ) |>
  cols_nanoplot(
    columns = humidity,
    columns_x_vals = time,
    expand_x = c(0, 86400),
    autoscale = TRUE,
    new_col_name = "humidity_nano",
    new_col_label = "Humidity",
    options = nanoplot_options_list
  ) |>
  cols_nanoplot(
    columns = wind_speed,
    columns_x_vals = time,
    expand_x = c(0, 86400),
    autoscale = TRUE,
    new_col_name = "wind_speed_nano",
    new_col_label = "Wind Speed",
    options = nanoplot_options_list
  ) |>
  cols_units(
    temperature_nano = ":degree:C",
    humidity_nano = "% (RH)",
    wind_speed_nano = "m s^-1"
  ) |>
  cols_hide(columns = is_satsun) |>
  tab_style_body(
    style = cell_fill(color = "#E5FEFE"),
    values = TRUE,
    targets = "row",
    extents = c("body", "stub")
  ) |>
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_column_labels()
  )
Meteorological Summary of Gibraltar Station
Data taken from May 1-14, 2023.
Temperature, °C Humidity, % (RH) Wind Speed, m s−1
Mon, May 1, 2023
30.0 16.1 18.9 18.9 17.8 18.9 18.9 17.8 17.8 17.8 18.9 18.9 17.8 17.8 17.2 17.8 17.2 17.8 17.8 18.9 21.1 21.1 22.2 22.2 22.2 22.2 22.2 22.2 21.1 21.1 21.1 21.1 20.0 20.0 20.0 20.0 20.0 18.9 20.0 18.9 18.9 17.8 17.2 17.2 17.2 17.2 17.2 17.2
100 24 68 73 77 73 68 73 73 73 64 64 73 73 72 88 82 77 77 73 64 68 60 60 60 64 64 64 68 73 73 73 78 78 78 83 83 88 83 88 88 94 94 94 94 94 94 94
9.40 0.40 6.70 7.20 6.70 6.70 6.70 6.70 7.20 6.30 4.00 3.10 3.60 2.20 0.40 0.90 0.90 2.70 2.20 2.70 1.30 2.70 2.20 2.20 2.20 2.70 2.70 3.60 3.60 3.10 3.10 3.60 3.60 3.10 3.10 4.00 3.60 3.60 3.10 3.60 3.60 3.10 3.10 4.00 4.50 4.50 2.70 3.60
Tue, May 2, 2023
30.0 16.1 17.2 17.2 17.2 17.2 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.8 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9 20.0 21.1 21.1 21.1 22.2 22.2 22.2 22.2 22.2 22.2 22.2 22.2 22.2 21.1 21.1 20.0 20.0 18.9 18.9 18.9 18.9 18.9 18.9
100 24 100 100 100 100 94 94 94 94 94 94 94 94 88 88 88 88 88 88 88 88 88 88 83 78 73 68 64 64 60 64 60 60 60 64 64 68 68 78 78 83 83 83 83 83 83
9.40 0.40 3.60 3.60 4.00 4.00 4.50 5.40 5.40 6.30 6.70 6.30 4.50 5.40 5.40 5.40 5.40 5.40 6.30 5.80 5.80 5.80 5.40 5.40 5.40 5.40 5.40 5.40 5.40 5.80 5.80 5.80 5.80 5.40 5.40 5.40 5.80 5.40 4.50 4.00 4.00 4.00 4.00 3.60 3.10 6.30 5.80
Wed, May 3, 2023
30.0 16.1 18.9 18.9 18.9 20.0 18.9 18.9 18.9 20.0 20.0 18.9 18.9 18.9 18.9 18.9 20.0 20.0 20.0 20.0 21.1 21.1 20.0 20.0 21.1 21.1 21.1 21.1 22.2 21.1 21.1 21.1 21.1 21.1 21.1 21.1 21.1 20.0 20.0 20.0 20.0 20.0 20.0 18.9 18.9 18.9 18.9
100 24 83 83 83 73 78 78 83 73 73 78 78 78 73 73 68 68 73 73 68 68 73 73 68 68 64 68 64 68 68 68 68 68 68 68 73 78 78 73 78 78 78 83 83 83 83
9.40 0.40 3.60 3.60 5.80 7.20 7.20 9.40 6.70 7.60 9.40 9.40 9.40 3.10 4.00 7.60 5.40 6.30 6.30 5.40 5.80 5.40 5.40 5.40 5.40 5.40 5.40 5.80 5.40 5.40 5.40 4.00 4.00 3.10 3.10 3.10 3.10 3.10 3.10 3.10 2.70 2.20 2.70 2.70 2.70 2.70 2.20
Thu, May 4, 2023
30.0 16.1 18.9 17.8 17.2 17.2 17.2 17.2 17.2 17.2 17.2 17.2 16.1 17.2 17.8 17.8 17.8 17.8 17.8 17.2 18.9 17.8 20.0 21.1 21.1 22.2 22.8 22.2 22.8 22.8 22.8 23.9 26.1 25.0 26.1 26.1 25.0 25.0 25.0 25.0 25.0 26.1 25.0 23.9 22.8 22.8 22.8 22.8 22.2 21.1
100 24 83 83 88 88 88 88 88 88 82 82 88 82 73 68 83 83 83 82 78 77 68 68 68 69 65 69 65 65 65 61 47 54 47 47 47 41 41 39 41 39 44 47 50 47 47 44 53 60
9.40 0.40 1.30 0.90 2.20 1.30 2.20 2.70 2.70 3.10 3.10 2.70 4.00 3.10 3.10 3.10 4.00 4.50 5.80 3.10 2.70 3.10 3.10 2.70 4.50 4.00 3.10 5.80 4.00 6.30 4.00 3.10 3.10 5.80 4.00 4.50 5.80 6.30 6.30 5.80 6.30 5.40 5.40 5.80 6.30 4.50 6.30 5.80 6.30 6.70
Fri, May 5, 2023
30.0 16.1 21.1 21.1 21.1 21.1 21.1 21.1 21.1 21.1 21.1 20.0 18.9 17.2 17.2 17.2 17.2 17.8 17.8 17.8 17.8 17.8 17.8 18.9 18.9 18.9 18.9 20.0 20.0 20.0 21.1 21.1 20.0 23.9 25.0 23.9 22.8 22.8 22.2 22.2 22.2 20.0 20.0 20.0 20.0 18.9 18.9 18.9
100 24 60 56 56 53 53 53 53 53 56 64 64 82 94 94 94 88 88 88 88 88 88 83 83 83 83 78 78 78 73 73 78 57 54 53 57 57 60 64 69 78 78 78 83 88 88 88
9.40 0.40 6.30 6.70 6.30 5.80 6.70 5.40 5.40 4.00 4.50 3.60 0.90 2.20 1.30 1.30 1.30 1.30 2.20 2.20 2.70 2.70 3.10 3.10 3.10 3.10 3.10 3.60 3.10 2.70 2.70 3.10 3.60 3.10 2.20 1.30 2.70 2.20 2.20 0.90 0.90 1.30 0.90 2.70 2.70 3.60 3.10 3.60
Sat, May 6, 2023
30.0 16.1 18.9 18.9 18.9 18.9 17.8 17.8 17.8 17.2 17.2 17.8 17.2 17.2 17.8 18.9 20.0 21.1 22.2 22.2 23.9 23.9 22.8 22.8 22.8 22.8 23.9 25.0 23.9 25.0 25.0 25.0 25.0 25.0 22.8 22.8 22.8 22.2 21.1 21.1 21.1 21.1 20.0 20.0
100 24 88 94 94 83 88 88 83 88 94 88 82 82 77 78 73 68 64 64 53 53 57 57 57 57 57 50 50 44 47 47 47 44 57 47 47 50 64 60 53 64 68 78
9.40 0.40 3.10 2.70 2.70 0.90 0.90 1.30 2.70 3.10 3.10 3.10 2.70 3.10 2.70 3.10 3.10 3.60 4.00 5.40 4.00 5.40 6.30 6.70 7.20 7.20 6.70 7.20 7.20 6.30 6.30 6.70 7.20 6.70 5.40 6.30 6.30 6.30 5.80 4.00 6.70 7.60 5.80 7.20
Sun, May 7, 2023
30.0 16.1 20.0 20.0 18.9 20.0 20.0 20.0 20.0 20.0 20.0 21.1 20.0 20.0 20.0 20.0 20.0 20.0 21.1 21.1 22.2 22.8 23.9 25.0 26.1 26.1 26.1 25.0 22.8 22.8 23.9 23.9 22.8 22.8 23.9 23.9 22.8 23.9 22.8 22.8 22.2 22.8 23.9 23.9 23.9 22.8 22.8
100 24 78 78 83 78 78 78 78 78 78 68 78 73 73 73 78 78 73 73 64 65 61 54 47 47 51 57 65 65 61 61 65 65 61 61 65 61 65 65 69 61 53 47 47 47 47
9.40 0.40 7.60 8.90 7.60 5.80 6.30 6.30 6.30 6.30 5.40 6.70 6.30 5.40 5.40 5.80 5.40 5.40 4.50 4.50 5.40 5.40 4.00 4.50 5.40 5.40 5.40 6.70 8.00 7.20 7.20 7.20 8.00 7.20 7.20 5.40 6.30 5.40 5.80 5.80 4.50 4.00 5.80 5.80 5.40 5.40 3.60
Mon, May 8, 2023
30.0 16.1 22.2 21.1 21.1 20.0 20.0 18.9 18.9 18.9 17.8 18.9 17.8 18.9 17.8 17.8 17.8 17.8 17.8 17.8 18.9 18.9 18.9 18.9 18.9 20.0 18.9 20.0 21.1 21.1 21.1 21.1 21.1 21.1 20.0 20.0 21.1 20.0 21.1 21.1 22.2 22.8 23.9 22.8 22.8 22.2 22.2 21.1 21.1 18.9 18.9 18.9
100 24 60 68 73 78 78 88 83 88 88 83 94 88 94 94 94 100 100 100 94 94 94 94 94 88 88 88 78 78 78 78 78 78 83 83 78 83 78 78 73 69 65 69 65 73 73 78 78 88 88 88
9.40 0.40 0.40 1.30 3.10 2.70 3.10 4.00 3.60 4.00 4.50 6.70 5.40 1.30 1.30 2.70 2.70 1.30 1.30 2.20 2.20 2.70 1.30 2.70 2.70 3.10 3.10 3.10 3.10 3.60 3.60 4.50 5.40 4.50 4.00 3.60 3.10 3.60 3.10 3.10 2.20 1.30 0.90 0.90 0.90 0.40 0.90 0.40 0.40 2.20 3.60 4.00
Tue, May 9, 2023
30.0 16.1 20.0 21.1 22.8 23.9 22.8 22.8 22.2 21.1 17.8 17.8 18.9 18.9 18.9 17.8 17.8 17.2 17.2 17.2 17.2 17.8 17.8 17.8 17.8 17.8 17.8 17.8 18.9 20.0 18.9 18.9 21.1 22.8 27.8 30.0 30.0 30.0 27.2 27.8 28.9 28.9 28.9 27.2 27.2 27.2 27.2 27.2 26.1 26.1 25.0
100 24 83 73 57 50 53 53 57 64 94 94 88 88 94 100 94 94 100 100 94 94 88 88 88 88 88 88 83 78 83 83 78 69 45 37 37 37 48 42 42 40 40 48 48 45 45 45 47 47 50
9.40 0.40 4.00 4.00 4.50 4.50 5.40 4.00 3.10 2.20 3.60 3.10 2.70 2.20 0.90 0.40 0.40 1.30 2.70 2.70 0.90 0.90 1.30 3.10 3.60 3.10 2.70 2.70 2.70 3.10 3.10 3.10 2.70 1.30 5.40 6.30 5.40 5.40 7.20 7.20 5.40 4.50 4.00 4.00 4.50 5.40 6.70 4.50 7.20 6.30 5.40
Wed, May 10, 2023
30.0 16.1 25.0 25.0 25.0 25.0 25.0 25.0 23.9 23.9 23.9 23.9 23.9 22.8 22.8 22.8 22.2 21.1 22.2 23.9 22.8 22.2 22.2 22.2 22.2 22.2 22.2 22.8 22.8 22.8 22.8 22.2 22.8 22.8 22.8 22.8 22.2 22.2 22.2 22.2 21.1 21.1 21.1 21.1 20.0 20.0 20.0 20.0 20.0 20.0
100 24 50 50 50 50 50 50 53 53 53 50 47 50 53 50 53 68 60 47 50 73 69 69 69 69 69 65 65 65 65 69 65 61 61 61 64 64 64 69 73 73 68 73 73 73 73 73 73 73
9.40 0.40 4.50 5.80 6.30 5.40 4.50 4.50 4.50 5.80 4.50 4.50 5.40 5.40 5.40 5.40 6.30 6.70 6.30 2.20 3.60 5.40 6.70 7.60 8.90 8.00 8.00 7.60 7.60 6.30 5.80 6.30 5.80 5.40 4.50 4.50 4.50 4.50 4.00 3.60 3.60 3.10 3.10 2.70 2.70 2.70 3.60 2.20 2.70 2.70
Thu, May 11, 2023
30.0 16.1 20.0 20.0 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9 17.8 17.8 17.8 18.9 18.9 18.9 20.0 20.0 20.0 20.0 20.0 21.1 21.1 21.1 21.1 21.1 21.1 21.1 21.1 22.2 21.1 22.2 21.1 21.1 20.0 20.0 21.1 21.1 20.0 20.0 18.9 18.9 18.9 18.9
100 24 73 73 78 83 78 78 78 78 78 83 83 83 88 88 83 83 88 83 83 83 83 83 78 78 78 78 78 78 78 78 73 78 73 78 78 83 83 78 78 83 88 94 94 94 94
9.40 0.40 2.20 2.70 2.20 2.20 2.70 2.70 3.10 2.20 3.10 3.10 2.20 2.20 2.70 3.10 2.70 3.10 3.60 3.60 4.00 4.50 4.00 4.50 3.60 4.00 4.00 3.60 3.60 4.00 4.00 3.60 3.60 3.60 3.60 3.60 3.10 3.60 3.10 4.00 3.10 3.10 2.70 2.70 1.30 2.20 2.20
Fri, May 12, 2023
30.0 16.1 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9 17.8 17.8 17.8 17.8 17.8 17.8 18.9 18.9 20.0 20.0 20.0 20.0 21.1 21.1 21.1 21.1 21.1 22.2 21.1 22.2 22.8 22.8 22.8 23.9 22.8 22.8 22.8 22.8 22.8 22.8 22.2 22.2 22.2 21.1 21.1 21.1 20.0
100 24 88 94 94 94 88 88 88 88 94 94 94 94 94 94 88 88 83 83 83 83 78 78 73 73 73 73 78 69 57 57 57 50 53 57 57 65 69 69 69 60 53 56 49 46 52
9.40 0.40 2.20 2.20 3.10 4.00 5.40 4.00 4.00 3.10 2.20 2.70 2.20 0.90 1.30 1.30 2.20 3.60 4.00 4.00 3.60 4.00 3.60 3.10 3.60 3.60 4.00 3.60 3.60 3.60 4.00 3.60 4.00 4.50 3.60 3.10 3.60 3.60 4.50 4.00 4.00 4.00 3.10 3.10 3.10 3.10 0.40
Sat, May 13, 2023
30.0 16.1 21.1 20.0 18.9 18.9 18.9 18.9 17.8 17.8 17.8 18.9 18.9 17.8 17.8 17.8 18.9 18.9 18.9 17.8 17.2 17.2 17.2 17.8 17.8 18.9 18.9 20.0 20.0 20.0 20.0 20.0 21.1 21.1 21.1 20.0 21.1 20.0 20.0 20.0 20.0 20.0 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9 18.9
100 24 49 52 83 83 83 83 83 83 83 88 88 94 88 88 83 83 83 88 88 88 88 88 83 78 78 73 68 68 68 68 64 64 64 68 68 73 73 73 68 68 78 73 78 78 78 78 78 78 78
9.40 0.40 0.40 3.60 2.70 2.20 2.20 2.70 1.30 1.30 0.40 3.10 3.10 2.20 0.90 2.20 8.90 6.30 3.60 5.80 7.20 8.00 7.20 7.20 5.40 6.70 6.30 5.80 5.40 5.40 4.50 5.40 4.50 4.50 4.00 3.60 5.40 5.40 5.40 5.40 4.00 3.60 4.50 5.40 4.50 4.50 4.00 5.40 6.30 6.30 6.70
Sun, May 14, 2023
30.0 16.1 18.9 18.9 18.9 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.8 17.2 17.2 17.8 17.8 17.8 18.9 20.0 20.0 20.0 20.0 20.0 21.1 22.2 22.2 22.8 23.9 22.8 22.8 22.8 22.8 23.9 26.1 27.2 26.1 26.1 25.0 22.8 21.1 21.1 22.2 22.2 21.1 20.0
100 24 78 78 83 83 83 83 83 83 83 83 83 77 82 82 77 77 73 68 64 68 68 68 68 64 60 60 50 47 47 53 57 57 53 32 28 24 24 28 41 56 56 46 46 53 60
9.40 0.40 5.80 5.40 5.80 5.40 5.40 5.40 4.00 5.40 4.00 4.00 4.00 3.10 0.90 2.20 2.70 2.70 2.20 2.70 2.70 2.70 3.10 3.60 3.60 4.00 4.00 3.60 3.60 3.10 5.40 6.70 7.20 6.30 5.40 4.50 6.30 7.20 6.30 5.40 6.30 6.30 7.20 5.80 6.30 5.40 6.70

Box plots can be generated, and we just need to use plot_type = "boxplot" to make that type of nanoplot. Using a small portion of the pizzaplace dataset, we will create a simple table that displays a box plot of pizza sales for a selection of days. By converting the string-time 24-hour-clock time values to the number of seconds elapsed in a day, we get continuous values that can be incorporated into each box plot. And, by supplying a function to the y_val_fmt_fn argument within nanoplot_options(), we can transform the integer seconds values back to clock times for display on hover.

pizzaplace |>
  dplyr::filter(date <= "2015-01-14") |>
  dplyr::mutate(time = as.numeric(hms::as_hms(time))) |>
  dplyr::summarize(time = paste(time, collapse = ","), .by = date) |>
  dplyr::mutate(is_weekend = lubridate::wday(date) %in% 6:7) |>
  gt() |>
  tab_header(title = "Pizza Sales in Early January 2015") |>
  fmt_date(columns = date, date_style = 2) |>
  cols_nanoplot(
    columns = time,
    plot_type = "boxplot",
    options = nanoplot_options(y_val_fmt_fn = function(x) hms::as_hms(x))
  ) |>
  cols_hide(columns = is_weekend) |>
  cols_width(everything() ~ px(250)) |>
  cols_align(align = "center", columns = nanoplots) |>
  cols_align(align = "left", columns = date) |>
  tab_style(
    style = cell_borders(
      sides = "left", color = "gray"),
    locations = cells_body(columns = nanoplots)
  ) |>
  tab_style_body(
    style = cell_fill(color = "#E5FEFE"),
    values = TRUE,
    targets = "row"
  ) |>
  tab_options(column_labels.hidden = TRUE)
Pizza Sales in Early January 2015
Thursday, January 1, 2015
11:38:3613:34:0715:53:1818:31:25.522:12:13
Friday, January 2, 2015
11:38:5113:34:4917:54:0419:23:0222:32:49
Saturday, January 3, 2015
11:34:1014:42:42.7517:01:3819:36:0022:50:29
Sunday, January 4, 2015
11:30:4813:56:35.7516:41:4820:11:09.7522:22:13
Monday, January 5, 2015
11:23:3514:22:1916:49:3818:46:5421:59:46
Tuesday, January 6, 2015
11:39:0613:03:5315:03:1217:59:4822:26:59
Wednesday, January 7, 2015
11:45:1813:04:5614:31:1018:07:4622:46:13
Thursday, January 8, 2015
11:17:1312:34:2014:19:5817:52:4222:26:08
Friday, January 9, 2015
11:16:2113:32:5016:14:2818:57:4622:32:32
Saturday, January 10, 2015
12:11:1913:48:4918:33:2520:13:40.522:48:39
Sunday, January 11, 2015
11:42:0813:37:4616:34:0718:13:1221:29:50
Monday, January 12, 2015
11:38:1514:08:1616:21:1018:22:55.521:35:14
Tuesday, January 13, 2015
11:31:3413:40:0816:14:4318:31:0721:39:41
Wednesday, January 14, 2015
11:28:4412:54:3517:04:0818:38:19.2522:16:24