Skip to content

Commit 9b86cc7

Browse files
author
Dana Paige Seidel
authored
Simplify sec.axis for proper transformed breaks (#2796)
Fixes #2729
1 parent d9f2cd4 commit 9b86cc7

File tree

3 files changed

+62
-22
lines changed

3 files changed

+62
-22
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# ggplot2 3.0.0.9000
22

3+
* `sec_axis()` and `dup_axis()` now return appropriate breaks for the secondary
4+
axis when applied to log transformed scales (@dpseidel, #2729).
5+
36
* `sec_axis()` now works as expected when used in combination with tidy eval
47
(@dpseidel, #2788).
58

R/axis-secondary.R

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ AxisSecondary <- ggproto("AxisSecondary", NULL,
109109
rlang::eval_tidy(rlang::f_rhs(self$trans), data = range)
110110
},
111111

112-
113112
break_info = function(self, range, scale) {
114113
if (self$empty()) return()
115114

@@ -125,29 +124,22 @@ AxisSecondary <- ggproto("AxisSecondary", NULL,
125124
stop("transformation for secondary axes must be monotonic")
126125

127126
# Get break info for the secondary axis
128-
new_range <- range(full_range, na.rm = TRUE)
129-
temp_scale <- self$create_scale(new_range)
130-
range_info <- temp_scale$break_info()
131-
132-
# Map the break values back to their correct position on the primary scale
133-
old_val <- lapply(range_info$major_source, function(x) which.min(abs(full_range - x)))
134-
old_val <- old_range[unlist(old_val)]
135-
old_val_trans <- scale$trans$transform(old_val)
136-
range_info$major[] <- round(rescale(scale$map(old_val_trans, range(old_val_trans)), from = range), digits = 3)
137-
127+
new_range <- range(scale$transform(full_range), na.rm = TRUE)
128+
sec_scale <- self$create_scale(new_range, scale)
129+
range_info <- sec_scale$break_info()
138130
names(range_info) <- paste0("sec.", names(range_info))
139131
range_info
140132
},
141133

142134
# Temporary scale for the purpose of calling break_info()
143-
create_scale = function(self, range) {
135+
create_scale = function(self, range, primary) {
144136
scale <- ggproto(NULL, ScaleContinuousPosition,
145137
name = self$name,
146138
breaks = self$breaks,
147139
labels = self$labels,
148140
limits = range,
149141
expand = c(0, 0),
150-
trans = identity_trans()
142+
trans = primary$trans
151143
)
152144
scale$train(range)
153145
scale

tests/testthat/test-sec-axis.R

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,70 @@ context("sec-axis")
33
x <- exp(seq(log(0.001), log(1000), length.out = 100))
44
foo <- data.frame(
55
x = x,
6-
y = x/(1+x)
6+
y = x / (1 + x)
77
)
88

99
test_that("dup_axis() works", {
1010
p <- ggplot(foo, aes(x, y)) +
1111
geom_point() +
12-
scale_x_continuous(name = "Unit A",
13-
sec.axis = dup_axis())
12+
scale_x_continuous(
13+
name = "Unit A",
14+
sec.axis = dup_axis()
15+
)
1416
scale <- layer_scales(p)$x
1517
expect_equal(scale$sec_name(), scale$name)
1618
breaks <- scale$break_info()
1719
expect_equal(breaks$minor, breaks$sec.minor)
1820
expect_equal(breaks$major_source, breaks$sec.major_source)
1921
})
2022

23+
test_that("sec_axis() breaks work for log-transformed scales", {
24+
df <- data.frame(
25+
x = c("A", "B", "C"),
26+
y = c(10, 100, 1000)
27+
)
28+
29+
# dup_axis()
30+
p <- ggplot(data = df, aes(x, y)) +
31+
geom_point() +
32+
scale_y_log10(sec.axis = dup_axis())
33+
34+
scale <- layer_scales(p)$y
35+
breaks <- scale$break_info()
36+
37+
expect_equal(breaks$major_source, breaks$sec.major_source)
38+
39+
# sec_axis() with transform
40+
p <- ggplot(data = df, aes(x, y)) +
41+
geom_point() +
42+
scale_y_log10(sec.axis = sec_axis(~. * 100))
43+
44+
scale <- layer_scales(p)$y
45+
breaks <- scale$break_info()
46+
47+
expect_equal(breaks$major_source, breaks$sec.major_source - 2)
48+
49+
# sec_axis() with transform and breaks
50+
custom_breaks <- c(10, 20, 40, 200, 400, 800)
51+
p <- ggplot(data = df, aes(x, y)) +
52+
geom_point() +
53+
scale_y_log10(breaks = custom_breaks, sec.axis = sec_axis(~. * 100))
54+
55+
scale <- layer_scales(p)$y
56+
breaks <- scale$break_info()
57+
58+
expect_equal(breaks$major_source, log(custom_breaks, base = 10))
59+
expect_equal(log_breaks()(df$y) * 100, 10^(breaks$sec.major_source))
60+
})
61+
2162
test_that("custom breaks work", {
2263
custom_breaks <- c(0.01, 0.1, 1, 10, 100)
2364
p <- ggplot(foo, aes(x, y)) +
2465
geom_point() +
2566
scale_x_continuous(
2667
name = "Unit A",
2768
sec.axis = sec_axis(
28-
trans = y~.,
69+
trans = y ~ .,
2970
breaks = custom_breaks
3071
)
3172
)
@@ -39,11 +80,15 @@ test_that("sec axis works with skewed transform", {
3980
"sec_axis, skewed transform",
4081
ggplot(foo, aes(x, y)) +
4182
geom_point() +
42-
scale_x_continuous(name = "Unit A", trans = 'log',
43-
breaks = c(0.001, 0.01, 0.1, 1, 10, 100, 1000),
44-
sec.axis = sec_axis(~. * 100, name = "Unit B",
45-
labels = derive(),
46-
breaks = derive()))
83+
scale_x_continuous(
84+
name = "Unit A", trans = "log",
85+
breaks = c(0.001, 0.01, 0.1, 1, 10, 100, 1000),
86+
sec.axis = sec_axis(~. * 100,
87+
name = "Unit B",
88+
labels = derive(),
89+
breaks = derive()
90+
)
91+
)
4792
)
4893
})
4994

0 commit comments

Comments
 (0)