diff --git a/DESCRIPTION b/DESCRIPTION index 6f0215a..6b618a5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -20,7 +20,7 @@ Encoding: UTF-8 LazyData: true biocViews: Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Depends: R (>= 4.0) Imports: @@ -29,14 +29,15 @@ Imports: grid, graphics, png, - grImport2 (>= 0.3.0), + grImport2 (>= 0.3.3), rsvg (>= 2.6.0), httr, curl, methods, lifecycle, pbapply, - knitr + knitr, + scales Suggests: testthat (>= 3.0.0), vdiffr (>= 1.0.0), diff --git a/NAMESPACE b/NAMESPACE index 3611b9f..fc16bcc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -25,10 +25,13 @@ export(recolor_phylopic) export(resolve_phylopic) export(rotate_phylopic) export(save_phylopic) +export(scale_height_continuous) +export(scale_width_continuous) importFrom(curl,nslookup) importFrom(ggplot2,Geom) importFrom(ggplot2,aes) importFrom(ggplot2,annotate) +importFrom(ggplot2,continuous_scale) importFrom(ggplot2,coord_equal) importFrom(ggplot2,element_text) importFrom(ggplot2,expansion) @@ -40,6 +43,7 @@ importFrom(ggplot2,layer) importFrom(ggplot2,remove_missing) importFrom(ggplot2,theme) importFrom(ggplot2,theme_void) +importFrom(ggplot2,waiver) importFrom(grDevices,bmp) importFrom(grDevices,col2rgb) importFrom(grDevices,dev.off) @@ -74,12 +78,14 @@ importFrom(httr,content) importFrom(jsonlite,fromJSON) importFrom(jsonlite,toJSON) importFrom(knitr,combine_words) +importFrom(lifecycle,deprecated) importFrom(methods,is) importFrom(methods,slotNames) importFrom(pbapply,pblapply) importFrom(png,readPNG) importFrom(rsvg,rsvg_png) importFrom(rsvg,rsvg_svg) +importFrom(scales,pal_area) importFrom(stats,setNames) importFrom(utils,URLdecode) importFrom(utils,URLencode) diff --git a/NEWS.md b/NEWS.md index 5696826..b3c82c4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # rphylopic (development version) +* Added ability to specify horizontal and vertical justification of silhouettes (#101) +* Added ability to specify width or height for silhouettes (#103) + * Note that all "ysize" and "size" arguments/aesthetics are now deprecated in favor of "height" and "width" arguments/aesthetics + # rphylopic 1.4.0 * Added add_phylopic_legend (#83) diff --git a/R/add_phylopic.r b/R/add_phylopic.r index 7d04090..761a0d0 100644 --- a/R/add_phylopic.r +++ b/R/add_phylopic.r @@ -14,9 +14,18 @@ #' ShareAlike clause. The user can also combine these filters as a vector. #' @param x \code{numeric}. x value of the silhouette center. #' @param y \code{numeric}. y value of the silhouette center. -#' @param ysize \code{numeric}. Height of the silhouette. The width is -#' determined by the aspect ratio of the original image. If "Inf", the -#' default, the height will be as tall as will fit within the plot area. +#' @param ysize `r lifecycle::badge("deprecated")` use the `height` or `width` +#' argument instead. +#' @param height \code{numeric}. Height of the silhouette in coordinate space. +#' If "NA", the default, and `width` is "NA", the silhouette will be as large +#' as fits in the plot area. If "NA" and `width` is specified, the height is +#' determined by the aspect ratio of the original image. One or both of +#' `height` and `width` must be "NA". +#' @param width \code{numeric}. Width of the silhouette in coordinate space. If +#' "NA", the default, and `height` is "NA", the silhouette will be as large as +#' fits in the plot area. If "NA", the default, and `height` is specified, the +#' width is determined by the aspect ratio of the original image. One or both +#' of `height` and `width` must be "NA". #' @param alpha \code{numeric}. A value between 0 and 1, specifying the opacity #' of the silhouette (0 is fully transparent, 1 is fully opaque). #' @param color \code{character}. Color of silhouette outline. If "original" or @@ -33,6 +42,16 @@ #' @param vertical \code{logical}. Should the silhouette be flipped vertically? #' @param angle \code{numeric}. The number of degrees to rotate the silhouette #' clockwise. The default is no rotation. +#' @param hjust \code{numeric}. A numeric vector between 0 and 1 specifying +#' horizontal justification (left = 0, center = 0.5, right = 1). Note that, +#' due to the enforcement of the silhouette's aspect ratio, there may be +#' unexpected behavior due to interactions between the aspect ratio of the +#' plot and the aspect ratio of the silhouette. +#' @param vjust \code{numeric}. A numeric vector between 0 and 1 specifying +#' vertical justification (top = 1, middle = 0.5, bottom = 0). Note that, due +#' to the enforcement of the silhouette's aspect ratio, there may be +#' unexpected behavior due to interactions between the aspect ratio of the +#' plot and the aspect ratio of the silhouette. #' @param remove_background \code{logical}. Should any white background be #' removed from the silhouette(s)? See [recolor_phylopic()] for details. #' @param verbose \code{logical}. Should the attribution information for the @@ -55,6 +74,7 @@ #' Note that png array objects can only be rotated by multiples of 90 degrees. #' Also, outline colors do not currently work for png array objects. #' @importFrom ggplot2 annotate +#' @importFrom lifecycle deprecated #' @export #' @examples \dontrun{ #' # Put a silhouette behind a plot based on a taxonomic name @@ -66,7 +86,7 @@ #' # Put a silhouette in several places based on UUID #' posx <- runif(10, 0, 10) #' posy <- runif(10, 0, 10) -#' sizey <- runif(10, 0.4, 2) +#' heights <- runif(10, 0.4, 2) #' angle <- runif(10, 0, 360) #' hor <- sample(c(TRUE, FALSE), 10, TRUE) #' ver <- sample(c(TRUE, FALSE), 10, TRUE) @@ -77,15 +97,16 @@ #' p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + #' geom_blank() + #' add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", -#' x = posx, y = posy, ysize = sizey, +#' x = posx, y = posy, height = heights, #' fill = fills, alpha = alpha, angle = angle, #' horizontal = hor, vertical = ver) #' p + ggtitle("R Cat Herd!!") #' } add_phylopic <- function(img = NULL, name = NULL, uuid = NULL, filter = NULL, - x, y, ysize = Inf, + x, y, ysize = deprecated(), height = NA, width = NA, alpha = 1, color = NA, fill = "black", horizontal = FALSE, vertical = FALSE, angle = 0, + hjust = 0.5, vjust = 0.5, remove_background = TRUE, verbose = FALSE) { if (all(sapply(list(img, name, uuid), is.null))) { stop("One of `img`, `name`, or `uuid` is required.") @@ -97,25 +118,35 @@ add_phylopic <- function(img = NULL, name = NULL, uuid = NULL, filter = NULL, stop("`verbose` should be a logical value.") } + if (lifecycle::is_present(ysize)) { + lifecycle::deprecate_warn("1.5.0", "add_phylopic(ysize)", + "add_phylopic(height)") + if (is.null(height) || all(is.na(height))) height <- ysize + } + # Make all variables the same length x_len <- length(x) y_len <- length(y) max_len <- max(x_len, y_len) x <- rep_len(x, max_len) y <- rep_len(y, max_len) - ysize <- rep_len(ysize, max_len) + height <- rep_len(height, max_len) + width <- rep_len(width, max_len) alpha <- rep_len(alpha, max_len) color <- rep_len(color, max_len) fill <- rep_len(fill, max_len) horizontal <- rep_len(horizontal, max_len) vertical <- rep_len(vertical, max_len) angle <- rep_len(angle, max_len) + hjust <- rep_len(hjust, max_len) + vjust <- rep_len(vjust, max_len) # Put together all of the variables args <- list(geom = GeomPhylopic, - x = x, y = y, size = ysize, + x = x, y = y, height = height, width = width, alpha = alpha, color = color, fill = fill, horizontal = horizontal, vertical = vertical, angle = angle, + hjust = hjust, vjust = vjust, remove_background = remove_background, verbose = verbose, filter = list(filter)) # Only include the one silhouette argument diff --git a/R/add_phylopic_base.r b/R/add_phylopic_base.r index a8790cd..303e484 100644 --- a/R/add_phylopic_base.r +++ b/R/add_phylopic_base.r @@ -12,13 +12,22 @@ #' Use "by" to limit results to images which do not require attribution, "nc" #' for images which allows commercial usage, and "sa" for images without a #' ShareAlike clause. The user can also combine these filters as a vector. -#' @param x \code{numeric}. x value of the silhouette center. Ignored if `y` and -#' `ysize` are not specified. -#' @param y \code{numeric}. y value of the silhouette center. Ignored if `x` and -#' `ysize` are not specified. -#' @param ysize \code{numeric}. Height of the silhouette. The width is -#' determined by the aspect ratio of the original image. Ignored if `x` and -#' `y` are not specified. +#' @param x \code{numeric}. x value of the silhouette center. If "NULL", the +#' default, the mean value of the x-axis is used. +#' @param y \code{numeric}. y value of the silhouette center. If "NULL", the +#' default, the mean value of the y-axis is used. +#' @param ysize `r lifecycle::badge("deprecated")` use the `height` or `width` +#' argument instead. +#' @param height \code{numeric}. Height of the silhouette in coordinate space. +#' If "NULL", the default, and `width` is also "NULL", the silhouette will be +#' as large as fits in the plot area. If "NULL" and `width` is specified, the +#' height is determined by the aspect ratio of the original image. One or both +#' of `height` and `width` must be "NULL". +#' @param width \code{numeric}. Width of the silhouette in coordinate space. If +#' "NULL", the default, and `height` is also "NULL", the silhouette will be as +#' large as fits in the plot area. If "NULL" and `height` is specified, the +#' width is determined by the aspect ratio of the original image. One or both +#' of `height` and `width` must be "NULL". #' @param alpha \code{numeric}. A value between 0 and 1, specifying the opacity #' of the silhouette (0 is fully transparent, 1 is fully opaque). #' @param color \code{character}. Color of silhouette outline. If "original" or @@ -35,17 +44,22 @@ #' @param vertical \code{logical}. Should the silhouette be flipped vertically? #' @param angle \code{numeric}. The number of degrees to rotate the silhouette #' clockwise. The default is no rotation. +#' @param hjust \code{numeric}. A numeric vector between 0 and 1 specifying +#' horizontal justification (left = 0, center = 0.5, right = 1). +#' @param vjust \code{numeric}. A numeric vector between 0 and 1 specifying +#' vertical justification (top = 1, middle = 0.5, bottom = 0). #' @param remove_background \code{logical}. Should any white background be #' removed from the silhouette(s)? See [recolor_phylopic()] for details. #' @param verbose \code{logical}. Should the attribution information for the #' used silhouette(s) be printed to the console (see [get_attribution()])? #' @details One (and only one) of `img`, `name`, or `uuid` must be specified. -#' Use parameters `x`, `y`, and `ysize` to place the silhouette at a specified -#' position on the plot. If all three of these parameters are unspecified, -#' then the silhouette will be plotted to the full height and width of the -#' plot. The aspect ratio of the silhouette will always be maintained (even -#' when a plot is resized). However, if the plot is resized after plotting the -#' silhouette, the absolute size and/or position of the silhouette may change. +#' Use parameters `x`, `y`, `hjust`, and `vjust` to place the silhouette at a +#' specified position on the plot. If `height` and `width` are both +#' unspecified, then the silhouette will be plotted to the full height and/or +#' width of the plot. The aspect ratio of `Picture` objects will always be +#' maintained (even when a plot is resized). However, if the plot is resized +#' after plotting a silhouette, the absolute size and/or position of the +#' silhouette may change. #' #' Any argument (except for `remove_background`) may be a vector of values if #' multiple silhouettes should be plotted. In this case, all other arguments @@ -63,12 +77,13 @@ #' @importFrom grid grid.raster #' @importFrom grImport2 grid.picture #' @importFrom methods is slotNames +#' @importFrom lifecycle deprecated #' @export #' @examples \dontrun{ #' # single image #' plot(1, 1, type = "n", main = "A cat") #' add_phylopic_base(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", -#' x = 1, y = 1, ysize = 0.4) +#' x = 1, y = 1, height = 0.4) #' #' # lots of images using a uuid #' posx <- runif(10, 0, 1) @@ -82,7 +97,7 @@ #' #' plot(posx, posy, type = "n", main = "A cat herd") #' add_phylopic_base(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", -#' x = posx, y = posy, ysize = size, +#' x = posx, y = posy, height = size, #' fill = fills, angle = angle, #' horizontal = hor, vertical = ver) #' @@ -94,13 +109,15 @@ #' # plot background cat #' add_phylopic_base(img = cat, alpha = 0.2) #' # overlay smaller cats -#' add_phylopic_base(img = cat, x = posx, y = posy, ysize = size, alpha = 0.8) +#' add_phylopic_base(img = cat, x = posx, y = posy, height = size, alpha = 0.8) #' } add_phylopic_base <- function(img = NULL, name = NULL, uuid = NULL, filter = NULL, - x = NULL, y = NULL, ysize = NULL, + x = NULL, y = NULL, ysize = deprecated(), + height = NULL, width = NULL, alpha = 1, color = NA, fill = "black", horizontal = FALSE, vertical = FALSE, angle = 0, + hjust = 0.5, vjust = 0.5, remove_background = TRUE, verbose = FALSE) { if (all(sapply(list(img, name, uuid), is.null))) { stop("One of `img`, `name`, or `uuid` is required.") @@ -111,9 +128,23 @@ add_phylopic_base <- function(img = NULL, name = NULL, uuid = NULL, if (any(alpha > 1 | alpha < 0)) { stop("`alpha` must be between 0 and 1.") } + if (any(hjust > 1 | hjust < 0)) { + stop("`hjust` must be between 0 and 1.") + } + if (any(vjust > 1 | vjust < 0)) { + stop("`vjust` must be between 0 and 1.") + } if (!is.logical(verbose)) { stop("`verbose` should be a logical value.") } + if (lifecycle::is_present(ysize)) { + lifecycle::deprecate_warn("1.5.0", "add_phylopic_base(ysize)", + "add_phylopic_base(height)") + if (is.null(height)) height <- ysize + } + if (!is.null(height) & !is.null(width)) { + stop("At least one of `height` or `width` must be NULL.") + } if (!is.null(name)) { if (!is.character(name)) { @@ -173,20 +204,62 @@ add_phylopic_base <- function(img = NULL, name = NULL, uuid = NULL, # get plot limits usr <- par()$usr usr_x <- if (par()$xlog) 10^usr[1:2] else usr[1:2] + #usr_x <- usr[1:2] usr_y <- if (par()$ylog) 10^usr[3:4] else usr[3:4] + #usr_y <- usr[3:4] - # set default position and size if need be - if (is.null(x)) x <- mean(usr_x) - if (is.null(y)) y <- mean(usr_y) - if (is.null(ysize)) ysize <- abs(diff(usr_y)) - - # convert x, y, and ysize to normalized device coordinates + # set default position and dimensions if need be + if (is.null(x)) { + mn <- mean(usr[1:2]) + x <- if (par()$xlog) 10 ^ mn else mn + } + if (is.null(y)) { + mn <- mean(usr[3:4]) + y <- if (par()$ylog) 10 ^ mn else mn + } + if (is.null(height) && is.null(width)) { + height <- abs(diff(usr_y)) + width <- abs(diff(usr_x)) + } + + # convert x and y to normalized device coordinates x <- grconvertX(x, to = "ndc") y <- grconvertY(y, to = "ndc") - ysize <- grconvertY(ysize, to = "ndc") - grconvertY(0, to = "ndc") + + # convert width and/or height to normalized device coordinates if need be + if (!is.null(height)) { + if (any(height < (abs(diff(usr[3:4])) / 1000), na.rm = TRUE)) { + warning(paste("Your specified silhouette `height`(s) are more than", + "1000 times smaller than your y-axis range. You probably", + "want to use a larger `height`."), call. = FALSE) + } + if (par()$ylog) { + base_y <- grconvertY(1, to = "ndc") + } else { + base_y <- grconvertY(0, to = "ndc") + } + height <- grconvertY(height, to = "ndc") - base_y + } + if (!is.null(width)) { + if (any(width < (abs(diff(usr[1:2])) / 1000), na.rm = TRUE)) { + warning(paste("Your specified silhouette `width`(s) are more than 1000", + "times smaller than your x-axis range. You probably want", + "to use a larger `width`."), call. = FALSE) + } + if (par()$xlog) { + base_x <- grconvertX(1, to = "ndc") + } else { + base_x <- grconvertX(0, to = "ndc") + } + width <- grconvertX(width, to = "ndc") - base_x + } + + # change NULLs to NAs + if (is.null(width)) width <- NA + if (is.null(height)) height <- NA - invisible(mapply(function(img, x, y, ysize, alpha, color, fill, - horizontal, vertical, angle) { + invisible(mapply(function(img, x, y, height, width, alpha, color, fill, + horizontal, vertical, angle, hjust, vjust) { if (is.null(img)) return(NULL) if (horizontal || vertical) img <- flip_phylopic(img, horizontal, vertical) @@ -201,6 +274,10 @@ add_phylopic_base <- function(img = NULL, name = NULL, uuid = NULL, if (fill == "original") fill <- NULL img <- recolor_phylopic(img, alpha, color, fill, remove_background) + # convert NAs back to NULLs + if (is.na(width)) width <- NULL + if (is.na(height)) height <- NULL + # grobify and plot if (is(img, "Picture")) { # svg if ("summary" %in% slotNames(img) && @@ -209,14 +286,21 @@ add_phylopic_base <- function(img = NULL, name = NULL, uuid = NULL, all(is.finite(img@summary@xscale)) && diff(img@summary@xscale) != 0 && is.numeric(img@summary@yscale) && length(img@summary@yscale) == 2 && all(is.finite(img@summary@yscale)) && diff(img@summary@yscale) != 0) { - grid.picture(img, x = x, y = y, height = ysize, expansion = 0) + grid.picture(img, x = x, y = y, height = height, width = width, + expansion = 0, hjust = hjust, vjust = vjust, + delayContent = TRUE) } else { return(NULL) } } else { # png - grid.raster(img, x = x, y = y, height = ysize) + # check width and height are correct aspect ratio + grid.raster(img, x = x, y = y, width = width, height = height, + hjust = hjust, vjust = vjust) + } }, - img = imgs, x = x, y = y, ysize = ysize, alpha = alpha, color = color, - fill = fill, horizontal = horizontal, vertical = vertical, angle = angle)) + img = imgs, x = x, y = y, + height = height, width = width, alpha = alpha, color = color, fill = fill, + horizontal = horizontal, vertical = vertical, angle = angle, + hjust = hjust, vjust = vjust)) } diff --git a/R/add_phylopic_legend.R b/R/add_phylopic_legend.R index 46c5504..203b38d 100644 --- a/R/add_phylopic_legend.R +++ b/R/add_phylopic_legend.R @@ -10,7 +10,9 @@ #' legend. Can be `NULL` (default) if using keywords in `x`. #' @param legend \code{character}. A character vector of the labels to appear #' in the legend. -#' @param ysize \code{numeric}. Height of the legend silhouette(s). The width +#' @param ysize `r lifecycle::badge("deprecated")` use the `height` +#' argument instead. +#' @param height \code{numeric}. Height of the legend silhouette(s). The width #' is determined by the aspect ratio of the original image. #' @inheritParams add_phylopic_base #' @param ... Additional arguments passed to [legend()]. @@ -35,16 +37,22 @@ #' # Add data points #' add_phylopic_base(uuid = uuids, #' color = "black", fill = c("blue", "green"), -#' x = c(2.5, 7.5), y = c(2.5, 7.5), ysize = 2) +#' x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) #' # Add legend #' add_phylopic_legend(uuid = uuids, -#' ysize = 0.5, color = "black", fill = c("blue", "green"), +#' height = 0.5, color = "black", fill = c("blue", "green"), #' x = "bottomright", legend = c("Wolf 1", "Wolf 2"), #' bg = "lightgrey") add_phylopic_legend <- function(x, y = NULL, legend, img = NULL, name = NULL, uuid = NULL, - ysize = NULL, color = NA, fill = "black", + ysize = deprecated(), height = NULL, + color = NA, fill = "black", ...) { + if (lifecycle::is_present(ysize)) { + lifecycle::deprecate_warn("1.5.0", "add_phylopic_legend(ysize)", + "add_phylopic_legend(height)") + if (is.null(height)) height <- ysize + } # Get supplied arguments args <- list(x = x, y = y, legend = legend, ...) # Remove legend object to avoid issues with do.call @@ -67,9 +75,9 @@ add_phylopic_legend <- function(x, y = NULL, legend, if (!is.null(bg)) fill <- bg # size values size <- args[["pt.cex"]] - if (!is.null(size)) ysize <- size - # Set default ysize if required - if (is.null(ysize)) ysize <- (abs(diff(leg_pos$text$y)) * 0.5) + if (!is.null(size)) height <- size + # Set default height if required + if (is.null(height)) height <- (abs(diff(leg_pos$text$y)) * 0.5) # Extract positions # Adjust x position slightly to account for width x <- (leg_pos$text$x + leg_pos$rect$left) / 2 @@ -80,5 +88,5 @@ add_phylopic_legend <- function(x, y = NULL, legend, y = y, color = color, fill = fill, - ysize = ysize) + height = height) } diff --git a/R/geom_phylopic.R b/R/geom_phylopic.R index 28fa4c1..ae49491 100644 --- a/R/geom_phylopic.R +++ b/R/geom_phylopic.R @@ -10,9 +10,12 @@ phylopic_env <- new.env() #' be specified. The `img` aesthetic can be #' [Picture][grImport2::Picture-class] objects or png array objects, e.g., #' from using [get_phylopic()]. Use the `x` and `y` aesthetics to place the -#' silhouettes at specified positions on the plot. The `size` aesthetic -#' specifies the height of the silhouettes in the units of the y axis. The -#' aspect ratio of the silhouettes will always be maintained. +#' silhouettes at specified positions on the plot. The `height` or `width` +#' aesthetic specifies the height or width, respectively, of the silhouettes +#' in the units of the y axis (only one is allowed). The aspect ratio of the +#' silhouettes will always be maintained. The `hjust` and `vjust` aesthetics +#' can be used to manage the justification of the silhouettes with respect to +#' the `x` and `y` coordinates. #' #' The `color` (default: NA), `fill` (default: "black"), and `alpha` ( #' default: 1) aesthetics can be used to change the outline color, fill color, @@ -39,14 +42,18 @@ phylopic_env <- new.env() #' #' - **x** (required) #' - **y** (required) -#' - **img/uuid/name** (one, and only one, required) -#' - size -#' - color/colour +#' - **img** *or* **uuid** *or* **name** (one, and only one, required) +#' - height *or* width (optional, maximum of only one allowed) +#' - ysize `r lifecycle::badge("deprecated")` Deprecated in favor of height or +#' width +#' - color *or* colour #' - fill #' - alpha #' - horizontal #' - vertical #' - angle +#' - hjust +#' - vjust #' #' Learn more about setting these aesthetics in [add_phylopic()]. #' @@ -74,7 +81,7 @@ phylopic_env <- new.env() #' name = c("Felis silvestris catus", "Odobenus rosmarus")) #' ggplot(df) + #' geom_phylopic(aes(x = x, y = y, name = name), -#' fill = "purple", size = 10) + +#' fill = "purple", height = 10) + #' facet_wrap(~name) + #' coord_cartesian(xlim = c(1,6), ylim = c(5, 30)) #' } @@ -98,6 +105,16 @@ geom_phylopic <- function(mapping = NULL, data = NULL, if ("img" %in% names(dots) && !is.list(dots$img)) { dots$img <- list(dots$img) } + if (!is.null(dots$size)) { + lifecycle::deprecate_warn("1.5.0", + I("Using the `size` aesthetic in this geom"), + I("the `height` and `width` aesthetics"), + user_env = globalenv()) + if (is.null(dots$height)) { + dots$height <- dots$size + dots$size <- NULL + } + } layer( data = data, mapping = mapping, @@ -120,11 +137,16 @@ geom_phylopic <- function(mapping = NULL, data = NULL, #' @importFrom grid gTree gList nullGrob GeomPhylopic <- ggproto("GeomPhylopic", Geom, required_aes = c("x", "y"), - non_missing_aes = c("size", "alpha", "color", "fill", - "horizontal", "vertical", "angle"), - optional_aes = c("img", "name", "uuid"), # one and only one of these - default_aes = aes(size = 6, alpha = 1, color = NA, fill = "black", - horizontal = FALSE, vertical = FALSE, angle = 0), + non_missing_aes = c("alpha", "color", "fill", + "horizontal", "vertical", "angle", + "hjust", "vjust"), + optional_aes = c("height", "width", "img", "name", "uuid"), + # one and only one of img/name/uuid + # size is deprecated + default_aes = aes(height = NA, width = NA, + alpha = 1, color = NA, fill = "black", + horizontal = FALSE, vertical = FALSE, angle = 0, + hjust = 0.5, vjust = 0.5), extra_params = c("na.rm", "remove_background", "verbose", "filter"), setup_data = function(data, params) { # Clean data @@ -205,6 +227,18 @@ GeomPhylopic <- ggproto("GeomPhylopic", Geom, data }, use_defaults = function(self, data, params = list(), modifiers = aes()) { + default_aes <- self$default_aes + # Inherit size as height if no height aesthetic and param exist + if (!is.null(data$size)) { + lifecycle::deprecate_warn("1.5.0", + I("Using the `size` aesthetic in this geom"), + I("the `height` and `width` aesthetics"), + user_env = globalenv()) + if (is.null(data$height) && is.null(params$height)) { + data$height <- data$size + data$size <- NULL + } + } # if fill isn't specified in the original data, copy over the colour column col_fill <- c("colour", "fill") %in% colnames(data) | c("colour", "fill") %in% names(params) @@ -225,39 +259,78 @@ GeomPhylopic <- ggproto("GeomPhylopic", Geom, if (any(data$alpha > 1 | data$alpha < 0)) { stop("`alpha` must be between 0 and 1.") } + if (any(data$hjust > 1 | data$hjust < 0)) { + stop("`hjust` must be between 0 and 1.") + } + if (any(data$vjust > 1 | data$vjust < 0)) { + stop("`vjust` must be between 0 and 1.") + } + if (!is.null(data$size)) { + lifecycle::deprecate_warn("1.5.0", + I("Using the `size` aesthetic in this geom"), + I("the `height` and `width` aesthetics"), + user_env = globalenv()) + if (is.null(data$height) && is.null(params$height)) { + data$height <- data$size + data$size <- NULL + } + } + if (any(!is.na(data$height) & !is.na(data$width))) { + stop("At least one of `height` or `width` must be NA.") + } # Transform data data <- coord$transform(data, panel_params) - # Calculate height as percentage of y limits - # (or r limits for polar coordinates) - if ("y.range" %in% names(panel_params)) { - y_diff <- diff(panel_params$y.range) - } else if ("y_range" %in% names(panel_params)) { # exclusive to coord_sf - y_diff <- diff(panel_params$y_range) - } else if ("r.range" %in% names(panel_params)) { # exclusive to coord_polar - y_diff <- diff(panel_params$r.range) - } else { - y_diff <- 1 + if (any(!is.na(data$height))) { + # Calculate height as percentage of y limits + # (or r limits for polar coordinates) + if ("y.range" %in% names(panel_params)) { + y_diff <- diff(panel_params$y.range) + } else if ("y_range" %in% names(panel_params)) { # exclusive to coord_sf + y_diff <- diff(panel_params$y_range) + } else if ("r.range" %in% names(panel_params)) { # exclusive to coord_polar + y_diff <- diff(panel_params$r.range) + } else { + y_diff <- 1 + } + if (any(data$height < (y_diff / 1000), na.rm = TRUE)) { + warning(paste("Your specified silhouette `height`(s) are more than", + "1000 times smaller than your y-axis range. You probably", + "want to use a larger `height`."), call. = FALSE) + } + data$height <- data$height / y_diff } - if (any(data$size < (y_diff / 1000))) { - warning(paste("Your specified silhouette `size`(s) are more than 1000", - "times smaller than your y-axis range. You probably want", - "to use a larger `size`."), call. = FALSE) + if (any(!is.na(data$width))) { + # Calculate width as percentage of x limits + # (or r limits for polar coordinates) + if ("x.range" %in% names(panel_params)) { + x_diff <- diff(panel_params$x.range) + } else if ("x_range" %in% names(panel_params)) { # exclusive to coord_sf + x_diff <- diff(panel_params$x_range) + } else if ("r.range" %in% names(panel_params)) { # exclusive to coord_polar + x_diff <- diff(panel_params$r.range) + } else { + x_diff <- 1 + } + if (any(data$width < (x_diff / 1000), na.rm = TRUE)) { + warning(paste("Your specified silhouette `width`(s) are more than 1000", + "times smaller than your x-axis range. You probably want", + "to use a larger `width`."), call. = FALSE) + } + data$width <- data$width / x_diff } - heights <- data$size / y_diff - - # Hack to make silhouettes the full height of the plot - heights[is.infinite(heights)] <- 1 # Make a grob for each silhouette grobs <- lapply(seq_len(nrow(data)), function(i) { if (is.null(data$img[[i]])) { nullGrob() } else { - phylopicGrob(data$img[[i]], data$x[i], data$y[i], heights[i], + phylopicGrob(data$img[[i]], data$x[i], data$y[i], + data$height[i], data$width[i], data$colour[i], data$fill[i], data$alpha[i], data$horizontal[i], data$vertical[i], data$angle[i], + data$hjust[i], data$vjust[i], remove_background) } }) @@ -360,9 +433,11 @@ phylopic_key_glyph <- function(img = NULL, name = NULL, uuid = NULL) { } else { asp_rat <- aspect_ratio(imgs[[i]]) height <- unit(ifelse(asp_rat >= 1, .95 / asp_rat, .95), "npc") - grob <- phylopicGrob(imgs[[i]], 0.5, 0.5, - height, data$colour[1], data$fill[1], data$alpha[1], + grob <- phylopicGrob(imgs[[i]], x = 0.5, y = 0.5, + height, width = unit(1, "npc"), + data$colour[1], data$fill[1], data$alpha[1], data$horizontal[1], data$vertical[1], data$angle[1], + hjust = 0.5, vjust = 0.5, phylopic_env$remove_background) } if (i == length(imgs)) { @@ -377,10 +452,11 @@ phylopic_key_glyph <- function(img = NULL, name = NULL, uuid = NULL) { #' @importFrom grImport2 pictureGrob #' @importFrom grid rasterGrob gList gTree nullGrob #' @importFrom methods slotNames -phylopicGrob <- function(img, x, y, height, color, fill, alpha, +phylopicGrob <- function(img, x, y, height, width, + color, fill, alpha, horizontal, vertical, angle, + hjust, vjust, remove_background) { - # modified from add_phylopic for now if (horizontal || vertical) img <- flip_phylopic(img, horizontal, vertical) if (!is.na(angle) && angle != 0) img <- rotate_phylopic(img, angle) @@ -390,6 +466,10 @@ phylopicGrob <- function(img, x, y, height, color, fill, alpha, fill <- if (!is.null(fill) && fill == "original") NULL else fill img <- recolor_phylopic(img, alpha, color, fill, remove_background) + # convert NAs to NULLs + if (is.na(height)) height <- NULL + if (is.na(width)) width <- NULL + # grobify if (is(img, "Picture")) { # svg if ("summary" %in% slotNames(img) && @@ -400,20 +480,59 @@ phylopicGrob <- function(img, x, y, height, color, fill, alpha, all(is.finite(img@summary@yscale)) && diff(img@summary@yscale) != 0) { # modified from # https://github.com/k-hench/hypoimg/blob/master/R/hypoimg_recolor_svg.R - img_grob <- pictureGrob(img, x = x, y = y, height = height, - default.units = "native", expansion = 0) + img_grob <- pictureGrob(img, x = x, y = y, + height = height, width = width, + default.units = "native", expansion = 0, + hjust = hjust, vjust = vjust, + delayContent = TRUE) img_grob <- gList(img_grob) img_grob <- gTree(children = img_grob) } else { img_grob <- nullGrob() } } else { # png - img_grob <- rasterGrob(img, x = x, y = y, height = height, - default.units = "native") + img_grob <- rasterGrob(img, x = x, y = y, + height = height, width = width, + default.units = "native", + hjust = hjust, vjust = vjust) } return(img_grob) } +#' Scales for phylopic height or width +#' +#' `scale_height_continuous()` scales the height of silhouettes whereas +#' `scale_width_continuous()` scales the height of silhouettes. +#' @inheritParams ggplot2::scale_size_continuous +#' @export +#' @importFrom ggplot2 continuous_scale waiver +#' @importFrom scales pal_area +#' @rdname scales +scale_height_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(), + limits = NULL, range = c(1, 6), + transform = "identity", + trans = lifecycle::deprecated(), + guide = "none") { + continuous_scale("height", palette = scales::pal_area(range), name = name, + breaks = breaks, labels = labels, limits = limits, + transform = transform, trans = trans, guide = guide) +} + +#' @inheritParams ggplot2::scale_size_continuous +#' @export +#' @importFrom ggplot2 continuous_scale waiver +#' @importFrom scales pal_area +#' @rdname scales +scale_width_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(), + limits = NULL, range = c(1, 6), + transform = "identity", + trans = lifecycle::deprecated(), + guide = "none") { + continuous_scale("width", palette = scales::pal_area(range), name = name, + breaks = breaks, labels = labels, limits = limits, + transform = transform, trans = trans, guide = guide) +} + #' @importFrom grid grobName ggname <- function(prefix, grob) { # copied from ggplot2 diff --git a/R/phylopic_utils.R b/R/phylopic_utils.R index 78f1b6a..b60510a 100644 --- a/R/phylopic_utils.R +++ b/R/phylopic_utils.R @@ -39,6 +39,7 @@ flip_phylopic.Picture <- function(img, horizontal = TRUE, vertical = FALSE) { #' @export flip_phylopic.array <- function(img, horizontal = TRUE, vertical = FALSE) { + cls <- class(img) if (length(dim(img)) != 3) { stop("`img` must be an array with three dimensions.") } @@ -50,6 +51,7 @@ flip_phylopic.array <- function(img, horizontal = TRUE, vertical = FALSE) { if (vertical) { img <- img[rev(seq_len(nrow(img))), , , drop = FALSE] } + class(img) <- cls img } @@ -112,6 +114,7 @@ rotate_phylopic.array <- function(img, angle = 90) { function(i) rotate(img_new[, , i])) ) } + class(img_new) <- class(img) img_new } @@ -180,6 +183,7 @@ recolor_phylopic <- function(img, alpha = 1, color = NULL, fill = NULL, #' @export recolor_phylopic.array <- function(img, alpha = 1, color = NULL, fill = NULL, remove_background = TRUE) { + cls <- class(img) if (!is.null(color)) { message("Outline color does not currently work with png image objects.") } @@ -210,6 +214,7 @@ recolor_phylopic.array <- function(img, alpha = 1, color = NULL, fill = NULL, rep(cols[3, 1], imglen), img[, , 4] * alpha), dim = dims) } + class(new_img) <- cls return(new_img) } @@ -282,8 +287,12 @@ recolor_content <- function(x, alpha, color, fill, remove_background) { #' @importFrom grImport2 grid.picture #' @export plot.Picture <- function(x, ...) { + args <- list(...) + if (is.null(args$expansion)) args$expansion <- 0 + if (is.null(args$delayContent)) args$delayContent <- TRUE + args$picture <- x grid.newpage() - grid.picture(x, ...) + do.call(grid.picture, args) } #' @rdname plot_phylopic diff --git a/R/pick_phylopic.R b/R/pick_phylopic.R index 744b424..5957071 100644 --- a/R/pick_phylopic.R +++ b/R/pick_phylopic.R @@ -156,7 +156,7 @@ pick_phylopic <- function(name = NULL, n = 5, uuid = NULL, view = 1, # Plot silhouettes p <- ggplot(data = df) + geom_phylopic(aes(x = x, y = y, img = img), - size = df$size, + height = df$size, color = "original") + facet_wrap(~label) + coord_equal(xlim = c(0, 1), ylim = c(0, 1)) + diff --git a/README.md b/README.md index 763c59c..5d46332 100644 --- a/README.md +++ b/README.md @@ -59,17 +59,17 @@ img <- pick_phylopic(name = "Canis lupus", n = 5) ```r # OK, now we've got the image we want... let's add it to a plot! plot(x = 1, y = 1, type = "n") -add_phylopic_base(img = img, x = 1.25, y = 1.25, ysize = 0.25) +add_phylopic_base(img = img, x = 1.25, y = 1.25, height = 0.25) # But can't we just add an image straight away using the uuid? Sure! uuid <- get_uuid(name = "Canis lupus", n = 1) -add_phylopic_base(uuid = uuid, x = 1, y = 1, ysize = 0.25) +add_phylopic_base(uuid = uuid, x = 1, y = 1, height = 0.25) # What about just using the first image linked to the name? Definitely! -add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, ysize = 0.25) +add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, height = 0.25) # Black is a bit boring? OK... -add_phylopic_base(name = "Canis lupus", x = 0.75, y = 1.25, ysize = 0.25, color = "orange") +add_phylopic_base(name = "Canis lupus", x = 0.75, y = 1.25, height = 0.25, color = "orange") ``` ### ggplot2 @@ -89,7 +89,7 @@ ggplot(iris) + # Plot silhouettes as points! ggplot(iris) + geom_phylopic(aes(x = Sepal.Length, y = Sepal.Width), img = img, - color = "purple", size = 0.25) + color = "purple", height = 0.25) ``` ## Get attribution diff --git a/_pkgdown.yml b/_pkgdown.yml index 29f8fd4..ef2c673 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -37,6 +37,8 @@ reference: contents: - geom_phylopic - phylopic_key_glyph + - scale_height_continuous + - scale_width_continuous - add_phylopic - add_phylopic_base - add_phylopic_legend diff --git a/man/add_phylopic.Rd b/man/add_phylopic.Rd index fb088cd..a1ec391 100644 --- a/man/add_phylopic.Rd +++ b/man/add_phylopic.Rd @@ -11,13 +11,17 @@ add_phylopic( filter = NULL, x, y, - ysize = Inf, + ysize = deprecated(), + height = NA, + width = NA, alpha = 1, color = NA, fill = "black", horizontal = FALSE, vertical = FALSE, angle = 0, + hjust = 0.5, + vjust = 0.5, remove_background = TRUE, verbose = FALSE ) @@ -40,9 +44,20 @@ ShareAlike clause. The user can also combine these filters as a vector.} \item{y}{\code{numeric}. y value of the silhouette center.} -\item{ysize}{\code{numeric}. Height of the silhouette. The width is -determined by the aspect ratio of the original image. If "Inf", the -default, the height will be as tall as will fit within the plot area.} +\item{ysize}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} use the \code{height} or \code{width} +argument instead.} + +\item{height}{\code{numeric}. Height of the silhouette in coordinate space. +If "NA", the default, and \code{width} is "NA", the silhouette will be as large +as fits in the plot area. If "NA" and \code{width} is specified, the height is +determined by the aspect ratio of the original image. One or both of +\code{height} and \code{width} must be "NA".} + +\item{width}{\code{numeric}. Width of the silhouette in coordinate space. If +"NA", the default, and \code{height} is "NA", the silhouette will be as large as +fits in the plot area. If "NA", the default, and \code{height} is specified, the +width is determined by the aspect ratio of the original image. One or both +of \code{height} and \code{width} must be "NA".} \item{alpha}{\code{numeric}. A value between 0 and 1, specifying the opacity of the silhouette (0 is fully transparent, 1 is fully opaque).} @@ -66,6 +81,18 @@ horizontally?} \item{angle}{\code{numeric}. The number of degrees to rotate the silhouette clockwise. The default is no rotation.} +\item{hjust}{\code{numeric}. A numeric vector between 0 and 1 specifying +horizontal justification (left = 0, center = 0.5, right = 1). Note that, +due to the enforcement of the silhouette's aspect ratio, there may be +unexpected behavior due to interactions between the aspect ratio of the +plot and the aspect ratio of the silhouette.} + +\item{vjust}{\code{numeric}. A numeric vector between 0 and 1 specifying +vertical justification (top = 1, middle = 0.5, bottom = 0). Note that, due +to the enforcement of the silhouette's aspect ratio, there may be +unexpected behavior due to interactions between the aspect ratio of the +plot and the aspect ratio of the silhouette.} + \item{remove_background}{\code{logical}. Should any white background be removed from the silhouette(s)? See \code{\link[=recolor_phylopic]{recolor_phylopic()}} for details.} @@ -106,7 +133,7 @@ ggplot(iris) + # Put a silhouette in several places based on UUID posx <- runif(10, 0, 10) posy <- runif(10, 0, 10) -sizey <- runif(10, 0.4, 2) +heights <- runif(10, 0.4, 2) angle <- runif(10, 0, 360) hor <- sample(c(TRUE, FALSE), 10, TRUE) ver <- sample(c(TRUE, FALSE), 10, TRUE) @@ -117,7 +144,7 @@ alpha <- runif(10, 0.3, 1) p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + geom_blank() + add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", - x = posx, y = posy, ysize = sizey, + x = posx, y = posy, height = heights, fill = fills, alpha = alpha, angle = angle, horizontal = hor, vertical = ver) p + ggtitle("R Cat Herd!!") diff --git a/man/add_phylopic_base.Rd b/man/add_phylopic_base.Rd index affdfb3..0ba67c9 100644 --- a/man/add_phylopic_base.Rd +++ b/man/add_phylopic_base.Rd @@ -11,13 +11,17 @@ add_phylopic_base( filter = NULL, x = NULL, y = NULL, - ysize = NULL, + ysize = deprecated(), + height = NULL, + width = NULL, alpha = 1, color = NA, fill = "black", horizontal = FALSE, vertical = FALSE, angle = 0, + hjust = 0.5, + vjust = 0.5, remove_background = TRUE, verbose = FALSE ) @@ -36,15 +40,26 @@ Use "by" to limit results to images which do not require attribution, "nc" for images which allows commercial usage, and "sa" for images without a ShareAlike clause. The user can also combine these filters as a vector.} -\item{x}{\code{numeric}. x value of the silhouette center. Ignored if \code{y} and -\code{ysize} are not specified.} +\item{x}{\code{numeric}. x value of the silhouette center. If "NULL", the +default, the mean value of the x-axis is used.} -\item{y}{\code{numeric}. y value of the silhouette center. Ignored if \code{x} and -\code{ysize} are not specified.} +\item{y}{\code{numeric}. y value of the silhouette center. If "NULL", the +default, the mean value of the y-axis is used.} -\item{ysize}{\code{numeric}. Height of the silhouette. The width is -determined by the aspect ratio of the original image. Ignored if \code{x} and -\code{y} are not specified.} +\item{ysize}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} use the \code{height} or \code{width} +argument instead.} + +\item{height}{\code{numeric}. Height of the silhouette in coordinate space. +If "NULL", the default, and \code{width} is also "NULL", the silhouette will be +as large as fits in the plot area. If "NULL" and \code{width} is specified, the +height is determined by the aspect ratio of the original image. One or both +of \code{height} and \code{width} must be "NULL".} + +\item{width}{\code{numeric}. Width of the silhouette in coordinate space. If +"NULL", the default, and \code{height} is also "NULL", the silhouette will be as +large as fits in the plot area. If "NULL" and \code{height} is specified, the +width is determined by the aspect ratio of the original image. One or both +of \code{height} and \code{width} must be "NULL".} \item{alpha}{\code{numeric}. A value between 0 and 1, specifying the opacity of the silhouette (0 is fully transparent, 1 is fully opaque).} @@ -68,6 +83,12 @@ horizontally?} \item{angle}{\code{numeric}. The number of degrees to rotate the silhouette clockwise. The default is no rotation.} +\item{hjust}{\code{numeric}. A numeric vector between 0 and 1 specifying +horizontal justification (left = 0, center = 0.5, right = 1).} + +\item{vjust}{\code{numeric}. A numeric vector between 0 and 1 specifying +vertical justification (top = 1, middle = 0.5, bottom = 0).} + \item{remove_background}{\code{logical}. Should any white background be removed from the silhouette(s)? See \code{\link[=recolor_phylopic]{recolor_phylopic()}} for details.} @@ -80,12 +101,13 @@ silhouettes on top of an existing base R plot (like \code{\link[=points]{points( } \details{ One (and only one) of \code{img}, \code{name}, or \code{uuid} must be specified. -Use parameters \code{x}, \code{y}, and \code{ysize} to place the silhouette at a specified -position on the plot. If all three of these parameters are unspecified, -then the silhouette will be plotted to the full height and width of the -plot. The aspect ratio of the silhouette will always be maintained (even -when a plot is resized). However, if the plot is resized after plotting the -silhouette, the absolute size and/or position of the silhouette may change. +Use parameters \code{x}, \code{y}, \code{hjust}, and \code{vjust} to place the silhouette at a +specified position on the plot. If \code{height} and \code{width} are both +unspecified, then the silhouette will be plotted to the full height and/or +width of the plot. The aspect ratio of \code{Picture} objects will always be +maintained (even when a plot is resized). However, if the plot is resized +after plotting a silhouette, the absolute size and/or position of the +silhouette may change. Any argument (except for \code{remove_background}) may be a vector of values if multiple silhouettes should be plotted. In this case, all other arguments @@ -105,7 +127,7 @@ Also, outline colors do not currently work for png array objects. # single image plot(1, 1, type = "n", main = "A cat") add_phylopic_base(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", - x = 1, y = 1, ysize = 0.4) + x = 1, y = 1, height = 0.4) # lots of images using a uuid posx <- runif(10, 0, 1) @@ -119,7 +141,7 @@ fills <- sample(c("black", "darkorange", "grey42", "white"), 10, plot(posx, posy, type = "n", main = "A cat herd") add_phylopic_base(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", - x = posx, y = posy, ysize = size, + x = posx, y = posy, height = size, fill = fills, angle = angle, horizontal = hor, vertical = ver) @@ -131,6 +153,6 @@ plot(posx, posy, type = "n", main = "A cat herd, on top of a cat", # plot background cat add_phylopic_base(img = cat, alpha = 0.2) # overlay smaller cats -add_phylopic_base(img = cat, x = posx, y = posy, ysize = size, alpha = 0.8) +add_phylopic_base(img = cat, x = posx, y = posy, height = size, alpha = 0.8) } } diff --git a/man/add_phylopic_legend.Rd b/man/add_phylopic_legend.Rd index 998e76f..9c68a6a 100644 --- a/man/add_phylopic_legend.Rd +++ b/man/add_phylopic_legend.Rd @@ -11,7 +11,8 @@ add_phylopic_legend( img = NULL, name = NULL, uuid = NULL, - ysize = NULL, + ysize = deprecated(), + height = NULL, color = NA, fill = "black", ... @@ -36,7 +37,10 @@ from using \code{\link[=get_phylopic]{get_phylopic()}}.} \item{uuid}{\code{character}. A valid uuid for a PhyloPic silhouette (such as that returned by \code{\link[=get_uuid]{get_uuid()}} or \code{\link[=pick_phylopic]{pick_phylopic()}}).} -\item{ysize}{\code{numeric}. Height of the legend silhouette(s). The width +\item{ysize}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} use the \code{height} +argument instead.} + +\item{height}{\code{numeric}. Height of the legend silhouette(s). The width is determined by the aspect ratio of the original image.} \item{color}{\code{character}. Color of silhouette outline. If "original" or @@ -76,10 +80,10 @@ plot(0:10, 0:10, type = "n", main = "Wolves") # Add data points add_phylopic_base(uuid = uuids, color = "black", fill = c("blue", "green"), - x = c(2.5, 7.5), y = c(2.5, 7.5), ysize = 2) + x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) # Add legend add_phylopic_legend(uuid = uuids, - ysize = 0.5, color = "black", fill = c("blue", "green"), + height = 0.5, color = "black", fill = c("blue", "green"), x = "bottomright", legend = c("Wolf 1", "Wolf 2"), bg = "lightgrey") } diff --git a/man/geom_phylopic.Rd b/man/geom_phylopic.Rd index 78e0887..ba7fe93 100644 --- a/man/geom_phylopic.Rd +++ b/man/geom_phylopic.Rd @@ -39,20 +39,59 @@ the plot data. The return value must be a \code{data.frame}, and 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, 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]{layer()}}. These are -often aesthetics, used to set an aesthetic to a fixed value, like -\code{colour = "red"} or \code{size = 3}. They may also be parameters -to the paired geom/stat.} +\item{stat}{The statistical transformation to use on the data for this layer. +When using a \verb{geom_*()} function to construct a layer, the \code{stat} +argument can be used the override the default coupling between geoms and +stats. The \code{stat} argument accepts the following: +\itemize{ +\item A \code{Stat} ggproto subclass, for example \code{StatCount}. +\item A string naming the stat. To give the stat as a string, strip the +function name of the \code{stat_} prefix. For example, to use \code{stat_count()}, +give the stat as \code{"count"}. +\item For more information and other ways to specify the stat, see the +\link[ggplot2:layer_stats]{layer stat} documentation. +}} + +\item{position}{A position adjustment to use on the data for this layer. This +can be used in various ways, including to prevent overplotting and +improving the display. The \code{position} argument accepts the following: +\itemize{ +\item The result of calling a position function, such as \code{position_jitter()}. +This method allows for passing extra arguments to the position. +\item A string naming the position adjustment. To give the position as a +string, strip the function name of the \code{position_} prefix. For example, +to use \code{position_jitter()}, give the position as \code{"jitter"}. +\item For more information and other ways to specify the position, see the +\link[ggplot2:layer_positions]{layer position} documentation. +}} + +\item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}'s \code{params} argument. These +arguments broadly fall into one of 4 categories below. Notably, further +arguments to the \code{position} argument, or aesthetics that are required +can \emph{not} be passed through \code{...}. Unknown arguments that are not part +of the 4 categories below are ignored. +\itemize{ +\item Static aesthetics that are not mapped to a scale, but are at a fixed +value and apply to the layer as a whole. For example, \code{colour = "red"} +or \code{linewidth = 3}. The geom's documentation has an \strong{Aesthetics} +section that lists the available options. The 'required' aesthetics +cannot be passed on to the \code{params}. Please note that while passing +unmapped aesthetics as vectors is technically possible, the order and +required length is not guaranteed to be parallel to the input data. +\item When constructing a layer using +a \verb{stat_*()} function, the \code{...} argument can be used to pass on +parameters to the \code{geom} part of the layer. An example of this is +\code{stat_density(geom = "area", outline.type = "both")}. The geom's +documentation lists which parameters it can accept. +\item Inversely, when constructing a layer using a +\verb{geom_*()} function, the \code{...} argument can be used to pass on parameters +to the \code{stat} part of the layer. An example of this is +\code{geom_area(stat = "density", adjust = 0.5)}. The stat's documentation +lists which parameters it can accept. +\item The \code{key_glyph} argument of \code{\link[ggplot2:layer]{layer()}} may also be passed on through +\code{...}. This can be one of the functions described as +\link[ggplot2:draw_key]{key glyphs}, to change the display of the layer in the legend. +}} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} @@ -89,9 +128,12 @@ One (and only one) of the \code{img}, \code{name}, or \code{uuid} aesthetics mus be specified. The \code{img} aesthetic can be \link[grImport2:Picture-class]{Picture} objects or png array objects, e.g., from using \code{\link[=get_phylopic]{get_phylopic()}}. Use the \code{x} and \code{y} aesthetics to place the -silhouettes at specified positions on the plot. The \code{size} aesthetic -specifies the height of the silhouettes in the units of the y axis. The -aspect ratio of the silhouettes will always be maintained. +silhouettes at specified positions on the plot. The \code{height} or \code{width} +aesthetic specifies the height or width, respectively, of the silhouettes +in the units of the y axis (only one is allowed). The aspect ratio of the +silhouettes will always be maintained. The \code{hjust} and \code{vjust} aesthetics +can be used to manage the justification of the silhouettes with respect to +the \code{x} and \code{y} coordinates. The \code{color} (default: NA), \code{fill} (default: "black"), and \code{alpha} ( default: 1) aesthetics can be used to change the outline color, fill color, @@ -119,14 +161,18 @@ Also, outline colors do not currently work for png array objects. \itemize{ \item \strong{x} (required) \item \strong{y} (required) -\item \strong{img/uuid/name} (one, and only one, required) -\item size -\item color/colour +\item \strong{img} \emph{or} \strong{uuid} \emph{or} \strong{name} (one, and only one, required) +\item height \emph{or} width (optional, maximum of only one allowed) +\item ysize \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Deprecated in favor of height or +width +\item color \emph{or} colour \item fill \item alpha \item horizontal \item vertical \item angle +\item hjust +\item vjust Learn more about setting these aesthetics in \code{\link[=add_phylopic]{add_phylopic()}}. } @@ -139,7 +185,7 @@ df <- data.frame(x = c(2, 4), y = c(10, 20), name = c("Felis silvestris catus", "Odobenus rosmarus")) ggplot(df) + geom_phylopic(aes(x = x, y = y, name = name), - fill = "purple", size = 10) + + fill = "purple", height = 10) + facet_wrap(~name) + coord_cartesian(xlim = c(1,6), ylim = c(5, 30)) } diff --git a/man/scales.Rd b/man/scales.Rd new file mode 100644 index 0000000..a24f675 --- /dev/null +++ b/man/scales.Rd @@ -0,0 +1,98 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/geom_phylopic.R +\name{scale_height_continuous} +\alias{scale_height_continuous} +\alias{scale_width_continuous} +\title{Scales for phylopic height or width} +\usage{ +scale_height_continuous( + name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + range = c(1, 6), + transform = "identity", + trans = lifecycle::deprecated(), + guide = "none" +) + +scale_width_continuous( + name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + range = c(1, 6), + transform = "identity", + trans = lifecycle::deprecated(), + guide = "none" +) +} +\arguments{ +\item{name}{The name of the scale. Used as the axis or legend title. If +\code{waiver()}, the default, the name of the scale is taken from the first +mapping used for that aesthetic. If \code{NULL}, the legend title will be +omitted.} + +\item{breaks}{One of: +\itemize{ +\item \code{NULL} for no breaks +\item \code{waiver()} for the default breaks computed by the +\link[scales:new_transform]{transformation object} +\item A numeric vector of positions +\item A function that takes the limits as input and returns breaks +as output (e.g., a function returned by \code{\link[scales:breaks_extended]{scales::extended_breaks()}}). +Note that for position scales, limits are provided after scale expansion. +Also accepts rlang \link[rlang:as_function]{lambda} function notation. +}} + +\item{labels}{One of: +\itemize{ +\item \code{NULL} for no labels +\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. +}} + +\item{limits}{One of: +\itemize{ +\item \code{NULL} to use the default scale range +\item A numeric vector of length two providing limits of the scale. +Use \code{NA} to refer to the existing minimum or maximum +\item A function that accepts the existing (automatic) limits and returns +new limits. Also accepts rlang \link[rlang:as_function]{lambda} function +notation. +Note that setting limits on positional scales will \strong{remove} data outside of the limits. +If the purpose is to zoom, use the limit argument in the coordinate system +(see \code{\link[ggplot2:coord_cartesian]{coord_cartesian()}}). +}} + +\item{range}{a numeric vector of length 2 that specifies the minimum and +maximum size of the plotting symbol after transformation.} + +\item{transform}{For continuous scales, the name of a transformation object +or the object itself. Built-in transformations include "asn", "atanh", +"boxcox", "date", "exp", "hms", "identity", "log", "log10", "log1p", "log2", +"logit", "modulus", "probability", "probit", "pseudo_log", "reciprocal", +"reverse", "sqrt" and "time". + +A transformation object bundles together a transform, its inverse, +and methods for generating breaks and labels. Transformation objects +are defined in the scales package, and are called \verb{transform_}. If +transformations require arguments, you can call them from the scales +package, e.g. \code{\link[scales:transform_boxcox]{scales::transform_boxcox(p = 2)}}. +You can create your own transformation with \code{\link[scales:new_transform]{scales::new_transform()}}.} + +\item{trans}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Deprecated in favour of +\code{transform}.} + +\item{guide}{A function used to create a guide or its name. See +\code{\link[ggplot2:guides]{guides()}} for more information.} +} +\description{ +\code{scale_height_continuous()} scales the height of silhouettes whereas +\code{scale_width_continuous()} scales the height of silhouettes. +} diff --git a/tests/testthat/_snaps/add_phylopic/phylopics-with-alt-height-and-width.svg b/tests/testthat/_snaps/add_phylopic/phylopics-with-alt-height-and-width.svg new file mode 100644 index 0000000..2faae27 --- /dev/null +++ b/tests/testthat/_snaps/add_phylopic/phylopics-with-alt-height-and-width.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0.0 +2.5 +5.0 +7.5 + + + + + + + + + +0.0 +2.5 +5.0 +7.5 +10.0 +cat.x +cat.y +phylopics with alt height and width + + diff --git a/tests/testthat/_snaps/add_phylopic/phylopics-with-widths.svg b/tests/testthat/_snaps/add_phylopic/phylopics-with-widths.svg new file mode 100644 index 0000000..4978be1 --- /dev/null +++ b/tests/testthat/_snaps/add_phylopic/phylopics-with-widths.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +0.0 +2.5 +5.0 +7.5 + + + + + + + + + +0.0 +2.5 +5.0 +7.5 +10.0 +cat.x +cat.y +phylopics with widths + + diff --git a/tests/testthat/_snaps/add_phylopic_base/phylopic-with-width.svg b/tests/testthat/_snaps/add_phylopic_base/phylopic-with-width.svg new file mode 100644 index 0000000..cc28f7d --- /dev/null +++ b/tests/testthat/_snaps/add_phylopic_base/phylopic-with-width.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + +0.6 +0.8 +1.0 +1.2 +1.4 + + + + + + +0.6 +0.8 +1.0 +1.2 +1.4 + +A cat +1 +1 + + + + + + + + + + + + + diff --git a/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-alt-height-and-width.svg b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-alt-height-and-width.svg new file mode 100644 index 0000000..add7eb3 --- /dev/null +++ b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-alt-height-and-width.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +10 +20 +30 + + + + + + + +2 +4 +6 +x +y +geom_phylopic with alt height and width + + diff --git a/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-no-dims.svg b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-no-dims.svg new file mode 100644 index 0000000..b633357 --- /dev/null +++ b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-no-dims.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +10 +20 +30 + + + + + + + +2 +4 +6 +x +y +geom_phylopic with no dims + + diff --git a/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-width.svg b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-width.svg new file mode 100644 index 0000000..18dc345 --- /dev/null +++ b/tests/testthat/_snaps/geom_phylopic/geom-phylopic-with-width.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +d2575005-1fcb-4a86-8c83-e3bda619adf2 + + + + + + + + + + +e25f1863-331b-4891-8084-fe8602e4cf8d + + + + + + + + + + +0a8ab4f9-04c9-4485-b21a-df683d506055 + + + + + + + + + + +c8f71c27-71db-4b34-ac2d-e97fea8762cf + + + + + + +2 +4 +6 + + + + +2 +4 +6 + +10 +20 +30 + + + + +10 +20 +30 + + + +x +y +geom_phylopic with width + + diff --git a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-img.svg b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-img.svg index 04689c4..15f2a4f 100644 --- a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-img.svg +++ b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-img.svg @@ -21,34 +21,34 @@ - - + + - - + + - - + + - - - + + + - + - - + + - - - + + + - + @@ -58,43 +58,43 @@ - - - - -2 -4 -6 -x + + + + +2 +4 +6 +x y - -name - + +name + - - + + - - - + + + - + - - + + - - - + + + -Felis silvestris catus -Odobenus rosmarus +Felis silvestris catus +Odobenus rosmarus phylopic_key_glyph with img diff --git a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-uuid.svg b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-uuid.svg index 8bc4ada..263d8c5 100644 --- a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-uuid.svg +++ b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph-with-uuid.svg @@ -21,34 +21,34 @@ - - + + - - + + - - + + - - - + + + - + - - + + - - - + + + - + @@ -58,43 +58,43 @@ - - - - -2 -4 -6 -x + + + + +2 +4 +6 +x y - -name - + +name + - - + + - - - + + + - + - - + + - - - + + + -Felis silvestris catus -Odobenus rosmarus +Felis silvestris catus +Odobenus rosmarus phylopic_key_glyph with uuid diff --git a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph.svg b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph.svg index f2f40d6..89b2914 100644 --- a/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph.svg +++ b/tests/testthat/_snaps/geom_phylopic/phylopic-key-glyph.svg @@ -21,34 +21,34 @@ - - + + - - + + - - + + - - - + + + - + - - + + - - - + + + - + @@ -58,43 +58,43 @@ - - - - -2 -4 -6 -x + + + + +2 +4 +6 +x y - -name - + +name + - - + + - - - + + + - + - - + + - - - + + + -Felis silvestris catus -Odobenus rosmarus +Felis silvestris catus +Odobenus rosmarus phylopic_key_glyph diff --git a/tests/testthat/_snaps/phylopic_utils/plot-picture.svg b/tests/testthat/_snaps/phylopic_utils/plot-picture.svg index 27a16c3..ea6ac88 100644 --- a/tests/testthat/_snaps/phylopic_utils/plot-picture.svg +++ b/tests/testthat/_snaps/phylopic_utils/plot-picture.svg @@ -25,8 +25,8 @@ - - + + diff --git a/tests/testthat/test-add_phylopic.R b/tests/testthat/test-add_phylopic.R index 79da2c6..4a58322 100644 --- a/tests/testthat/test-add_phylopic.R +++ b/tests/testthat/test-add_phylopic.R @@ -35,18 +35,62 @@ test_that("add_phylopic works", { p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + geom_blank() + add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", - x = posx, y = posy, ysize = sizey, + x = posx, y = posy, height = sizey, fill = fills, color = cols, alpha = alpha, angle = angle, horizontal = hor, vertical = ver) p <- p + ggtitle("R Cat Herd!!") expect_doppelganger("phylopics on top of plot", p) + + p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + + geom_blank() + + add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", + x = posx, y = posy, width = sizey, + fill = fills, color = cols, alpha = alpha, + angle = angle, horizontal = hor, vertical = ver) + expect_doppelganger("phylopics with widths", p) + + p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + + geom_blank() + + add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", + x = posx, y = posy, + width = c(1, NA, 2, NA), height = c(NA, 1, NA, 2), + fill = fills, color = cols, alpha = alpha, + angle = angle, horizontal = hor, vertical = ver) + expect_doppelganger("phylopics with alt height and width", p) + lifecycle::expect_deprecated({ + p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + + geom_blank() + + add_phylopic(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", + x = posx, y = posy, ysize = sizey) + plot(p) + }) + + p <- ggplot(data.frame(cat.x = posx, cat.y = posy), aes(cat.x, cat.y)) + + geom_blank() + cat_svg <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9") # Expect error expect_error(add_phylopic(img = "cat")) - expect_error(add_phylopic(cat, name = "cat")) + expect_error(add_phylopic(cat_svg, name = "cat")) expect_error(add_phylopic()) - expect_error(add_phylopic(cat, alpha = 3)) - expect_error(add_phylopic(name = 42)) - expect_error(add_phylopic(name = "bueller")) - expect_error(add_phylopic(uuid = 42)) + expect_error({ + plot(p + add_phylopic(cat_svg, alpha = 3, x = 5, y = 5)) + }) + expect_error({ + plot(p + add_phylopic(cat_svg, hjust = 3, x = 5, y = 5)) + }) + expect_error({ + plot(p + add_phylopic(cat_svg, vjust = 3, x = 5, y = 5)) + }) + expect_error({ + plot(p + add_phylopic(name = 42, x = 5, y = 5, verbose = TRUE)) + }) + expect_error({ + plot(p + add_phylopic(uuid = 42, x = 5, y = 5, verbose = TRUE)) + }) + + # Expect warning + expect_warning({ + plot(p + add_phylopic(name = "bueller", x = 5, y = 5, verbose = TRUE)) + }) }) diff --git a/tests/testthat/test-add_phylopic_base.R b/tests/testthat/test-add_phylopic_base.R index a5d47a0..4f6e6f1 100644 --- a/tests/testthat/test-add_phylopic_base.R +++ b/tests/testthat/test-add_phylopic_base.R @@ -4,7 +4,13 @@ test_that("add_phylopic_base works", { # phylopic in background, with name expect_doppelganger("phylopic in background", function() { plot(1, 1, type = "n", main = "A cat") - add_phylopic_base(name = "Felis silvestris catus", ysize = .7, + add_phylopic_base(name = "Felis silvestris catus", height = .7, + verbose = TRUE) + }) + + expect_doppelganger("phylopic with width", function() { + plot(1, 1, type = "n", main = "A cat") + add_phylopic_base(name = "Felis silvestris catus", width = .4, verbose = TRUE) }) @@ -13,7 +19,7 @@ test_that("add_phylopic_base works", { cat_png <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9", format = "raster") plot(1, 1, type = "n", main = "A cat") - add_phylopic_base(cat_png, x = 1, y = 1, ysize = .4, fill = "blue", + add_phylopic_base(cat_png, x = 1, y = 1, height = .4, fill = "blue", alpha = .5, angle = -90, horizontal = TRUE) }) @@ -33,7 +39,7 @@ test_that("add_phylopic_base works", { expect_doppelganger("phylopics on top of plot", function() { plot(posx, posy, type = "n", main = "A cat herd") add_phylopic_base(uuid = "23cd6aa4-9587-4a2e-8e26-de42885004c9", - x = posx, y = posy, ysize = sizey, + x = posx, y = posy, height = sizey, fill = fills, color = cols, alpha = alpha, angle = angle, horizontal = hor, vertical = ver) @@ -45,12 +51,20 @@ test_that("add_phylopic_base works", { verbose = TRUE))) expect_warning(add_phylopic_base(uuid = "jkl;daf", filter = "by")) + cat_svg <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9") + lifecycle::expect_deprecated({ + add_phylopic_base(cat_svg, ysize = .7) + }) + # Expect error expect_error(add_phylopic_base(img = "cat")) - expect_error(add_phylopic_base(img = cat, verbose = "yes")) - expect_error(add_phylopic_base(cat, name = "cat")) + expect_error(add_phylopic_base(img = cat_svg, verbose = "yes")) + expect_error(add_phylopic_base(cat_svg, name = "cat")) expect_error(add_phylopic_base()) - expect_error(add_phylopic_base(cat, alpha = 3)) + expect_error(add_phylopic_base(cat_svg, alpha = 3)) expect_error(add_phylopic_base(name = 42)) expect_error(add_phylopic_base(uuid = 42)) + expect_error(add_phylopic_base(cat_svg, height = 5, width = 5)) + expect_error(add_phylopic_base(cat_svg, hjust = 5)) + expect_error(add_phylopic_base(cat_svg, vjust = 5)) }) diff --git a/tests/testthat/test-add_phylopic_legend.R b/tests/testthat/test-add_phylopic_legend.R index b66fde5..9aef0c9 100644 --- a/tests/testthat/test-add_phylopic_legend.R +++ b/tests/testthat/test-add_phylopic_legend.R @@ -10,9 +10,9 @@ test_that("add_phylopic_legend works", { plot(0:10, 0:10, type = "n", main = "Wolves") add_phylopic_base(uuid = uuids, color = "black", fill = c("blue", "green"), - x = c(2.5, 7.5), y = c(2.5, 7.5), ysize = 2) + x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) add_phylopic_legend(uuid = uuids, - ysize = 0.25, color = "black", + height = 0.25, color = "black", fill = c("blue", "green"), x = "bottomright", legend = c("Wolf 1", "Wolf 2"), bg = "lightgrey") @@ -23,7 +23,7 @@ test_that("add_phylopic_legend works", { plot(0:10, 0:10, type = "n", main = "Wolves") add_phylopic_base(uuid = uuids, color = "black", fill = c("blue", "green"), - x = c(2.5, 7.5), y = c(2.5, 7.5), ysize = 2) + x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) add_phylopic_legend(uuid = uuids, x = "bottomright", legend = c("Wolf 1", "Wolf 2"), col = "black", pt.bg = c("blue", "green"), @@ -35,9 +35,20 @@ test_that("add_phylopic_legend works", { plot(0:10, 0:10, type = "n", main = "Wolves") add_phylopic_base(uuid = uuids, color = "black", fill = c("blue", "green"), - x = c(2.5, 7.5), y = c(2.5, 7.5), ysize = 2) + x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) add_phylopic_legend(uuid = uuids, x = "bottomright", legend = c("Wolf 1", "Wolf 2"), col = "black", pt.bg = c("blue", "green")) }) + + lifecycle::expect_deprecated({ + plot(0:10, 0:10, type = "n", main = "Wolves") + add_phylopic_base(uuid = uuids, + color = "black", fill = c("blue", "green"), + x = c(2.5, 7.5), y = c(2.5, 7.5), height = 2) + add_phylopic_legend(uuid = uuids, + x = "bottomright", legend = c("Wolf 1", "Wolf 2"), + col = "black", pt.bg = c("blue", "green"), + ysize = 2) + }) }) diff --git a/tests/testthat/test-geom_phylopic.R b/tests/testthat/test-geom_phylopic.R index 152794d..41b0051 100644 --- a/tests/testthat/test-geom_phylopic.R +++ b/tests/testthat/test-geom_phylopic.R @@ -10,7 +10,7 @@ test_that("geom_phylopic works", { "c8f71c27-71db-4b34-ac2d-e97fea8762cf", "0a8ab4f9-04c9-4485-b21a-df683d506055")) gg <- ggplot(df) + - geom_phylopic(aes(x = x, y = y, uuid = uuid), color = "purple", size = 10, + geom_phylopic(aes(x = x, y = y, uuid = uuid), color = "purple", height = 10, horizontal = TRUE, angle = 45) + facet_wrap(~uuid) + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + @@ -18,24 +18,55 @@ test_that("geom_phylopic works", { expect_true(is.ggplot(gg)) expect_true(is(gg$layers[[1]]$geom, "GeomPhylopic")) expect_doppelganger("geom_phylopic", gg) + + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), width = 0.5) + + facet_wrap(~uuid) + + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + + theme_classic(base_size = 16) + expect_doppelganger("geom_phylopic with width", gg) + cat_svg <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9") + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y), img = list(cat_svg)) + + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + + theme_classic(base_size = 16) + expect_doppelganger("geom_phylopic with no dims", gg) + + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), + height = c(NA, 10, NA, 10), width = c(0.5, NA, 0.5, NA)) + + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + + theme_classic(base_size = 16) + expect_doppelganger("geom_phylopic with alt height and width", gg) + cat_png <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9", format = "raster") gg <- ggplot(df) + geom_phylopic(aes(x = x, y = y), img = list(cat_png), - fill = "purple", size = 10) + + fill = "purple", height = 10) + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + theme_classic(base_size = 16) expect_doppelganger("geom_phylopic with png", gg) # Errors and warnings + lifecycle::expect_deprecated({ + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), size = 5) + plot(gg) + }) gg <- ggplot(df) + geom_phylopic(aes(x = x, y = y, uuid = uuid), alpha = -5) expect_error(plot(gg)) expect_error(ggplot(df) + - geom_phylopic(aes(x = x, y = y, uuid = uuid), remove_background = "yes")) + geom_phylopic(aes(x = x, y = y, uuid = uuid), + remove_background = "yes")) expect_error(ggplot(df) + geom_phylopic(aes(x = x, y = y, uuid = uuid), verbose = "yes")) + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), + name = "cat", height = 1, width = 1) + expect_error(plot(gg)) gg <- ggplot(df) + geom_phylopic(aes(x = x, y = y, uuid = uuid), name = "cat", verbose = TRUE) expect_error(plot(gg)) @@ -48,6 +79,12 @@ test_that("geom_phylopic works", { gg <- ggplot(df) + geom_phylopic(aes(x = x, y = y), img = -5) expect_error(plot(gg)) + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), hjust = 5) + expect_error(plot(gg)) + gg <- ggplot(df) + + geom_phylopic(aes(x = x, y = y, uuid = uuid), vjust = 5) + expect_error(plot(gg)) gg <- ggplot(df) + geom_phylopic(aes(x = x, y = y), name = "asdfghjkl", verbose = TRUE) expect_warning(plot(gg)) @@ -55,7 +92,7 @@ test_that("geom_phylopic works", { geom_phylopic(aes(x = x, y = y), uuid = "asdfghjkl") expect_warning(plot(gg)) gg <- ggplot(df) + - geom_phylopic(aes(x = x, y = y, uuid = uuid), size = 1E-6) + geom_phylopic(aes(x = x, y = y, uuid = uuid), height = 1E-6) expect_warning(plot(gg)) }) @@ -66,7 +103,7 @@ test_that("phylopic_key_glyph works", { df <- data.frame(x = c(2, 4), y = c(10, 20), name = c("Felis silvestris catus", "Odobenus rosmarus")) gg <- ggplot(df) + - geom_phylopic(aes(x = x, y = y, name = name, color = name), size = 10, + geom_phylopic(aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(name = df$name)) + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + @@ -78,7 +115,7 @@ test_that("phylopic_key_glyph works", { gg <- ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(uuid = c("23cd6aa4-9587-4a2e-8e26-de42885004c9", @@ -90,7 +127,7 @@ test_that("phylopic_key_glyph works", { cat <- get_phylopic("23cd6aa4-9587-4a2e-8e26-de42885004c9") gg <- ggplot(df) + - geom_phylopic(aes(x = x, y = y, name = name, color = name), size = 10, + geom_phylopic(aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(img = cat)) + coord_cartesian(xlim = c(1, 6), ylim = c(5, 30)) + @@ -100,7 +137,7 @@ test_that("phylopic_key_glyph works", { # errors/warnings expect_error(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph( @@ -112,7 +149,7 @@ test_that("phylopic_key_glyph works", { theme_classic(base_size = 16)) expect_error(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(name = 12345) @@ -121,7 +158,7 @@ test_that("phylopic_key_glyph works", { theme_classic(base_size = 16)) expect_warning(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(name = "12345") @@ -130,7 +167,7 @@ test_that("phylopic_key_glyph works", { theme_classic(base_size = 16)) expect_error(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(uuid = 12345) @@ -139,7 +176,7 @@ test_that("phylopic_key_glyph works", { theme_classic(base_size = 16)) expect_warning(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(uuid = "12345") @@ -148,7 +185,7 @@ test_that("phylopic_key_glyph works", { theme_classic(base_size = 16)) expect_error(ggplot(df) + geom_phylopic( - aes(x = x, y = y, name = name, color = name), size = 10, + aes(x = x, y = y, name = name, color = name), height = 10, show.legend = TRUE, verbose = TRUE, key_glyph = phylopic_key_glyph(img = 12345) diff --git a/vignettes/a-getting-started.Rmd b/vignettes/a-getting-started.Rmd index 79b8f4a..d602f02 100644 --- a/vignettes/a-getting-started.Rmd +++ b/vignettes/a-getting-started.Rmd @@ -9,7 +9,7 @@ vignette: > **Authors:** Lewis A. Jones & William Gearty -**Last updated:** 2024-04-23 +**Last updated:** 2024-07-30 @@ -24,14 +24,14 @@ vignette: > The **rphylopic** package can be installed via CRAN or its dedicated [GitHub repository](https://github.com/palaeoverse/rphylopic) if the development version is preferred. To install via CRAN, simply use: -```r +``` r install.packages("rphylopic") ``` To install the development version, first install the `{remotes}` package, and then use `install_github()` to install **rphylopic** directly from GitHub. -```r +``` r install.packages("remotes") remotes::install_github("palaeoverse/rphylopic") ``` @@ -39,22 +39,22 @@ remotes::install_github("palaeoverse/rphylopic") You can now load **rphylopic** using the default `library()` function: -```r +``` r library(rphylopic) ``` **Before we get onto the good stuff, the development team has a small request**. If you use **rphylopic** in your research, please cite the associated publication. This will help us to continue our work in supporting you to do yours. You can access the appropriate citation via: -```r +``` r citation("rphylopic") ``` ``` ## To cite rphylopic in publications, use the following citation: ## -## Gearty, W. and Jones, L.A. 2023. rphylopic: An R package for fetching, transforming, and visualising PhyloPic silhouettes. -## Methods in Ecology and Evolution, 14(11), 2700-2708. doi: 10.1111/2041-210X.14221. +## Gearty, W. and Jones, L.A. 2023. rphylopic: An R package for fetching, transforming, and visualising +## PhyloPic silhouettes. Methods in Ecology and Evolution, 14(11), 2700-2708. doi: 10.1111/2041-210X.14221. ## ## A BibTeX entry for LaTeX users is ## @@ -79,7 +79,7 @@ Every silhouette available via [PhyloPic](https://www.phylopic.org) has a univer ## Get an image uuid -```r +``` r # Load rphylopic library(rphylopic) # Get a single image UUID for a species @@ -95,7 +95,7 @@ uuid <- get_uuid(name = "Canis lupus", n = 5) As multiple silhouettes can exist for a searched name, it can be difficult to pick the correct UUID, especially without visualizing the images. The `pick_phylopic()` function plots all requested silhouettes and provides an interactive menu to allow you to select the right image for you. Let's go with option 1! -```r +``` r # How do I pick?! # It's difficult without seeing the image itself, let's use: img <- pick_phylopic(name = "Canis lupus", n = 4, view = 4) @@ -109,17 +109,17 @@ Now we have selected our silhouette, we can make some plots! Let's start with base R by using `add_phylopic_base()`: -```r +``` r # OK, now we've got the image we want... let's add it to a plot! plot(x = 1, y = 1, type = "n", ann = FALSE) -add_phylopic_base(img = img, x = 1.25, y = 1.25, ysize = 0.25) +add_phylopic_base(img = img, x = 1.25, y = 1.25, height = 0.25) # But can't we just add an image straight away using the UUID? Sure! uuid <- get_uuid(name = "Canis lupus", n = 1) -add_phylopic_base(uuid = uuid, x = 1, y = 1, ysize = 0.25) +add_phylopic_base(uuid = uuid, x = 1, y = 1, height = 0.25) # What about just using the first image linked to the name? Definitely! -add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, ysize = 0.25) +add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, height = 0.25) ```
@@ -133,18 +133,18 @@ Ah, you've found out our little secret! You can actually skip the steps of getti You can also accomplish the same plot with the `{ggplot2}` package. Here, we'll use the `add_phylopic()` function, but the functionality and all of the arguments are the same: -```r +``` r library(ggplot2) p <- ggplot() + coord_cartesian(xlim = c(0.6, 1.4), ylim = c(0.6, 1.4)) + - add_phylopic(img = img, x = 1.25, y = 1.25, ysize = 0.25) + add_phylopic(img = img, x = 1.25, y = 1.25, height = 0.25) # But can't we just add an image straight away using the UUID? Sure! uuid <- get_uuid(name = "Canis lupus", n = 1) -p <- p + add_phylopic(uuid = uuid, x = 1, y = 1, ysize = 0.25) +p <- p + add_phylopic(uuid = uuid, x = 1, y = 1, height = 0.25) # What about just using the first image linked to the name? Definitely! -p + add_phylopic(name = "Canis lupus", x = 0.75, y = 0.75, ysize = 0.25) +p + add_phylopic(name = "Canis lupus", x = 0.75, y = 0.75, height = 0.25) ```
@@ -158,7 +158,7 @@ Once a silhouette is picked and saved in the your R environment, it may be usefu The `flip_phylopic()` function can be used to flip a silhouette horizontally and/or vertically. This may be useful if, for example, you want all of the silhouettes to face the same direction. -```r +``` r # Flip silhouette horizontally img_flip <- flip_phylopic(img = img, horizontal = TRUE, vertical = FALSE) ``` @@ -166,7 +166,7 @@ img_flip <- flip_phylopic(img = img, horizontal = TRUE, vertical = FALSE) The `rotate_phylopic()` function can be used to rotate a silhouette an arbitrary number of degrees. This may be useful when trying to align a silhouette with text or other objects within a figure. -```r +``` r # Rotate silhouette by 45 degrees img_rot <- rotate_phylopic(img = img, angle = 45) ``` @@ -174,7 +174,7 @@ img_rot <- rotate_phylopic(img = img, angle = 45) Finally, the `recolor_phylopic()` function can be used to modify the fill color, outline color, and/or transparency of a silhouette. The vast majority of PhyloPic silhouettes are solid black, are fully opaque, and have a transparent outline by default. However, it may be useful to change this when the you are trying to either match an existing visualization color palette or trying to convey extra information, such as categorical data, through color. -```r +``` r # Change fill color to blue and transparency to 50% img_col <- recolor_phylopic(img = img, alpha = 0.5, fill = "blue") ``` @@ -182,12 +182,12 @@ img_col <- recolor_phylopic(img = img, alpha = 0.5, fill = "blue") Let's see what those look like in the same plot: -```r +``` r ggplot() + coord_cartesian(xlim = c(0.6, 1.4), ylim = c(0.6, 1.4)) + - add_phylopic(img = img_flip, x = 1.25, y = 1.25, ysize = 0.25) + - add_phylopic(img = img_rot, x = 1, y = 1, ysize = 0.25) + - add_phylopic(img = img_col, x = 0.75, y = 0.75, ysize = 0.25, + add_phylopic(img = img_flip, x = 1.25, y = 1.25, height = 0.25) + + add_phylopic(img = img_rot, x = 1, y = 1, height = 0.25) + + add_phylopic(img = img_col, x = 0.75, y = 0.75, height = 0.25, fill = "original") ``` @@ -196,7 +196,7 @@ ggplot() +

