-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Simplify alignment for column geoms #4899
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
Comments
Thanks for the suggestion, but this doesn't sound convincing to me. The problem of this example looks the width of each bar, rather than the alignment? (not sure if the intention of your example is to show daily values or monthly values) library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
library(lubridate, warn.conflicts = FALSE)
df <- tibble(
month = as_date(c("2020-01-01", "2020-02-01", "2020-03-01")),
value = 1:3
)
ggplot(df, aes(month, value)) +
geom_col(width = 1) +
scale_x_date(date_labels = "%b %d") Created on 2022-07-23 by the reprex package (v2.0.1) |
Apologies, my initial example was a bit rushed and possibly didn't show my issue clearly enough. Perhaps this edit will help clarify. Here, columns would indicate monthly totals of library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
library(lubridate, warn.conflicts = FALSE)
df <- tibble(
month = seq.Date(as_date("2020-01-01"), as_date("2020-03-31"), length.out = 9),
value = 1:9
)
ggplot(df, aes(month, value)) +
# Colums show totals for each month. Here the values of `month` are always
# the first day of the month. The obvious solution is 'don't do this', but I'd
# argue that it's such common practice that ggplot2 should facilitate this
# sort of approach
geom_col(
data = ~ .x |>
group_by(month = floor_date(month, "month")) |>
summarise(value = sum(value))
) +
# Points show the more granular values
geom_point() Created on 2022-07-25 by the reprex package (v2.0.1) I guess the broader point is that the current behaviour is fine if using a discrete axis, which is probably the case for 90% of bar charts. For the remaining 10% which use a continuous axis it's not (as) obvious how the bar should be aligned, so I'd argue a bit more control is warranted. For this sort of thing, the current |
Ah, sorry, I didn't get your point. So, is this the plot you want to draw? library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
library(lubridate, warn.conflicts = FALSE)
df <- tibble(
month = seq.Date(as_date("2020-01-01"), as_date("2020-03-31"), length.out = 9),
value = 1:9
)
width <- 0.9 * 30
ggplot(df, aes(month, value)) +
geom_col(
data = ~ .x |>
group_by(month = floor_date(month, "month")) |>
summarise(value = sum(value)),
position = position_nudge(x = width / 2),
width = width
) +
geom_point() Created on 2022-07-25 by the reprex package (v2.0.1) |
I think it's very close. Correct me if I'm wrong, but I think that usually the width of the columns would be
I'm also not sure the left border of the column should exactly line up with the first of each month. With the default behaviour, some padding is added to the left and right of the column. It feels like this should possibly be the case with Anyway, I think this somewhat demonstrates what I'm trying to say - to achieve this a user has to know some fairly obscure details:
Seems to me much simpler to just add an |
Thanks, I think your calculation is correct. I agree it might make sense. |
Would you be happy to review a PR if I submitted one? To be honest I think it'd be quite simple to implement. |
Yes, I'm happy to review. I too feel the implementation won't be very complicated. One thing I'd like to discuss here is the interface. In my opinion, |
Great, I'll get working on something. Good point about the interface. I think, for the sake of consistency, you're right that Possible second featureThis may be out of scope for this discussion, but another gripe I occasionally have with bar geoms is that it's only possible to 'base' the bars at library(ggplot2)
library(dplyr, warn.conflicts = FALSE)
df1 <- tibble(
x = c(1, 1, 2, 2),
y = c(-2, 1, -1, 2),
fill = c("a", "b", "c", "d")
)
df2 <- tibble(
xmin = c(1, 2) - 0.45,
xmax = c(1, 2) + 0.45,
ymin = c(-2, -1),
ymax = c(1, 2)
)
ggplot(df1) +
geom_col(aes(x, y, fill = fill)) +
# The only way to achieve a border around the columns is to simulate a column
# geom using `geom_rect()`, which requires a lot of knowledge about how
# width/resolution are calculated.
geom_rect(
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
colour = "black", fill = "transparent",
data = df2
) Created on 2022-07-26 by the reprex package (v2.0.1) This is again a fairly obscure use, but my opinion is that exposing |
Sorry to reopen this in the eleventh hour of release. While writing the blog post I realise that I feel the meaning of 0 and 1 is backwards. In my head the Any objections to me switching it around before release? |
Personally I'm a bit torn. My intuition is 0 = further left, 1 = further right, which is currently the case if your point of reference is the x-axis, but not if your point of reference is the bar itself. I find the former more intuitive, but happy to go with what you think as you'll be more familiar with the conventions in ggplot2. |
Throughout ggplot, we're using justification values in two different contexts. Let's explain them for the case of The second is how an object is placed relative to a reference range. This is the case for example in the placement of the axis title relative to the horizontal extent of the plot. In this case, To be consistent with the rest of ggplot, here, I think we need to figure out whether we're operating in the first or the second context, and apply the justification accordingly. I haven't looked into this too closely, but it sounds to me like we're operating under context 1, and therefore |
I was curious so took a look at other geoms - to me, behaviour doesn't seem to be that consistent, but maybe there's a rule I haven't spotted.
|
It's possible Context 1 is used all over grid, in the way I've described. Also, legend justification follows context 1, if I remember correctly. |
Thanks. When I reviewed the pull request, I didn't consider the semantics of I'm not sure I'm for or against the suggestion at the moment, but, at least, the behavior of library(ggplot2)
d <- expand.grid(x = 1, y = 1:2)
ggplot(d, aes(x, y)) +
geom_raster(hjust = 1, fill = "red", alpha = 0.5) +
geom_raster(hjust = 0, fill = "blue", alpha = 0.5) +
coord_equal() ggplot(d[1,], aes(x, y)) +
geom_text(size = 20, hjust = 1, label = "hjust = 1", colour = "red", alpha = 0.5) +
geom_text(size = 20, hjust = 0, label = "hjust = 0", colour = "blue", alpha = 0.5) +
coord_equal() ggplot(d[1,], aes(x, y)) +
geom_col(width = 1, just = 1, fill = "red", alpha = 0.5) +
geom_col(width = 1, just = 0, fill = "blue", alpha = 0.5) +
coord_equal() Created on 2022-10-28 with reprex v2.0.2 |
Currently the alignment of columns is always centre, which may not always be desired. E.g. in the following case, values of
date
always give the first of the month, but are used to indicate the whole month (as is fairly common practice):In this case an
align
argument togeom_col()
would be really useful to align the columns with the first of each month.align
could accept values"centre"
(the default),"right"
and"left"
, which would be the option used here. The current alternatives are to useposition = position_nudge()
, which is fairly esoteric for such a simple task (and wouldn't always work that well, e.g. since February only has 28 days), or to instead usegeom_rect()
, which again seems much too complex for such a simple task.If you agree that this sounds like a useful feature I'd be happy to submit a PR.
As always, thanks for the hard work on this beautiful package!
(N.B, this example is a bit contrived due to the use of
scale_x_date()
but it's the simplest example I could think of)The text was updated successfully, but these errors were encountered: