Skip to content

Change minor breaks interface #5569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# ggplot2 (development version)

* The `minor_breaks` function argument in scales can now take a function with
two arguments: the scale's limits and the scale's major breaks (#3583).

* (internal) The `ScaleContinuous$get_breaks()` method no longer censors
the computed breaks.

* Plot scales now ignore `AsIs` objects constructed with `I(x)`, instead of
invoking the identity scale. This allows these columns to co-exist with other
layers that need a non-identity scale for the same aesthetic. Also, it makes
Expand Down
3 changes: 2 additions & 1 deletion R/guide-.R
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ Guide <- ggproto(
key$.label <- labels

if (is.numeric(breaks)) {
vec_slice(key, is.finite(breaks))
range <- scale$continuous_range %||% scale$get_limits()
key <- vec_slice(key, is.finite(oob_censor_any(breaks, range)))
} else {
key
}
Expand Down
1 change: 1 addition & 0 deletions R/guide-bins.R
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ GuideBins <- ggproto(
}

key$.label <- labels
key <- vec_slice(key, !is.na(oob_censor_any(key$.value)))

return(key)
},
Expand Down
2 changes: 2 additions & 0 deletions R/guide-colorsteps.R
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ GuideColoursteps <- ggproto(
params$key$.value <- rescale(params$key$.value, from = limits)
params$decor$min <- rescale(params$decor$min, from = limits)
params$decor$max <- rescale(params$decor$max, from = limits)
params$key <-
vec_slice(params$key, !is.na(oob_censor_any(params$key$.value)))
params
},

Expand Down
37 changes: 25 additions & 12 deletions R/scale-.R
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#' each major break)
#' - A numeric vector of positions
#' - A function that given the limits returns a vector of minor breaks. Also
#' accepts rlang [lambda][rlang::as_function()] function notation.
#' accepts rlang [lambda][rlang::as_function()] function notation. When
#' the function has two arguments, it will be given the limits and major
#' breaks.
#' @param n.breaks An integer guiding the number of major breaks. The algorithm
#' may choose a slightly different number to ensure nice break labels. Will
#' only have an effect if `breaks = waiver()`. Use `NULL` to use the default
Expand Down Expand Up @@ -714,11 +716,7 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
}

# Breaks in data space need to be converted back to transformed space
breaks <- self$trans$transform(breaks)
# Any breaks outside the dimensions are flagged as missing
breaks <- censor(breaks, self$trans$transform(limits), only.finite = FALSE)

breaks
self$trans$transform(breaks)
},

get_breaks_minor = function(self, n = 2, b = self$break_positions(), limits = self$get_limits()) {
Expand All @@ -736,6 +734,9 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
call = self$call
)
}
# major breaks are not censored, however;
# some transforms assume finite major breaks
b <- b[is.finite(b)]

if (is.waive(self$minor_breaks)) {
if (is.null(b)) {
Expand All @@ -744,8 +745,18 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
breaks <- self$trans$minor_breaks(b, limits, n)
}
} else if (is.function(self$minor_breaks)) {
# Find breaks in data space, and convert to numeric
breaks <- self$minor_breaks(self$trans$inverse(limits))
# Using `fetch_ggproto` here to avoid auto-wrapping the user-supplied
# breaks function as a ggproto method.
break_fun <- fetch_ggproto(self, "minor_breaks")
arg_names <- fn_fmls_names(break_fun)

# Find breaks in data space
if (length(arg_names) == 1L) {
breaks <- break_fun(self$trans$inverse(limits))
} else {
breaks <- break_fun(self$trans$inverse(limits), self$trans$inverse(b))
}
# Convert breaks to numeric
breaks <- self$trans$transform(breaks)
} else {
breaks <- self$trans$transform(self$minor_breaks)
Expand Down Expand Up @@ -819,14 +830,16 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
# labels
labels <- self$get_labels(major)

# drop oob breaks/labels by testing major == NA
if (!is.null(labels)) labels <- labels[!is.na(major)]
if (!is.null(major)) major <- major[!is.na(major)]

# minor breaks
minor <- self$get_breaks_minor(b = major, limits = range)
if (!is.null(minor)) minor <- minor[!is.na(minor)]

major <- oob_censor_any(major, range)

# drop oob breaks/labels by testing major == NA
if (!is.null(labels)) labels <- labels[!is.na(major)]
if (!is.null(major)) major <- major[!is.na(major)]

# rescale breaks [0, 1], which are used by coord/guide
major_n <- rescale(major, from = range)
minor_n <- rescale(minor, from = range)
Expand Down
4 changes: 3 additions & 1 deletion R/scale-view.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ view_scale_primary <- function(scale, limits = scale$get_limits(),
continuous_scale_sorted <- sort(continuous_range)
breaks <- scale$get_breaks(continuous_scale_sorted)
minor_breaks <- scale$get_breaks_minor(b = breaks, limits = continuous_scale_sorted)
breaks <- censor(breaks, continuous_scale_sorted, only.finite = FALSE)
} else {
breaks <- scale$get_breaks(limits)
minor_breaks <- scale$get_breaks_minor(b = breaks, limits = limits)
}
minor_breaks <- censor(minor_breaks, continuous_range, only.finite = FALSE)

ggproto(NULL, ViewScale,
scale = scale,
Expand Down Expand Up @@ -76,7 +78,7 @@ view_scale_secondary <- function(scale, limits = scale$get_limits(),
aesthetics = scale$aesthetics,
name = scale$sec_name(),
make_title = function(self, title) self$scale$make_sec_title(title),

continuous_range = sort(continuous_range),
dimension = function(self) self$break_info$range,
get_limits = function(self) self$break_info$range,
get_breaks = function(self) self$break_info$major_source,
Expand Down
4 changes: 3 additions & 1 deletion man/continuous_scale.Rd

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

4 changes: 3 additions & 1 deletion man/scale_continuous.Rd

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

4 changes: 3 additions & 1 deletion man/scale_gradient.Rd

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

4 changes: 3 additions & 1 deletion man/scale_size.Rd

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

6 changes: 3 additions & 3 deletions tests/testthat/test-scales-breaks-labels.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
test_that("labels match breaks, even when outside limits", {
sc <- scale_y_continuous(breaks = 1:4, labels = 1:4, limits = c(1, 3))

expect_equal(sc$get_breaks(), c(1:3, NA))
expect_equal(sc$get_breaks(), 1:4)
expect_equal(sc$get_labels(), 1:4)
expect_equal(sc$get_breaks_minor(), c(1, 1.5, 2, 2.5, 3))
})
Expand Down Expand Up @@ -231,7 +231,7 @@ test_that("breaks can be specified by names of labels", {
test_that("only finite or NA values for breaks for transformed scales (#871)", {
sc <- scale_y_continuous(limits = c(0.01, 0.99), trans = "probit",
breaks = seq(0, 1, 0.2))
breaks <- sc$get_breaks()
breaks <- sc$break_info()$major_source
expect_true(all(is.finite(breaks) | is.na(breaks)))
})

Expand All @@ -257,7 +257,7 @@ test_that("equal length breaks and labels can be passed to ViewScales with limit
limits = c(10, 30)
)

expect_identical(test_scale$get_breaks(), c(NA, 20, NA))
expect_identical(test_scale$get_breaks(), c(0, 20, 40))
expect_identical(test_scale$get_labels(), c(c("0", "20", "40")))

test_view_scale <- view_scale_primary(test_scale)
Expand Down