install.packages("gtExtras")
# or if wanting the dev version
# if needed install.packages("remotes")
remotes::install_github("jthomasmock/gtExtras")
I’m very excited to have the first release of gtExtras
available on CRAN!
The goal of gtExtras
is to provide opinionated helper functions to assist in creating beautiful and functional tables with gt
.
The functions are generally wrappers around boilerplate table-making code or adding opinionated functions like data journalism inspired table themes and inline graphics. The gt
package is amazing, make sure to go read the official documentation.
For installation:
Using gtExtras
Overall, there are a lot of available functions in gtExtras
:
You can read about each of the functions in the function reference.
Overall, there are four families of functions in gtExtras
:
- Themes: 7 themes that style almost every element of a
gt
table, built off of data journalism-styled tables - Utilities: Helper functions for aligning/padding numbers, adding
fontawesome
icons, images, highlighting, dividers, styling by group, creating two tables or two column layouts, extracting ordered data from agt
table internals, or generating a random dataset forreprex
- Plotting: 12 plotting functions for inline sparklines, win-loss charts, distributions (density/histogram), percentiles, dot + bar, bar charts, confidence intervals, or summarizing an entire dataframe!
- Colors: 3 functions, a palette for “Hulk” style scale (purple/green), coloring rows with good defaults from
paletteer
, or adding a “color box” along with the cell value
Also see the Plotting with gtExtras
article for more examples of combining tables and graphics together.
A subset of functions are included below, or see the full function reference.
Importantly, gtExtras
is not at all a replacement for gt
, but rather is almost a “cookbook” where common or repeated function calls are grouped into their own respective functions. At a technical level, gtExtras
is literally just gt
functions under the hood and I’ll highlight a few examples of how to do the same thing in each package.
Load libraries
Themes
The package includes seven different themes, and 3 examples are the gt_theme_538()
styled after FiveThirtyEight style tables, the gt_theme_espn()
styled after ESPN style tables, and the gt_theme_nytimes()
styled after The New York Times tables.
head(mtcars) %>%
gt() %>%
gt_theme_538() %>%
tab_header(title = "Table styled like the FiveThirtyEight")
Table styled like the FiveThirtyEight | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
head(mtcars) %>%
gt() %>%
gt_theme_guardian() %>%
tab_header(title = "Table styled like the Guardian")
Table styled like the Guardian | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
head(mtcars) %>%
gt() %>%
gt_theme_nytimes() %>%
tab_header(title = "Table styled like the NY Times")
Table styled like the NY Times | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
There are also themes that are bit more specific or somewhat “tongue in cheek”:
head(mtcars) %>%
gt() %>%
gt_theme_excel() %>%
tab_header(title = "Table styled like Excel")
Table styled like Excel | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
head(mtcars) %>%
gt() %>%
gt_theme_dot_matrix() %>%
tab_header(title = "Table styled like a dot matrix printer")
Table styled like a dot matrix printer | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
If you wanted to write your own gt_theme_YOURTHEME()
function, you could do this with something like the below:
my_theme <- function(gt_object, ...){
gt_object %>%
tab_options(
column_labels.background.color = "black",
heading.align = "left",
...
) %>%
tab_style(
style = cell_text(color = "red", size = px(32)),
locations = cells_title("title")
)
}
My own custom theme! | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Hulk data_color
This is an opinionated diverging color palette. It diverges from low to high as purple to green. It is a good alternative to a red-green diverging palette as a color-blind friendly palette. The specific colors come from colorbrewer2.
Basic usage below, where a specific column is passed.
# basic use
head(mtcars) %>%
gt::gt() %>%
gt_hulk_col_numeric(mpg)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Trim provides a tighter range of purple/green so the colors are less pronounced.
head(mtcars) %>%
gt::gt() %>%
# trim gives smaller range of colors
# so the green and purples are not as dark
gt_hulk_col_numeric(mpg:disp, trim = TRUE)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Reverse makes higher values represented by purple and lower by green. The default is to have high = green, low = purple.
# option to reverse the color palette
# so that purple is higher
head(mtcars) %>%
gt::gt() %>%
# reverse = green for low, purple for high
gt_hulk_col_numeric(mpg:disp, reverse = TRUE)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
gt_color_rows()
The gt_color_rows()
function is a more generic, thin boilerplate wrapper around gt::data_color()
. A quick example of gt::data_color()
is below.
Using named colors or hex colors is very simple!
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Some complexity arises when wanting to use a color palette with tighter control. The code below is good but requires you to write out a lot of your own control.
color_fn <- scales::col_numeric(
domain = NULL,
palette = as.character(
paletteer::paletteer_d(
palette = "ggsci::red_material" ,
type = "continuous"))
)
head(mtcars) %>%
gt() %>%
gt::data_color(columns = mpg:disp, colors = color_fn)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
gtExtras::gt_color_rows()
simple to use but provides rich color choices thanks to the native inclusion of paletteer::paletteer_d()
. This can provide 100s of discrete (ie categorical) or continuous color palettes.
Note that it is very close to the color_fn
from above but throws a warning if domain is NULL since that will use range within EACH column rather than a shared range ACROSS columns.
Warning: Domain not specified, defaulting to observed range within each
specified column.
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
You can change the specific palette with palette = "package_name::palette_name"
# recognizes all of the dynamic palettes from paletteer
mtcars %>%
head() %>%
gt() %>%
gt_color_rows(mpg:disp, palette = "ggsci::blue_material")
Warning: Domain not specified, defaulting to observed range within each
specified column.
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
You can also use custom-defined palettes with named colors in R or hex color values however, this has minimal value over gt::data_color()
. The main difference would be ability to specify a domain and throwing a warning without it.
Warning: Domain not specified, defaulting to observed range within each
specified column.
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
# could also use palette = c("#ffffff", "##00FF00")
gt
-native example gives you basically the same result.
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Lastly, you can also provide categorical or discrete data to be colored.
# provide type = "discrete"
mtcars %>%
head() %>%
gt() %>%
gt_color_rows(
cyl,
palette = "ggthemes::colorblind",
# note that you can manually define range like c(4, 6, 8)
domain = range(mtcars$cyl),
pal_type = "discrete"
)
mpg | cyl | disp | hp | drat | wt | qsec | vs | am | gear | carb |
---|---|---|---|---|---|---|---|---|---|---|
21.0 | 6 | 160 | 110 | 3.90 | 2.620 | 16.46 | 0 | 1 | 4 | 4 |
21.0 | 6 | 160 | 110 | 3.90 | 2.875 | 17.02 | 0 | 1 | 4 | 4 |
22.8 | 4 | 108 | 93 | 3.85 | 2.320 | 18.61 | 1 | 1 | 4 | 1 |
21.4 | 6 | 258 | 110 | 3.08 | 3.215 | 19.44 | 1 | 0 | 3 | 1 |
18.7 | 8 | 360 | 175 | 3.15 | 3.440 | 17.02 | 0 | 0 | 3 | 2 |
18.1 | 6 | 225 | 105 | 2.76 | 3.460 | 20.22 | 1 | 0 | 3 | 1 |
Again, this function is an example of something that is easily possible with gt
but would require a good chunk of repeated boilerplate code.
gt_highlight_rows()
This provides the ability to highlight and optionally bold entire rows within an existing gt
table. Basic use defaults to a light-blue highlight which can be changed with the fill
argument.
head_car <- head(mtcars[,1:5]) %>%
tibble::rownames_to_column("car")
gt(head_car) %>%
gt_highlight_rows(rows = 2, font_weight = "normal")
car | mpg | cyl | disp | hp | drat |
---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160 | 110 | 3.90 |
Mazda RX4 Wag | 21.0 | 6 | 160 | 110 | 3.90 |
Datsun 710 | 22.8 | 4 | 108 | 93 | 3.85 |
Hornet 4 Drive | 21.4 | 6 | 258 | 110 | 3.08 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 | 3.15 |
Valiant | 18.1 | 6 | 225 | 105 | 2.76 |
You can optionally specify a target column with target_col
that will be bold, while the rest of the row’s text will be default weight.
gt(head_car) %>%
gt_highlight_rows(
rows = 5,
fill = "lightgrey",
bold_target_only = TRUE,
target_col = car
)
car | mpg | cyl | disp | hp | drat |
---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160 | 110 | 3.90 |
Mazda RX4 Wag | 21.0 | 6 | 160 | 110 | 3.90 |
Datsun 710 | 22.8 | 4 | 108 | 93 | 3.85 |
Hornet 4 Drive | 21.4 | 6 | 258 | 110 | 3.08 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 | 3.15 |
Valiant | 18.1 | 6 | 225 | 105 | 2.76 |
And because gtExtras
is just using gt::tab_style()
under the hood, it also accepts logical statements for specific rows.
gt(head_car) %>%
gt_highlight_rows(
rows = drat == 3.08,# a logic statement
fill = "lightgrey",
bold_target_only = TRUE,
target_col = car
)
car | mpg | cyl | disp | hp | drat |
---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160 | 110 | 3.90 |
Mazda RX4 Wag | 21.0 | 6 | 160 | 110 | 3.90 |
Datsun 710 | 22.8 | 4 | 108 | 93 | 3.85 |
Hornet 4 Drive | 21.4 | 6 | 258 | 110 | 3.08 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 | 3.15 |
Valiant | 18.1 | 6 | 225 | 105 | 2.76 |
The equivalent gt
code - again, easy to figure out but some repeated calls.
gt(head_car) %>%
tab_style(
style = cell_fill(color = "lightgrey"),
locations = cells_body(everything(), rows = drat == 3.08)
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_body(car, rows = drat == 3.08)
)
car | mpg | cyl | disp | hp | drat |
---|---|---|---|---|---|
Mazda RX4 | 21.0 | 6 | 160 | 110 | 3.90 |
Mazda RX4 Wag | 21.0 | 6 | 160 | 110 | 3.90 |
Datsun 710 | 22.8 | 4 | 108 | 93 | 3.85 |
Hornet 4 Drive | 21.4 | 6 | 258 | 110 | 3.08 |
Hornet Sportabout | 18.7 | 8 | 360 | 175 | 3.15 |
Valiant | 18.1 | 6 | 225 | 105 | 2.76 |
Plotting in gt
with gtExtras
As we get into plotting with gt
the complexity really ramps up internally, as you’re wrapping gt
+ ggplot2
code internally.
Note that if you just want to create ggplot2
plots and embed them in gt
, you can use gt::ggplot_image()
! That gives you full and separate control of the two items, ie just use ggplot2
and use gt
separately.
plot_object <-
ggplot(
data = gtcars,
aes(x = hp, y = trq, size = msrp)
) +
geom_point(color = "blue") +
theme(legend.position = "none")
dplyr::tibble(
text = "Here is a ggplot:",
ggplot = NA
) %>%
gt() %>%
text_transform(
locations = cells_body(columns = ggplot),
fn = function(x) {
plot_object %>%
ggplot_image(height = px(200))
}
)
text | ggplot |
---|---|
Here is a ggplot: |
However, with the plotting functions in gtExtras
, I’ve made some opinionated choices as to the output style/size/options - taking away some of your creativity for a simple to use user interface.
A side effect of these gtExtras
functions is that almost exclusively they require you to pass datasets with list columns. These are easy enough to create!
mtcars %>%
dplyr::group_by(cyl) %>%
# must end up with list of data for each row in the input dataframe
dplyr::summarize(mpg_data = list(mpg), .groups = "drop")
# A tibble: 3 × 2
cyl mpg_data
<dbl> <list>
1 4 <dbl [11]>
2 6 <dbl [7]>
3 8 <dbl [14]>
gt_sparkline()
A typical sparkline for your table!
gt_plt_dist()
If you’d rather plot some distributions, you could use gt_plt_dist()
. This functions defaults to an inline density plot, but accepts a type = "boxplot"
, "histogram"
, "rug_strip"
or "density"
.
gt_bar_plot()
The gt_bar_plot
function takes an existing gt_tbl
object and adds horizontal barplots via native HTML. This is a wrapper around raw HTML strings, gt::text_transform()
and gt::cols_align()
. Note that values default to being normalized to the percent of the maximum observed value in the specified column. You can turn this off if the values already represent a percentage value representing 0-100.
mtcars %>%
head() %>%
dplyr::select(cyl, mpg) %>%
dplyr::mutate(mpg_pct_max = round(mpg/max(mpg) * 100, digits = 2),
mpg_scaled = mpg/max(mpg) * 100) %>%
dplyr::mutate(mpg_unscaled = mpg) %>%
gt() %>%
gt_plt_bar_pct(column = mpg_scaled, scaled = TRUE) %>%
gt_plt_bar_pct(column = mpg_unscaled, scaled = FALSE, fill = "blue", background = "lightblue") %>%
cols_align("center", contains("scale")) %>%
cols_width(4 ~ px(125),
5 ~ px(125))
cyl | mpg | mpg_pct_max | mpg_scaled | mpg_unscaled |
---|---|---|---|---|
6 | 21.0 | 92.11 | ||
6 | 21.0 | 92.11 | ||
4 | 22.8 | 100.00 | ||
6 | 21.4 | 93.86 | ||
8 | 18.7 | 82.02 | ||
6 | 18.1 | 79.39 |
gt_merge_stack()
The gt_merge_stack()
function takes an existing gt
table and merges column 1 and column 2, stacking column 1’s text on top of column 2’s. Top text is in all caps with black bold text, while the lower text is smaller and dark grey.
Note that team_nick
has the team nickname over the team’s division.
team_df <- readRDS(url("https://github.com/nflverse/nflfastR-data/raw/master/teams_colors_logos.rds"))
team_df %>%
dplyr::select(team_nick, team_abbr, team_conf, team_division, team_wordmark) %>%
head(8) %>%
gt(groupname_col = "team_conf") %>%
gt_merge_stack(col1 = team_nick, col2 = team_division) %>%
gt_img_rows(team_wordmark)
team_nick | team_abbr | team_wordmark |
---|---|---|
NFC | ||
Cardinals
NFC West
|
ARI | |
Falcons
NFC South
|
ATL | |
Panthers
AFC North
|
CAR | |
Bears
AFC East
|
CHI | |
AFC | ||
Ravens
NFC South
|
BAL | |
Bills
NFC North
|
BUF | |
Bengals
AFC North
|
CIN | |
Browns
AFC North
|
CLE |
gt_plt_winloss()
This function takes a list-column of win loss values (ie, 0=loss, 0.5 = tie, 1 = win) and ouputs an inline plot representing the win/loss squares with blue = win, red = loss, grey = tie. Points are also also redundantly coded with height, where wins are highest, ties are middle, and losses are at the bottom.
The example below generates an example dataset and then embeds a plot.
create_input_df <- function(repeats = 3){
input_df <- dplyr::tibble(
team = c("A1", "B2", "C3", "C4"),
Wins = c(3, 2, 1, 1),
Losses = c(2, 3, 2, 4),
Ties = c(0, 0, 2, 0),
outcomes = list(
c(1, .5, 0) %>% rep(each = repeats),
c(0, 1, 0.5) %>% rep(each = repeats),
c(0, 0.5, 1) %>% rep(each = repeats),
c(0.5, 1, 0) %>% rep(each = repeats)
)
)
input_df
}
create_input_df(5) %>%
dplyr::glimpse()
Rows: 4
Columns: 5
$ team <chr> "A1", "B2", "C3", "C4"
$ Wins <dbl> 3, 2, 1, 1
$ Losses <dbl> 2, 3, 2, 4
$ Ties <dbl> 0, 0, 2, 0
$ outcomes <list> <1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, …
Now that we have way to quickly generate example data, we can show the ability to incrementally add the win/losses.
Starting with 3 games. Please ignore the Wins/Loss/Ties columns, as they are simply placeholders. I am iterating the length of the outcomes list row.
create_input_df(1) %>%
gt() %>%
gt_plt_winloss(outcomes, max_wins = 15) %>%
tab_options(data_row.padding = px(2))
team | Wins | Losses | Ties | outcomes |
---|---|---|---|---|
A1 | 3 | 2 | 0 | |
B2 | 2 | 3 | 0 | |
C3 | 1 | 2 | 2 | |
C4 | 1 | 4 | 0 |
And moving to 12 games, we can see that the scale is unchanged, and “empty” points are replaced with outcomes once the values are present in the data.
create_input_df(4) %>%
gt() %>%
gt_plt_winloss(outcomes, max_wins = 15) %>%
tab_options(data_row.padding = px(2))
team | Wins | Losses | Ties | outcomes |
---|---|---|---|---|
A1 | 3 | 2 | 0 | |
B2 | 2 | 3 | 0 | |
C3 | 1 | 2 | 2 | |
C4 | 1 | 4 | 0 |
You can also switch over to ‘squares’ instead of ‘pills’ by changing the type
argument.
create_input_df(4) %>%
gt() %>%
gt_plt_winloss(outcomes, max_wins = 15, type = "square") %>%
tab_options(data_row.padding = px(2))
team | Wins | Losses | Ties | outcomes |
---|---|---|---|---|
A1 | 3 | 2 | 0 | |
B2 | 2 | 3 | 0 | |
C3 | 1 | 2 | 2 | |
C4 | 1 | 4 | 0 |
A more realistic use case is seen below with data from nflreadr:
Creating dataset
library(dplyr)
library(tidyr)
library(nflreadr)
games_df <- nflreadr::load_schedules() %>%
filter(season == 2020, game_type == "REG") %>%
select(game_id, team_home = home_team, team_away = away_team, result, week) %>%
pivot_longer(contains('team'), names_to = 'home_away', values_to = 'team', names_prefix = 'team_') %>%
mutate(
result = ifelse(home_away == 'home', result, -result),
win = ifelse(result == 0 , 0.5, ifelse(result > 0, 1, 0))
) %>%
select(week, team, win) %>%
mutate(
team = case_when(
team == 'STL' ~ 'LA',
team == 'OAK' ~ 'LV',
team == 'SD' ~ 'LAC',
T ~ team
)
)
team_df <- nflreadr::load_teams() %>%
select(team_wordmark, team_abbr, team_conf, team_division)
joined_df <- games_df %>%
group_by(team) %>%
summarise(
Wins = length(win[win==1]),
Losses = length(win[win==0]),
outcomes = list(win), .groups = "drop") %>%
left_join(team_df, by = c("team" = "team_abbr")) %>%
select(team_wordmark, team_conf, team_division, Wins:outcomes)
final_df <- joined_df %>%
filter(team_conf == "AFC") %>%
group_by(team_division) %>%
arrange(desc(Wins)) %>%
ungroup() %>%
arrange(team_division)
final_df %>%
gt(groupname_col = "team_division") %>%
gt_plt_winloss(outcomes, max_wins = 16) %>%
gt_img_rows(columns = team_wordmark) %>%
gt_theme_538() %>%
tab_header(title = "2020 Results by Division for the AFC")
2020 Results by Division for the AFC | ||||
---|---|---|---|---|
team_wordmark | team_conf | Wins | Losses | outcomes |
AFC East | ||||
AFC | 13 | 3 | ||
AFC | 10 | 6 | ||
AFC | 7 | 9 | ||
AFC | 2 | 14 | ||
AFC North | ||||
AFC | 12 | 4 | ||
AFC | 11 | 5 | ||
AFC | 11 | 5 | ||
AFC | 4 | 11 | ||
AFC South | ||||
AFC | 11 | 5 | ||
AFC | 11 | 5 | ||
AFC | 4 | 12 | ||
AFC | 1 | 15 | ||
AFC West | ||||
AFC | 14 | 2 | ||
AFC | 8 | 8 | ||
AFC | 7 | 9 | ||
AFC | 5 | 11 |
Closing
So that has been a brief overview of some of the possibilities of gtExtras
- so go out, use gt
, bring in gtExtras
when you’d like to extend some of the work you’re doing and let me know if you enjoy the package!