How can I specify the limit of geom_bar() properly when the x axis is continuous?

(Originally I saw this issue on ggplot removing data without warnings · Issue #2879 · tidyverse/ggplot2 · GitHub)

Suppose I want to plot a bar chart with x axis ranged from 2 to 4. It's not enough to set limits of x axis as [2, 4], since it doesn't cover the width of bars. So, I need to manually add 0.5, which is half the width of the bar, to the limits. This seems too tricky.

Are there any good way to ensure the whole bars are included in the limits? (Note that expand seems to expand the limit after cutting the data, so it doesn't help here.)

library(ggplot2)

d <- data.frame(x = 1:5)

ggplot(d) +
  geom_bar(aes(x)) +
  xlim(2, 4)
#> Warning: Removed 2 rows containing non-finite values (stat_count).
#> Warning: Removed 2 rows containing missing values (geom_bar).


ggplot(d) +
  geom_bar(aes(x)) +
  xlim(1.5, 4.5)
#> Warning: Removed 2 rows containing non-finite values (stat_count).

Created on 2018-09-05 by the reprex package (v0.2.0).

2 Likes

Hello @yutannihilation,

I'm not sure if I'm tracking fully, but I think you are looking for either ggplot2::coord_cartesian() or the width argument of geom_bar.

Here is a quick example of each...


library(ggplot2)

d <- data.frame(x = 1:5)

ggplot(d) +
    geom_bar(aes(x), width = 0.25) +
    coord_cartesian(xlim = c(1, 5))

Hope that helps!

Cheers,
Ben

1 Like

Thanks! But, I don't want to specify the width.

I want to plot bar charts without caring about the bar widths. I don't want to change the width for bar to be included, but want the scale to include them automatically...!

1 Like

Why not filter the data prior to passing it to ggplot?

library(ggplot2)
library(dplyr)

d <- data.frame(x = 1:5)

filter(d, x > 1 & x < 5) %>%
  ggplot(aes(x)) + geom_bar()

Thanks. We always can transform data at the outside of ggplot2; e.g. we might not need scale_*_log10() because we can log10() before, etc.

But, as we can set the limits in ggplot2, I expect ggplot2 provides a proper way to do it...

Does your use case require that the x axis be mapped to scale? If not, you could convert to factors and then ggplot will take care of the spacing without intervention.

library(ggplot2)
d <- data.frame(x = c(1:5,90:95) %>% as.factor())
ggplot(d) +
  geom_bar(aes(x))

Rplot01

I know using the discrete scale solve the problem quickly as below, but my concern is different; I just wonder why the bars at 2 and 4 won't be included whrereas 2 and 4 are definitely within the range of the x axis.

library(ggplot2)

d <- data.frame(x = 1:5)

ggplot(d) +
  geom_bar(aes(factor(x))) +
  # BTW, I don't know why I lose the tick at x=2 when I specify limits=2:4... 
  scale_x_discrete(limits = as.character(2:4))
#> Warning: Removed 2 rows containing non-finite values (stat_count).

Created on 2018-09-10 by the reprex package (v0.2.0).

Now also in ggplot2 issue thread, below.

2 Likes