Skip to content
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# ggplot2 2.2.1.9000

* `stat_bin` now accepts functions for `binwidth`. This allows better binning when faceting along variables with different ranges (@botanize).

* Legends no longer try and use set aesthetics that are not length one
(fixes #1932).

Expand Down
7 changes: 7 additions & 0 deletions R/geom-histogram.r
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@
#' m <- ggplot(movies, aes(x = rating))
#' m + geom_histogram(binwidth = 0.5) + scale_y_sqrt()
#' }
#'
#' # You can specify a function for calculating binwidth,
#' # particularly useful when faceting along variables with
#' # different ranges
#' mtlong <- reshape2::melt(mtcars)
#' ggplot(mtlong, aes(value)) + facet_wrap(~variable, scales = 'free_x') +
#' geom_histogram(binwidth = function(x) 2 * IQR(x) / (length(x)^(1/3)))
geom_histogram <- function(mapping = NULL, data = NULL,
stat = "bin", position = "stack",
...,
Expand Down
11 changes: 8 additions & 3 deletions R/stat-bin.r
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#' \code{stat_bin} is suitable only for continuous x data. If your x data is
#' discrete, you probably want to use \code{\link{stat_count}}.
#'
#' @param binwidth The width of the bins. The default is to use \code{bins}
#' @param binwidth The width of the bins. Can be specified as a numeric value,
#' or a function that calculates width from x.
#' The default is to use \code{bins}
#' bins that cover the range of the data. You should always override
#' this value, exploring multiple widths to find the best to illustrate the
#' stories in your data.
Expand Down Expand Up @@ -130,8 +132,11 @@ StatBin <- ggproto("StatBin", Stat,
if (!is.null(breaks)) {
bins <- bin_breaks(breaks, closed)
} else if (!is.null(binwidth)) {
bins <- bin_breaks_width(scales$x$dimension(), binwidth, center = center,
boundary = boundary, closed = closed)
if (is.function(binwidth)) {
binwidth <- binwidth(data$x)
}
bins <- bin_breaks_width(scales$x$dimension(), binwidth,
center = center, boundary = boundary, closed = closed)
} else {
bins <- bin_breaks_bins(scales$x$dimension(), bins, center = center,
boundary = boundary, closed = closed)
Expand Down
11 changes: 10 additions & 1 deletion man/geom_histogram.Rd

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

7 changes: 7 additions & 0 deletions tests/testthat/test-stat-bin.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ test_that("bins specifies the number of bins", {
expect_equal(nrow(out(bins = 100)), 100)
})

test_that("binwidth computes widths for function input", {
df <- data.frame(x = 1:100)
out <- layer_data(ggplot(df, aes(x)) + geom_histogram(binwidth = function(x) 5))

expect_equal(nrow(out), 21)
})

test_that("geom_histogram defaults to pad = FALSE", {
df <- data.frame(x = 1:3)
out <- layer_data(ggplot(df, aes(x)) + geom_histogram(binwidth = 1))
Expand Down