plot of chunk intro-transform-plot

-You'll notice that the rotated silhouette is smaller than the other two silhouettes. This is because our functions have arguments to specify the height (`ysize`). The width is automatically set to maintain the original aspect ratio of the silhouette. In this case, the aspect ratio of the rotated silhouette has changed, so the same height results in a smaller silhouette overall. +You'll notice that the rotated silhouette is smaller than the other two silhouettes. This is because we've specifed the `height` of our silhouettes. The width is then automatically set to maintain the original aspect ratio of the silhouette. In this case, the aspect ratio of the rotated silhouette has changed, so the same `height` results in a smaller silhouette overall. If you'd prefer, you could also specify the `width` of the silhouettes. For convenience, we have also included these transformation options within all of the visualization functions. The default fill is "black", hence why we needed to specify `fill = "original"` above. However, when the same transformed silhouette will be used for multiple visualizations, we suggest transforming the silhouette first, saving it as a new object, then using this new object for visualization purposes. @@ -204,7 +204,7 @@ For convenience, we have also included these transformation options within all o Now that you've made a plot and used some silhouettes, you should acknowledge the contributors that made those silhouettes. Fortunately, **rphylopic** includes the `get_attribution()` function to get contributor data about specific images: -```r +``` r # Get valid uuid uuid <- get_uuid(name = "Nycticebus") # Get attribution data for uuid @@ -242,7 +242,7 @@ get_attribution(uuid = uuid) This function can even write a little blurb for you to include in your publications: -```r +``` r # Get valid uuid uuid <- get_uuid(name = "Nycticebus") # Get attribution data for uuid @@ -250,14 +250,14 @@ get_attribution(uuid = uuid, text = TRUE) ``` ``` -## Organism silhouettes are from PhyloPic (https://www.phylopic.org/; T. Michael Keesey, 2023) and were added using the rphylopic R package ver. 1.3.0.9000 (Gearty & Jones, 2023). Silhouette was made by Mareike C. Janiak, 2020 (Public Domain Mark 1.0). Silhouette was contributed by Mareike Janiak. +## Organism silhouettes are from PhyloPic (https://www.phylopic.org/; T. Michael Keesey, 2023) and were added using the rphylopic R package ver. 1.4.0.9000 (Gearty & Jones, 2023). Silhouette was made by Mareike C. Janiak, 2020 (Public Domain Mark 1.0). Silhouette was contributed by Mareike Janiak. ``` ## Save an image You should be able to accomplish all of your visualization needs within R (see our other vignettes for examples), but in the rare case that need to use a silhouette outside of R, we've also got you covered with the `save_phylopic()` function. You can save silhouettes in a range of formats, including: Portable Document Format (PDF), Portable Network Graphics (PNG), Scale Vector Graphics (SVG), Tag Image File Format (TIFF), Joint Photographic Experts Group (JPEG), and bitmap (BMP). -```r +``` r # How do I save an image? # Get image img <- pick_phylopic(name = "Phascolarctos cinereus", n = 1) diff --git a/vignettes/a-getting-started.Rmd.orig b/vignettes/a-getting-started.Rmd.orig index 346f3ce..c852581 100644 --- a/vignettes/a-getting-started.Rmd.orig +++ b/vignettes/a-getting-started.Rmd.orig @@ -89,14 +89,14 @@ Let's start with base R by using `add_phylopic_base()`: ```{r intro-base-plot, warning = FALSE} # OK, now we've got the image we want... let's add it to a plot! plot(x = 1, y = 1, type = "n", ann = FALSE) -add_phylopic_base(img = img, x = 1.25, y = 1.25, ysize = 0.25) +add_phylopic_base(img = img, x = 1.25, y = 1.25, height = 0.25) # But can't we just add an image straight away using the UUID? Sure! uuid <- get_uuid(name = "Canis lupus", n = 1) -add_phylopic_base(uuid = uuid, x = 1, y = 1, ysize = 0.25) +add_phylopic_base(uuid = uuid, x = 1, y = 1, height = 0.25) # What about just using the first image linked to the name? Definitely! -add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, ysize = 0.25) +add_phylopic_base(name = "Canis lupus", x = 0.75, y = 0.75, height = 0.25) ``` Ah, you've found out our little secret! You can actually skip the steps of getting the UUID altogether by just searching for the desired taxon in `add_phylopic_base()`. However, this will always return the first matched silhouette meaning you might be missing out on all the other options! It's always worth checking out your options with `pick_phylopic()` first. @@ -108,14 +108,14 @@ You can also accomplish the same plot with the `{ggplot2}` package. Here, we'll library(ggplot2) p <- ggplot() + coord_cartesian(xlim = c(0.6, 1.4), ylim = c(0.6, 1.4)) + - add_phylopic(img = img, x = 1.25, y = 1.25, ysize = 0.25) + add_phylopic(img = img, x = 1.25, y = 1.25, height = 0.25) # But can't we just add an image straight away using the UUID? Sure! uuid <- get_uuid(name = "Canis lupus", n = 1) -p <- p + add_phylopic(uuid = uuid, x = 1, y = 1, ysize = 0.25) +p <- p + add_phylopic(uuid = uuid, x = 1, y = 1, height = 0.25) # What about just using the first image linked to the name? Definitely! -p + add_phylopic(name = "Canis lupus", x = 0.75, y = 0.75, ysize = 0.25) +p + add_phylopic(name = "Canis lupus", x = 0.75, y = 0.75, height = 0.25) ``` ## Transforming silhouettes @@ -147,13 +147,13 @@ Let's see what those look like in the same plot: ```{r intro-transform-plot} ggplot() + coord_cartesian(xlim = c(0.6, 1.4), ylim = c(0.6, 1.4)) + - add_phylopic(img = img_flip, x = 1.25, y = 1.25, ysize = 0.25) + - add_phylopic(img = img_rot, x = 1, y = 1, ysize = 0.25) + - add_phylopic(img = img_col, x = 0.75, y = 0.75, ysize = 0.25, + add_phylopic(img = img_flip, x = 1.25, y = 1.25, height = 0.25) + + add_phylopic(img = img_rot, x = 1, y = 1, height = 0.25) + + add_phylopic(img = img_col, x = 0.75, y = 0.75, height = 0.25, fill = "original") ``` -You'll notice that the rotated silhouette is smaller than the other two silhouettes. This is because our functions have arguments to specify the height (`ysize`). The width is automatically set to maintain the original aspect ratio of the silhouette. In this case, the aspect ratio of the rotated silhouette has changed, so the same height results in a smaller silhouette overall. +You'll notice that the rotated silhouette is smaller than the other two silhouettes. This is because we've specifed the `height` of our silhouettes. The width is then automatically set to maintain the original aspect ratio of the silhouette. In this case, the aspect ratio of the rotated silhouette has changed, so the same `height` results in a smaller silhouette overall. If you'd prefer, you could also specify the `width` of the silhouettes. For convenience, we have also included these transformation options within all of the visualization functions. The default fill is "black", hence why we needed to specify `fill = "original"` above. However, when the same transformed silhouette will be used for multiple visualizations, we suggest transforming the silhouette first, saving it as a new object, then using this new object for visualization purposes. diff --git a/vignettes/b-advanced-ggplot.Rmd b/vignettes/b-advanced-ggplot.Rmd index f158d13..557f8d5 100644 --- a/vignettes/b-advanced-ggplot.Rmd +++ b/vignettes/b-advanced-ggplot.Rmd @@ -9,7 +9,7 @@ vignette: > **Authors:** William Gearty & Lewis A. Jones -**Last updated:** 2024-04-23 +**Last updated:** 2024-07-30 @@ -26,7 +26,7 @@ The **rphylopic** package provides robust and flexible tools to access and trans First, let's load our libraries and the penguin data: -```r +``` r # Load libraries library(rphylopic) library(ggplot2) @@ -39,7 +39,7 @@ penguins_subset <- subset(penguins, !is.na(sex)) Now, let's pick a silhouette to use for the penguins. Let's pick #2: -```r +``` r # Pick a silhouette for Pygoscelis (here we pick #2) penguin <- pick_phylopic("Pygoscelis", n = 3, view = 3) ``` @@ -49,7 +49,7 @@ penguin <- pick_phylopic("Pygoscelis", n = 3, view = 3) You may have noticed in the preview that the silhouette was a little slanted. Let's rotate it clockwise just a smidgen: -```r +``` r # It's a little slanted, so let's rotate it a little bit penguin_rot <- rotate_phylopic(img = penguin, angle = 15) ``` @@ -57,7 +57,7 @@ penguin_rot <- rotate_phylopic(img = penguin, angle = 15) Now, let's draft the plot that we want to make. In this case, let's plot the penguins' bill lengths vs. their flipper lengths: -```r +``` r ggplot(penguins_subset) + geom_point(aes(x = bill_length_mm, y = flipper_length_mm)) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + @@ -70,14 +70,14 @@ ggplot(penguins_subset) +

