Skip to content

Commit 793c232

Browse files
committed
integrate with main
Merge branch 'main' into guide_positioning # Conflicts: # R/guides-.R # R/plot-build.R
2 parents 73d98c5 + 916dc89 commit 793c232

File tree

70 files changed

+1033
-704
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1033
-704
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ Suggests:
5959
nlme,
6060
profvis,
6161
quantreg,
62-
ragg,
62+
ragg (>= 1.2.6),
6363
RColorBrewer,
6464
rmarkdown,
6565
rpart,
6666
sf (>= 0.7-3),
67-
svglite (>= 1.2.0.9001),
67+
svglite (>= 2.1.2),
6868
testthat (>= 3.1.2),
6969
vdiffr (>= 1.0.6),
7070
xml2

NEWS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# ggplot2 (development version)
22

3+
* `ggsave()` no longer sometimes creates new directories, which is now
4+
controlled by the new `create.dir` argument (#5489).
5+
6+
* `guide_coloursteps(even.steps = FALSE)` now draws one rectangle per interval
7+
instead of many small ones (#5481).
8+
9+
* (internal) guide building is now part of `ggplot_build()` instead of
10+
`ggplot_gtable()` to allow guides to observe unmapped data (#5483).
11+
12+
* `geom_violin()` gains a `bounds` argument analogous to `geom_density()`s (@eliocamp, #5493).
13+
314
* Legend titles no longer take up space if they've been removed by setting
415
`legend.title = element_blank()` (@teunbrand, #3587).
516

@@ -114,6 +125,7 @@
114125
* More informative error for mismatched
115126
`direction`/`theme(legend.direction = ...)` arguments (#4364, #4930).
116127
* `guide_coloursteps()` and `guide_bins()` sort breaks (#5152).
128+
* `guide_axis()` gains a `minor.ticks` argument to draw minor ticks (#4387).
117129
* `guide_axis()` gains a `cap` argument that can be used to trim the
118130
axis line to extreme breaks (#4907).
119131
* `guide_colourbar()` and `guide_coloursteps()` merge properly when one

R/annotation.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#' @section Unsupported geoms:
1515
#' Due to their special nature, reference line geoms [geom_abline()],
1616
#' [geom_hline()], and [geom_vline()] can't be used with [annotate()].
17-
#' You can use these geoms directory for annotations.
17+
#' You can use these geoms directly for annotations.
1818
#' @param geom name of geom to use for annotation
1919
#' @param x,y,xmin,ymin,xmax,ymax,xend,yend positioning aesthetics -
2020
#' you must specify at least one of these.

R/coord-cartesian-.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,5 @@ panel_guides_grob <- function(guides, position, theme) {
151151
return(zeroGrob())
152152
}
153153
pair <- guides$get_position(position)
154-
pair$guide$draw(theme, pair$params)
154+
pair$guide$draw(theme, params = pair$params)
155155
}

R/coord-sf.R

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
9393
# transform and normalize regular position data
9494
data <- transform_position(
9595
sf_transform_xy(data, target_crs, source_crs),
96-
function(x) sf_rescale01_x(x, panel_params$x_range),
97-
function(x) sf_rescale01_x(x, panel_params$y_range)
96+
function(x) rescale(x, from = panel_params$x_range),
97+
function(x) rescale(x, from = panel_params$y_range)
9898
)
9999

100100
transform_position(data, squish_infinite, squish_infinite)
@@ -250,10 +250,10 @@ CoordSf <- ggproto("CoordSf", CoordCartesian,
250250

251251
# Rescale graticule for panel grid
252252
sf::st_geometry(graticule) <- sf_rescale01(sf::st_geometry(graticule), x_range, y_range)
253-
graticule$x_start <- sf_rescale01_x(graticule$x_start, x_range)
254-
graticule$x_end <- sf_rescale01_x(graticule$x_end, x_range)
255-
graticule$y_start <- sf_rescale01_x(graticule$y_start, y_range)
256-
graticule$y_end <- sf_rescale01_x(graticule$y_end, y_range)
253+
graticule$x_start <- rescale(graticule$x_start, from = x_range)
254+
graticule$x_end <- rescale(graticule$x_end, from = x_range)
255+
graticule$y_start <- rescale(graticule$y_start, from = y_range)
256+
graticule$y_end <- rescale(graticule$y_end, from = y_range)
257257

258258
list2(
259259
x_range = x_range,
@@ -405,11 +405,6 @@ sf_rescale01 <- function(x, x_range, y_range) {
405405
sf::st_normalize(x, c(x_range[1], y_range[1], x_range[2], y_range[2]))
406406
}
407407

408-
# normalize position data (variable x is x or y position)
409-
sf_rescale01_x <- function(x, range) {
410-
(x - range[1]) / diff(range)
411-
}
412-
413408
# different limits methods
414409
calc_limits_bbox <- function(method, xlim, ylim, crs, default_crs) {
415410
if (any(!is.finite(c(xlim, ylim))) && method != "geometry_bbox") {

R/geom-violin.R

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#' to the range of the data. If `FALSE`, don't trim the tails.
1717
#' @param geom,stat Use to override the default connection between
1818
#' `geom_violin()` and `stat_ydensity()`.
19+
#' @param bounds Known lower and upper bounds for estimated data. Default
20+
#' `c(-Inf, Inf)` means that there are no (finite) bounds. If any bound is
21+
#' finite, boundary effect of default density estimation will be corrected by
22+
#' reflecting tails outside `bounds` around their closest edge. Data points
23+
#' outside of bounds are removed with a warning.
1924
#' @export
2025
#' @references Hintze, J. L., Nelson, R. D. (1998) Violin Plots: A Box
2126
#' Plot-Density Trace Synergism. The American Statistician 52, 181-184.
@@ -86,6 +91,7 @@ geom_violin <- function(mapping = NULL, data = NULL,
8691
...,
8792
draw_quantiles = NULL,
8893
trim = TRUE,
94+
bounds = c(-Inf, Inf),
8995
scale = "area",
9096
na.rm = FALSE,
9197
orientation = NA,
@@ -105,6 +111,7 @@ geom_violin <- function(mapping = NULL, data = NULL,
105111
draw_quantiles = draw_quantiles,
106112
na.rm = na.rm,
107113
orientation = orientation,
114+
bounds = bounds,
108115
...
109116
)
110117
)

R/guide-.R

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,12 @@ new_guide <- function(..., available_aes = "any", super) {
117117
#' `params$hash`. This ensures that e.g. `guide_legend()` can display both
118118
#' `shape` and `colour` in the same guide.
119119
#'
120-
#' - `get_layer_key()` Extract information from layers. This can be used to
121-
#' check that the guide's aesthetic is actually in use, or to gather
122-
#' information about how legend keys should be displayed.
120+
#' - `process_layers()` Extract information from layers. This acts mostly
121+
#' as a filter for which layers to include and these are then (typically)
122+
#' forwarded to `get_layer_key()`.
123+
#'
124+
#' - `get_layer_key()` This can be used to gather information about how legend
125+
#' keys should be displayed.
123126
#'
124127
#' - `setup_params()` Set up parameters at the beginning of drawing stages.
125128
#' It can be used to overrule user-supplied parameters or perform checks on
@@ -253,7 +256,11 @@ Guide <- ggproto(
253256

254257
# Function for extracting information from the layers.
255258
# Mostly applies to `guide_legend()` and `guide_binned()`
256-
get_layer_key = function(params, layers) {
259+
process_layers = function(self, params, layers, data = NULL) {
260+
self$get_layer_key(params, layers, data)
261+
},
262+
263+
get_layer_key = function(params, layers, data = NULL) {
257264
return(params)
258265
},
259266

@@ -280,11 +287,14 @@ Guide <- ggproto(
280287

281288
# Main drawing function that organises more specialised aspects of guide
282289
# drawing.
283-
draw = function(self, theme, params = self$params) {
290+
draw = function(self, theme, position = NULL, direction = NULL,
291+
params = self$params) {
284292

285293
key <- params$key
286294

287295
# Setup parameters and theme
296+
params$position <- params$position %||% position
297+
params$direction <- params$direction %||% direction
288298
params <- self$setup_params(params)
289299
elems <- self$setup_elements(params, self$elements, theme)
290300
elems <- self$override_elements(params, elems, theme)
@@ -351,7 +361,14 @@ Guide <- ggproto(
351361
},
352362

353363
# Renders tickmarks
354-
build_ticks = function(key, elements, params, position = params$position) {
364+
build_ticks = function(key, elements, params, position = params$position,
365+
length = elements$ticks_length) {
366+
if (!inherits(elements, "element")) {
367+
elements <- elements$ticks
368+
}
369+
if (!inherits(elements, "element_line")) {
370+
return(zeroGrob())
371+
}
355372

356373
if (!is.list(key)) {
357374
breaks <- key
@@ -365,8 +382,7 @@ Guide <- ggproto(
365382
return(zeroGrob())
366383
}
367384

368-
tick_len <- rep(elements$ticks_length %||% unit(0.2, "npc"),
369-
length.out = n_breaks)
385+
tick_len <- rep(length %||% unit(0.2, "npc"), length.out = n_breaks)
370386

371387
# Resolve mark
372388
mark <- unit(rep(breaks, each = 2), "npc")
@@ -375,12 +391,12 @@ Guide <- ggproto(
375391
pos <- unname(c(top = 1, bottom = 0, left = 0, right = 1)[position])
376392
dir <- -2 * pos + 1
377393
pos <- unit(rep(pos, 2 * n_breaks), "npc")
378-
dir <- rep(vec_interleave(0, dir), n_breaks) * tick_len
394+
dir <- rep(vec_interleave(dir, 0), n_breaks) * tick_len
379395
tick <- pos + dir
380396

381397
# Build grob
382398
flip_element_grob(
383-
elements$ticks,
399+
elements,
384400
x = tick, y = mark,
385401
id.lengths = rep(2, n_breaks),
386402
flip = position %in% c("top", "bottom")

R/guide-axis.R

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#' @param n.dodge The number of rows (for vertical axes) or columns (for
1515
#' horizontal axes) that should be used to render the labels. This is
1616
#' useful for displaying labels that would otherwise overlap.
17+
#' @param minor.ticks Whether to draw the minor ticks (`TRUE`) or not draw
18+
#' minor ticks (`FALSE`, default).
1719
#' @param cap A `character` to cut the axis line back to the last breaks. Can
1820
#' be `"none"` (default) to draw the axis line along the whole panel, or
1921
#' `"upper"` and `"lower"` to draw the axis to the upper or lower break, or
@@ -42,23 +44,23 @@
4244
#' # can also be used to add a duplicate guide
4345
#' p + guides(x = guide_axis(n.dodge = 2), y.sec = guide_axis())
4446
guide_axis <- function(title = waiver(), check.overlap = FALSE, angle = NULL,
45-
n.dodge = 1, cap = "none", order = 0,
46-
position = waiver()) {
47-
47+
n.dodge = 1, minor.ticks = FALSE, cap = "none",
48+
order = 0, position = waiver()) {
49+
check_bool(minor.ticks)
4850
if (is.logical(cap)) {
4951
check_bool(cap)
5052
cap <- if (cap) "both" else "none"
5153
}
5254
cap <- arg_match0(cap, c("none", "both", "upper", "lower"))
5355

54-
5556
new_guide(
5657
title = title,
5758

5859
# customisations
5960
check.overlap = check.overlap,
6061
angle = angle,
6162
n.dodge = n.dodge,
63+
minor.ticks = minor.ticks,
6264
cap = cap,
6365

6466
# parameter
@@ -87,6 +89,7 @@ GuideAxis <- ggproto(
8789
direction = NULL,
8890
angle = NULL,
8991
n.dodge = 1,
92+
minor.ticks = FALSE,
9093
cap = "none",
9194
order = 0,
9295
check.overlap = FALSE
@@ -100,9 +103,37 @@ GuideAxis <- ggproto(
100103
line = "axis.line",
101104
text = "axis.text",
102105
ticks = "axis.ticks",
103-
ticks_length = "axis.ticks.length"
106+
minor = "axis.minor.ticks",
107+
major_length = "axis.ticks.length",
108+
minor_length = "axis.minor.ticks.length"
104109
),
105110

111+
extract_key = function(scale, aesthetic, minor.ticks, ...) {
112+
major <- Guide$extract_key(scale, aesthetic, ...)
113+
if (!minor.ticks) {
114+
return(major)
115+
}
116+
117+
minor_breaks <- scale$get_breaks_minor()
118+
minor_breaks <- setdiff(minor_breaks, major$.value)
119+
minor_breaks <- minor_breaks[is.finite(minor_breaks)]
120+
121+
if (length(minor_breaks) < 1) {
122+
return(major)
123+
}
124+
125+
minor <- data_frame0(!!aesthetic := scale$map(minor_breaks))
126+
minor$.value <- minor_breaks
127+
minor$.type <- "minor"
128+
129+
if (nrow(major) > 0) {
130+
major$.type <- "major"
131+
vec_rbind(major, minor)
132+
} else {
133+
minor
134+
}
135+
},
136+
106137
extract_params = function(scale, params, ...) {
107138
params$name <- paste0(params$name, "_", params$aesthetic)
108139
params
@@ -185,7 +216,7 @@ GuideAxis <- ggproto(
185216
},
186217

187218
setup_elements = function(params, elements, theme) {
188-
axis_elem <- c("line", "text", "ticks", "ticks_length")
219+
axis_elem <- c("line", "text", "ticks", "minor", "major_length", "minor_length")
189220
is_char <- vapply(elements[axis_elem], is.character, logical(1))
190221
axis_elem <- axis_elem[is_char]
191222
elements[axis_elem] <- lapply(
@@ -225,26 +256,17 @@ GuideAxis <- ggproto(
225256
"horizontal"
226257
}
227258

228-
# TODO: delete following comment at some point:
229-
# I found the 'position_*'/'non-position_*' and '*_dim' names confusing.
230-
# For my own understanding, these have been renamed as follows:
231-
# * 'aes' and 'orth_aes' for the aesthetic direction and the direction
232-
# orthogonal to the aesthetic direction, respectively.
233-
# * 'para_sizes' and 'orth_size(s)' for the dimension parallel to the
234-
# aesthetic and orthogonal to the aesthetic respectively.
235-
# I also tried to trim down the verbosity of the variable names a bit
236-
237259
new_params <- c("aes", "orth_aes", "para_sizes", "orth_size", "orth_sizes",
238260
"vertical", "measure_gtable", "measure_text")
239261
if (direction == "vertical") {
240262
params[new_params] <- list(
241263
"y", "x", "heights", "width", "widths",
242-
TRUE, gtable_width, grobWidth
264+
TRUE, gtable_width, width_cm
243265
)
244266
} else {
245267
params[new_params] <- list(
246268
"x", "y", "widths", "height", "heights",
247-
FALSE, gtable_height, grobHeight
269+
FALSE, gtable_height, height_cm
248270
)
249271
}
250272

@@ -275,7 +297,32 @@ GuideAxis <- ggproto(
275297
)
276298
},
277299

300+
build_ticks = function(key, elements, params, position = params$opposite) {
301+
302+
major <- Guide$build_ticks(
303+
vec_slice(key, (key$.type %||% "major") == "major"),
304+
elements$ticks, params, position,
305+
elements$major_length
306+
)
307+
308+
if (!params$minor.ticks) {
309+
return(major)
310+
}
311+
312+
minor <- Guide$build_ticks(
313+
vec_slice(key, (key$.type %||% "major") == "minor"),
314+
elements$minor, params, position,
315+
elements$minor_length
316+
)
317+
grobTree(major, minor, name = "ticks")
318+
},
319+
278320
build_labels = function(key, elements, params) {
321+
322+
if (".type" %in% names(key)) {
323+
key <- vec_slice(key, key$.type == "major")
324+
}
325+
279326
labels <- validate_labels(key$.label)
280327
n_labels <- length(labels)
281328

@@ -309,10 +356,20 @@ GuideAxis <- ggproto(
309356

310357
measure <- params$measure_text
311358

312-
length <- elements$ticks_length
313-
spacer <- max(unit(0, "pt"), -1 * length)
314-
labels <- do.call(unit.c, lapply(grobs$labels, measure))
315-
title <- measure(grobs$title)
359+
# Ticks
360+
major_cm <- convertUnit(elements$major_length, "cm", valueOnly = TRUE)
361+
range <- range(0, major_cm)
362+
if (params$minor.ticks && !inherits(elements$minor, "element_blank")) {
363+
minor_cm <- convertUnit(elements$minor_length, "cm", valueOnly = TRUE)
364+
range <- range(range, minor_cm)
365+
}
366+
367+
length <- unit(range[2], "cm")
368+
spacer <- max(unit(0, "pt"), unit(-1 * diff(range), "cm"))
369+
370+
# Text
371+
labels <- unit(measure(grobs$label), "cm")
372+
title <- unit(measure(grobs$title), "cm")
316373

317374
sizes <- unit.c(length, spacer, labels, title)
318375
if (params$lab_first) {
@@ -429,7 +486,7 @@ draw_axis <- function(break_positions, break_labels, axis_position, theme,
429486
!!aes := c(0, 1),
430487
!!opp := opp_value
431488
)
432-
guide$draw(theme, params)
489+
guide$draw(theme, params = params)
433490
}
434491

435492
draw_axis_labels <- function(break_positions, break_labels, label_element, is_vertical,

0 commit comments

Comments
 (0)