We can use gt::summary_rows()
to insert summary rows
into a table. There are two main types of summary rows: (1) group-wise
summaries, and (2) the grand summary. The group-wise summaries operate
on one or more row groups, which can themselves be generated in a
variety of ways:
- with the
gt()
function’sgroupname_col
option - using
tab_row_group()
on a gt object - by passing in a grouped
tbl_df
object togt()
(usingdplyr::group_by()
)
We generate the summary data through specification of aggregation
functions. You choose how to format the values in the resulting summary
cells by use of a formatter function (e.g., fmt_number()
)
and any relevant options. These summary rows are automatically inserted
within the relevant row groups (for group-wise summaries) or at the
bottom of the table (as a grand summary), where each summary row is the
result of a different aggregation function.
Preparing the Input Data Table
Let’s use the exibble
dataset (included in the
gt package) to demonstrate how summary rows can be
added. That table contains categorical columns named row
and group
, along several columns with varying data types.
Here is a preview of the exibble
dataset using solely the
gt()
function with no other options:
exibble |> gt()
num | char | fctr | date | time | datetime | currency | row | group |
---|---|---|---|---|---|---|---|---|
1.111e-01 | apricot | one | 2015-01-15 | 13:35 | 2018-01-01 02:22 | 49.950 | row_1 | grp_a |
2.222e+00 | banana | two | 2015-02-15 | 14:40 | 2018-02-02 14:33 | 17.950 | row_2 | grp_a |
3.333e+01 | coconut | three | 2015-03-15 | 15:45 | 2018-03-03 03:44 | 1.390 | row_3 | grp_a |
4.444e+02 | durian | four | 2015-04-15 | 16:50 | 2018-04-04 15:55 | 65100.000 | row_4 | grp_a |
5.550e+03 | NA | five | 2015-05-15 | 17:55 | 2018-05-05 04:00 | 1325.810 | row_5 | grp_b |
NA | fig | six | 2015-06-15 | NA | 2018-06-06 16:11 | 13.255 | row_6 | grp_b |
7.770e+05 | grapefruit | seven | NA | 19:10 | 2018-07-07 05:22 | NA | row_7 | grp_b |
8.880e+06 | honeydew | eight | 2015-08-15 | 20:20 | NA | 0.440 | row_8 | grp_b |
We’ll create a table stub with both row labels (using the
row
column) and row groups (using the group
column). The end result will be a table organized with labeled rows that
are grouped together (the row group labels identify each of the row
groups). To make the examples a bit easier to follow, some of the
columns in exibble will first be dropped through a
dplyr::select()
statement.
# Create a gt table using the `exibble` dataset
exibble_a <-
exibble |>
select(-c(fctr, date, time, datetime)) |>
gt(rowname_col = "row", groupname_col = "group") |>
sub_missing()
exibble_a
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111e-01 | apricot | 49.950 |
row_2 | 2.222e+00 | banana | 17.950 |
row_3 | 3.333e+01 | coconut | 1.390 |
row_4 | 4.444e+02 | durian | 65100.000 |
grp_b | |||
row_5 | 5.550e+03 | — | 1325.810 |
row_6 | — | fig | 13.255 |
row_7 | 7.770e+05 | grapefruit | — |
row_8 | 8.880e+06 | honeydew | 0.440 |
There are two groups in this data table: grp_a
and
grp_b
. This gives us flexibility to create both a grand
summary and group-wise summary rows.
Generating Group-wise Summary Rows
Group-wise summary rows can be generated by using
summary_rows()
and, importantly, through specifying the
groups that will receive summary rows. We can provide a vector group
names, as in c("grp_a", "grp_b")
, or, use
everything()
to signify that all groups should receive
summary rows. Aside from the selection of groups, there is control over
which columns are to used for the summary. Since each call to
summary_rows()
only performs one set of aggregation
functions, we may want specific aggregations for different subsets of
columns.
To make any sort of summary, we need to use functions that will
perform the aggregation. We can provide base functions such as
mean()
, sum()
, min()
,
max()
, and more, within a list()
. Each
function provided will result in a summary row for each
group
.
Because each function will yield a row, we need to be able to label
that row. So, each summary row will receive a summary row label. We can
provide our preferred names by naming the functions within the list
(e.g,
list(average = "mean", total = "sum", SD = "sd")
).
# Create group-wise summary rows for both
# groups (using `groups = everything()`); use the
# `mean()`, `sum()`, and `sd()` functions
# (only for the `num` column)
exibble_b <-
exibble_a |>
summary_rows(
groups = everything(),
columns = num,
fns = list(
average = "mean",
total = "sum",
SD = "sd"
)
)
exibble_b
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111e-01 | apricot | 49.950 |
row_2 | 2.222e+00 | banana | 17.950 |
row_3 | 3.333e+01 | coconut | 1.390 |
row_4 | 4.444e+02 | durian | 65100.000 |
mean | 120.0158 | — | — |
sum | 480.0631 | — | — |
sd | 216.7887 | — | — |
grp_b | |||
row_5 | 5.550e+03 | — | 1325.810 |
row_6 | — | fig | 13.255 |
row_7 | 7.770e+05 | grapefruit | — |
row_8 | 8.880e+06 | honeydew | 0.440 |
mean | 3220850.0000 | — | — |
sum | 9662550.0000 | — | — |
sd | 4916123.2508 | — | — |
We can specify the aggregation functions by use of function names in
quotes (e.g., "sum"
), as bare functions (e.g.,
sum
), or as one-sided R formulas using a leading
~
. In the formula representation, a .
serves
as the data to be summarized, so we can use
sum(., na.rm = TRUE)
. The use of named arguments is
recommended as those names will serve as summary row labels (the labels
can derived from the function names but only when not providing bare
function names).
Now that summary_rows()
has been somewhat explained,
let’s look at how we can create group-wise summary rows for the
exibble_a
table. We’ll create summaries for both available
groups (groups = everything()
) and use the
mean()
, sum()
, and sd()
functions
with the function-name-in-quotes method (and this will only
pertain to the num
column).
In the previous example we have an NA
value in the
num/row_6
cell, and so we get NA
outputs from
mean()
, sum()
, and sd()
in
grp_b
’s summary rows (which are replaced with em dashes,
itself controllable through the missing_text
option). To
avoid this, let’s rewrite the above using the
names-and-formulae method.
# Create group-wise summary rows for both
# groups (using `groups = everything()`); we will
# use names and formulas this time in `fns`
exibble_c <-
exibble_a |>
summary_rows(
groups = everything(),
columns = num,
fns = list(
avg = ~ mean(., na.rm = TRUE),
total = ~ sum(., na.rm = TRUE),
s.d. = ~ sd(., na.rm = TRUE)
)
)
exibble_c
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111e-01 | apricot | 49.950 |
row_2 | 2.222e+00 | banana | 17.950 |
row_3 | 3.333e+01 | coconut | 1.390 |
row_4 | 4.444e+02 | durian | 65100.000 |
avg | 120.0158 | — | — |
total | 480.0631 | — | — |
s.d. | 216.7887 | — | — |
grp_b | |||
row_5 | 5.550e+03 | — | 1325.810 |
row_6 | — | fig | 13.255 |
row_7 | 7.770e+05 | grapefruit | — |
row_8 | 8.880e+06 | honeydew | 0.440 |
avg | 3220850.0000 | — | — |
total | 9662550.0000 | — | — |
s.d. | 4916123.2508 | — | — |
Here we see that summary rows were created for both groups. However,
the output of the summary row data is quite different than that of the
cell data. The formatter
argument (and extra
...
arguments) allows for use of any of the
fmt_*()
functions that we’d normally use to format cell
data. In this example (another rewrite of the above), the cell data in
the num
column is formatted in scientific notation and the
resulting summary cell data is also formatted in the same way (including
the options of decimals = 3
).
# Define a named list of aggregation
# functions and summary row labels
fns_labels <-
list(
avg = ~mean(., na.rm = TRUE),
total = ~sum(., na.rm = TRUE),
s.d. = ~sd(., na.rm = TRUE)
)
# Create group-wise summary rows as
# before, supply `fns_labels` to `fns`,
# and format the cell summary data
exibble_d <-
exibble_a |>
fmt_scientific(
columns = num,
decimals = 3
) |>
summary_rows(
groups = everything(),
columns = num,
fns = fns_labels,
fmt = list(~ fmt_scientific(., decimals = 3))
)
exibble_d
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111 × 10−1 | apricot | 49.950 |
row_2 | 2.222 | banana | 17.950 |
row_3 | 3.333 × 101 | coconut | 1.390 |
row_4 | 4.444 × 102 | durian | 65100.000 |
avg | 1.200 × 102 | — | — |
total | 4.801 × 102 | — | — |
s.d. | 2.168 × 102 | — | — |
grp_b | |||
row_5 | 5.550 × 103 | — | 1325.810 |
row_6 | — | fig | 13.255 |
row_7 | 7.770 × 105 | grapefruit | — |
row_8 | 8.880 × 106 | honeydew | 0.440 |
avg | 3.221 × 106 | — | — |
total | 9.663 × 106 | — | — |
s.d. | 4.916 × 106 | — | — |
The input to fns
is very permissive in regard to how the
functions are defined. It is entirely valid to provide functions in the
various forms shown earlier such that
list("sum", avg = ~mean(., na.rm = TRUE), SD = "sd")
will
be correctly interpreted. It is recommended to use formula notation.
The default for formatter
is set to
fmt_number
which is a sensible default for many scenarios.
The setting of argument values for a particular formatter can be done in
the ...
area of the function call (as was done above for
the decimals
argument).
Using Multiple Calls of summary_rows()
We can re-use summary row labels and fill the otherwise empty summary
cells with similar aggregations but perhaps with different formatting
options. Here’s an example where the currency
column
contains aggregate values that share the same summary rows as for the
num
column, adds two more rows, and uses currency
formatting:
# Create group-wise summary rows as
# before, supply `fns_labels` to `fns`,
# and format the cell summary data
exibble_e <-
exibble_a |>
fmt_scientific(
columns = num,
decimals = 3
) |>
fmt_currency(
columns = currency,
currency = "EUR"
) |>
summary_rows(
groups = everything(),
columns = num,
fns = fns_labels,
fmt = list(~ fmt_scientific(., decimals = 3))
) |>
summary_rows(
groups = "grp_a",
columns = currency,
fns = c(
fns_labels,
min = ~ min(.),
max = ~ max(.)
),
fmt = list(~ fmt_currency(., currency = "EUR"))
)
exibble_e
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111 × 10−1 | apricot | €49.95 |
row_2 | 2.222 | banana | €17.95 |
row_3 | 3.333 × 101 | coconut | €1.39 |
row_4 | 4.444 × 102 | durian | €65,100.00 |
avg | 1.200 × 102 | — | €16,292.32 |
total | 4.801 × 102 | — | €65,169.29 |
s.d. | 2.168 × 102 | — | €32,538.46 |
min | — | — | €1.39 |
max | — | — | €65,100.00 |
grp_b | |||
row_5 | 5.550 × 103 | — | €1,325.81 |
row_6 | — | fig | €13.26 |
row_7 | 7.770 × 105 | grapefruit | — |
row_8 | 8.880 × 106 | honeydew | €0.44 |
avg | 3.221 × 106 | — | — |
total | 9.663 × 106 | — | — |
s.d. | 4.916 × 106 | — | — |
A thing to again note in the above example is that even though two
independent calls of summary_rows()
were made, summary data
within common summary row names were ‘squashed’ together, thus avoiding
the fragmentation of summary rows. Put another way, we don’t create
additional summary rows across separate calls if we are referencing the
same summary row labels. If the summary row labels provided in
fns
were to be different across columns however, additional
summary rows would be produced even if the types of data aggregations
were to be functionally equivalent.
We can also store these argument values as local variables and pass
them in both separate fmt_*number*()
calls also to
arguments within summary_rows()
calls. This is useful for
standardizing formatting parameters across different table cell types.
Here’s an example of that, which additional passes the
fr_BE
locale to all functions that take a
locale
value.
# Provide common formatting parameters to a list
# object named `formats`; the number of decimal
# places will be `2` and the locale is "fr_BE"
formats <-
list(
decimals = 3,
locale = "fr_BE",
currency = "EUR"
)
# Format the `num` and `currency` columns
# (using the values stored in `formats`);
# when generating summary rows we can also
# supply formatter options from this list
exibble_f <-
exibble_a |>
fmt_scientific(
columns = num,
decimals = formats$decimals,
locale = formats$locale
) |>
fmt_currency(
columns = currency,
currency = formats$currency,
locale = formats$locale
) |>
summary_rows(
groups = everything(),
columns = num,
fns = fns_labels,
fmt = list(~ fmt_scientific(.,
decimals = formats$decimals,
locale = formats$locale
))
) |>
summary_rows(
groups = "grp_a",
columns = currency,
fns = c(
fns_labels,
min = ~min(.),
max = ~max(.)
),
fmt = list(~ fmt_currency(.,
currency = formats$currency,
locale = formats$locale
))
)
exibble_f
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1,111 × 10−1 | apricot | €49,95 |
row_2 | 2,222 | banana | €17,95 |
row_3 | 3,333 × 101 | coconut | €1,39 |
row_4 | 4,444 × 102 | durian | €65 100,00 |
avg | 1,200 × 102 | — | €16 292,32 |
total | 4,801 × 102 | — | €65 169,29 |
s.d. | 2,168 × 102 | — | €32 538,46 |
min | — | — | €1,39 |
max | — | — | €65 100,00 |
grp_b | |||
row_5 | 5,550 × 103 | — | €1 325,81 |
row_6 | — | fig | €13,26 |
row_7 | 7,770 × 105 | grapefruit | — |
row_8 | 8,880 × 106 | honeydew | €0,44 |
avg | 3,221 × 106 | — | — |
total | 9,663 × 106 | — | — |
s.d. | 4,916 × 106 | — | — |
Passing in parameters like this is useful, especially if there are
larger numbers of columns. When we store formatting parameters outside
of the gt()
pipeline, we separate our concerns between data
structuring and data formatting. Putting styles and options into objects
becomes more important if we intend to centralize formatting options for
reuse.
Creating a Grand Summary
A grand summary aggregates column data regardless of the groups within the data. Grand summaries can also be created for gt tables that don’t have row groups, or, don’t have a stub. Finally, we can create a table that has both group-wise summaries and a grand summary.
Let’s keep it simple and create grand summary rows on a table without
a stub. We’ll use exibble
dataset for this once more. A few
exibble
columns are select()
ed, passed to
gt()
, and then grand_summary_rows()
. Notice
that, in the resulting table, a stub is created just for the summary row
labels (they have to go somewhere).
# Create a simple grand summary on a gt
# table that contains no stub
exibble_g <-
exibble |>
select(num, char, currency) |>
gt() |>
grand_summary_rows(
columns = c(num, currency),
fns = fns_labels
)
exibble_g
num | char | currency | |
---|---|---|---|
1.111e-01 | apricot | 49.950 | |
2.222e+00 | banana | 17.950 | |
3.333e+01 | coconut | 1.390 | |
4.444e+02 | durian | 65100.000 | |
5.550e+03 | NA | 1325.810 | |
NA | fig | 13.255 | |
7.770e+05 | grapefruit | NA | |
8.880e+06 | honeydew | 0.440 | |
avg | 1380433 | — | 9501.256 |
total | 9663030 | — | 66508.795 |
s.d. | 3319613 | — | 24521.602 |
A grand summary can be used in conjunction with group-wise summaries. Here’s an table where both types of summaries are present:
# Using the table in `exibble_f`, create
# grand summary rows (using two separate
# calls of `grand_summary_rows()` since
# the formatting will be different)
exibble_h <-
exibble_f |>
grand_summary_rows(
columns = num,
fns = fns_labels,
fmt = list(~ fmt_number(.,
suffixing = TRUE,
locale = formats$locale
))
) |>
grand_summary_rows(
columns = currency,
fns = fns_labels,
fmt = list(~ fmt_currency(.,
suffixing = TRUE,
locale = formats$locale
))
)
exibble_h
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1,111 × 10−1 | apricot | €49,95 |
row_2 | 2,222 | banana | €17,95 |
row_3 | 3,333 × 101 | coconut | €1,39 |
row_4 | 4,444 × 102 | durian | €65 100,00 |
avg | 1,200 × 102 | — | €16 292,32 |
total | 4,801 × 102 | — | €65 169,29 |
s.d. | 2,168 × 102 | — | €32 538,46 |
min | — | — | €1,39 |
max | — | — | €65 100,00 |
grp_b | |||
row_5 | 5,550 × 103 | — | €1 325,81 |
row_6 | — | fig | €13,26 |
row_7 | 7,770 × 105 | grapefruit | — |
row_8 | 8,880 × 106 | honeydew | €0,44 |
avg | 3,221 × 106 | — | — |
total | 9,663 × 106 | — | — |
s.d. | 4,916 × 106 | — | — |
avg | 1,38M | — | €9,50K |
total | 9,66M | — | €66,51K |
s.d. | 3,32M | — | €24,52K |
Note that the grand summary has a double line separating it from
group-wise summary that’s part of grp_b
. If this default
styling appears to be too subtle, we can elect to add further styling to
both group-wise summaries and the grand summary by using
tab_options()
.
Adding Some Style to the Summary Cells
While the summary cells (both group-wise and grand) have a distinct
appearance that sets them apart from the data cells, there’s always the
option to modify their appearance. We can use tab_options()
to perform these customizations. Here are the options specific to the
summary cells (for group-wise summaries) and the grand summary
cells:
-
summary_row.background.color
&grand_summary_row.background.color
-
summary_row.padding
&grand_summary_row.padding
-
summary_row.text_transform
&grand_summary_row.text_transform
We can also target the summary cells and grand summary cells with the
location helper functions cells_summary()
and
cells_grand_summary()
. This is important for adding
footnotes with tab_footnote()
and for setting styles with
tab_style()
(both have the locations
argument).
Here is an example that uses multiple calls of
tab_options()
and tab_footnote()
. The cell
background color for both types of summary cells is modified and two
footnotes are added.
# Using the gt table of `exibble_h` as a
# starting point, style summary cells with
# `tab_options()` and add two footnotes
exibble_i <-
exibble_h |>
tab_options(
summary_row.background.color = "lightblue",
grand_summary_row.background.color = "lightgreen"
) |>
tab_footnote(
footnote = md("Mean of all *num* values."),
locations = cells_grand_summary(
columns = "num", rows = "avg"
)
) |>
tab_footnote(
footnote = md("Highest `currency` value in **grp_a**"),
locations = cells_summary(
groups = "grp_a",
columns = "currency",
rows = "max"
)
)
exibble_i
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1,111 × 10−1 | apricot | €49,95 |
row_2 | 2,222 | banana | €17,95 |
row_3 | 3,333 × 101 | coconut | €1,39 |
row_4 | 4,444 × 102 | durian | €65 100,00 |
avg | 1,200 × 102 | — | €16 292,32 |
total | 4,801 × 102 | — | €65 169,29 |
s.d. | 2,168 × 102 | — | €32 538,46 |
min | — | — | €1,39 |
max | — | — | €65 100,001 |
grp_b | |||
row_5 | 5,550 × 103 | — | €1 325,81 |
row_6 | — | fig | €13,26 |
row_7 | 7,770 × 105 | grapefruit | — |
row_8 | 8,880 × 106 | honeydew | €0,44 |
avg | 3,221 × 106 | — | — |
total | 9,663 × 106 | — | — |
s.d. | 4,916 × 106 | — | — |
avg | 1,38M2 | — | €9,50K |
total | 9,66M | — | €66,51K |
s.d. | 3,32M | — | €24,52K |
1 Highest currency value in grp_a
|
|||
2 Mean of all num values. |
Extracting the Summary Data from the gt Table Object
For a reproducible workflow, we do not want to have situations where any data created or modified cannot be accessed. While having summarized values be created in a gt pipeline presents advantages to readability and intent of analysis, it is recognized that the output table itself is essentially ‘read only’, as the input data undergoes processing and movement to an entirely different format.
However, the object created still contains data and we can obtain the
summary data from a gt table object with
extract_summary()
. Taking the gt_summary
object, we get a list of tibbles containing the summary data while
preserving the correct data types:
# Extract the summary data from `exibble_d`
# to a list object
summary_list <- exibble_d |> extract_summary()
# Print out the summary for the `grp_a` group
summary_list$summary_df_data_list$grp_a
#> # A tibble: 3 × 8
#> group_id row_id rowname num char currency row group
#> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 grp_a avg avg 120. NA NA NA NA
#> 2 grp_a total total 480. NA NA NA NA
#> 3 grp_a s.d. s.d. 217. NA NA NA NA
# Print out the summary for the `grp_b` group
summary_list$summary_df_data_list$grp_b
#> # A tibble: 3 × 8
#> group_id row_id rowname num char currency row group
#> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 grp_b avg avg 3220850 NA NA NA NA
#> 2 grp_b total total 9662550 NA NA NA NA
#> 3 grp_b s.d. s.d. 4916123. NA NA NA NA
The output tibbles within the list always contain the
groupname
and rowname
columns. The
groupname
column is filled with the name of the row group
that was given to summary_rows()
. The rowname
column contains the descriptive stub labels for the summary rows (recall
that values are either supplied explicitly in
summary_rows()
, or, are generated from the function names).
The remaining columns are those from the original dataset.
The output data from extract_summary()
can be
reintroduced to a reproducible workflow and serve as downstream inputs
or undergo validation. Perhaps interestingly, the output tibbles are
structured in a way that facilitates direct input back to
gt()
(i.e., it has the magic groupname
and
rowname
columns). This can produce a new, standalone
summary table where the summary rows are now data rows:
# Take `exibble_d`, which internally has a list
# of summary data frames, extract the summaries,
# and then combine them; input that into `gt()`,
# and format the `num` column with `fmt_number()`
exibble_d |>
extract_summary() |>
unlist(recursive = FALSE) |>
bind_rows() |>
gt() |>
fmt_number(
columns = num,
decimals = 1
) |>
sub_missing(columns = c(char, currency, row, group))
group_id | row_id | num | char | currency | row | group | |
---|---|---|---|---|---|---|---|
avg | grp_a | avg | 120.0 | — | — | — | — |
total | grp_a | total | 480.1 | — | — | — | — |
s.d. | grp_a | s.d. | 216.8 | — | — | — | — |
avg | grp_b | avg | 3,220,850.0 | — | — | — | — |
total | grp_b | total | 9,662,550.0 | — | — | — | — |
s.d. | grp_b | s.d. | 4,916,123.3 | — | — | — | — |
Providing Our Own Aggregation Functions to Generate Summary Rows
While many of the functions available in base R and within packages
are useful as aggregate functions, we may occasionally have the need to
create our own custom functions. When taking this approach the main
things to keep in mind are that a vector of values is the main input,
and, a single value should be returned. The return value can be pretty
much any class (e.g., numeric
, character
,
logical
) and it’s the formatter
function that
will handle any custom formatting while also converting to
character
.
Here, we’ll define a function that takes a vector of numeric values
and outputs the two highest values (sorted low to high) above a
threshold
value. The output from this function is always a
formatted character
string.
# Define a function that gives the
# highest two values above a threshold
agg_highest_two_above_value <- function(x, threshold) {
# Get sorted values above threshold value
values <- sort(round(x[x >= threshold], 2))
# Return character string with 2 highest values above threshold
if (length(values) == 0) {
return(paste0("No values above ", threshold))
} else {
return(
paste(
formatC(
tail(
sort(round(x[x > threshold], 2)), 2),
format = "f", digits = 2), collapse = ", "))
}
}
# Let's test this function with some values
agg_highest_two_above_value(
x = c(0.73, 0.93, 0.75, 0.86, 0.23, 0.81),
threshold = 0.8
)
#> [1] "0.86, 0.93"
Because this is character value that’s returned, we don’t need
formatting functions like fmt_number()
,
fmt_percent()
, etc. However, a useful formatter (and we do
need some formatter) is fmt_passthrough()
. Like
the name suggests, it to great extent passes values through but formats
as character
(like all the fmt_*()
function
do) and it provides the option to decorate the output with a
pattern
. Let’s have a look at how
agg_highest_two_above_value()
can be used with
fmt_passthrough()
.
# Create a gt table with `exibble_a` and use
# the custom function with a threshold of `20`;
# `fmt_passthrough()` allows for minimal formatting
# of the aggregate values
exibble_j <-
exibble_a |>
grand_summary_rows(
columns = c(num, currency),
fns = list(high = ~ agg_highest_two_above_value(., 20)),
fmt = list(~ fmt_passthrough(., pattern = "({x})"))
)
exibble_j
num | char | currency | |
---|---|---|---|
grp_a | |||
row_1 | 1.111e-01 | apricot | 49.950 |
row_2 | 2.222e+00 | banana | 17.950 |
row_3 | 3.333e+01 | coconut | 1.390 |
row_4 | 4.444e+02 | durian | 65100.000 |
grp_b | |||
row_5 | 5.550e+03 | — | 1325.810 |
row_6 | — | fig | 13.255 |
row_7 | 7.770e+05 | grapefruit | — |
row_8 | 8.880e+06 | honeydew | 0.440 |
high | (777000.00, 8880000.00) | — | (1325.81, 65100.00) |
We can extract the grand summary data from the exibble_j
object. Note that columns num
and currency
are
classed as character since it was character outputs that were generated
by the agg_highest_two_above_value()
function.
# Extract the summary list from `exibble_j`
# and inspect using `str()`
exibble_j |>
extract_summary() |>
str()
#> List of 1
#> $ summary_df_data_list:List of 1
#> ..$ ::GRAND_SUMMARY: tibble [1 × 8] (S3: tbl_df/tbl/data.frame)
#> .. ..$ group_id: chr "::GRAND_SUMMARY"
#> .. ..$ row_id : chr "high"
#> .. ..$ rowname : chr "high"
#> .. ..$ num : chr "777000.00, 8880000.00"
#> .. ..$ char : num NA
#> .. ..$ currency: chr "1325.81, 65100.00"
#> .. ..$ row : num NA
#> .. ..$ group : num NA