plot of chunk ggplot-penguin-plot-1

-That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. We'll use the `geom_phylopic()` function, which will require us to make a `data.frame`. Note that the `x` and `y` aesthetics specify the center of the silhouette, and the `size` argument specifies how tall the silhouette is in the units of the y-axis. +That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. We'll use the `geom_phylopic()` function, which will require us to make a `data.frame`. Note that the `x` and `y` aesthetics specify the center of the silhouette, and the `height` argument specifies how tall the silhouette is in the units of the y-axis. -```r +``` r silhouette_df <- data.frame(x = 59, y = 215, species = "Adelie") ggplot(penguins_subset) + geom_point(aes(x = bill_length_mm, y = flipper_length_mm)) + - geom_phylopic(data = silhouette_df, aes(x = x, y = y), size = 30, + geom_phylopic(data = silhouette_df, aes(x = x, y = y), height = 30, img = penguin_rot) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + facet_wrap(~species, ncol = 1) + @@ -92,7 +92,7 @@ ggplot(penguins_subset) + Isn't that nifty! We can go a step further, though. What if we used little penguins instead of points?! To do that, we can use the `geom_phylopic()` function instead of the `geom_point()` function (in this case, we want to use the same image for each x-y pair): -```r +``` r ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm)) + @@ -106,14 +106,31 @@ ggplot(penguins_subset) +

plot of chunk ggplot-penguin-plot-3

-The default silhouette size for `geom_phylopic()` is 1.5 which appears to work well given the range of the y-axis here. However, we can also vary the size based on some other aspect of data. In this case, let's try making the size of the silhouettes relative to the penguins' body masses. `{ggplot2}` should work its magic and make them reasonable sizes for the plot: +The default silhouette size for `geom_phylopic()` is as large as will fit within the plot area. That won't work well here. Instead, we can specify a `height` or `width` to use (in y-axis or x-axis units, respectively): -```r +``` r +ggplot(penguins_subset) + + geom_phylopic(img = penguin_rot, + aes(x = bill_length_mm, y = flipper_length_mm), height = 5) + + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + + facet_wrap(~species, ncol = 1) + + theme_bw(base_size = 15) +``` + +
+plot of chunk ggplot-penguin-plot-3b +

plot of chunk ggplot-penguin-plot-3b

+
+ +Alternatively, we can vary the height based on some other aspect of data, and the values will be automatically scaled for us. In this case, let's try making the size of the silhouettes relative to the penguins' body masses. Behind the scenes, __rphylopic__ will work its magic and rescale them to values between 1 and 6. Note that, depending on your own data, you may want to customize how the values are scaled by using `scale_height_continuous()` (or `scale_width_continuous()` if you are using the `width` aesthetic) just as you would use `scale_size_continuous()`. We'll just use the defaults here: + + +``` r ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g)) + + height = body_mass_g)) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) @@ -124,14 +141,14 @@ ggplot(penguins_subset) +

plot of chunk ggplot-penguin-plot-4

-Finally, let's give the female and male penguins different fill colors. Note that the default for `geom_phylopic()` is to not display a legend, so we need to set `show.legend = TRUE`. However, we only want a legend for the fill colors, so we use `guide = "none"` for the size scale. We also want to show the fill color in the legend, so we need to override the shape: +Nice! Finally, let's give the female and male penguins different fill colors. Note that the default for `geom_phylopic()` is to not display a legend, so we need to set `show.legend = TRUE`. However, we only want a legend for the fill colors, so we use `guide = "none"` for the size scale. We also want to show the fill color in the legend, so we need to override the shape: -```r +``` r ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g, fill = sex), + height = body_mass_g, fill = sex), show.legend = TRUE) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + scale_size_continuous(guide = "none") + @@ -140,7 +157,7 @@ ggplot(penguins_subset) + guide = guide_legend(override.aes = list(shape = 21))) + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) + - theme(legend.position = c(0.9, 0.9)) + theme(legend.position = "inside", legend.position.inside = c(0.9, 0.9)) ```
@@ -148,14 +165,14 @@ ggplot(penguins_subset) +

plot of chunk ggplot-penguin-plot-5

-Hmm...the colored dots in the legend are great, but lucky for us, the package also supplies a convenient way to include silhouettes in the legend. Due to technical constraints, you'll need to specify the images/uuids/names again within `phylopic_key_glyph()`. If you supply more than one silhouette to this function, it will cycle through them as it generates legend keys (recycling as needed). Note that `phylopic_key_glyph()` does not currently support the size aesthetic. +Hmm...the colored dots in the legend are great, but lucky for us, the package also supplies a convenient way to include silhouettes in the legend. Due to technical constraints, you'll need to specify the images/uuids/names again within `phylopic_key_glyph()`. If you supply more than one silhouette to this function, it will cycle through them as it generates legend keys (recycling as needed). Note that `phylopic_key_glyph()` does not currently support the `height`/`width` aesthetics. -```r +``` r ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g, fill = sex), + height = body_mass_g, fill = sex), show.legend = TRUE, key_glyph = phylopic_key_glyph(img = penguin_rot)) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + @@ -164,7 +181,7 @@ ggplot(penguins_subset) + labels = c("Female", "Male")) + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) + - theme(legend.position.inside = c(0.9, 0.9)) + theme(legend.position = "inside", legend.position.inside = c(0.9, 0.9)) ```
@@ -180,7 +197,7 @@ In much the same way as generic x-y plotting, the **rphylopic** package can be u First, let's load our libraries and the tetrapod data: -```r +``` r # Load libraries library(rphylopic) library(ggplot2) @@ -194,7 +211,7 @@ data(tetrapods) Then we'll subset our occurrences to only those for *Diplocaulus*: -```r +``` r # Subset to desired group tetrapods <- subset(tetrapods, genus == "Diplocaulus") ``` @@ -202,7 +219,7 @@ tetrapods <- subset(tetrapods, genus == "Diplocaulus") Now, let's plot those occurrences on a world map. `{ggplot2}` and it's built-in function `map_data()` make this a breeze. Note that we use `alpha = 0.75` in case there are multiple occurrences in the same place. That way, the darker the fill color, the more occurrences in that geographic location. -```r +``` r # Get map data world <- st_as_sf(map("world", fill = TRUE, plot = FALSE)) world <- st_wrap_dateline(world) @@ -210,7 +227,7 @@ world <- st_wrap_dateline(world) ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_point(data = tetrapods, aes(x = lng, y = lat), - size = 4, alpha = 0.75, fill = "blue") + + height = 4, alpha = 0.75, fill = "blue") + theme_void() + coord_sf() ``` @@ -223,11 +240,11 @@ ggplot(world) + Now, as with the penguin figure above, we can easily replace those points with silhouettes. -```r +``` r ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_phylopic(data = tetrapods, aes(x = lng, y = lat, name = genus), - size = 4, alpha = 0.75, fill = "blue") + + height = 4, alpha = 0.75, fill = "blue") + theme_void() + coord_sf() ``` @@ -241,17 +258,17 @@ Snazzy! Note that while we used the genus name as the `name` aesthetic here, we easily could have done `name = "Diplocaulus"` outside of the `aes()` call instead. However, if we were plotting occurrences of multiple genera, we'd definitely want to plot them as different silhouettes using `name = genus` within the `aes()` call. -Also, note that we could change the projection of the map and data using the `crs` and `default_crs` arguments in `coord_sf()`. When projecting data, note that the y-axis limits will change to projected limits. For example, in the Robinson projection, the y-axis limits are roughly -8,600,000 and 8,600,000 in projected coordinates. Therefore, you may need to adjust the `size` argument/aesthetic accordingly when projecting maps and data. +Also, note that we could change the projection of the map and data using the `crs` and `default_crs` arguments in `coord_sf()`. When projecting data, note that the y-axis limits will change to projected limits. For example, in the Robinson projection, the y-axis limits are roughly -8,600,000 and 8,600,000 in projected coordinates. Therefore, you may need to adjust the `height` argument/aesthetic accordingly when projecting maps and data. -```r +``` r # Set up a bounding box bbox <- st_graticule(crs = st_crs("ESRI:54030"), lat = c(-89.9, 89.9), lon = c(-179.9, 179.9)) ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_phylopic(data = tetrapods, aes(x = lng, y = lat, name = genus), - size = 4E5, alpha = 0.75, fill = "blue") + + height = 4E5, alpha = 0.75, fill = "blue") + geom_sf(data = bbox) + theme_void() + coord_sf(default_crs = st_crs(4326), crs = st_crs("ESRI:54030")) @@ -266,7 +283,7 @@ ggplot(world) + Another common use case of PhyloPic silhouettes is to represent taxonomic information. In this example, we demonstrate how to use silhouettes within a phylogenetic framework. In this case, the phylogeny, taken from the `{phytools}` package, includes taxa across all vertebrates. Even many taxonomic experts are unlikely to know the scientific names of these 11 disparate taxa, so we'll replace the names with PhyloPic silhouettes. First, let's load our libraries and data: -```r +``` r # Load libraries library(rphylopic) library(ggplot2) @@ -278,7 +295,7 @@ data(vertebrate.tree) We can use a vectorized version of the `get_uuid()` function to retrieve UUID values for all of the species at once. However, just in case we get an error, we wrap the `get_uuid()` call in a `tryCatch()` call. This way, we should get either a UUID or `NA` for each species: -```r +``` r # Make a data.frame for the PhyloPic names vertebrate_data <- data.frame(species = vertebrate.tree$tip.label, uuid = NA) # Try to get PhyloPic UUIDs for the species names @@ -292,7 +309,7 @@ vertebrate_data ``` ## species uuid ## 1 Carcharodon_carcharias 00f208a3-887d-4ae8-838c-2124f53b9fc1 -## 2 Carassius_auratus b1995423-0170-4ff1-af49-1cdf692d8fc7 +## 2 Carassius_auratus ace2b280-abe8-4dce-96db-be4e393f836d ## 3 Latimeria_chalumnae 12c38a8a-6d68-4af3-ada3-05cafdfc25c2 ## 4 Homo_sapiens 9c6af553-390c-4bdd-baeb-6992cbc540b1 ## 5 Lemur_catta 8a187391-82a3-4d9b-a402-3a310bf7dc38 @@ -307,7 +324,7 @@ vertebrate_data Oh no, we weren't able to find a silhouette for *Myotis lucifugus* (little brown bat)! Good thing we used `tryCatch()`! Given the coarse resolution of this phylogeny, we can just grab a silhouette for the subfamily (Vespertilioninae): -```r +``` r vertebrate_data$uuid[vertebrate_data$species == "Myotis_lucifugus"] <- get_uuid("Vespertilioninae") ``` @@ -315,7 +332,7 @@ vertebrate_data$uuid[vertebrate_data$species == "Myotis_lucifugus"] <- I'm also not a huge fan of the boar picture. Let's choose an alternative with `pick_phylopic()`. -```r +``` r # Pick a different boar image; we'll pick #2 boar_svg <- pick_phylopic("Sus scrofa", view = 5) # Extract the UUID @@ -328,14 +345,14 @@ vertebrate_data$uuid[vertebrate_data$species == "Sus_scrofa"] <- Now that we've got our phylogeny and UUIDs, we could go ahead and create our figure. However, time for a quick aside. The time required for `geom_phylopic()` and the other **rphylopic** visualization functions scales with the number of *unique* names/UUIDs, not the number of plotted silhouettes. Therefore, if you are plotting a lot of *different* silhouettes, these functions can take quite a long time to poll PhyloPic for each unique name, download the silhouettes, and convert them to be added to the plot. If you plan to use the same silhouettes for multiple figures, we strongly suggest that you poll PhyloPic yourself using `get_phylopic()` or `pick_phylopic()`, save the silhouettes to your R environment, and then these use image objects in the visualization functions (with the `img` argument/aesthetic). Following this advice, let's get image objects for these 11 species before we make our figure. Note that, since we've used `get_uuid()` to get these 11 UUIDs, we know that they are valid, so we don't need to catch any errors this time. -```r +``` r vertebrate_data$svg <- lapply(vertebrate_data$uuid, get_phylopic) ``` Now let's go ahead and plot our phylogeny with the [ggtree](https://www.bioconductor.org/packages/ggtree) package: -```r +``` r library(ggtree) # Plot the tree ggtree(vertebrate.tree, size = 1, layout = "circular") @@ -349,7 +366,7 @@ ggtree(vertebrate.tree, size = 1, layout = "circular") Hmm...that's a bit boring. Let's add a geological timescale to the background using `coord_geo_polar()` from the `{deeptime}` package. Note that we need to use the `revts()` function to reverse the time axis to work with `coord_geo_polar()`. -```r +``` r library(deeptime) # Plot the tree with a geological timescale in the background revts(ggtree(vertebrate.tree, size = 1)) + @@ -362,11 +379,6 @@ revts(ggtree(vertebrate.tree, size = 1)) + theme_classic() ``` -``` -## Scale for y is already present. -## Adding another scale for y, which will replace the existing scale. -``` -
plot of chunk ggplot-phylo-plot-2

