Skip to content

Commit

Permalink
Merge branch 'main' into time_to_datetime_scale
Browse files Browse the repository at this point in the history
  • Loading branch information
teunbrand authored Jan 28, 2025
2 parents 467990b + b9d1c79 commit a69ccb3
Show file tree
Hide file tree
Showing 206 changed files with 3,162 additions and 1,388 deletions.
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ Collate:
'scales-.R'
'stat-align.R'
'stat-bin.R'
'stat-summary-2d.R'
'stat-bin2d.R'
'stat-bindot.R'
'stat-binhex.R'
Expand All @@ -263,7 +264,6 @@ Collate:
'stat-smooth-methods.R'
'stat-smooth.R'
'stat-sum.R'
'stat-summary-2d.R'
'stat-summary-bin.R'
'stat-summary-hex.R'
'stat-summary.R'
Expand All @@ -274,6 +274,7 @@ Collate:
'theme.R'
'theme-defaults.R'
'theme-current.R'
'theme-sub.R'
'utilities-break.R'
'utilities-grid.R'
'utilities-help.R'
Expand Down
11 changes: 11 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,17 @@ export(theme_linedraw)
export(theme_minimal)
export(theme_replace)
export(theme_set)
export(theme_sub_axis)
export(theme_sub_axis_bottom)
export(theme_sub_axis_left)
export(theme_sub_axis_right)
export(theme_sub_axis_top)
export(theme_sub_axis_x)
export(theme_sub_axis_y)
export(theme_sub_legend)
export(theme_sub_panel)
export(theme_sub_plot)
export(theme_sub_strip)
export(theme_test)
export(theme_transparent)
export(theme_update)
Expand Down
55 changes: 52 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
# ggplot2 (development version)

