diff --git a/DESCRIPTION b/DESCRIPTION index bb688a8..de810b9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: nflplotR Title: NFL Logo Plots in 'ggplot2' -Version: 1.1.0.9001 +Version: 1.1.0.9002 Authors@R: person("Sebastian", "Carl", , "mrcaseb@gmail.com", role = c("aut", "cre")) Description: A set of functions to visualize National Football League @@ -24,10 +24,12 @@ Imports: rlang (>= 0.4.11), scales (>= 1.1.0) Suggests: + base64enc (>= 0.1-3), covr, dplyr (>= 1.0.0), ggtext (>= 0.1.1), gridtext (>= 0.1.4), + gt (>= 0.8.0), knitr, rmarkdown, rstudioapi (>= 0.13), @@ -38,4 +40,4 @@ Suggests: Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.1 +RoxygenNote: 7.2.3 diff --git a/NAMESPACE b/NAMESPACE index e7430ab..4bbe206 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,8 @@ export(geom_nfl_headshots) export(geom_nfl_logos) export(geom_nfl_wordmarks) export(ggpreview) +export(gt_nfl_logos) +export(gt_nfl_wordmarks) export(nfl_team_factor) export(nfl_team_tiers) export(nflverse_sitrep) diff --git a/NEWS.md b/NEWS.md index ff34e2f..ec64250 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # nflplotR (development version) * Import/export `nflverse_sitrep()` +* Add new functions `gt_nfl_logos()` and `gt_nfl_wordmarks()` to render logos and wordmarks in `gt()` html tables. (#161) # nflplotR 1.1.0 diff --git a/R/gt_nfl_logos.R b/R/gt_nfl_logos.R new file mode 100644 index 0000000..b46d3ce --- /dev/null +++ b/R/gt_nfl_logos.R @@ -0,0 +1,123 @@ +#' Render Logos and Wordmarks in 'gt' Tables +#' +#' @description Translate NFL team abbreviations into logos and wordmarks and +#' render these images in html tables with the 'gt' package. +#' @param gt_object A table object that is created using the [gt::gt()] function. +#' @param columns The columns for which the image translation should be applied. +#' Argument has no effect if `locations` is not `NULL`. +#' @param height The absolute height (px) of the image in the table cell. +#' @param locations If `NULL` (the default), the function will render +#' logos/wordmarks in argument `columns`. +#' Otherwise, the cell or set of cells to be associated with the team name +#' transformation. Only the [gt::cells_body()], [gt::cells_stub()], +#' [gt::cells_column_labels()], and [gt::cells_row_groups()] helper functions +#' can be used here. We can enclose several of these calls within a `list()` +#' if we wish to make the transformation happen at different locations. +#' +#' @return An object of class `gt_tbl`. +#' @export +#' @section Output of below example: +#' \if{html}{\figure{logo_tbl.png}{options: width=75\%}} +#' @examples +#' \donttest{ +#' library(gt) +#' library(nflplotR) +#' teams <- valid_team_names() +#' # remove conference logos from this example +#' teams <- teams[!teams %in% c("AFC", "NFC", "NFL")] +#' # create dataframe with all 32 team names +#' df <- data.frame( +#' team_a = head(teams, 16), +#' logo_a = head(teams, 16), +#' wordmark_a = head(teams, 16), +#' team_b = tail(teams, 16), +#' logo_b = tail(teams, 16), +#' wordmark_b = tail(teams, 16) +#' ) +#' # create gt table and translate team names to logo/wordmark images +#' table <- df %>% +#' gt() %>% +#' gt_nfl_logos(columns = gt::starts_with("logo")) %>% +#' gt_nfl_wordmarks(columns = gt::starts_with("wordmark")) +#' } +gt_nfl_logos <- function(gt_object, + columns, + height = 30, + locations = NULL){ + gt_nflplotR_image( + gt_object = gt_object, + columns = columns, + height = height, + locations = locations, + type = "logos" + ) +} + +#' @rdname gt_nfl_logos +#' @export +gt_nfl_wordmarks <- function(gt_object, + columns, + height = 30, + locations = NULL){ + gt_nflplotR_image( + gt_object = gt_object, + columns = columns, + height = height, + locations = locations, + type = "wordmarks" + ) +} + +gt_nflplotR_image <- function(gt_object, + columns, + height = 30, + locations = NULL, + type = c("logos", "wordmarks")){ + + rlang::check_installed("gt (>= 0.8.0)", "to render images in gt tables.") + + type <- match.arg(type) + + if(is.null(locations)){ + locations <- gt::cells_body({{ columns }}) + } + + if (is.numeric(height)) { + height <- paste0(height, "px") + } + + gt::text_transform( + data = gt_object, + locations = locations, + fn = function(x){ + team_abbr <- nflreadr::clean_team_abbrs(as.character(x), keep_non_matches = FALSE) + # Create the image URI + uri <- get_image_uri(team_abbr = team_abbr, type = type) + # Generate the Base64-encoded image and place it within tags + paste0("") + } + ) + +} + +# Taken from gt package and modified for nflplotR purposes +# Get image URIs from image lists as a vector Base64-encoded image strings +get_image_uri <- function(team_abbr, type = c("logos", "wordmarks")) { + + lookup_list <- switch (type, + "logos" = logo_list, + "wordmarks" = wordmark_list + ) + + vapply( + team_abbr, + FUN.VALUE = character(1), + USE.NAMES = FALSE, + FUN = function(team) { + paste0( + "data:", "image/png", + ";base64,", base64enc::base64encode(lookup_list[[team]]) + ) + } + ) +} diff --git a/man/figures/logo_tbl.png b/man/figures/logo_tbl.png new file mode 100644 index 0000000..b0d0373 Binary files /dev/null and b/man/figures/logo_tbl.png differ diff --git a/man/geom_from_path.Rd b/man/geom_from_path.Rd index a2cae83..c644f97 100644 --- a/man/geom_from_path.Rd +++ b/man/geom_from_path.Rd @@ -16,10 +16,10 @@ geom_from_path( ) } \arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or -\code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the -default), it is combined with the default mapping at the top level of the -plot. You must supply \code{mapping} if there is no plot mapping.} +\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and +\code{inherit.aes = TRUE} (the default), it is combined with the default mapping +at the top level of the plot. You must supply \code{mapping} if there is no plot +mapping.} \item{data}{The data to be displayed in this layer. There are three options: @@ -37,10 +37,14 @@ will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{stat}{The statistical transformation to use on the data for this -layer, as a string.} - -\item{position}{Position adjustment, either as a string, or the result of -a call to a position adjustment function.} +layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the +stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than +\code{"stat_count"})} + +\item{position}{Position adjustment, either as a string naming the adjustment +(e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a +position adjustment function. Use the latter if you need to change the +settings of the adjustment.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{ggplot2::layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value. See the below diff --git a/man/geom_lines.Rd b/man/geom_lines.Rd index 5a6ac5f..3122c97 100644 --- a/man/geom_lines.Rd +++ b/man/geom_lines.Rd @@ -24,7 +24,7 @@ geom_mean_lines( ) } \arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or \code{\link[ggplot2:aes_]{aes_()}}.} +\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}.} \item{data}{The data to be displayed in this layer. There are three options: diff --git a/man/geom_nfl_headshots.Rd b/man/geom_nfl_headshots.Rd index 8dff732..4d5b4f3 100644 --- a/man/geom_nfl_headshots.Rd +++ b/man/geom_nfl_headshots.Rd @@ -16,10 +16,10 @@ geom_nfl_headshots( ) } \arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or -\code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the -default), it is combined with the default mapping at the top level of the -plot. You must supply \code{mapping} if there is no plot mapping.} +\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and +\code{inherit.aes = TRUE} (the default), it is combined with the default mapping +at the top level of the plot. You must supply \code{mapping} if there is no plot +mapping.} \item{data}{The data to be displayed in this layer. There are three options: @@ -37,10 +37,14 @@ will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{stat}{The statistical transformation to use on the data for this -layer, as a string.} - -\item{position}{Position adjustment, either as a string, or the result of -a call to a position adjustment function.} +layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the +stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than +\code{"stat_count"})} + +\item{position}{Position adjustment, either as a string naming the adjustment +(e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a +position adjustment function. Use the latter if you need to change the +settings of the adjustment.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{ggplot2::layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value. See the below diff --git a/man/geom_nfl_logos.Rd b/man/geom_nfl_logos.Rd index f31684f..ac89940 100644 --- a/man/geom_nfl_logos.Rd +++ b/man/geom_nfl_logos.Rd @@ -16,10 +16,10 @@ geom_nfl_logos( ) } \arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or -\code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the -default), it is combined with the default mapping at the top level of the -plot. You must supply \code{mapping} if there is no plot mapping.} +\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and +\code{inherit.aes = TRUE} (the default), it is combined with the default mapping +at the top level of the plot. You must supply \code{mapping} if there is no plot +mapping.} \item{data}{The data to be displayed in this layer. There are three options: @@ -37,10 +37,14 @@ will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{stat}{The statistical transformation to use on the data for this -layer, as a string.} - -\item{position}{Position adjustment, either as a string, or the result of -a call to a position adjustment function.} +layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the +stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than +\code{"stat_count"})} + +\item{position}{Position adjustment, either as a string naming the adjustment +(e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a +position adjustment function. Use the latter if you need to change the +settings of the adjustment.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{ggplot2::layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value. See the below diff --git a/man/geom_nfl_wordmarks.Rd b/man/geom_nfl_wordmarks.Rd index 8045215..4aa9e28 100644 --- a/man/geom_nfl_wordmarks.Rd +++ b/man/geom_nfl_wordmarks.Rd @@ -16,10 +16,10 @@ geom_nfl_wordmarks( ) } \arguments{ -\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or -\code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the -default), it is combined with the default mapping at the top level of the -plot. You must supply \code{mapping} if there is no plot mapping.} +\item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and +\code{inherit.aes = TRUE} (the default), it is combined with the default mapping +at the top level of the plot. You must supply \code{mapping} if there is no plot +mapping.} \item{data}{The data to be displayed in this layer. There are three options: @@ -37,10 +37,14 @@ will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{stat}{The statistical transformation to use on the data for this -layer, as a string.} - -\item{position}{Position adjustment, either as a string, or the result of -a call to a position adjustment function.} +layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the +stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than +\code{"stat_count"})} + +\item{position}{Position adjustment, either as a string naming the adjustment +(e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a +position adjustment function. Use the latter if you need to change the +settings of the adjustment.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{ggplot2::layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value. See the below diff --git a/man/gt_nfl_logos.Rd b/man/gt_nfl_logos.Rd new file mode 100644 index 0000000..833c01d --- /dev/null +++ b/man/gt_nfl_logos.Rd @@ -0,0 +1,62 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/gt_nfl_logos.R +\name{gt_nfl_logos} +\alias{gt_nfl_logos} +\alias{gt_nfl_wordmarks} +\title{Render Logos and Wordmarks in 'gt' Tables} +\usage{ +gt_nfl_logos(gt_object, columns, height = 30, locations = NULL) + +gt_nfl_wordmarks(gt_object, columns, height = 30, locations = NULL) +} +\arguments{ +\item{gt_object}{A table object that is created using the \code{\link[gt:gt]{gt::gt()}} function.} + +\item{columns}{The columns for which the image translation should be applied. +Argument has no effect if \code{locations} is not \code{NULL}.} + +\item{height}{The absolute height (px) of the image in the table cell.} + +\item{locations}{If \code{NULL} (the default), the function will render +logos/wordmarks in argument \code{columns}. +Otherwise, the cell or set of cells to be associated with the team name +transformation. Only the \code{\link[gt:cells_body]{gt::cells_body()}}, \code{\link[gt:cells_stub]{gt::cells_stub()}}, +\code{\link[gt:cells_column_labels]{gt::cells_column_labels()}}, and \code{\link[gt:cells_row_groups]{gt::cells_row_groups()}} helper functions +can be used here. We can enclose several of these calls within a \code{list()} +if we wish to make the transformation happen at different locations.} +} +\value{ +An object of class \code{gt_tbl}. +} +\description{ +Translate NFL team abbreviations into logos and wordmarks and +render these images in html tables with the 'gt' package. +} +\section{Output of below example}{ + +\if{html}{\figure{logo_tbl.png}{options: width=75\%}} +} + +\examples{ +\donttest{ +library(gt) +library(nflplotR) +teams <- valid_team_names() +# remove conference logos from this example +teams <- teams[!teams \%in\% c("AFC", "NFC", "NFL")] +# create dataframe with all 32 team names +df <- data.frame( + team_a = head(teams, 16), + logo_a = head(teams, 16), + wordmark_a = head(teams, 16), + team_b = tail(teams, 16), + logo_b = tail(teams, 16), + wordmark_b = tail(teams, 16) +) +# create gt table and translate team names to logo/wordmark images +table <- df \%>\% + gt() \%>\% + gt_nfl_logos(columns = gt::starts_with("logo")) \%>\% + gt_nfl_wordmarks(columns = gt::starts_with("wordmark")) +} +} diff --git a/man/scale_axes_nfl.Rd b/man/scale_axes_nfl.Rd index c543b6f..948dfba 100644 --- a/man/scale_axes_nfl.Rd +++ b/man/scale_axes_nfl.Rd @@ -86,6 +86,7 @@ omitted.} \item \code{waiver()} for the default labels computed by the transformation object \item A character vector giving labels (must be same length as \code{breaks}) +\item An expression vector (must be the same length as breaks). See ?plotmath for details. \item A function that takes the breaks as input and returns labels as output. Also accepts rlang \link[rlang:as_function]{lambda} function notation. diff --git a/man/scale_nfl.Rd b/man/scale_nfl.Rd index cd75530..23b9e2c 100644 --- a/man/scale_nfl.Rd +++ b/man/scale_nfl.Rd @@ -82,6 +82,7 @@ omitted.} \item \code{waiver()} for the default labels computed by the transformation object \item A character vector giving labels (must be same length as \code{breaks}) +\item An expression vector (must be the same length as breaks). See ?plotmath for details. \item A function that takes the breaks as input and returns labels as output. Also accepts rlang \link[rlang:as_function]{lambda} function notation. diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index 9409745..77b6d1e 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -96,6 +96,7 @@ reference: Various helper functions. contents: - ggpreview + - starts_with("gt_nfl") - nfl_team_factor - nfl_team_tiers - valid_team_names diff --git a/tests/testthat/_snaps/nfl_team_factors/p1.svg b/tests/testthat/_snaps/nfl_team_factors/p1.svg new file mode 100644 index 0000000..836be75 --- /dev/null +++ b/tests/testthat/_snaps/nfl_team_factors/p1.svg @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +DEN + + + + + + + + + +CLE + + + + + + + + + +CIN + + + + + + + + + +BAL + + + + + + + + + +PIT + + + + + + + + + +LV + + + + + + + + + +LAC + + + + + + + + + +KC + + +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +20 +30 +40 +20 +30 +40 +displ +hwy +p1 + + diff --git a/tests/testthat/_snaps/nfl_team_factors/p2.svg b/tests/testthat/_snaps/nfl_team_factors/p2.svg new file mode 100644 index 0000000..08eb1dc --- /dev/null +++ b/tests/testthat/_snaps/nfl_team_factors/p2.svg @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +DEN + + + + + + + + + +LAC + + + + + + + + + +KC + + + + + + + + + +LV + + + + + + + + + +CIN + + + + + + + + + +CLE + + + + + + + + + +BAL + + + + + + + + + +PIT + + +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +20 +30 +40 +20 +30 +40 +displ +hwy +p2 + + diff --git a/tests/testthat/_snaps/scale_nfl/p1.svg b/tests/testthat/_snaps/scale_nfl/p1.svg index febedfd..9061743 100644 --- a/tests/testthat/_snaps/scale_nfl/p1.svg +++ b/tests/testthat/_snaps/scale_nfl/p1.svg @@ -66,38 +66,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.00 diff --git a/tests/testthat/_snaps/theme-elements/p1.svg b/tests/testthat/_snaps/theme-elements/p1.svg index 5aa4a65..df07824 100644 --- a/tests/testthat/_snaps/theme-elements/p1.svg +++ b/tests/testthat/_snaps/theme-elements/p1.svg @@ -25,8 +25,8 @@ - - + + diff --git a/tests/testthat/_snaps/theme-elements/p2.svg b/tests/testthat/_snaps/theme-elements/p2.svg index c194dff..8d5faec 100644 --- a/tests/testthat/_snaps/theme-elements/p2.svg +++ b/tests/testthat/_snaps/theme-elements/p2.svg @@ -25,8 +25,8 @@ - - + + diff --git a/tests/testthat/test-nfl_team_factors.R b/tests/testthat/test-nfl_team_factors.R index 90ab4b6..2f49850 100644 --- a/tests/testthat/test-nfl_team_factors.R +++ b/tests/testthat/test-nfl_team_factors.R @@ -4,6 +4,8 @@ test_that("nfl team factors work", { library(ggplot2) + set.seed(20220128) + # unsorted vector including NFL team abbreviations teams <- c("LAC", "LV", "CLE", "BAL", "DEN", "PIT", "CIN", "KC")