Skip to content

Commit 5d23038

Browse files
committed
stat_bin2d: specify just one set of breaks
1 parent 0fa165b commit 5d23038

File tree

4 files changed

+77
-8
lines changed

4 files changed

+77
-8
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ggplot2 1.0.1.9xxx
55
that would allocated for it) with `NULL` in the `scale_` function. To
66
use the default lable, use `waiver()` (#1145).
77

8+
* `geom_bin2d()` will now let you specify one dimension's breaks exactly,
9+
without touching the other dimension's default breaks at all (#1126).
10+
811
* `labels = NULL` now works with `guide_legend()` and `guide_colorbar()`.
912
(#1175, #1183).
1013

R/stat-bin2d.r

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ StatBin2d <- proto2("StatBin2d", Stat,
3333
y = scale_dimension(scales$y, c(0, 0))
3434
)
3535

36+
# is.integer(...) below actually deals with factor input data, which is
37+
# integer by now. Bins for factor data should take the width of one level,
38+
# and should show up centered over their tick marks.
39+
3640
# Determine origin, if omitted
3741
if (is.null(origin)) {
3842
origin <- c(NA, NA)
@@ -63,17 +67,22 @@ StatBin2d <- proto2("StatBin2d", Stat,
6367

6468
# Determine breaks, if omitted
6569
if (is.null(breaks)) {
66-
breaks <- list(
67-
seq(origin[1], max(range$x) + binwidth[1], binwidth[1]),
68-
seq(origin[2], max(range$y) + binwidth[2], binwidth[2])
69-
)
70-
} else {
71-
stopifnot(is.list(breaks))
72-
stopifnot(length(breaks) == 2)
73-
stopifnot(all(sapply(breaks, is.numeric)))
70+
breaks <- list(x = NULL, y = NULL)
7471
}
72+
73+
stopifnot(length(breaks) == 2)
7574
names(breaks) <- c("x", "y")
7675

76+
if (is.null(breaks$x)) {
77+
breaks$x <- seq(origin[1], max(range$x) + binwidth[1], binwidth[1])
78+
}
79+
if (is.null(breaks$y)) {
80+
breaks$y <- seq(origin[2], max(range$y) + binwidth[2], binwidth[2])
81+
}
82+
83+
stopifnot(is.list(breaks))
84+
stopifnot(all(sapply(breaks, is.numeric)))
85+
7786
xbin <- cut(data$x, sort(breaks$x), include.lowest = TRUE)
7887
ybin <- cut(data$y, sort(breaks$y), include.lowest = TRUE)
7988

man/geom_bin2d.Rd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ d + geom_bin2d(bins = 30)
6969
7070
# Or by specifying the width of the bins
7171
d + geom_bin2d(binwidth = c(0.1, 0.1))
72+
73+
# Or with a list of breaks (NULL to generate one dimension the default
74+
# way)
75+
x <- seq(min(diamonds$carat), max(diamonds$carat), by = 0.1)
76+
y <- seq(min(diamonds$price), max(diamonds$price), length = 50)
77+
d + geom_bin2d(breaks = list(x = x, y = y))
78+
d + geom_bin2d(breaks = list(x = x, y = NULL))
7279
}
7380
\seealso{
7481
\code{\link{stat_binhex}} for hexagonal binning

tests/testthat/test-stats.r

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,56 @@ test_that("stat-bin2d", {
113113
y = scale_y_continuous(limits = range(d$depth, na.rm=TRUE)))
114114
ret <- test_stat_scale(stat_bin2d(aes(x = carat, y = depth), data=d), full_scales)
115115
expect_equal(dim(ret), c(191,12))
116+
117+
breaks <- list(x = seq(min(d$carat, na.rm=TRUE),
118+
max(d$carat, na.rm=TRUE), length.out=41),
119+
y = NULL)
120+
ret <- test_stat_scale(stat_bin2d(aes(x = carat, y = depth),
121+
data=d, breaks=breaks), full_scales)
122+
expect_equal(length(levels(ret$xbin)), 40)
123+
expect_equal(length(levels(ret$ybin)), 31)
124+
expect_equal(dim(ret), c(230,12))
125+
})
126+
127+
test_that(
128+
"stat_bin2d(breaks=...)",
129+
{
130+
df <- data.frame(x = 0:3, y = 0:3)
131+
132+
g <- ggplot(df, aes(x, y))
133+
134+
# Test explicitly setting the breaks for x, overriding
135+
# the binwidth.
136+
integer_breaks <- (0:4) - 0.5 # Will use for x
137+
half_breaks <- seq(0, 3.5, 0.5) # Will test against this for y
138+
139+
got <- ggplot_build(
140+
g + stat_bin2d(breaks = list(x = integer_breaks, y = NULL),
141+
binwidth=c(0.5, 0.5)))
142+
143+
expect_equal(got$data[[1]]$xmin, (0:3) - 0.5)
144+
expect_equal(got$data[[1]]$xmax, (0:3) + 0.5)
145+
expect_equal(got$data[[1]]$xbin,
146+
cut(df$x, integer_breaks, include.lowest = TRUE))
147+
148+
expect_equal(got$data[[1]]$ybin,
149+
cut(df$y, half_breaks, include.lowest = TRUE))
150+
151+
# Test that we can get the same results with binwidth= and
152+
# with breaks=.
153+
expected <- ggplot_build(g + stat_bin2d(binwidth=c(0.5, 0.5)))
154+
155+
breaks_to_try <- list(
156+
list(x = half_breaks, y = half_breaks),
157+
list(x = half_breaks, y = NULL),
158+
list(x = NULL, y = half_breaks),
159+
list(x = NULL, y = NULL))
160+
161+
for (breaks in breaks_to_try) {
162+
got <- ggplot_build(g + stat_bin2d(breaks = breaks, binwidth=c(0.5, 0.5)))
163+
164+
expect_equal(got$data[[1]], expected$data[[1]])
165+
}
116166
})
117167

118168

0 commit comments

Comments
 (0)