Skip to content

Commit 5edfbbe

Browse files
authored
Change minor breaks interface (#5569)
* reimplement #3591 * Do not censor major breaks * view scales censor major breaks after calculation of minor breaks * guides censor breaks * tests expect non-censored breaks * add news bullet * adjust docs * fix typo
1 parent dad8a4b commit 5edfbbe

11 files changed

+54
-21
lines changed

NEWS.md

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

3+
* The `minor_breaks` function argument in scales can now take a function with
4+
two arguments: the scale's limits and the scale's major breaks (#3583).
5+
6+
* (internal) The `ScaleContinuous$get_breaks()` method no longer censors
7+
the computed breaks.
8+
39
* Plot scales now ignore `AsIs` objects constructed with `I(x)`, instead of
410
invoking the identity scale. This allows these columns to co-exist with other
511
layers that need a non-identity scale for the same aesthetic. Also, it makes

R/guide-.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ Guide <- ggproto(
224224
key$.label <- labels
225225

226226
if (is.numeric(breaks)) {
227-
vec_slice(key, is.finite(breaks))
227+
range <- scale$continuous_range %||% scale$get_limits()
228+
key <- vec_slice(key, is.finite(oob_censor_any(breaks, range)))
228229
} else {
229230
key
230231
}

R/guide-bins.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ GuideBins <- ggproto(
267267
}
268268

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

271272
return(key)
272273
},

R/guide-colorsteps.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ GuideColoursteps <- ggproto(
181181
params$key$.value <- rescale(params$key$.value, from = limits)
182182
params$decor$min <- rescale(params$decor$min, from = limits)
183183
params$decor$max <- rescale(params$decor$max, from = limits)
184+
params$key <-
185+
vec_slice(params$key, !is.na(oob_censor_any(params$key$.value)))
184186
params
185187
},
186188

R/scale-.R

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

716718
# Breaks in data space need to be converted back to transformed space
717-
breaks <- self$trans$transform(breaks)
718-
# Any breaks outside the dimensions are flagged as missing
719-
breaks <- censor(breaks, self$trans$transform(limits), only.finite = FALSE)
720-
721-
breaks
719+
self$trans$transform(breaks)
722720
},
723721

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

740741
if (is.waive(self$minor_breaks)) {
741742
if (is.null(b)) {
@@ -744,8 +745,18 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
744745
breaks <- self$trans$minor_breaks(b, limits, n)
745746
}
746747
} else if (is.function(self$minor_breaks)) {
747-
# Find breaks in data space, and convert to numeric
748-
breaks <- self$minor_breaks(self$trans$inverse(limits))
748+
# Using `fetch_ggproto` here to avoid auto-wrapping the user-supplied
749+
# breaks function as a ggproto method.
750+
break_fun <- fetch_ggproto(self, "minor_breaks")
751+
arg_names <- fn_fmls_names(break_fun)
752+
753+
# Find breaks in data space
754+
if (length(arg_names) == 1L) {
755+
breaks <- break_fun(self$trans$inverse(limits))
756+
} else {
757+
breaks <- break_fun(self$trans$inverse(limits), self$trans$inverse(b))
758+
}
759+
# Convert breaks to numeric
749760
breaks <- self$trans$transform(breaks)
750761
} else {
751762
breaks <- self$trans$transform(self$minor_breaks)
@@ -819,14 +830,16 @@ ScaleContinuous <- ggproto("ScaleContinuous", Scale,
819830
# labels
820831
labels <- self$get_labels(major)
821832

822-
# drop oob breaks/labels by testing major == NA
823-
if (!is.null(labels)) labels <- labels[!is.na(major)]
824-
if (!is.null(major)) major <- major[!is.na(major)]
825-
826833
# minor breaks
827834
minor <- self$get_breaks_minor(b = major, limits = range)
828835
if (!is.null(minor)) minor <- minor[!is.na(minor)]
829836

837+
major <- oob_censor_any(major, range)
838+
839+
# drop oob breaks/labels by testing major == NA
840+
if (!is.null(labels)) labels <- labels[!is.na(major)]
841+
if (!is.null(major)) major <- major[!is.na(major)]
842+
830843
# rescale breaks [0, 1], which are used by coord/guide
831844
major_n <- rescale(major, from = range)
832845
minor_n <- rescale(minor, from = range)

R/scale-view.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ view_scale_primary <- function(scale, limits = scale$get_limits(),
2121
continuous_scale_sorted <- sort(continuous_range)
2222
breaks <- scale$get_breaks(continuous_scale_sorted)
2323
minor_breaks <- scale$get_breaks_minor(b = breaks, limits = continuous_scale_sorted)
24+
breaks <- censor(breaks, continuous_scale_sorted, only.finite = FALSE)
2425
} else {
2526
breaks <- scale$get_breaks(limits)
2627
minor_breaks <- scale$get_breaks_minor(b = breaks, limits = limits)
2728
}
29+
minor_breaks <- censor(minor_breaks, continuous_range, only.finite = FALSE)
2830

2931
ggproto(NULL, ViewScale,
3032
scale = scale,
@@ -76,7 +78,7 @@ view_scale_secondary <- function(scale, limits = scale$get_limits(),
7678
aesthetics = scale$aesthetics,
7779
name = scale$sec_name(),
7880
make_title = function(self, title) self$scale$make_sec_title(title),
79-
81+
continuous_range = sort(continuous_range),
8082
dimension = function(self) self$break_info$range,
8183
get_limits = function(self) self$break_info$range,
8284
get_breaks = function(self) self$break_info$major_source,

man/continuous_scale.Rd

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_continuous.Rd

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_gradient.Rd

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_size.Rd

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-scales-breaks-labels.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
test_that("labels match breaks, even when outside limits", {
22
sc <- scale_y_continuous(breaks = 1:4, labels = 1:4, limits = c(1, 3))
33

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

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

260-
expect_identical(test_scale$get_breaks(), c(NA, 20, NA))
260+
expect_identical(test_scale$get_breaks(), c(0, 20, 40))
261261
expect_identical(test_scale$get_labels(), c(c("0", "20", "40")))
262262

263263
test_view_scale <- view_scale_primary(test_scale)

0 commit comments

Comments
 (0)