Skip to content

Commit 8d0cef1

Browse files
authored
Feat/issue 4899 simplify alignment for column geoms (#4921)
1 parent cb3ba4a commit 8d0cef1

File tree

5 files changed

+71
-8
lines changed

5 files changed

+71
-8
lines changed

NEWS.md

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

3+
* `geom_col()` and `geom_bar()` gain a new `just` argument. This is set to `0.5`
4+
by default; use `just = 0`/`just = 1` to place columns on the left/right
5+
of the axis breaks.
6+
(@wurli, #4899)
7+
38
* Fix a bug in `position_jitter()` where infinity values were dropped (@javlon,
49
#4790).
510

@@ -14,6 +19,7 @@
1419
columns were dropped and warns about this. If stats intend to drop
1520
data columns they can declare them in the new field `dropped_aes`.
1621
(@clauswilke, #3250)
22+
1723
* Added `stat_align()` to align data without common x-coordinates prior to
1824
stacking. This is now the default stat for `geom_area()` (@thomasp85, #4850)
1925

R/geom-bar.r

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@
4040
#' automatically determines the orientation from the aesthetic mapping. In the
4141
#' rare event that this fails it can be given explicitly by setting `orientation`
4242
#' to either `"x"` or `"y"`. See the *Orientation* section for more detail.
43-
#' @param width Bar width. By default, set to 90% of the resolution of the data.
43+
#' @param just Adjustment for column placement. Set to `0.5` by default, meaning
44+
#' that columns will be centered about axis breaks. Set to `0` or `1` to place
45+
#' columns to the left/right of axis breaks. Note that this argument may have
46+
#' unintended behaviour when used with alternative positions, e.g.
47+
#' `position_dodge()`.
48+
#' @param width Bar width. By default, set to 90% of the [resolution()] of the
49+
#' data.
4450
#' @param geom,stat Override the default connection between `geom_bar()` and
4551
#' `stat_count()`.
4652
#' @examples
@@ -80,9 +86,17 @@
8086
#' ggplot(df, aes(x)) + geom_bar()
8187
#' # cf. a histogram of the same data
8288
#' ggplot(df, aes(x)) + geom_histogram(binwidth = 0.5)
89+
#'
90+
#' # Use `just` to control how columns are aligned with axis breaks:
91+
#' df <- data.frame(x = as.Date(c("2020-01-01", "2020-02-01")), y = 1:2)
92+
#' # Columns centered on the first day of the month
93+
#' ggplot(df, aes(x, y)) + geom_col(just = 0.5)
94+
#' # Columns begin on the first day of the month
95+
#' ggplot(df, aes(x, y)) + geom_col(just = 1)
8396
geom_bar <- function(mapping = NULL, data = NULL,
8497
stat = "count", position = "stack",
8598
...,
99+
just = 0.5,
86100
width = NULL,
87101
na.rm = FALSE,
88102
orientation = NA,
@@ -97,6 +111,7 @@ geom_bar <- function(mapping = NULL, data = NULL,
97111
show.legend = show.legend,
98112
inherit.aes = inherit.aes,
99113
params = list2(
114+
just = just,
100115
width = width,
101116
na.rm = na.rm,
102117
orientation = orientation,
@@ -123,16 +138,18 @@ GeomBar <- ggproto("GeomBar", GeomRect,
123138
params
124139
},
125140

126-
extra_params = c("na.rm", "orientation"),
141+
extra_params = c("just", "na.rm", "orientation"),
127142

128143
setup_data = function(data, params) {
129144
data$flipped_aes <- params$flipped_aes
130145
data <- flip_data(data, params$flipped_aes)
131146
data$width <- data$width %||%
132147
params$width %||% (resolution(data$x, FALSE) * 0.9)
148+
data$just <- params$just %||% 0.5
133149
data <- transform(data,
134150
ymin = pmin(y, 0), ymax = pmax(y, 0),
135-
xmin = x - width / 2, xmax = x + width / 2, width = NULL
151+
xmin = x - width * (1 - just), xmax = x + width * just,
152+
width = NULL, just = NULL
136153
)
137154
flip_data(data, params$flipped_aes)
138155
},

R/geom-col.r

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
geom_col <- function(mapping = NULL, data = NULL,
44
position = "stack",
55
...,
6+
just = 0.5,
67
width = NULL,
78
na.rm = FALSE,
89
show.legend = NA,
@@ -17,6 +18,7 @@ geom_col <- function(mapping = NULL, data = NULL,
1718
show.legend = show.legend,
1819
inherit.aes = inherit.aes,
1920
params = list2(
21+
just = just,
2022
width = width,
2123
na.rm = na.rm,
2224
...
@@ -42,16 +44,19 @@ GeomCol <- ggproto("GeomCol", GeomRect,
4244
params
4345
},
4446

45-
extra_params = c("na.rm", "orientation"),
47+
extra_params = c("just", "na.rm", "orientation"),
4648

4749
setup_data = function(data, params) {
4850
data$flipped_aes <- params$flipped_aes
4951
data <- flip_data(data, params$flipped_aes)
5052
data$width <- data$width %||%
5153
params$width %||% (resolution(data$x, FALSE) * 0.9)
52-
data <- transform(data,
53-
ymin = pmin(y, 0), ymax = pmax(y, 0),
54-
xmin = x - width / 2, xmax = x + width / 2, width = NULL
54+
data$just <- params$just %||% 0.5
55+
data <- transform(
56+
data,
57+
ymin = pmin(y, 0), ymax = pmax(y, 0),
58+
xmin = x - width * (1 - just), xmax = x + width * just,
59+
width = NULL, just = NULL
5560
)
5661
flip_data(data, params$flipped_aes)
5762
},

man/geom_bar.Rd

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

tests/testthat/test-geom-col.R

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,22 @@ test_that("geom_col works in both directions", {
2828
y$flipped_aes <- NULL
2929
expect_identical(x, flip_data(y, TRUE)[,names(x)])
3030
})
31+
32+
test_that("geom_col supports alignment of columns", {
33+
dat <- data_frame(x = c("a", "b"), y = c(1.2, 2.5))
34+
35+
p <- ggplot(dat, aes(x, y)) + geom_col(just = 0.5)
36+
y <- layer_data(p)
37+
expect_equal(as.numeric(y$xmin), c(0.55, 1.55))
38+
expect_equal(as.numeric(y$xmax), c(1.45, 2.45))
39+
40+
p <- ggplot(dat, aes(x, y)) + geom_col(just = 0.0)
41+
y <- layer_data(p)
42+
expect_equal(as.numeric(y$xmin), c(0.1, 1.1))
43+
expect_equal(as.numeric(y$xmax), c(1.0, 2.0))
44+
45+
p <- ggplot(dat, aes(x, y)) + geom_col(just = 1.0)
46+
y <- layer_data(p)
47+
expect_equal(as.numeric(y$xmin), c(1.0, 2.0))
48+
expect_equal(as.numeric(y$xmax), c(1.9, 2.9))
49+
})

0 commit comments

Comments
 (0)