From 3e5f687c36bc25781c36d07a6210311129077cc5 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 13:14:46 -0700 Subject: [PATCH 1/6] first stab at segments support --- R/tinyplot.R | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index 5a780409..f967003d 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -562,7 +562,7 @@ tinyplot.default = function( # Capture deparsed expressions early, before x, y and by are evaluated x_dep = if (!missing(x)) { deparse1(substitute(x)) - } else if (type == "rect") { + } else if (type %in% c("rect", "segments")) { x = NULL NULL } @@ -624,8 +624,8 @@ tinyplot.default = function( } if (is.null(x)) { - ## Special catch for area plots without a specified y-var - if (type %in% c("rect")) { + ## Special catch for rect and segment plots without a specified y-var + if (type %in% c("rect", "segments")) { xmin_dep = deparse(substitute(xmin)) xmax_dep = deparse(substitute(xmax)) x_dep = paste0("[", xmin_dep, ", ", xmax_dep, "]") @@ -635,7 +635,7 @@ tinyplot.default = function( } if (is.null(y)) { ## Special catch for area and interval plots without a specified y-var - if (type %in% c("rect", "pointrange", "errorbar", "ribbon")) { + if (type %in% c("rect", "segments", "pointrange", "errorbar", "ribbon")) { ymin_dep = deparse(substitute(ymin)) ymax_dep = deparse(substitute(ymax)) y_dep = paste0("[", ymin_dep, ", ", ymax_dep, "]") @@ -1370,7 +1370,7 @@ tinyplot.default = function( # empty plot flag empty_plot = FALSE - if (type=="n" || ((length(xx)==0) && type!="rect")) { + if (type=="n" || ((length(xx)==0) && !(type %in% c("rect","segments")))) { empty_plot = TRUE } @@ -1488,9 +1488,17 @@ tinyplot.default = function( rect( xleft = xxmin, ybottom = yymin, xright = xxmax, ytop = yymax, lty = ilty, + lwd = ilwd, border = icol, col = ibg ) + } else if (type == "segments") { + segments( + x0 = xxmin, y0 = yymin, x1 = xxmax, y1 = yymax, + lty = ilty, + lwd = ilwd, + col = icol + ) } else { stop("`type` argument not supported.", call. = FALSE) } From a71bc708421d2e4b1228e4153375bc49b34086a1 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 13:24:42 -0700 Subject: [PATCH 2/6] tests --- inst/tinytest/_tinysnapshot/segments_by.svg | 77 +++++++++++++++++++++ inst/tinytest/test-segments.R | 18 +++++ 2 files changed, 95 insertions(+) create mode 100644 inst/tinytest/_tinysnapshot/segments_by.svg create mode 100644 inst/tinytest/test-segments.R diff --git a/inst/tinytest/_tinysnapshot/segments_by.svg b/inst/tinytest/_tinysnapshot/segments_by.svg new file mode 100644 index 00000000..e2dbce50 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/segments_by.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + +grp +A +B + + + + + + + +[x[s], x[s + 2]] +[y[s], y[s + 2]] + + + + + + + +0.2 +0.4 +0.6 +0.8 + + + + + + +-2 +-1 +0 +1 +2 + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-segments.R b/inst/tinytest/test-segments.R new file mode 100644 index 00000000..93ebf697 --- /dev/null +++ b/inst/tinytest/test-segments.R @@ -0,0 +1,18 @@ +source("helpers.R") +using("tinysnapshot") + +f = function() { + # test case adapted from ?segments Examples + set.seed(42L) + x = stats::runif(12); y <- stats::rnorm(12) + i = order(x, y); x <- x[i]; y <- y[i] + s = seq(length(x)-1) # one shorter than data + s = s[-length(s)] + grp = rep(LETTERS[1:2], 5) + plt( + xmin = x[s], ymin = y[s], xmax = x[s+2], ymax = y[s+2], + by = grp, + type = "segments" + ) +} +expect_snapshot_plot(f, label = "segments_by") From ff25dfb947d0c8fb33e5df8653008385f3029b8f Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 13:52:20 -0700 Subject: [PATCH 3/6] docs --- R/tinyplot.R | 8 +++++--- man/tinyplot.Rd | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/R/tinyplot.R b/R/tinyplot.R index f967003d..dab64744 100644 --- a/R/tinyplot.R +++ b/R/tinyplot.R @@ -78,6 +78,11 @@ #' for segment intervals, and "ribbon" or "area" for polygon intervals (where #' area plots are a special case of ribbon plots with `ymin` set to 0 and #' `ymax` set to `y`; see below). +#' @param xmin,xmax,ymin,ymax minimum and maximum coordinates of relevant area +#' or interval plot types. Only used when the `type` argument is one of +#' "rect" or "segments" (where all four min-max coordinates are required), or +#' "pointrange", "errorbar", or "ribbon" (where only `ymin` and `ymax` +#' required alongside `x`). #' @param xlim the x limits (x1, x2) of the plot. Note that x1 > x2 is allowed #' and leads to a ‘reversed axis’. The default value, NULL, indicates that #' the range of the `finite` values to be plotted should be used. @@ -208,9 +213,6 @@ #' longer discussion about the trade-offs involved. #' @param subset,na.action,drop.unused.levels arguments passed to `model.frame` #' when extracting the data from `formula` and `data`. -#' @param xmin,xmax,ymin,ymax minimum and maximum coordinates of relevant area -#' or interval plot types. Only used when the `type` argument is one of -#' "pointrange", "errorbar", "ribbon", or "rect". #' @param ribbon.alpha numeric factor modifying the opacity alpha of any ribbon #' shading; typically in `[0, 1]`. Only used when `type = "ribbon"`, or when #' the `bg` fill argument is specified in a density plot (since filled density diff --git a/man/tinyplot.Rd b/man/tinyplot.Rd index 40580493..84cafc55 100644 --- a/man/tinyplot.Rd +++ b/man/tinyplot.Rd @@ -353,7 +353,9 @@ longer discussion about the trade-offs involved.} \item{xmin, xmax, ymin, ymax}{minimum and maximum coordinates of relevant area or interval plot types. Only used when the \code{type} argument is one of -"pointrange", "errorbar", "ribbon", or "rect".} +"rect" or "segments" (where all four min-max coordinates are required), or +"pointrange", "errorbar", or "ribbon" (where only \code{ymin} and \code{ymax} +required alongside \code{x}).} \item{ribbon.alpha}{numeric factor modifying the opacity alpha of any ribbon shading; typically in \verb{[0, 1]}. Only used when \code{type = "ribbon"}, or when From b0524c18dd681f480eb90dd52b5c051de8032ba1 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 13:53:01 -0700 Subject: [PATCH 4/6] news --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 23a41c3f..8d38b9a5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,7 @@ New features: numeric is plotted against a factor. (#154 @grantmcdermott) - `type = "polypath`. (#159 @grantmcdermott) - `type = "rect"`. (#161 @grantmcdermott) + - `type = "segments"`. (#163 @grantmcdermott) Misc: From e8e9dc93a3330c8698827e22f425023b46eee7d7 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 14:08:13 -0700 Subject: [PATCH 5/6] support lty = "by" --- R/by_aesthetics.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/by_aesthetics.R b/R/by_aesthetics.R index 8025463f..76dd10ba 100755 --- a/R/by_aesthetics.R +++ b/R/by_aesthetics.R @@ -167,7 +167,7 @@ by_pch = function(ngrps, type, pch=NULL) { by_lty = function(ngrps, type, lty=NULL) { # We only care about line types, otherwise return NULL - if (!type %in% c("l", "b", "o", "c", "h", "s", "S", "ribbon", "boxplot")) { + if (!type %in% c("l", "b", "o", "c", "h", "s", "S", "ribbon", "boxplot", "rect", "segments")) { out = NULL # special "by" convenience keyword From 5f5caea9dceb5ac7881c0449a925d9dca24db723 Mon Sep 17 00:00:00 2001 From: Grant McDermott Date: Sun, 7 Jul 2024 14:20:59 -0700 Subject: [PATCH 6/6] more tests --- inst/tinytest/_tinysnapshot/rect_by_fill.svg | 84 +++++++++--------- inst/tinytest/_tinysnapshot/segments_by.svg | 58 +++++++------ .../_tinysnapshot/segments_by_extra.svg | 79 +++++++++++++++++ .../_tinysnapshot/segments_by_xequal.svg | 85 +++++++++++++++++++ .../_tinysnapshot/segments_by_yequal.svg | 79 +++++++++++++++++ inst/tinytest/test-segments.R | 50 +++++++++-- 6 files changed, 358 insertions(+), 77 deletions(-) create mode 100644 inst/tinytest/_tinysnapshot/segments_by_extra.svg create mode 100644 inst/tinytest/_tinysnapshot/segments_by_xequal.svg create mode 100644 inst/tinytest/_tinysnapshot/segments_by_yequal.svg diff --git a/inst/tinytest/_tinysnapshot/rect_by_fill.svg b/inst/tinytest/_tinysnapshot/rect_by_fill.svg index ac564ad1..6dced252 100644 --- a/inst/tinytest/_tinysnapshot/rect_by_fill.svg +++ b/inst/tinytest/_tinysnapshot/rect_by_fill.svg @@ -21,40 +21,40 @@ - - 0 - 10 - 20 - 30 - 40 -- - -- - -- - -- - -- - -i + + 0 + 10 + 20 + 30 + 40 +- - +- - +- - +- - +- - +i - - + + - -[100 + i, 150 + i] + +[100 + i, 150 + i] [300 + i, 380 + i] - - - - - - -100 -120 -140 -160 -180 + + + + + + +100 +120 +140 +160 +180 @@ -70,24 +70,24 @@ 380 400 420 - + - - + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/segments_by.svg b/inst/tinytest/_tinysnapshot/segments_by.svg index e2dbce50..4f394833 100644 --- a/inst/tinytest/_tinysnapshot/segments_by.svg +++ b/inst/tinytest/_tinysnapshot/segments_by.svg @@ -21,29 +21,31 @@ -grp + + +grp A B - - + + - -[x[s], x[s + 2]] + +[x[s], x[s + 2]] [y[s], y[s + 2]] - - - - - -0.2 -0.4 -0.6 -0.8 + + + + + +0.2 +0.4 +0.6 +0.8 @@ -55,23 +57,23 @@ 0 1 2 - + - - + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/segments_by_extra.svg b/inst/tinytest/_tinysnapshot/segments_by_extra.svg new file mode 100644 index 00000000..a7eb5b80 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/segments_by_extra.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + +grp +A +B + + + + + + + +[x[s], x[s + 2]] +[y[s], y[s + 2]] + + + + + + + +0.2 +0.4 +0.6 +0.8 + + + + + + +-2 +-1 +0 +1 +2 + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/segments_by_xequal.svg b/inst/tinytest/_tinysnapshot/segments_by_xequal.svg new file mode 100644 index 00000000..6be78610 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/segments_by_xequal.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + +grp +A +B + + + + + + + +[x[s], x[s]] +[y[s], y[s + 2]] + + + + + + + + + + +0.2 +0.3 +0.4 +0.5 +0.6 +0.7 +0.8 + + + + + + +-2 +-1 +0 +1 +2 + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/_tinysnapshot/segments_by_yequal.svg b/inst/tinytest/_tinysnapshot/segments_by_yequal.svg new file mode 100644 index 00000000..3dfdf1bc --- /dev/null +++ b/inst/tinytest/_tinysnapshot/segments_by_yequal.svg @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + +grp +A +B + + + + + + + +[x[s], x[s + 2]] +[y[s], y[s]] + + + + + + + +0.2 +0.4 +0.6 +0.8 + + + + + + +-2 +-1 +0 +1 +2 + + + + + + + + + + + + + + + + + + + + diff --git a/inst/tinytest/test-segments.R b/inst/tinytest/test-segments.R index 93ebf697..9ed22dec 100644 --- a/inst/tinytest/test-segments.R +++ b/inst/tinytest/test-segments.R @@ -1,14 +1,15 @@ source("helpers.R") using("tinysnapshot") +# test case adapted from ?segments Examples +set.seed(42L) +x = stats::runif(12); y <- stats::rnorm(12) +i = order(x, y); x = x[i]; y = y[i] +s = seq(length(x)-1) # one shorter than data +s = s[-length(s)] +grp = rep(LETTERS[1:2], 5) + f = function() { - # test case adapted from ?segments Examples - set.seed(42L) - x = stats::runif(12); y <- stats::rnorm(12) - i = order(x, y); x <- x[i]; y <- y[i] - s = seq(length(x)-1) # one shorter than data - s = s[-length(s)] - grp = rep(LETTERS[1:2], 5) plt( xmin = x[s], ymin = y[s], xmax = x[s+2], ymax = y[s+2], by = grp, @@ -16,3 +17,38 @@ f = function() { ) } expect_snapshot_plot(f, label = "segments_by") + +# also vary lty and lwd by groups +f = function() { + plt( + xmin = x[s], ymin = y[s], xmax = x[s+2], ymax = y[s+2], + by = grp, + lty = "by", lwd = "by", + type = "segments" + ) +} +expect_snapshot_plot(f, label = "segments_by_extra") + +# xmin = xmax +f = function() { + plt( + xmin = x[s], ymin = y[s], xmax = x[s], ymax = y[s+2], + by = grp, + lty = "by", lwd = "by", + type = "segments" + ) +} +expect_snapshot_plot(f, label = "segments_by_xequal") + +# ymin = ymax +f = function() { + plt( + xmin = x[s], ymin = y[s], xmax = x[s+2], ymax = y[s], + by = grp, + lty = "by", lwd = "by", + type = "segments" + ) +} +expect_snapshot_plot(f, label = "segments_by_yequal") + +rm(x, y, i, s, grp)