* Added `scale_{x/y}_time(date_breaks, date_minor_breaks, date_labels)`
(@teunbrand, #4335).
* `coord_radial()` now displays no axis instead of throwing an error when
a scale has no breaks (@teunbrand, #6271).
* The `fatten` argument has been deprecated in `geom_boxplot()`,
`geom_crossbar()` and `geom_pointrange()` (@teunbrand, #4881).
* Axis labels are now preserved better when using `coord_sf(expand = TRUE)` and
graticule lines are straight but do not meet the edge (@teunbrand, #2985).
* Attempt to boost detail in `coord_polar()` and `coord_radial()` near the
center (@teunbrand, #5023)
* Scale names, guide titles and aesthetic labels can now accept functions
(@teunbrand, #4313)
* Binned scales with zero-width data expand the default limits by 0.1
(@teunbrand, #5066)
* New default `geom_qq_line(geom = "abline")` for better clipping in the
vertical direction. In addition, `slope` and `intercept` are new computed
variables in `stat_qq_line()` (@teunbrand, #6087).
* Position adjustments can now have auxiliary aesthetics (@teunbrand).
* `position_nudge()` gains `nudge_x` and `nudge_y` aesthetics (#3026, #5445).
* `position_dodge()` gains `order` aesthetic (#3022, #3345)
* More stability for vctrs-based palettes (@teunbrand, #6117).
* Fixed regression in `guide_bins(reverse = TRUE)` (@teunbrand, #6183).
* 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
should allow slightly terser and more organised theme declarations
(@teunbrand, #5301).
* `scale_{x/y}_discrete(continuous.limits)` is a new argument to control the
display range of discrete scales (@teunbrand, #4174, #6259).
* `geom_ribbon()` now appropriately warns about, and removes, missing values
(@teunbrand, #6243).
* `guide_*()` can now accept two inside legend theme elements:
Expand Down Expand Up @@ -46,6 +71,13 @@
(@teunbrand, #4320)
* `geom_boxplot()` gains additional arguments to style the colour, linetype and
linewidths of the box, whiskers, median line and staples (@teunbrand, #5126)
* `geom_violin()` gains additional arguments to style the colour, linetype and
linewidths of the quantiles, which replace the now-deprecated `draw_quantiles`
argument (#5912).
* (breaking) `geom_violin(quantiles)` now has actual quantiles based on
the data, rather than inferred quantiles based on the computed density. The
`quantiles` parameter that replaces `draw_quantiles` now belongs to
`stat_ydensity()` instead of `geom_violin()` (@teunbrand, #4120).
* (internal) Using `after_scale()` in the `Geom*$default_aes()` field is now
evaluated in the context of data (@teunbrand, #6135)
* Fixed bug where binned scales wouldn't simultaneously accept transformations
Expand Down Expand Up @@ -234,7 +266,7 @@
* The ellipsis argument is now checked in `fortify()`, `get_alt_text()`,
`labs()` and several guides (@teunbrand, #3196).
* `stat_summary_bin()` no longer ignores `width` parameter (@teunbrand, #4647).
* Added `keep.zeroes` argument to `stat_bin()` (@teunbrand, #3449)
* Reintroduced `drop` argument to `stat_bin()` (@teunbrand, #3449)
* (internal) removed barriers for using 2D structures as aesthetics
(@teunbrand, #4189).
* `coord_sf()` no longer errors when dealing with empty graticules (@teunbrand, #6052)
Expand All @@ -247,6 +279,23 @@
* `geom_abline()` clips to the panel range in the vertical direction too
(@teunbrand, #6086).
* Added `panel.widths` and `panel.heights` to `theme()` (#5338, @teunbrand).
* Standardised the calculation of `width`, which are now implemented as
aesthetics (@teunbrand, #2800).
* Stricter check on `register_theme_elements(element_tree)` (@teunbrand, #6162)
* Added `weight` aesthetic for `stat_ellipse()` (@teunbrand, #5272)
* Fixed a bug where the `guide_custom(order)` wasn't working (@teunbrand, #6195)
* All binning stats now use the `boundary`/`center` parametrisation rather
than `origin`, following in `stat_bin()`'s footsteps (@teunbrand).
* `stat_summary_2d()` and `stat_bin_2d()` now deal with zero-range data
more elegantly (@teunbrand, #6207).
* Munching in `coord_polar()` and `coord_radial()` now adds more detail,
particularly for data-points with a low radius near the center
(@teunbrand, #5023).
* All scales now expose the `aesthetics` parameter (@teunbrand, #5841)
* New `theme(legend.key.justification)` to control the alignment of legend keys
(@teunbrand, #3669).
* Added `scale_{x/y}_time(date_breaks, date_minor_breaks, date_labels)`
(@teunbrand, #4335).

# ggplot2 3.5.1

Expand Down
7 changes: 7 additions & 0 deletions R/aes.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ NULL
#'
#' [Delayed evaluation][aes_eval] for working with computed variables.
#'
#' @note
#' Using `I()` to create objects of class 'AsIs' causes scales to ignore the
#' variable and assumes the wrapped variable is direct input for the grid
#' package. Please be aware that variables are sometimes combined, like in
#' some stats or position adjustments, that may yield unexpected results with
#' 'AsIs' variables.
#'
#' @family aesthetics documentation
#' @return A list with class `uneval`. Components of the list are either
#' quosures or constants.
Expand Down
4 changes: 2 additions & 2 deletions R/axis-secondary.R
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ AxisSecondary <- ggproto("AxisSecondary", NULL,
scale$train(range)
scale
},
make_title = function(title) {
title
make_title = function(...) {
ScaleContinuous$make_title(...)
}
)
109 changes: 94 additions & 15 deletions R/bin.R
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,12 @@ bin_breaks <- function(breaks, closed = c("right", "left")) {

bin_breaks_width <- function(x_range, width = NULL, center = NULL,
boundary = NULL, closed = c("right", "left")) {
check_length(x_range, 2L)

# binwidth seems to be the argument name supplied to width. (stat-bin and stat-bindot)
check_number_decimal(width, min = 0, allow_infinite = FALSE, arg = "binwidth")

if (!is.null(boundary) && !is.null(center)) {
cli::cli_abort("Only one of {.arg boundary} and {.arg center} may be specified.")
} else if (is.null(boundary)) {
if (is.null(boundary)) {
if (is.null(center)) {
# If neither edge nor center given, compute both using tile layer's
# algorithm. This puts min and max of data in outer half of their bins.
boundary <- width / 2

} else {
# If center given but not boundary, compute boundary.
boundary <- center - width / 2
Expand All @@ -75,9 +68,6 @@ bin_breaks_width <- function(x_range, width = NULL, center = NULL,

# Find the left side of left-most bin: inputs could be Dates or POSIXct, so
# coerce to numeric first.
x_range <- as.numeric(x_range)
width <- as.numeric(width)
boundary <- as.numeric(boundary)
shift <- floor((x_range[1] - boundary) / width)
origin <- boundary + shift * width

Expand All @@ -104,9 +94,7 @@ bin_breaks_width <- function(x_range, width = NULL, center = NULL,

bin_breaks_bins <- function(x_range, bins = 30, center = NULL,
boundary = NULL, closed = c("right", "left")) {
check_length(x_range, 2L)

check_number_whole(bins, min = 1)
if (zero_range(x_range)) {
# 0.1 is the same width as the expansion `default_expansion()` gives for 0-width data
width <- 0.1
Expand All @@ -128,6 +116,56 @@ bin_breaks_bins <- function(x_range, bins = 30, center = NULL,

# Compute bins ------------------------------------------------------------

compute_bins <- function(x, scale = NULL, breaks = NULL, binwidth = NULL, bins = NULL,
center = NULL, boundary = NULL,
closed = c("right", "left")) {

range <- if (is.scale(scale)) scale$dimension() else range(x)
check_length(range, 2L)

if (!is.null(breaks)) {
breaks <- allow_lambda(breaks)
if (is.function(breaks)) {
breaks <- breaks(x)
}
if (is.scale(scale) && !scale$is_discrete()) {
breaks <- scale$transform(breaks)
}
check_numeric(breaks)
bins <- bin_breaks(breaks, closed)
return(bins)
}

check_number_decimal(boundary, allow_infinite = FALSE, allow_null = TRUE)
check_number_decimal(center, allow_infinite = FALSE, allow_null = TRUE)
if (!is.null(boundary) && !is.null(center)) {
cli::cli_abort("Only one of {.arg boundary} and {.arg center} may be specified.")
}

if (!is.null(binwidth)) {
binwidth <- allow_lambda(binwidth)
if (is.function(binwidth)) {
binwidth <- binwidth(x)
}
check_number_decimal(binwidth, min = 0, allow_infinite = FALSE)
bins <- bin_breaks_width(
range, binwidth,
center = center, boundary = boundary, closed = closed
)
return(bins)
}

bins <- allow_lambda(bins)
if (is.function(bins)) {
bins <- bins(x)
}
check_number_whole(bins, min = 1, allow_infinite = FALSE)
bin_breaks_bins(
range, bins,
center = center, boundary = boundary, closed = closed
)
}

bin_vector <- function(x, bins, weight = NULL, pad = FALSE) {
check_object(bins, is_bins, "a {.cls ggplot2_bins} object")

Expand All @@ -141,8 +179,7 @@ bin_vector <- function(x, bins, weight = NULL, pad = FALSE) {
weight[is.na(weight)] <- 0
}

bin_idx <- cut(x, bins$fuzzy, right = bins$right_closed,
include.lowest = TRUE)
bin_idx <- bin_cut(x, bins)
bin_count <- as.numeric(tapply(weight, bin_idx, sum, na.rm = TRUE))
bin_count[is.na(bin_count)] <- 0

Expand Down Expand Up @@ -170,6 +207,10 @@ bin_vector <- function(x, bins, weight = NULL, pad = FALSE) {
bin_out(bin_count, bin_x, bin_widths)
}

bin_cut <- function(x, bins) {
cut(x, bins$fuzzy, right = bins$right_closed, include.lowest = TRUE)
}

bin_out <- function(count = integer(0), x = numeric(0), width = numeric(0),
xmin = x - width / 2, xmax = x + width / 2) {
density <- count / width / sum(abs(count))
Expand All @@ -186,3 +227,41 @@ bin_out <- function(count = integer(0), x = numeric(0), width = numeric(0),
.size = length(count)
)
}

bin_loc <- function(x, id) {
left <- x[-length(x)]
right <- x[-1]

list(
left = left[id],
right = right[id],
mid = ((left + right) / 2)[id],
length = diff(x)[id]
)
}

fix_bin_params = function(params, fun, version) {

if (!is.null(params$origin)) {
args <- paste0(fun, c("(origin)", "(boundary)"))
deprecate_warn0(version, args[1], args[2])
params$boudnary <- params$origin
params$origin <- NULL
}

if (!is.null(params$right)) {
args <- paste0(fun, c("(right)", "(closed)"))
deprecate_warn0(version, args[1], args[2])
params$closed <- if (isTRUE(params$right)) "right" else "left"
params$right <- NULL
}

if (is.null(params$breaks %||% params$binwidth %||% params$bins)) {
cli::cli_inform(
"{.fn {fun}} using {.code bins = 30}. Pick better value {.arg binwidth}."
)
params$bins <- 30
}

params
}
6 changes: 3 additions & 3 deletions R/coord-polar.R
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ CoordPolar <- ggproto("CoordPolar", Coord,

is_free = function() TRUE,

distance = function(self, x, y, details) {
distance = function(self, x, y, details, boost = 0.75) {
arc <- self$start + c(0, 2 * pi)
dir <- self$direction
if (self$theta == "x") {
Expand All @@ -94,8 +94,8 @@ CoordPolar <- ggproto("CoordPolar", Coord,
r <- rescale(x, from = details$r.range)
theta <- theta_rescale_no_clip(y, details$theta.range, arc, dir)
}

dist_polar(r, theta)
# The ^boost boosts detailed munching when r is small
dist_polar(r^boost, theta)
},

backtransform_range = function(self, panel_params) {
Expand Down
Loading

0 comments on commit a69ccb3

Please sign in to comment.