Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: ggplot2
Title: Create Elegant Data Visualisations Using the Grammar of Graphics
Version: 4.0.0.9000
Version: 4.0.2.9000
Authors@R: c(
person("Hadley", "Wickham", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0003-4757-117X")),
Expand Down
47 changes: 37 additions & 10 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
# ggplot2 (development version)
# Development version

This is a hotfix release fixing a test, a bug and introducing a feature.

* Adapt to changes in `rlang::warn_dots_used()` (@lionel-, #6830).
* Fixed bug where `guide_axis_theta()` didn't anticipate old-style text elements (#6803).
* `geom_boxplot()`/`stat_boxplot()` gain a `quantile.type` parameter (default `7`)
to control the percentile definition used for hinges and median; set `quantile.type = 2`
to match SAS's default `PCTLDEF = 5`, enabling parity with SAS boxplots out-of-the-box.
(@munoztd0, #6819)

# ggplot2 4.0.2

This hotfix release makes ggplot2 more interoperable between rlang versions.

* `make_constructor()` no longer captures `rlang::list2()` at build time.

# ggplot2 4.0.1

This is a smaller patch release focussed on fixing regressions from 4.0.0 and
polishing the recent features.

## Bug fixes

* Fixed regression where `geom_area()` didn't draw panels with single groups
when `stat = "align"` (@teunbrand, #6680)
* Fixed regression where `position_stack(vjust)` was ignored when there are
only single groups (#6692)
* Fixed bug where `NA` handling in `geom_path()` was ignoring panels (@teunbrand, #6533)
* Logical values for the linetype aesthetic will be interpreted numerically,
so that `linetype = FALSE` becomes 0/'blank' and `linetype = TRUE` becomes
1/'solid' (@teunbrand, #6641)
* Out-of-bounds datapoints used as padding by `stat_align()` now get removed
silently rather than verbosely (@teunbrand, #6667)
* Fixed bug where `stat_bin(boundary)` was ignored (#6682).
* `geom_text()` and `geom_label()` accept expressions as the `label` aesthetic
(@teunbrand, #6638)
* Fixed regression where `draw_key_rect()` stopped using `fill` colours
(@mitchelloharawild, #6609).
* Fixed regression where `scale_{x,y}_*()` threw an error when an expression
object is set to `labels` argument (@yutannihilation, #6617).
* Improved palette fallback mechanism in scales (@teunbrand, #6669).
* Allow `stat` in `geom_hline`, `geom_vline`, and `geom_abline`. (@sierrajohnson, #6559)
* `stat_boxplot()` treats `width` as an optional aesthetic (@Yunuuuu, #6575)
* Fixed regression where the first (unnamed) argument to colour/fill scales was
not passed as the `name` argument (@teunbrand, #6623)
* Fixed issue where vectorised `arrow()`s caused errors in drawing the
Expand All @@ -28,10 +42,21 @@
insistently. Now they contribute only as fallback labels (@teunbrand, #6616)
* Fixed regression where empty arguments to colour/fill scale caused errors
(@jmbarbone, #6710)
* Fixed axis misplacement in `coor_radial()` when labels are blank (@teunbrand, #6574)

## Improvements

* Improved palette fallback mechanism in scales (@teunbrand, #6669).
* Allow `stat` in `geom_hline`, `geom_vline`, and `geom_abline`. (@sierrajohnson, #6559)
* `stat_boxplot()` treats `width` as an optional aesthetic (@Yunuuuu, #6575)
* The `theme(panel.widths, panel.heights)` setting attempts to preserve the
plot's aspect ratio when only one of the two settings is given, and the plot
has a single panel (@teunbrand, #6701).
* Fixed axis misplacement in `coor_radial()` when labels are blank (@teunbrand, #6574)
* Logical values for the linetype aesthetic will be interpreted numerically,
so that `linetype = FALSE` becomes 0/'blank' and `linetype = TRUE` becomes
1/'solid' (@teunbrand, #6641)
* Out-of-bounds datapoints used as padding by `stat_align()` now get removed
silently rather than verbosely (@teunbrand, #6667)

# ggplot2 4.0.0

Expand Down Expand Up @@ -125,6 +150,8 @@
* `header_family` to easily set the font for headers and titles (#5886)
* To accommodate, `plot.subtitle`, `plot.caption` and `plot.tag` now
inherit from the root `text` element instead of the `title` element.
* The `base_size` argument also propagates to settings in the `theme(geom)`
setting.
* New function family for setting parts of a theme. For example, you can now use
`theme_sub_axis(line, text, ticks, ticks.length, line)` as a substitute for
`theme(axis.line, axis.text, axis.ticks, axis.ticks.length, axis.line)`. This
Expand Down
8 changes: 4 additions & 4 deletions R/facet-.R
Original file line number Diff line number Diff line change
Expand Up @@ -1421,14 +1421,14 @@ censor_labels <- function(ranges, layout, labels) {
)

if (!labels$x) {
xmax <- stats::ave(layout$ROW, layout$COL, FUN = max)
xmin <- stats::ave(layout$ROW, layout$COL, FUN = min)
xmax <- vec_ave(layout$ROW, layout$COL, max)
xmin <- vec_ave(layout$ROW, layout$COL, min)
draw[which(layout$ROW != xmax), "bottom"] <- FALSE
draw[which(layout$ROW != xmin), "top"] <- FALSE
}
if (!labels$y) {
ymax <- stats::ave(layout$COL, layout$ROW, FUN = max)
ymin <- stats::ave(layout$COL, layout$ROW, FUN = min)
ymax <- vec_ave(layout$COL, layout$ROW, max)
ymin <- vec_ave(layout$COL, layout$ROW, min)
draw[which(layout$COL != ymax), "right"] <- FALSE
draw[which(layout$COL != ymin), "left"] <- FALSE
}
Expand Down
4 changes: 2 additions & 2 deletions R/geom-path.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ GeomPath <- ggproto("GeomPath", Geom,
# middle since you expect those to be shown by a break in the line
aesthetics <- c(self$required_aes, self$non_missing_aes)
complete <- stats::complete.cases(data[names(data) %in% aesthetics])
kept <- stats::ave(complete, data$group, data$PANEL, FUN = keep_mid_true)
kept <- vec_ave(complete, interaction(data$group, data$PANEL, drop = TRUE), keep_mid_true)
data <- data[kept, ]

if (!all(kept) && !params$na.rm) {
Expand Down Expand Up @@ -48,7 +48,7 @@ GeomPath <- ggproto("GeomPath", Geom,
munched <- coord_munch(coord, data, panel_params)

# Silently drop lines with less than two points, preserving order
rows <- stats::ave(seq_len(nrow(munched)), munched$group, FUN = length)
rows <- vec_ave(seq_len(nrow(munched)), munched$group, length)
munched <- munched[rows >= 2, ]
if (nrow(munched) < 2) return(zeroGrob())

Expand Down
2 changes: 1 addition & 1 deletion R/guide-.R
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ Guide <- ggproto(

if (is.numeric(breaks)) {
range <- scale$continuous_range %||% scale$get_limits()
key <- vec_slice(key, is.finite(oob_censor_any(breaks, range)))
key <- key[is.finite(oob_censor_any(breaks, range)), , drop = FALSE]
} else {
key
}
Expand Down
6 changes: 5 additions & 1 deletion R/guide-axis-theta.R
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,11 @@ GuideAxisTheta <- ggproto(

# Resolve text angle
if (is_waiver(params$angle) || is.null(params$angle)) {
angle <- elements$text@angle
angle <- if (S7::S7_inherits(elements$text)) {
elements$text@angle
} else {
elements$text$angle
}
} else {
angle <- flip_text_angle(params$angle - rad2deg(key$theta))
}
Expand Down
2 changes: 1 addition & 1 deletion R/guide-bins.R
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ GuideBins <- ggproto(
}

key$.label <- labels
key <- vec_slice(key, !is.na(oob_censor_any(key$.value)))
key <- key[!is.na(oob_censor_any(key$.value)), , drop = FALSE]

return(key)
},
Expand Down
4 changes: 1 addition & 3 deletions R/layer.R
Original file line number Diff line number Diff line change
Expand Up @@ -972,10 +972,8 @@ normalise_label <- function(label) {
return(NULL)
}
if (obj_is_list(label)) {
# Ensure that each element in the list has length 1
# Ensure no elements are empty
label[lengths(label) == 0] <- ""
truncate <- !vapply(label, is.call, logical(1)) # Don't mess with call/formula
label[truncate] <- lapply(label[truncate], `[`, 1)
}
if (is.expression(label)) {
# Classed expressions, when converted to lists, retain their class.
Expand Down
7 changes: 5 additions & 2 deletions R/make-constructor.R
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ make_constructor.Geom <- function(x, ..., checks = exprs(), omit = character(),
body <- call2("{", !!!checks, body)

# We encapsulate rlang::list2
new_env <- new_environment(list(list2 = list2), env)
new_env <- new_environment(list(list2 = list2_wrapper), env)

new_function(fmls, body, new_env)
}
Expand Down Expand Up @@ -225,8 +225,11 @@ make_constructor.Stat <- function(x, ..., checks = exprs(), omit = character(),
body <- call2("{", !!!checks, body)

# We encapsulate rlang::list2
new_env <- new_environment(list(list2 = list2), env)
new_env <- new_environment(list(list2 = list2_wrapper), env)

new_function(fmls, body, new_env)
}

list2_wrapper = function(...) {
rlang::list2(...)
}
4 changes: 2 additions & 2 deletions R/position-dodge.R
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,13 @@ PositionDodge <- ggproto("PositionDodge", Position,
}

data$order <- xtfrm( # xtfrm makes anything 'sortable'
data$order %||% ave(data$group, data$x, data$PANEL, FUN = match_sorted)
data$order %||% vec_ave(data$group, data[c("x", "PANEL")], fn = match_sorted)
)
if (isTRUE(params$reverse)) {
data$order <- -data$order
}
if (is.null(params$n)) { # preserve = "total"
data$order <- ave(data$order, data$x, data$PANEL, FUN = match_sorted)
data$order <- vec_ave(data$order, data[c("x", "PANEL")], fn = match_sorted)
} else { # preserve = "single"
data$order <- match_sorted(data$order)
}
Expand Down
7 changes: 5 additions & 2 deletions R/stat-boxplot.R
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,16 @@ StatBoxplot <- ggproto("StatBoxplot", Stat,

extra_params = c("na.rm", "orientation"),

compute_group = function(data, scales, width = NULL, na.rm = FALSE, coef = 1.5, flipped_aes = FALSE) {
compute_group = function(data, scales, width = NULL, na.rm = FALSE, coef = 1.5, flipped_aes = FALSE, quantile.type = 7) {
data <- flip_data(data, flipped_aes)
qs <- c(0, 0.25, 0.5, 0.75, 1)

if (!is.null(data$weight)) {
mod <- quantreg::rq(y ~ 1, weights = weight, data = data, tau = qs)
stats <- as.numeric(stats::coef(mod))
} else {
stats <- as.numeric(stats::quantile(data$y, qs))
# Follow base R default (type = 7) unless overridden by user
stats <- as.numeric(stats::quantile(data$y, qs, type = quantile.type))
}
names(stats) <- c("ymin", "lower", "middle", "upper", "ymax")
iqr <- diff(stats[c(2, 4)])
Expand Down Expand Up @@ -99,6 +100,8 @@ StatBoxplot <- ggproto("StatBoxplot", Stat,

#' @rdname geom_boxplot
#' @param coef Length of the whiskers as multiple of IQR. Defaults to 1.5.
#' @param quantile.type An integer between 1 and 9 setting the quantile algorithm
#' per [`stats::quantile(type)`][stats::quantile]. Defaults to `7`
#' @inheritParams stat_identity
#' @export
#' @eval rd_computed_vars(
Expand Down
2 changes: 1 addition & 1 deletion R/stat-sum.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ StatSum <- ggproto(

counts <- count(data, group_by, wt_var = "weight")
counts <- rename(counts, c(freq = "n"))
counts$prop <- stats::ave(counts$n, counts$group, FUN = prop.table)
counts$prop <- vec_ave(counts$n, counts$group, prop.table)
counts
}
)
Expand Down
4 changes: 2 additions & 2 deletions R/stat-ydensity.R
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ StatYdensity <- ggproto(
"{.arg quantiles} for weighted data is not implemented."
)
}
quants <- quantile(data$y, probs = quantiles)
quants <- stats::quantile(data$y, probs = quantiles)
quants <- data_frame0(
y = unname(quants),
quantile = quantiles
Expand All @@ -82,7 +82,7 @@ StatYdensity <- ggproto(
# Interpolate other metrics
for (var in setdiff(names(dens), names(quants))) {
quants[[var]] <-
approx(dens$y, dens[[var]], xout = quants$y, ties = "ordered")$y
stats::approx(dens$y, dens[[var]], xout = quants$y, ties = "ordered")$y
}

dens <- vec_slice(dens, !dens$y %in% quants$y)
Expand Down
13 changes: 12 additions & 1 deletion R/utilities.R
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ compute_data_size <- function(data, size, default = 0.9,
res <- vapply(res, resolution, FUN.VALUE = numeric(1), ...)
res <- min(res, na.rm = TRUE)
} else if (panels == "by") {
res <- stats::ave(data[[var]], data$PANEL, FUN = function(x) resolution(x, ...))
res <- vec_ave(data[[var]], data$PANEL, function(x) resolution(x, ...))
} else {
res <- resolution(data[[var]], ...)
}
Expand All @@ -930,3 +930,14 @@ try_prop <- function(object, name, default = NULL) {
}
S7::prop(object, name)
}

vec_ave <- function(x, by, fn, ...) {
idx <- vec_group_loc(by)$loc
list_unchop(
lapply(
vec_chop(x, indices = idx),
FUN = fn, ...
),
indices = idx
)
}
4 changes: 2 additions & 2 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ If you are new to ggplot2 you are better off starting with a systematic introduc
[Communication][r4ds-comm] chapters in
[R for Data Science][r4ds]. R for Data Science is designed to
give you a comprehensive introduction to the
[tidyverse](https://www.tidyverse.org), and these two chapters will
[tidyverse](https://tidyverse.org/), and these two chapters will
get you up to speed with the essentials of ggplot2 as quickly as
possible.

Expand Down Expand Up @@ -119,4 +119,4 @@ There are two main places to get help with ggplot2:
[r4ds-vis]: https://r4ds.hadley.nz/data-visualize
[r4ds-comm]: https://r4ds.hadley.nz/communication
[oreilly]: https://learning.oreilly.com/videos/data-visualization-in/9781491963661/
[blog]: https://www.tidyverse.org/tags/ggplot2/
[blog]: https://tidyverse.org/tags/ggplot2/
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ documentation pages. Currently, there are several good places to start:
[Communication](https://r4ds.hadley.nz/communication) chapters in [R
for Data Science](https://r4ds.hadley.nz). R for Data Science is
designed to give you a comprehensive introduction to the
[tidyverse](https://www.tidyverse.org), and these two chapters will
get you up to speed with the essentials of ggplot2 as quickly as
[tidyverse](https://tidyverse.org/), and these two chapters will get
you up to speed with the essentials of ggplot2 as quickly as
possible.

2. If you’d like to take an online course, try [Data Visualization in R
Expand All @@ -105,7 +105,7 @@ documentation pages. Currently, there are several good places to start:
graphics specifically tailored to your needs.

6. For articles about announcements and deep-dives you can visit the
[tidyverse blog](https://www.tidyverse.org/tags/ggplot2/).
[tidyverse blog](https://tidyverse.org/tags/ggplot2/).

## Getting help

Expand Down
3 changes: 2 additions & 1 deletion _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ template:
data-project-name="ggplot2"
data-modal-title="tidyverse AI ✨"
data-project-logo="https://avatars.githubusercontent.com/u/22032646?s=200&u=235532df5cf8543246812f73db051b793f868807&v=4"
data-user-analytics-fingerprint-enabled="true"
data-user-analytics-fingerprint-enabled="false"
data-user-analytics-cookie-enabled="false"
data-bot-protection-mechanism="hcaptcha"
data-website-id="5dcac24a-bd5a-4874-9f5b-3341afddd8c3"
></script>
Expand Down
11 changes: 2 additions & 9 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
This is a major release of ggplot2. Among other things it includes an adaption
of S7 for all the S3 classes and methods that were currently in use.
Unfortunately such a change is not without issue with the number of reverse
dependencies that ggplot2 has as many packages wrongfully checks the internals
of ggplot2 objects in their tests.

Because of this you should expect a larger than usual number of breaking
packages. We have been very diligent to reach out to all maintainers over the
last 2-3 months and provided resolutions but breakages are still to be expected.
This is a patch release that resolves a failing test and supports some minimal bug fixes and a small uninvasive feature.
We expect no problems with reverse dependencies.
4 changes: 4 additions & 0 deletions man/geom_boxplot.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading