Skip to content

stat_bin accepts functions for binwidth #1890

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 14 commits into from
Jan 26, 2017
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