diff --git a/NEWS.md b/NEWS.md index 17b02e75..110102eb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,12 +6,20 @@ where the formatting is also better._ ## Dev version +### New features + +- `type_text()` gains a `family` argument for controlling the font family, + separate to the main plot text elements. (#494 @grantmcdermott) + ### Bug fixes - For bubble plots, we now drop the minimum legend category (label) if it is equal to 0. The previous behaviour was just an artifact of the `pretty` breaks algorithm that we use to create discrete legend categories. The interior plot elements, e.g. bubble points, are unaffected. (#498 @grantmcdermott) +- `type_text()` now defaults to displaying `y` values if an explicit `labels` + arg is not provided, mirroring the behaviour of the base `text()` function. + (#501 @grantmcdermott) ## 0.5.0 diff --git a/R/type_text.R b/R/type_text.R index dca76325..90ca2819 100644 --- a/R/type_text.R +++ b/R/type_text.R @@ -1,32 +1,52 @@ #' Text annotations plot type #' -#' @description Type function for adding text annotations to a plot. This function allows -#' you to draw text at specified (x,y) coordinates. +#' @description Type function for adding text annotations to a plot at the +#' specified (`x`,`y`) coordinates. #' -#' @param labels Character vector of length 1 or of the same length as the -#' number of x,y coordinates. -#' @param font Font to be used, following [graphics::par()]. +#' @param labels Character vector of length `1` or the same length as the +#' number of `x`,`y` coordinates. If left as `NULL`, then the labels will +#' automatically inherit the corresponding `y` values. See Examples. +#' @param family The name of a font family. Default of `NULL` means that the +#' family will be the same as the main plot text, following +#' \code{\link[graphics]{par}}. Note that if a `family` argument is provided, +#' then `vfont` (below) will automatically be ignored. +#' @param font Integer giving the font face to be used, +#' following \code{\link[graphics]{par}}. On most devices, the mapping is: `1` = +#' regular, `2` = bold, `3` = italic, `4` = bold italic, and `5` = symbol. #' @param xpd Logical value or `NA` denoting text clipping behaviour, following -#' [graphics::par()]. +#' \code{\link[graphics]{par}}. #' @param srt Numeric giving the desired string rotation in degrees. #' @param clim Numeric giving the lower and upper limits of the character #' expansion (`cex`) normalization for bubble charts. #' @inheritParams graphics::text #' @examples +#' # simplest case (no labels), will auto revert to y labels +#' tinyplot(1:12, type = "text") +#' +#' # pass explicit `labels` arg if you want specific text +#' tinyplot(1:12, type = "text", labels = month.abb) +#' +#' # for advanced customization, it's safer to pass args through `type_text()` +#' tinyplot(1:12, type = type_text( +#' labels = month.abb, family = "HersheyScript", srt = -20)) +#' +#' # same principles apply to grouped and/or facet data #' tinyplot(mpg ~ hp | factor(cyl), #' data = mtcars, #' type = type_text( #' labels = row.names(mtcars), +#' family = "HersheySans", #' font = 2, #' adj = 0 #' ) #' ) #' -#' # to avoid clipping text at the plot region, we can use xpd = NA +#' # tip: use `xpd = NA` to avoid clipping text at the plot region #' tinyplot(mpg ~ hp | factor(cyl), #' data = mtcars, #' type = type_text( #' labels = row.names(mtcars), +#' family = "HersheySans", #' font = 2, #' adj = 0, #' xpd = NA @@ -34,9 +54,29 @@ #' ) #' #' @export -type_text = function(labels, adj = NULL, pos = NULL, offset = 0.5, vfont = NULL, font = NULL, xpd = NULL, srt = 0, clim = c(0.5, 2.5)) { +type_text = function( + labels = NULL, + adj = NULL, + pos = NULL, + offset = 0.5, + family = NULL, + font = NULL, + vfont = NULL, + xpd = NULL, + srt = 0, + clim = c(0.5, 2.5) +) { out = list( - draw = draw_text(adj = adj, pos = pos, offset = offset, vfont = vfont, font = font, xpd = xpd, srt = srt), + draw = draw_text( + adj = adj, + pos = pos, + offset = offset, + vfont = vfont, + family = family, + font = font, + xpd = xpd, + srt = srt + ), data = data_text(labels = labels, clim = clim), name = "text" ) @@ -44,17 +84,23 @@ type_text = function(labels, adj = NULL, pos = NULL, offset = 0.5, vfont = NULL, return(out) } -data_text = function(labels, clim = c(0.5, 2.5)) { +data_text = function(labels = NULL, clim = c(0.5, 2.5)) { fun = function(datapoints, legend_args, cex = NULL, ...) { + if (is.null(labels)) { + labels = datapoints$y + } if (length(labels) != 1 && length(labels) != nrow(datapoints)) { msg = sprintf("`labels` must be of length 1 or %s.", nrow(datapoints)) stop(msg, call. = FALSE) } datapoints$labels = labels - if (is.factor(datapoints$x)) datapoints$x = as.numeric(datapoints$x) - if (is.factor(datapoints$y)) datapoints$y = as.numeric(datapoints$y) + if (is.factor(datapoints$x)) { + datapoints$x = as.numeric(datapoints$x) + } + if (is.factor(datapoints$y)) { + datapoints$y = as.numeric(datapoints$y) + } - # browser() bubble = FALSE bubble_cex = 1 if (!is.null(cex) && length(cex) == nrow(datapoints)) { @@ -89,13 +135,34 @@ data_text = function(labels, clim = c(0.5, 2.5)) { return(fun) } -draw_text = function(adj = NULL, pos = NULL, offset = 0.5, vfont = NULL, font = NULL, xpd = NULL, srt = 0) { - if (is.null(xpd)) xpd = par("xpd") +draw_text = function( + adj = NULL, + pos = NULL, + offset = 0.5, + vfont = NULL, + family = NULL, + font = NULL, + xpd = NULL, + srt = 0 +) { + if (is.null(xpd)) { + xpd = par("xpd") + } + if (!is.null(family)) { + vfont = NULL + } fun = function(ix, iy, ilabels, icol, icex, ...) { text( - x = ix, y = iy, labels = ilabels, col = icol, - adj = adj, pos = pos, offset = offset, - vfont = vfont, font = font, + x = ix, + y = iy, + labels = ilabels, + col = icol, + adj = adj, + pos = pos, + offset = offset, + family = family, + font = font, + vfont = vfont, xpd = xpd, srt = srt, cex = icex diff --git a/man/type_text.Rd b/man/type_text.Rd index 8b930e26..03879c98 100644 --- a/man/type_text.Rd +++ b/man/type_text.Rd @@ -5,20 +5,22 @@ \title{Text annotations plot type} \usage{ type_text( - labels, + labels = NULL, adj = NULL, pos = NULL, offset = 0.5, - vfont = NULL, + family = NULL, font = NULL, + vfont = NULL, xpd = NULL, srt = 0, clim = c(0.5, 2.5) ) } \arguments{ -\item{labels}{Character vector of length 1 or of the same length as the -number of x,y coordinates.} +\item{labels}{Character vector of length \code{1} or the same length as the +number of \code{x},\code{y} coordinates. If left as \code{NULL}, then the labels will +automatically inherit the corresponding \code{y} values. See Examples.} \item{adj}{one or two values in \eqn{[0, 1]} which specify the x (and optionally y) adjustment (\sQuote{justification}) of the @@ -36,16 +38,23 @@ number of x,y coordinates.} distance (\sQuote{offset}) of the text label from the specified coordinate in fractions of a character width.} +\item{family}{The name of a font family. Default of \code{NULL} means that the +family will be the same as the main plot text, following +\code{\link[graphics]{par}}. Note that if a \code{family} argument is provided, +then \code{vfont} (below) will automatically be ignored.} + +\item{font}{Integer giving the font face to be used, +following \code{\link[graphics]{par}}. On most devices, the mapping is: \code{1} = +regular, \code{2} = bold, \code{3} = italic, \code{4} = bold italic, and \code{5} = symbol.} + \item{vfont}{\code{NULL} for the current font family, or a character vector of length 2 for \code{\link[grDevices]{Hershey}} vector fonts. The first element of the vector selects a typeface and the second element selects a style. Ignored if \code{labels} is an expression.} -\item{font}{Font to be used, following \code{\link[graphics:par]{graphics::par()}}.} - \item{xpd}{Logical value or \code{NA} denoting text clipping behaviour, following -\code{\link[graphics:par]{graphics::par()}}.} +\code{\link[graphics]{par}}.} \item{srt}{Numeric giving the desired string rotation in degrees.} @@ -53,24 +62,37 @@ number of x,y coordinates.} expansion (\code{cex}) normalization for bubble charts.} } \description{ -Type function for adding text annotations to a plot. This function allows -you to draw text at specified (x,y) coordinates. +Type function for adding text annotations to a plot at the +specified (\code{x},\code{y}) coordinates. } \examples{ +# simplest case (no labels), will auto revert to y labels +tinyplot(1:12, type = "text") + +# pass explicit `labels` arg if you want specific text +tinyplot(1:12, type = "text", labels = month.abb) + +# for advanced customization, it's safer to pass args through `type_text()` +tinyplot(1:12, type = type_text( + labels = month.abb, family = "HersheyScript", srt = -20)) + +# same principles apply to grouped and/or facet data tinyplot(mpg ~ hp | factor(cyl), data = mtcars, type = type_text( labels = row.names(mtcars), + family = "HersheySans", font = 2, adj = 0 ) ) -# to avoid clipping text at the plot region, we can use xpd = NA +# tip: use `xpd = NA` to avoid clipping text at the plot region tinyplot(mpg ~ hp | factor(cyl), data = mtcars, type = type_text( labels = row.names(mtcars), + family = "HersheySans", font = 2, adj = 0, xpd = NA