Skip to content

Commit b571625

Browse files
authored
Merge branch 'main' into theme_geom_defaults
2 parents e718db1 + 5971ff4 commit b571625

25 files changed

+291
-187
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@ Imports:
3939
isoband,
4040
lifecycle (> 1.0.1),
4141
MASS,
42-
mgcv,
4342
rlang (>= 1.1.0),
4443
scales (>= 1.3.0),
4544
stats,
46-
tibble,
4745
vctrs (>= 0.6.0),
4846
withr (>= 2.5.0)
4947
Suggests:
@@ -55,6 +53,7 @@ Suggests:
5553
knitr,
5654
mapproj,
5755
maps,
56+
mgcv,
5857
multcomp,
5958
munsell,
6059
nlme,
@@ -67,6 +66,7 @@ Suggests:
6766
sf (>= 0.7-3),
6867
svglite (>= 2.1.2),
6968
testthat (>= 3.1.5),
69+
tibble,
7070
vdiffr (>= 1.0.6),
7171
xml2
7272
Enhances:

NAMESPACE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@ export(remove_missing)
516516
export(render_axes)
517517
export(render_strips)
518518
export(replace_theme)
519+
export(reset_geom_defaults)
520+
export(reset_stat_defaults)
519521
export(reset_theme_settings)
520522
export(resolution)
521523
export(scale_alpha)
@@ -736,7 +738,6 @@ importFrom(grid,unit)
736738
importFrom(lifecycle,deprecated)
737739
importFrom(scales,alpha)
738740
importFrom(stats,setNames)
739-
importFrom(tibble,tibble)
740741
importFrom(utils,.DollarNames)
741742
importFrom(utils,head)
742743
importFrom(utils,tail)

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
* The `element_geom()` function can be used to populate that argument.
77
* The `from_theme()` function allows access to the theme default fields from
88
inside the `aes()` function.
9+
* Passing empty unmapped aesthetics to layers raises a warning instead of
10+
throwing an error (@teunbrand, #6009).
11+
* Moved {mgcv} from Imports to Suggests (@teunbrand, #5986)
12+
* New `reset_geom_defaults()` and `reset_stat_defaults()` to restore all geom or
13+
stat default aesthetics at once (@teunbrand, #5975).
914
* `facet_wrap()` can have `space = "free_x"` with 1-row layouts and
1015
`space = "free_y"` with 1-column layouts (@teunbrand)
1116
* Secondary axes respect `n.breaks` setting in continuous scales (@teunbrand, #4483).
@@ -158,6 +163,11 @@
158163
(@teunbrand, #5945).
159164
* (internal) The summary function of `stat_summary()` and `stat_summary_bin()`
160165
is setup once in total instead of once per group (@teunbrand, #5971)
166+
* `facet_grid(space = "free")` can now be combined with `coord_fixed()`
167+
(@teunbrand, #4584).
168+
* `theme_classic()` now has black ticks and text instead of dark gray. In
169+
addition, `theme_classic()`'s axis line end is `"square"` (@teunbrand, #5978).
170+
* {tibble} is now suggested instead of imported (@teunbrand, #5986)
161171

162172
# ggplot2 3.5.1
163173

R/facet-.R

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,18 +139,22 @@ Facet <- ggproto("Facet", NULL,
139139
free <- params$free %||% list(x = FALSE, y = FALSE)
140140
space <- params$space_free %||% list(x = FALSE, y = FALSE)
141141

142-
if ((free$x || free$y) && !coord$is_free()) {
143-
cli::cli_abort(
144-
"{.fn {snake_class(self)}} can't use free scales with \\
145-
{.fn {snake_class(coord)}}."
146-
)
147-
}
148-
149142
aspect_ratio <- theme$aspect.ratio
150143
if (!is.null(aspect_ratio) && (space$x || space$y)) {
151144
cli::cli_abort("Free scales cannot be mixed with a fixed aspect ratio.")
152145
}
153146

147+
if (!coord$is_free()) {
148+
if (space$x && space$y) {
149+
aspect_ratio <- aspect_ratio %||% coord$ratio
150+
} else if (free$x || free$y) {
151+
cli::cli_abort(
152+
"{.fn {snake_class(self)}} can't use free scales with \\
153+
{.fn {snake_class(coord)}}."
154+
)
155+
}
156+
}
157+
154158
table <- self$init_gtable(
155159
panels, layout, theme, ranges, params,
156160
aspect_ratio = aspect_ratio %||% coord$aspect(ranges[[1]])
@@ -219,7 +223,7 @@ Facet <- ggproto("Facet", NULL,
219223
if (space$y) {
220224
idx <- layout$PANEL[layout$COL == 1]
221225
heights <- vapply(idx, function(i) diff(ranges[[i]]$y.range), numeric(1))
222-
heights <- unit(heights, "null")
226+
heights <- unit(heights * abs(aspect_ratio %||% 1), "null")
223227
}
224228

225229
# Build gtable
@@ -560,7 +564,7 @@ is_facets <- function(x) {
560564
# but that seems like a reasonable tradeoff.
561565
eval_facets <- function(facets, data, possible_columns = NULL) {
562566
vars <- compact(lapply(facets, eval_facet, data, possible_columns = possible_columns))
563-
data_frame0(tibble::as_tibble(vars))
567+
data_frame0(!!!vars)
564568
}
565569
eval_facet <- function(facet, data, possible_columns = NULL) {
566570
# Treat the case when `facet` is a quosure of a symbol specifically

R/geom-defaults.R

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#' Modify geom/stat aesthetic defaults for future plots
22
#'
3+
#' Functions to update or reset the default aesthetics of geoms and stats.
4+
#'
35
#' @param stat,geom Name of geom/stat to modify (like `"point"` or
46
#' `"bin"`), or a Geom/Stat object (like `GeomPoint` or
57
#' `StatBin`).
@@ -20,9 +22,11 @@
2022
#' GeomPoint$default_aes
2123
#' ggplot(mtcars, aes(mpg, wt)) + geom_point()
2224
#'
23-
#' # reset default
25+
#' # reset single default
2426
#' update_geom_defaults("point", NULL)
2527
#'
28+
#' # reset all defaults
29+
#' reset_geom_defaults()
2630
#'
2731
#' # updating a stat's default aesthetic settings
2832
#' # example: change stat_bin()'s default y-axis to the density scale
@@ -33,9 +37,12 @@
3337
#' geom_histogram() +
3438
#' geom_function(fun = dnorm, color = "red")
3539
#'
36-
#' # reset default
40+
#' # reset single default
3741
#' update_stat_defaults("bin", NULL)
3842
#'
43+
#' # reset all defaults
44+
#' reset_stat_defaults()
45+
#'
3946
#' @rdname update_defaults
4047
update_geom_defaults <- function(geom, new) {
4148
update_defaults(geom, "Geom", new, env = parent.frame())
@@ -98,6 +105,13 @@ get_geom_defaults <- function(geom, theme = theme_get()) {
98105
stop_input_type(geom, as_cli("a layer function, string or {.cls Geom} object"))
99106
}
100107

108+
#' @rdname update_defaults
109+
#' @export
110+
reset_geom_defaults <- function() reset_defaults("geom")
111+
112+
#' @rdname update_defaults
113+
#' @export
114+
reset_stat_defaults <- function() reset_defaults("stat")
101115

102116
cache_defaults <- new_environment()
103117

@@ -128,3 +142,20 @@ update_defaults <- function(name, subclass, new, env = parent.frame()) {
128142

129143
}
130144
}
145+
146+
reset_defaults <- function(type) {
147+
# Lookup matching names in cache
148+
prefix <- paste0("^", type, "_")
149+
full_names <- grep(prefix, ls(cache_defaults), value = TRUE)
150+
# Early exit if there is nothing to reset
151+
if (length(full_names) < 1) {
152+
return(invisible())
153+
}
154+
# Format names without prefix
155+
short_names <- gsub(prefix, "", full_names)
156+
names(short_names) <- full_names
157+
158+
# Run updates
159+
update <- switch(type, geom = update_geom_defaults, update_stat_defaults)
160+
invisible(lapply(short_names, update, new = NULL))
161+
}

R/layer.R

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ layer <- function(geom = NULL, stat = NULL,
146146
if (any(pattern)) {
147147
aes_params[pattern] <- lapply(aes_params[pattern], list)
148148
}
149+
# Drop empty aesthetics
150+
empty_aes <- names(aes_params)[lengths(aes_params) == 0]
151+
if (length(empty_aes) > 0) {
152+
cli::cli_warn(
153+
"Ignoring empty aesthetic{?s}: {.arg {empty_aes}}.",
154+
call = call_env
155+
)
156+
aes_params <- aes_params[setdiff(names(aes_params), empty_aes)]
157+
}
149158

150159
# Warn about extra params and aesthetics
151160
extra_param <- setdiff(names(params), all)

R/position-stack.R

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,12 @@
116116
#'
117117
#' # Negative values -----------------------------------------------------------
118118
#'
119-
#' df <- tibble::tribble(
120-
#' ~x, ~y, ~grp,
121-
#' "a", 1, "x",
122-
#' "a", 2, "y",
123-
#' "b", 1, "x",
124-
#' "b", 3, "y",
125-
#' "b", -1, "y"
119+
#' df <- data.frame(
120+
#' x = rep(c("a", "b"), 2:3),
121+
#' y = c(1, 2, 1, 3, -1),
122+
#' grp = c("x", "y", "x", "y", "y")
126123
#' )
124+
#'
127125
#' ggplot(data = df, aes(x, y, group = grp)) +
128126
#' geom_col(aes(fill = grp), position = position_stack(reverse = TRUE)) +
129127
#' geom_hline(yintercept = 0)

R/stat-contour.R

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ StatContour <- ggproto("StatContour", Stat,
108108
breaks <- contour_breaks(z.range, bins, binwidth, breaks)
109109

110110
isolines <- withr::with_options(list(OutDec = "."), xyz_to_isolines(data, breaks))
111-
path_df <- iso_to_path(isolines, data$group[1])
111+
path_df <- iso_to_geom(isolines, data$group[1], geom = "path")
112112

113113
path_df$level <- as.numeric(path_df$level)
114114
path_df$nlevel <- rescale_max(path_df$level)
@@ -142,7 +142,7 @@ StatContourFilled <- ggproto("StatContourFilled", Stat,
142142

143143
isobands <- withr::with_options(list(OutDec = "."), xyz_to_isobands(data, breaks))
144144
names(isobands) <- pretty_isoband_levels(names(isobands))
145-
path_df <- iso_to_polygon(isobands, data$group[1])
145+
path_df <- iso_to_geom(isobands, data$group[1], geom = "polygon")
146146

147147
path_df$level <- ordered(path_df$level, levels = names(isobands))
148148
path_df$level_low <- breaks[as.numeric(path_df$level)]
@@ -259,51 +259,17 @@ isoband_z_matrix <- function(data) {
259259
raster
260260
}
261261

262-
#' Convert the output of isolines functions
263-
#'
264-
#' @param iso the output of [isoband::isolines()]
265-
#' @param group the name of the group
266-
#'
267-
#' @return A data frame that can be passed to [geom_path()].
268-
#' @noRd
269-
#'
270-
iso_to_path <- function(iso, group = 1) {
271-
lengths <- vapply(iso, function(x) length(x$x), integer(1))
272-
273-
if (all(lengths == 0)) {
274-
cli::cli_warn("{.fn stat_contour}: Zero contours were generated")
275-
return(data_frame0())
276-
}
277-
278-
levels <- names(iso)
279-
xs <- unlist(lapply(iso, "[[", "x"), use.names = FALSE)
280-
ys <- unlist(lapply(iso, "[[", "y"), use.names = FALSE)
281-
ids <- unlist(lapply(iso, "[[", "id"), use.names = FALSE)
282-
item_id <- rep(seq_along(iso), lengths)
283-
284-
# Add leading zeros so that groups can be properly sorted
285-
groups <- paste(group, sprintf("%03d", item_id), sprintf("%03d", ids), sep = "-")
286-
groups <- factor(groups)
287-
288-
data_frame0(
289-
level = rep(levels, lengths),
290-
x = xs,
291-
y = ys,
292-
piece = as.integer(groups),
293-
group = groups,
294-
.size = length(xs)
295-
)
296-
}
297-
298262
#' Convert the output of isoband functions
299263
#'
300-
#' @param iso the output of [isoband::isobands()]
264+
#' @param iso the output of [isoband::isobands()] or [isoband::isolines()]
301265
#' @param group the name of the group
266+
#' @param geom The type of geometry to return. Either `"path"` or `"polygon"`
267+
#' for isolines and isobands respectively.
302268
#'
303-
#' @return A data frame that can be passed to [geom_polygon()].
269+
#' @return A data frame that can be passed to [geom_polygon()] or [geom_path()].
304270
#' @noRd
305271
#'
306-
iso_to_polygon <- function(iso, group = 1) {
272+
iso_to_geom <- function(iso, group = 1, geom = "path") {
307273
lengths <- vapply(iso, function(x) length(x$x), integer(1))
308274

309275
if (all(lengths == 0)) {
@@ -319,6 +285,11 @@ iso_to_polygon <- function(iso, group = 1) {
319285

320286
# Add leading zeros so that groups can be properly sorted
321287
groups <- paste(group, sprintf("%03d", item_id), sep = "-")
288+
if (geom == "path") {
289+
groups <- paste(groups, sprintf("%03d", ids), sep = "-")
290+
ids <- NULL
291+
}
292+
322293
groups <- factor(groups)
323294

324295
data_frame0(

0 commit comments

Comments
 (0)