From a31dadcfdcd12eddb8f1e860cdb8fe12bd4eb184 Mon Sep 17 00:00:00 2001 From: pwwang Date: Sun, 8 Nov 2026 21:35:56 -0700 Subject: [PATCH 1/2] fix(VelocityPlot): scale linewidth, not size, for stream plot type The stream branch maps the streamline thickness as an aesthetic, `linewidth = after_stat(step)`, but the accompanying scale was `scale_size(range = range(streamline_width), guide = "none")`. A `size` scale cannot act on a `linewidth` mapping, so: - `streamline_width` had no effect at all -- c(0, 0.1) rendered identically to the default c(0, 0.8), byte for byte; - ggplot's default continuous linewidth scale (roughly 1-6) applied instead, which is why streamlines rendered as thick ribbons that covered the cells underneath; - the `guide = "none"` was attached to the wrong scale, so an unhelpful "step" legend appeared next to the plot. Use `scale_linewidth(range = range(streamline_width), guide = "none")` instead. The default range c(0, 0.8) now really is the maximum stroke width, so streams are thin by default and `streamline_width` tunes them. Adds a regression test that compares the scaled layer's line width at two widths. The previous test only asserted `expect_s3_class(p, "ggplot")`, which passed throughout. --- R/velocityplot.R | 8 +++++--- man/DimPlotAtomic.Rd | 2 +- man/VelocityPlot.Rd | 2 +- man/dimplot.Rd | 2 +- tests/testthat/test-velocityplot.R | 27 +++++++++++++++++++++++++++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/R/velocityplot.R b/R/velocityplot.R index d0b30bcc..43348587 100644 --- a/R/velocityplot.R +++ b/R/velocityplot.R @@ -156,7 +156,7 @@ #' @param streamline_minl A numeric value specifying the minimum streamline length. Shorter streamlines are not drawn. Passed to \code{\link[metR]{geom_streamline}} as the \code{min.L} parameter. Default is 1. #' @param streamline_res A numeric value specifying the resolution of the streamline integration. Passed to \code{\link[metR]{geom_streamline}} as the \code{res} parameter. Default is 1. #' @param streamline_n A numeric value specifying the number of streamlines to draw. Passed to \code{\link[metR]{geom_streamline}} as the \code{n} parameter. Default is 15. -#' @param streamline_width A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_size(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}. +#' @param streamline_width A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_linewidth(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}. #' @param streamline_alpha A numeric value between 0 and 1 specifying the transparency of the velocity streamlines. Default is 1. #' @param streamline_color An optional character string specifying a fixed color for streamlines. When \code{NULL} (the default), streamlines are colored by velocity magnitude using \code{streamline_palette}. #' @param streamline_palette A character string specifying the color palette for streamline velocity magnitude. Passed to \code{\link{palette_this}}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{"RdYlBu"}. @@ -674,8 +674,10 @@ VelocityPlot <- function( order = 1 ) ), - # Size scale for streamline width - scale_size(range = range(streamline_width), guide = "none") + # The streamlines map `linewidth = after_stat(step)`, so the scale must be + # scale_linewidth(); scale_size() targets a different aesthetic and leaves the + # default 1-6 linewidth scale (and its "step" guide) in place. + scale_linewidth(range = range(streamline_width), guide = "none") ) attr(velocity_layer, "scales") <- unique(c( attr(velocity_layer, "scales"), diff --git a/man/DimPlotAtomic.Rd b/man/DimPlotAtomic.Rd index 9b1b23c0..1ac3b8d3 100644 --- a/man/DimPlotAtomic.Rd +++ b/man/DimPlotAtomic.Rd @@ -386,7 +386,7 @@ Default is \code{NULL} (auto-resolved from \code{velocity_group_palette}).} \item{arrow_alpha}{A numeric value between 0 and 1 specifying the transparency of the velocity arrows. Only used when \code{plot_type = "raw"} or \code{"grid"}; for \code{plot_type = "stream"}, use \code{streamline_alpha} instead. Default is 1.} -\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_size(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} +\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_linewidth(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} \item{streamline_alpha}{A numeric value between 0 and 1 specifying the transparency of the velocity streamlines. Default is 1.} diff --git a/man/VelocityPlot.Rd b/man/VelocityPlot.Rd index d063256e..2b272ba1 100644 --- a/man/VelocityPlot.Rd +++ b/man/VelocityPlot.Rd @@ -96,7 +96,7 @@ VelocityPlot( \item{streamline_n}{A numeric value specifying the number of streamlines to draw. Passed to \code{\link[metR]{geom_streamline}} as the \code{n} parameter. Default is 15.} -\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_size(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} +\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_linewidth(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} \item{streamline_alpha}{A numeric value between 0 and 1 specifying the transparency of the velocity streamlines. Default is 1.} diff --git a/man/dimplot.Rd b/man/dimplot.Rd index 5253fd75..43f9fcf6 100644 --- a/man/dimplot.Rd +++ b/man/dimplot.Rd @@ -504,7 +504,7 @@ Default is \code{NULL} (auto-resolved from \code{velocity_group_palette}).} \item{streamline_n}{A numeric value specifying the number of streamlines to draw. Passed to \code{\link[metR]{geom_streamline}} as the \code{n} parameter. Default is 15.} -\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_size(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} +\item{streamline_width}{A numeric vector of length 2 specifying the range of line widths for streamlines. Passed to \code{scale_linewidth(range = ...)}. Only used when \code{streamline_color} is \code{NULL}. Default is \code{c(0, 0.8)}.} \item{streamline_alpha}{A numeric value between 0 and 1 specifying the transparency of the velocity streamlines. Default is 1.} diff --git a/tests/testthat/test-velocityplot.R b/tests/testthat/test-velocityplot.R index 46f9455e..99a3a536 100644 --- a/tests/testthat/test-velocityplot.R +++ b/tests/testthat/test-velocityplot.R @@ -34,6 +34,33 @@ test_that("VelocityPlot with plot_type = 'stream' works", { expect_s3_class(p, "ggplot") }) +test_that("streamline_width controls stream line thickness", { + # The stream branch maps `linewidth = after_stat(step)`; scaling `size` instead left the + # default ggplot linewidth scale in place, so every streamline rendered 1-6 wide and the + # argument did nothing. The graph has three GeomStreamline layers -- a fixed-width halo, the + # scaled streamline layer, and a fixed-width arrow layer -- so assertions target the scaled + # one (the only layer with more than one distinct linewidth). + scaled_max <- function(w) { + p <- VelocityPlot(embedding, v_embedding, plot_type = "stream", + streamline_width = w) + expect_true(any(vapply(p$scales$scales, + function(s) "linewidth" %in% s$aesthetics, logical(1)))) + expect_false(any(vapply(p$scales$scales, + function(s) "size" %in% s$aesthetics, logical(1)))) + lws <- lapply(ggplot2::ggplot_build(p)$data, function(d) { + if ("linewidth" %in% names(d)) unique(d$linewidth) else numeric() + }) + scaled <- Filter(function(v) length(v) > 1, lws) + expect_length(scaled, 1L) + max(scaled[[1]]) + } + thin <- scaled_max(c(0, 0.2)) + thick <- scaled_max(c(0, 0.8)) + expect_lte(thin, 0.2) + expect_lte(thick, 0.8) + expect_lt(thin, thick) +}) + test_that("VelocityPlot with title and subtitle works", { p <- VelocityPlot(embedding, v_embedding, plot_type = "raw", title = "Velocity Title", subtitle = "Subtitle") From 2d0996335440445604b094ffee10ea1ef09b5d32 Mon Sep 17 00:00:00 2001 From: pwwang Date: Sun, 8 Nov 2026 21:42:06 -0700 Subject: [PATCH 2/2] 0.14.2-1 --- conda/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/meta.yaml b/conda/meta.yaml index 685b6610..aa97599a 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,12 +1,12 @@ package: name: r-plotthis - version: 0.14.1 + version: 0.14.2 source: path: .. build: - number: 2 + number: 1 rpaths: - lib/R/lib/ - lib/