add polys to spec_line, fix xlim/ylim and arg listifying
- added polys
- fix xlim/ylim when polymin is included
- fix various args length-determination
diff --git a/R/mini_plots.R b/R/mini_plots.R
index 764d7bf..068cc82 100644
--- a/R/mini_plots.R
+++ b/R/mini_plots.R
@@ -243,6 +243,16 @@
#' is False.
#' @param lwd Line width for `spec_line`; within `spec_line`, the `minmax`
#' argument defaults to use this value for `cex` for points. Default is 2.
+#' @param pch,cex Shape and size for points (if type is other than "l").
+#' @param type Passed to `plot`, often one of "l", "p", or "b", see
+#' [graphics::plot.default()] for more details. Ignored when 'polymin' is
+#' not 'NA'.
+#' @param polymin Special argument that converts a "line" to a polygon,
+#' where the flat portion is this value, and the other side of the polygon
+#' is the 'y' value ('x' if no 'y' provided). If 'NA' (the default), then
+#' this is ignored, otherwise if this is numeric then a polygon is
+#' created instead (and 'type' is ignored). Note that if 'polymin' is in
+#' the middle of the 'y' values, it will generate up/down polygons.
#' @param minmax,min,max Arguments passed to `points` to highlight minimum
#' and maximum values in `spec_line`. If `min` or `max` are `NULL`, they
#' default to the value of `minmax`. Set to an empty `list()` to disable.
@@ -258,20 +268,24 @@
xaxt = 'n', yaxt = 'n', ann = FALSE,
col = "lightgray", border = NULL,
frame.plot = FALSE, lwd = 2,
+ pch = ".", cex = 0.1, type = "l", polymin = NA,
minmax = list(pch = ".", cex = lwd, col = "red"),
min = minmax, max = minmax,
dir = if (is_latex()) rmd_files_dir() else tempdir(),
- file = NULL,
- file_type = if (is_latex()) "png" else "svg", ...) {
+ file = NULL, file_type = if (is_latex()) "png" else "svg", ...) {
if (is.list(x)) {
lenx <- length(x)
if (same_lim) {
if (is.null(xlim)) {
- xlim <- lapply(x, base::range)
+ xlim <- lapply(x, function(z) base::range(c(z, if (is.null(y)) polymin), na.rm = TRUE))
}
if (is.null(ylim) && !is.null(y)) {
- ylim <- lapply(y, base::range)
+ if (is.list(y)) {
+ ylim <- lapply(y, function(z) base::range(c(z, polymin), na.rm = TRUE))
+ } else {
+ ylim <- base::range(c(y, polymin), na.rm = TRUE)
+ }
}
}
if (is.null(y)) {
@@ -286,27 +300,37 @@
# enforce a restriction of recycling only length 1 or lenx
# first, start with the literals (x,y)
- # same_lim, not a factor anymore
+ # (same_lim is not a factor anymore)
dots <- list(x = x, y = y)
# second, we know these args are likely to be vectors (length > 1)
# or lists, so we have to handle them carefully and double-list if
# present
- notlen1 <- list(xlim = xlim, ylim = ylim,
- minmax = minmax, min = min, max = max)
+ notlen1vec <- list(xlim = xlim, ylim = ylim)
dots <- c(dots, Map(
function(L, nm) {
if (is.null(L)) return(list(NULL))
- if (!is.list(L) || !is.list(L[[1]])) return(list(L))
- if (!length(L) %in% c(1L, lenx)) {
- stop("length of '", nm, "' must be 1 or the same length as 'x'")
- }
- L
- }, notlen1, names(notlen1)))
+ if (!is.list(L)) return(list(L))
+ if (length(L) == lenx) return(L)
+ stop("length of '", nm, "' must be 1 or the same length as 'x'")
+ }, notlen1vec, names(notlen1vec)))
+
+ # these are special ... they are lists which may need to be
+ # nested, and we can't pass NULL since that may default to the
+ # actual values instead of the intended
+ notlen1lst <- list(minmax = minmax, min = min, max = max)
+ dots <- c(dots, Map(
+ function(L, nm) {
+ if (is.null(L)) return(list(NULL))
+ if (!length(L)) return(list(list()))
+ if (!is.list(L[[1]])) return (list(L))
+ if (length(L) == lenx) return(L)
+ stop("length of '", nm, "' must be 1 or the same length as 'x'")
+ }, notlen1lst, names(notlen1lst)))
# last, all remaining arguments that we don't already know about
# are length-1, so can be easily listified; using 'formals()'
- # allows us to not hard-code all params, for future expansion?
+ # allows us to not hard-code all params
len1args <- mget(setdiff(names(formals()),
c(names(dots), "same_lim", "x", "y", "...")))
dots <- c(dots, Map(
@@ -326,10 +350,11 @@
if (is.null(y) || !length(y)) {
y <- x
- x <- seq(0, 1, length.out = length(y))
- tmp <- ylim
- ylim <- xlim
- xlim <- tmp
+ x <- seq_along(y)
+ if (!is.null(xlim) && is.null(ylim)) {
+ ylim <- xlim
+ xlim <- range(x)
+ }
}
if (is.null(xlim)) {
@@ -337,7 +362,7 @@
}
if (is.null(ylim) && !is.null(y)) {
- ylim <- base::range(y)
+ ylim <- base::range(c(y, polymin), na.rm = TRUE)
}
if (is.null(min)) min <- minmax
@@ -370,10 +395,29 @@
curdev <- grDevices::dev.cur()
on.exit(grDevices::dev.off(curdev), add = TRUE)
- graphics::par(mar = c(0, 0, 0.2, 0), lwd = lwd)
- graphics::plot(x, y, type = "l", xlim = xlim, ylim = ylim,
+ graphics::par(mar = c(0, 0, 0, 0), lwd = lwd)
+
+ dots <- list(...)
+ if (!is.na(polymin) && "angle" %in% names(dots)) {
+ angle <- dots$angle
+ dots$angle <- NULL
+ } else angle <- 45
+
+ do.call(graphics::plot,
+ c(list(x, y, type = if (is.na(polymin)) type else "n",
+ xlim = xlim, ylim = ylim,
xaxt = xaxt, yaxt = yaxt, ann = ann, col = col,
- frame.plot = frame.plot, ...)
+ frame.plot = frame.plot, xpd = NA,
+ cex = cex, pch = pch # in case of type="p" or similar
+ ), dots))
+
+ if (!is.na(polymin)) {
+ lty <- if ("lty" %in% names(dots)) dots$lty else graphics::par("lty")
+ polygon(c(x[1], x, x[length(x)]), c(polymin, y, polymin),
+ border = NA, col = col, angle = angle,
+ lty = lty,
+ xpd = NA)
+ }
if (!is.null(min) && length(min)) {
ind <- which.min(y)