plot of chunk ggplot-phylo-plot-2

@@ -375,9 +387,9 @@ revts(ggtree(vertebrate.tree, size = 1)) + That's looking a lot prettier! Let's go ahead and add our silhouettes now. Note that we need to attach the `vertebrate_data` object with the `%<+%` operator from `{ggtree}`. -```r +``` r revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data + - geom_phylopic(aes(img = svg), size = 25) + + geom_phylopic(aes(img = svg), height = 25) + scale_x_continuous(breaks = seq(-500, 0, 100), labels = seq(500, 0, -100), limits = c(-500, 0), @@ -392,10 +404,10 @@ revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data +

plot of chunk ggplot-phylo-plot-3

-Note that only a single size is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: +Note that only a single height is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: -```r +``` r vertebrate_data$svg[[1]] <- rotate_phylopic(img = vertebrate_data$svg[[1]]) vertebrate_data$svg[[8]] <- rotate_phylopic(img = vertebrate_data$svg[[8]]) ``` @@ -403,9 +415,9 @@ vertebrate_data$svg[[8]] <- rotate_phylopic(img = vertebrate_data$svg[[8]]) And now the finished product: -```r +``` r revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data + - geom_phylopic(aes(img = svg), size = 25) + + geom_phylopic(aes(img = svg), height = 25) + scale_x_continuous(breaks = seq(-500, 0, 100), labels = seq(500, 0, -100), limits = c(-500, 0), diff --git a/vignettes/b-advanced-ggplot.Rmd.orig b/vignettes/b-advanced-ggplot.Rmd.orig index 5d78cfc..310f480 100644 --- a/vignettes/b-advanced-ggplot.Rmd.orig +++ b/vignettes/b-advanced-ggplot.Rmd.orig @@ -67,13 +67,13 @@ ggplot(penguins_subset) + theme_bw(base_size = 15) ``` -That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. We'll use the `geom_phylopic()` function, which will require us to make a `data.frame`. Note that the `x` and `y` aesthetics specify the center of the silhouette, and the `size` argument specifies how tall the silhouette is in the units of the y-axis. +That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. We'll use the `geom_phylopic()` function, which will require us to make a `data.frame`. Note that the `x` and `y` aesthetics specify the center of the silhouette, and the `height` argument specifies how tall the silhouette is in the units of the y-axis. ```{r ggplot-penguin-plot-2} silhouette_df <- data.frame(x = 59, y = 215, species = "Adelie") ggplot(penguins_subset) + geom_point(aes(x = bill_length_mm, y = flipper_length_mm)) + - geom_phylopic(data = silhouette_df, aes(x = x, y = y), size = 30, + geom_phylopic(data = silhouette_df, aes(x = x, y = y), height = 30, img = penguin_rot) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + facet_wrap(~species, ncol = 1) + @@ -91,25 +91,36 @@ ggplot(penguins_subset) + theme_bw(base_size = 15) ``` -The default silhouette size for `geom_phylopic()` is 1.5 which appears to work well given the range of the y-axis here. However, we can also vary the size based on some other aspect of data. In this case, let's try making the size of the silhouettes relative to the penguins' body masses. `{ggplot2}` should work its magic and make them reasonable sizes for the plot: +The default silhouette size for `geom_phylopic()` is as large as will fit within the plot area. That won't work well here. Instead, we can specify a `height` or `width` to use (in y-axis or x-axis units, respectively): + +```{r ggplot-penguin-plot-3b} +ggplot(penguins_subset) + + geom_phylopic(img = penguin_rot, + aes(x = bill_length_mm, y = flipper_length_mm), height = 5) + + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + + facet_wrap(~species, ncol = 1) + + theme_bw(base_size = 15) +``` + +Alternatively, we can vary the height based on some other aspect of data, and the values will be automatically scaled for us. In this case, let's try making the size of the silhouettes relative to the penguins' body masses. Behind the scenes, __rphylopic__ will work its magic and rescale them to values between 1 and 6. Note that, depending on your own data, you may want to customize how the values are scaled by using `scale_height_continuous()` (or `scale_width_continuous()` if you are using the `width` aesthetic) just as you would use `scale_size_continuous()`. We'll just use the defaults here: ```{r ggplot-penguin-plot-4} ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g)) + + height = body_mass_g)) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) ``` -Finally, let's give the female and male penguins different fill colors. Note that the default for `geom_phylopic()` is to not display a legend, so we need to set `show.legend = TRUE`. However, we only want a legend for the fill colors, so we use `guide = "none"` for the size scale. We also want to show the fill color in the legend, so we need to override the shape: +Nice! Finally, let's give the female and male penguins different fill colors. Note that the default for `geom_phylopic()` is to not display a legend, so we need to set `show.legend = TRUE`. However, we only want a legend for the fill colors, so we use `guide = "none"` for the size scale. We also want to show the fill color in the legend, so we need to override the shape: ```{r ggplot-penguin-plot-5} ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g, fill = sex), + height = body_mass_g, fill = sex), show.legend = TRUE) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + scale_size_continuous(guide = "none") + @@ -118,16 +129,16 @@ ggplot(penguins_subset) + guide = guide_legend(override.aes = list(shape = 21))) + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) + - theme(legend.position = c(0.9, 0.9)) + theme(legend.position = "inside", legend.position.inside = c(0.9, 0.9)) ``` -Hmm...the colored dots in the legend are great, but lucky for us, the package also supplies a convenient way to include silhouettes in the legend. Due to technical constraints, you'll need to specify the images/uuids/names again within `phylopic_key_glyph()`. If you supply more than one silhouette to this function, it will cycle through them as it generates legend keys (recycling as needed). Note that `phylopic_key_glyph()` does not currently support the size aesthetic. +Hmm...the colored dots in the legend are great, but lucky for us, the package also supplies a convenient way to include silhouettes in the legend. Due to technical constraints, you'll need to specify the images/uuids/names again within `phylopic_key_glyph()`. If you supply more than one silhouette to this function, it will cycle through them as it generates legend keys (recycling as needed). Note that `phylopic_key_glyph()` does not currently support the `height`/`width` aesthetics. ```{r ggplot-penguin-plot-6} ggplot(penguins_subset) + geom_phylopic(img = penguin_rot, aes(x = bill_length_mm, y = flipper_length_mm, - size = body_mass_g, fill = sex), + height = body_mass_g, fill = sex), show.legend = TRUE, key_glyph = phylopic_key_glyph(img = penguin_rot)) + labs(x = "Bill length (mm)", y = "Flipper length (mm)") + @@ -136,7 +147,7 @@ ggplot(penguins_subset) + labels = c("Female", "Male")) + facet_wrap(~species, ncol = 1) + theme_bw(base_size = 15) + - theme(legend.position.inside = c(0.9, 0.9)) + theme(legend.position = "inside", legend.position.inside = c(0.9, 0.9)) ``` Now that's a nice figure! @@ -174,7 +185,7 @@ world <- st_wrap_dateline(world) ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_point(data = tetrapods, aes(x = lng, y = lat), - size = 4, alpha = 0.75, fill = "blue") + + height = 4, alpha = 0.75, fill = "blue") + theme_void() + coord_sf() ``` @@ -185,7 +196,7 @@ Now, as with the penguin figure above, we can easily replace those points with s ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_phylopic(data = tetrapods, aes(x = lng, y = lat, name = genus), - size = 4, alpha = 0.75, fill = "blue") + + height = 4, alpha = 0.75, fill = "blue") + theme_void() + coord_sf() ``` @@ -194,7 +205,7 @@ Snazzy! Note that while we used the genus name as the `name` aesthetic here, we easily could have done `name = "Diplocaulus"` outside of the `aes()` call instead. However, if we were plotting occurrences of multiple genera, we'd definitely want to plot them as different silhouettes using `name = genus` within the `aes()` call. -Also, note that we could change the projection of the map and data using the `crs` and `default_crs` arguments in `coord_sf()`. When projecting data, note that the y-axis limits will change to projected limits. For example, in the Robinson projection, the y-axis limits are roughly -8,600,000 and 8,600,000 in projected coordinates. Therefore, you may need to adjust the `size` argument/aesthetic accordingly when projecting maps and data. +Also, note that we could change the projection of the map and data using the `crs` and `default_crs` arguments in `coord_sf()`. When projecting data, note that the y-axis limits will change to projected limits. For example, in the Robinson projection, the y-axis limits are roughly -8,600,000 and 8,600,000 in projected coordinates. Therefore, you may need to adjust the `height` argument/aesthetic accordingly when projecting maps and data. ```{r ggplot-geog-plot-3, fig.height = 3.5, warning = FALSE} # Set up a bounding box @@ -203,7 +214,7 @@ bbox <- st_graticule(crs = st_crs("ESRI:54030"), ggplot(world) + geom_sf(fill = "lightgray", color = "darkgrey", linewidth = 0.1) + geom_phylopic(data = tetrapods, aes(x = lng, y = lat, name = genus), - size = 4E5, alpha = 0.75, fill = "blue") + + height = 4E5, alpha = 0.75, fill = "blue") + geom_sf(data = bbox) + theme_void() + coord_sf(default_crs = st_crs(4326), crs = st_crs("ESRI:54030")) @@ -272,7 +283,7 @@ ggtree(vertebrate.tree, size = 1, layout = "circular") Hmm...that's a bit boring. Let's add a geological timescale to the background using `coord_geo_polar()` from the `{deeptime}` package. Note that we need to use the `revts()` function to reverse the time axis to work with `coord_geo_polar()`. -```{r ggplot-phylo-plot-2} +```{r ggplot-phylo-plot-2, message = FALSE} library(deeptime) # Plot the tree with a geological timescale in the background revts(ggtree(vertebrate.tree, size = 1)) + @@ -289,7 +300,7 @@ That's looking a lot prettier! Let's go ahead and add our silhouettes now. Note ```{r ggplot-phylo-plot-3, message = FALSE, warning = FALSE} revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data + - geom_phylopic(aes(img = svg), size = 25) + + geom_phylopic(aes(img = svg), height = 25) + scale_x_continuous(breaks = seq(-500, 0, 100), labels = seq(500, 0, -100), limits = c(-500, 0), @@ -299,7 +310,7 @@ revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data + theme_classic() ``` -Note that only a single size is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: +Note that only a single height is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: ```{r} vertebrate_data$svg[[1]] <- rotate_phylopic(img = vertebrate_data$svg[[1]]) @@ -310,7 +321,7 @@ And now the finished product: ```{r ggplot-phylo-plot-4, message = FALSE, warning = FALSE} revts(ggtree(vertebrate.tree, size = 1)) %<+% vertebrate_data + - geom_phylopic(aes(img = svg), size = 25) + + geom_phylopic(aes(img = svg), height = 25) + scale_x_continuous(breaks = seq(-500, 0, 100), labels = seq(500, 0, -100), limits = c(-500, 0), diff --git a/vignettes/base-phylo-plot-3-1.png b/vignettes/base-phylo-plot-3-1.png index 0e0ffc8..49d1718 100644 Binary files a/vignettes/base-phylo-plot-3-1.png and b/vignettes/base-phylo-plot-3-1.png differ diff --git a/vignettes/base-phylo-plot-4-1.png b/vignettes/base-phylo-plot-4-1.png index 475af7a..872e582 100644 Binary files a/vignettes/base-phylo-plot-4-1.png and b/vignettes/base-phylo-plot-4-1.png differ diff --git a/vignettes/c-advanced-base.Rmd b/vignettes/c-advanced-base.Rmd index 36bf297..cc33c11 100644 --- a/vignettes/c-advanced-base.Rmd +++ b/vignettes/c-advanced-base.Rmd @@ -9,7 +9,7 @@ vignette: > **Authors:** William Gearty & Lewis A. Jones -**Last updated:** 2024-04-23 +**Last updated:** 2024-07-30 @@ -26,7 +26,7 @@ The **rphylopic** package provides robust and flexible tools to access and trans First, let's load our libraries and the penguin data: -```r +``` r # Load libraries library(rphylopic) library(palmerpenguins) @@ -37,7 +37,7 @@ data(penguins) Now, let's pick a silhouette to use for the penguins. Let's pick #2: -```r +``` r # Pick a silhouette for Pygoscelis (here we pick #2) penguin <- pick_phylopic("Pygoscelis", n = 3, view = 3) ``` @@ -47,7 +47,7 @@ penguin <- pick_phylopic("Pygoscelis", n = 3, view = 3) You may have noticed in the preview that the silhouette was a little slanted. Let's rotate it clockwise just a smidgen: -```r +``` r # It's a little slanted, so let's rotate it a little bit penguin_rot <- rotate_phylopic(img = penguin, angle = 15) ``` @@ -55,7 +55,7 @@ penguin_rot <- rotate_phylopic(img = penguin, angle = 15) Now, let's clean the data and split the data among the three species: -```r +``` r # Subset the data to remove rows with missing sex values penguins_subset <- subset(penguins, !is.na(sex)) # Split the data by species @@ -65,7 +65,7 @@ species_split <- split(penguins_subset, penguins_subset$species) Now we're going to make a three panel plot, one panel for each species. Within each panel, we'll plot the penguins' bill lengths vs. their flipper lengths: -```r +``` r # Set up the plot area par(mfrow = c(3, 1), mar = c(4, 4, 2, 1)) @@ -85,10 +85,10 @@ for (i in seq_along(species_split)) {

plot of chunk base-penguin-plot-1

-That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. To do that, we can use the `add_phylopic_base()` function. Note that the `x` and `y` arguments specify the center of the silhouette, and the `ysize` argument specifies how tall the silhouette is in the units of the y-axis. +That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. To do that, we can use the `add_phylopic_base()` function. Note that the `x` and `y` arguments specify the center of the silhouette, and the `height` argument specifies how tall the silhouette is in the units of the y-axis. -```r +``` r # Set up the plot area par(mfrow = c(3, 1), mar = c(4, 4, 2, 1)) @@ -100,7 +100,7 @@ for (i in seq_along(species_split)) { main = names(species_split)[i], xlim = range(penguins_subset$bill_length_mm, na.rm = TRUE), ylim = range(penguins_subset$flipper_length_mm, na.rm = TRUE)) - if (i == 1) add_phylopic_base(img = penguin_rot, x = 59, y = 215, ysize = 30) + if (i == 1) add_phylopic_base(img = penguin_rot, x = 59, y = 215, height = 30) } ``` @@ -112,7 +112,7 @@ for (i in seq_along(species_split)) { Isn't that nifty! We can go a step further, though. What if we used little penguins instead of points?! To do that, we can once again use the `add_phylopic_base()` function. In this case, we can again specify `img = penguin_rot` since we want to use the same image for each x-y pair: -```r +``` r # Set up the plot area par(mfrow = c(3, 1), mar = c(4, 4, 2, 1)) @@ -137,7 +137,7 @@ for (i in seq_along(species_split)) { Oh no, the silhouettes are way too big! The default for `add_phylopic_base()` is to make the silhouette the same height as the plot, which is way too big for our case here. Let's make the size of the silhouettes relative to the penguins' body masses. A scaling factor of 8 seems to work well for this size figure. -```r +``` r par(mfrow = c(3, 1), mar = c(4, 4, 2, 1)) for (i in seq_along(species_split)) { @@ -149,7 +149,7 @@ for (i in seq_along(species_split)) { add_phylopic_base(img = penguin_rot, x = species_data$bill_length_mm, y = species_data$flipper_length_mm, - ysize = species_data$body_mass_g / + height = species_data$body_mass_g / max(penguins_subset$body_mass_g, na.rm = TRUE) * 8) } ``` @@ -162,7 +162,7 @@ for (i in seq_along(species_split)) { Finally, let's give the female and male penguins different fill colors. We'll also add a legend to the last panel. -```r +``` r par(mfrow = c(3, 1), mar = c(4, 4, 2, 1)) for (i in seq_along(species_split)) { @@ -174,7 +174,7 @@ for (i in seq_along(species_split)) { add_phylopic_base(img = penguin_rot, x = species_data$bill_length_mm, y = species_data$flipper_length_mm, - ysize = species_data$body_mass_g / + height = species_data$body_mass_g / max(penguins_subset$body_mass_g, na.rm = TRUE) * 8, fill = ifelse(species_data$sex == "male", "blue", "orange")) } @@ -197,7 +197,7 @@ In much the same way as generic x-y plotting, the **rphylopic** package can be u First, let's load our libraries and the tetrapod data: -```r +``` r # Load libraries library(rphylopic) library(maps) @@ -209,7 +209,7 @@ data(tetrapods) Then we'll subset our occurrences to only those for *Diplocaulus*: -```r +``` r # Subset to desired group tetrapods <- subset(tetrapods, genus == "Diplocaulus") ``` @@ -217,7 +217,7 @@ tetrapods <- subset(tetrapods, genus == "Diplocaulus") Now, let's plot those occurrences on a world map. Here we use the `{geodata}` and `{raster}` packages to generate the map. Then we add colored points on top of this. Note that we use `alpha = 0.75` in case there are multiple occurrences in the same place. That way, the darker the color, the more occurrences in that geographic location. -```r +``` r # Plot map map("world", col = "lightgrey", fill = TRUE) # Plot points @@ -233,10 +233,10 @@ points(x = tetrapods$lng, y = tetrapods$lat, cex = 2, pch = 16, Now, as with the penguin figure above, we can easily replace those points with silhouettes. -```r +``` r map("world", col = "lightgrey", fill = TRUE) add_phylopic_base(name = "Diplocaulus", x = tetrapods$lng, y = tetrapods$lat, - ysize = 8, fill = "blue", alpha = 0.75) + height = 8, fill = "blue", alpha = 0.75) ```
@@ -252,7 +252,7 @@ Note that we used the genus name as the `name` argument here. However, if we wer Another common use case of PhyloPic silhouettes is to represent taxonomic information. In this example, we demonstrate how to use silhouettes within a phylogenetic framework. In this case, the phylogeny, taken from the `{phytools}` package, includes taxa across all vertebrates. Even many taxonomic experts are unlikely to know the scientific names of these 11 disparate taxa, so we'll replace the names with PhyloPic silhouettes. First, let's load our libraries and data: -```r +``` r # Load libraries library(rphylopic) library(ggplot2) @@ -264,7 +264,7 @@ data(vertebrate.tree) We can use a vectorized version of the `get_uuid()` function to retrieve UUID values for all of the species at once. However, just in case we get an error, we wrap the `get_uuid()` call in a `tryCatch()` call. This way, we should get either a UUID or `NA` for each species: -```r +``` r # Make a data.frame for the PhyloPic names vertebrate_data <- data.frame(species = vertebrate.tree$tip.label, uuid = NA) # Try to get PhyloPic UUIDs for the species names @@ -278,7 +278,7 @@ vertebrate_data ``` ## species uuid ## 1 Carcharodon_carcharias 00f208a3-887d-4ae8-838c-2124f53b9fc1 -## 2 Carassius_auratus b1995423-0170-4ff1-af49-1cdf692d8fc7 +## 2 Carassius_auratus ace2b280-abe8-4dce-96db-be4e393f836d ## 3 Latimeria_chalumnae 12c38a8a-6d68-4af3-ada3-05cafdfc25c2 ## 4 Homo_sapiens 9c6af553-390c-4bdd-baeb-6992cbc540b1 ## 5 Lemur_catta 8a187391-82a3-4d9b-a402-3a310bf7dc38 @@ -293,7 +293,7 @@ vertebrate_data Oh no, we weren't able to find a silhouette for *Myotis lucifugus* (little brown bat)! Good thing we used `tryCatch()`! Given the coarse resolution of this phylogeny, we can just grab a silhouette for the subfamily (Vespertilioninae): -```r +``` r vertebrate_data$uuid[vertebrate_data$species == "Myotis_lucifugus"] <- get_uuid("Vespertilioninae") ``` @@ -301,7 +301,7 @@ vertebrate_data$uuid[vertebrate_data$species == "Myotis_lucifugus"] <- I'm also not a huge fan of the boar picture. Let's choose an alternative with `pick_phylopic()`. -```r +``` r # Pick a different boar image; we'll pick #2 boar_svg <- pick_phylopic("Sus scrofa", view = 5) # Extract the UUID @@ -314,14 +314,14 @@ vertebrate_data$uuid[vertebrate_data$species == "Sus_scrofa"] <- Now that we've got our phylogeny and UUIDs, we could go ahead and create our figure. However, time for a quick aside. The time required for `add_phylopic_base()` and the other **rphylopic** visualization functions scales with the number of *unique* names/UUIDs, not the number of plotted silhouettes. Therefore, if you are plotting a lot of *different* silhouettes, these functions can take quite a long time to poll PhyloPic for each unique name, download the silhouettes, and convert them to be added to the plot. If you plan to use the same silhouettes for multiple figures, we strongly suggest that you poll PhyloPic yourself using `get_phylopic()` or `pick_phylopic()`, save the silhouettes to your R environment, and then these use image objects in the visualization functions (with the `img` argument/aesthetic). Following this advice, let's get image objects for these 11 species before we make our figure. Note that, since we've used `get_uuid()` to get these 11 UUIDs, we know that they are valid, so we don't need to catch any errors this time. -```r +``` r vertebrate_data$svg <- lapply(vertebrate_data$uuid, get_phylopic) ``` Now let's go ahead and plot our phylogeny with the `{ape}` package: -```r +``` r library(ape) # Plot the tree plot(vertebrate.tree) @@ -335,7 +335,7 @@ plot(vertebrate.tree) Hmm...that's a bit boring. Let's add a geological timescale to the bottom using `axis_geo_phylo()` from the `{palaeoverse}` package. -```r +``` r library(palaeoverse) # Plot the tree with a geological timescale on the bottom plot(vertebrate.tree) @@ -350,11 +350,11 @@ axis_geo_phylo(intervals = "periods") That's looking a lot prettier! Let's go ahead and replace the tip labels with our silhouettes now using `add_phylopic_base()`. Note that while it may look like all of the tips have an x-axis value of 0, that's actually a trick from `axis_geo_phylo()`. In reality, the left end of the x-axis is 0, and the right end of the x-axis is the total height of the tree. We can calculate this using the `nodeHeights()` function. -```r +``` r plot(vertebrate.tree, show.tip.label = FALSE) axis_geo_phylo(intervals = "periods") add_phylopic_base(img = vertebrate_data$svg, - x = max(nodeHeights(vertebrate.tree)), y = 1:11, ysize = 0.5) + x = max(nodeHeights(vertebrate.tree)), y = 1:11, height = 0.5) ```
@@ -365,7 +365,7 @@ add_phylopic_base(img = vertebrate_data$svg, Note that only a single size is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: -```r +``` r vertebrate_data$svg[[1]] <- rotate_phylopic(img = vertebrate_data$svg[[1]]) vertebrate_data$svg[[8]] <- rotate_phylopic(img = vertebrate_data$svg[[8]]) ``` @@ -373,11 +373,11 @@ vertebrate_data$svg[[8]] <- rotate_phylopic(img = vertebrate_data$svg[[8]]) And now the finished product: -```r +``` r plot(vertebrate.tree, show.tip.label = FALSE) axis_geo_phylo(intervals = "periods") add_phylopic_base(img = vertebrate_data$svg, - x = max(nodeHeights(vertebrate.tree)), y = 1:11, ysize = 0.5) + x = max(nodeHeights(vertebrate.tree)), y = 1:11, height = 0.5) ```
diff --git a/vignettes/c-advanced-base.Rmd.orig b/vignettes/c-advanced-base.Rmd.orig index 47d432e..6b5b8d1 100644 --- a/vignettes/c-advanced-base.Rmd.orig +++ b/vignettes/c-advanced-base.Rmd.orig @@ -81,7 +81,7 @@ for (i in seq_along(species_split)) { } ``` -That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. To do that, we can use the `add_phylopic_base()` function. Note that the `x` and `y` arguments specify the center of the silhouette, and the `ysize` argument specifies how tall the silhouette is in the units of the y-axis. +That's a nice basic plot! But you know what would make it nicer? If we added a penguin silhouette to the plot. Sadly, we don't have a different silhouette for each species (although we could make one...), so let's just go with putting a single silhouette in the top panel. To do that, we can use the `add_phylopic_base()` function. Note that the `x` and `y` arguments specify the center of the silhouette, and the `height` argument specifies how tall the silhouette is in the units of the y-axis. ```{r base-penguin-plot-2} # Set up the plot area @@ -95,7 +95,7 @@ for (i in seq_along(species_split)) { main = names(species_split)[i], xlim = range(penguins_subset$bill_length_mm, na.rm = TRUE), ylim = range(penguins_subset$flipper_length_mm, na.rm = TRUE)) - if (i == 1) add_phylopic_base(img = penguin_rot, x = 59, y = 215, ysize = 30) + if (i == 1) add_phylopic_base(img = penguin_rot, x = 59, y = 215, height = 30) } ``` @@ -132,7 +132,7 @@ for (i in seq_along(species_split)) { add_phylopic_base(img = penguin_rot, x = species_data$bill_length_mm, y = species_data$flipper_length_mm, - ysize = species_data$body_mass_g / + height = species_data$body_mass_g / max(penguins_subset$body_mass_g, na.rm = TRUE) * 8) } ``` @@ -151,7 +151,7 @@ for (i in seq_along(species_split)) { add_phylopic_base(img = penguin_rot, x = species_data$bill_length_mm, y = species_data$flipper_length_mm, - ysize = species_data$body_mass_g / + height = species_data$body_mass_g / max(penguins_subset$body_mass_g, na.rm = TRUE) * 8, fill = ifelse(species_data$sex == "male", "blue", "orange")) } @@ -199,7 +199,7 @@ Now, as with the penguin figure above, we can easily replace those points with s ```{r base-geog-plot-2, fig.height = 5, warning = FALSE} map("world", col = "lightgrey", fill = TRUE) add_phylopic_base(name = "Diplocaulus", x = tetrapods$lng, y = tetrapods$lat, - ysize = 8, fill = "blue", alpha = 0.75) + height = 8, fill = "blue", alpha = 0.75) ``` Snazzy! @@ -282,7 +282,7 @@ That's looking a lot prettier! Let's go ahead and replace the tip labels with ou plot(vertebrate.tree, show.tip.label = FALSE) axis_geo_phylo(intervals = "periods") add_phylopic_base(img = vertebrate_data$svg, - x = max(nodeHeights(vertebrate.tree)), y = 1:11, ysize = 0.5) + x = max(nodeHeights(vertebrate.tree)), y = 1:11, height = 0.5) ``` Note that only a single size is specified and aspect ratio is always maintained, hence why the silhouettes all have the same height but different widths. Let's fix some of the silhouettes by rotating them 90 degrees: @@ -298,7 +298,7 @@ And now the finished product: plot(vertebrate.tree, show.tip.label = FALSE) axis_geo_phylo(intervals = "periods") add_phylopic_base(img = vertebrate_data$svg, - x = max(nodeHeights(vertebrate.tree)), y = 1:11, ysize = 0.5) + x = max(nodeHeights(vertebrate.tree)), y = 1:11, height = 0.5) ``` Beautiful! diff --git a/vignettes/ggplot-geog-plot-1-1.png b/vignettes/ggplot-geog-plot-1-1.png index 04a1be9..a1bba9e 100644 Binary files a/vignettes/ggplot-geog-plot-1-1.png and b/vignettes/ggplot-geog-plot-1-1.png differ diff --git a/vignettes/ggplot-penguin-plot-3-1.png b/vignettes/ggplot-penguin-plot-3-1.png index e5083ef..37824c0 100644 Binary files a/vignettes/ggplot-penguin-plot-3-1.png and b/vignettes/ggplot-penguin-plot-3-1.png differ diff --git a/vignettes/ggplot-penguin-plot-3b-1.png b/vignettes/ggplot-penguin-plot-3b-1.png new file mode 100644 index 0000000..a35b256 Binary files /dev/null and b/vignettes/ggplot-penguin-plot-3b-1.png differ diff --git a/vignettes/ggplot-penguin-plot-5-1.png b/vignettes/ggplot-penguin-plot-5-1.png index 689ce7a..1575895 100644 Binary files a/vignettes/ggplot-penguin-plot-5-1.png and b/vignettes/ggplot-penguin-plot-5-1.png differ diff --git a/vignettes/ggplot-penguin-plot-6-1.png b/vignettes/ggplot-penguin-plot-6-1.png index 1889731..f845fb4 100644 Binary files a/vignettes/ggplot-penguin-plot-6-1.png and b/vignettes/ggplot-penguin-plot-6-1.png differ diff --git a/vignettes/ggplot-phylo-plot-3-1.png b/vignettes/ggplot-phylo-plot-3-1.png index 68a830a..880eb41 100644 Binary files a/vignettes/ggplot-phylo-plot-3-1.png and b/vignettes/ggplot-phylo-plot-3-1.png differ diff --git a/vignettes/ggplot-phylo-plot-4-1.png b/vignettes/ggplot-phylo-plot-4-1.png index d77450a..5e6ed0e 100644 Binary files a/vignettes/ggplot-phylo-plot-4-1.png and b/vignettes/ggplot-phylo-plot-4-1.png differ