I would like to draw plot with the same width of the bars. Here's my minimal example code:
data <- data.frame(A = letters[1:17],
B = sample(1:500, 17),
C = c(rep(1, 5), rep(2, 6), rep(c(3,4,5), each = 2)))
ggplot(data,
aes(x = C, y = B, label = A,
fill = A)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(position = position_dodge(width = 0.9), angle = 90)
The result is shown in the picture above:
The width of the bars is dependent on numbers of observation in group given in variable C
. I want to have each bar to have the same width.
The facet_grid(~C)
works (bars are the same width) it's not what I mean:
ggplot(data,
aes(x = C, y = B, label = A,
fill = A)) +
geom_bar(stat = "identity", position = "dodge") +
geom_text(position = position_dodge(width = 0.9), angle = 90) +
facet_grid(~C)
What I want is to have plot like in the first picture but with bars's width independent on number of observation in each level from column C
. How can I do it?
[EDIT] geom_bar(width)
changes width of the bars'group but still bars in fifth group are wider than in the first group, so it's not the answer to my question.
position_dodge.Rd. Dodging preserves the vertical position of an geom while adjusting the horizontal position.
geom_bar() makes the height of the bar proportional to the number of cases in each group (or if the weight aesthetic is supplied, the sum of the weights). If you want the heights of the bars to represent values in the data, use geom_col() instead.
Dodging preserves the vertical position of an geom while adjusting the horizontal position. position_dodge() requires the grouping variable to be be specified in the global or geom_* layer. Unlike position_dodge() , position_dodge2() works without a grouping variable in a layer.
To Increase or Decrease width of Bars of BarPlot, we simply assign one more width parameter to geom_bar() function. We can give values from 0.00 to 1.00 as per our requirements.
Update
Since ggplot2_3.0.0
version you are now be able to use position_dodge2
with preserve = c("total", "single")
ggplot(data,aes(x = C, y = B, label = A, fill = A)) + geom_col(position = position_dodge2(width = 0.9, preserve = "single")) + geom_text(position = position_dodge2(width = 0.9, preserve = "single"), angle = 90, vjust=0.25)
Original answer
As already commented you can do it like in this answer: Transform A
and C
to factors and add unseen variables using tidyr
's complete
. Since the recent ggplot2
version it is recommended to use geom_col
instead of geom_bar
in cases of stat = "identity"
:
data %>% as.tibble() %>% mutate_at(c("A", "C"), as.factor) %>% complete(A,C) %>% ggplot(aes(x = C, y = B, fill = A)) + geom_col(position = "dodge")
Or work with an interaction term:
data %>% ggplot(aes(x = interaction(C, A), y = B, fill = A)) + geom_col(position = "dodge")
And by finally transforming the interaction to numeric you can setup the x-axis according to your desired output. By grouping (group_by
) you can calculate the matching breaks. The fancy stuff with the {}
around the ggplot argument is neseccary to directly use the vaiables Breaks
and C
within the pipe.
data %>% mutate(gr=as.numeric(interaction(C, A))) %>% group_by(C) %>% mutate(Breaks=mean(gr)) %>% {ggplot(data=.,aes(x = gr, y = B, fill = A, label = A)) + geom_col(position = "dodge") + geom_text(position = position_dodge(width = 0.9), angle = 90 ) + scale_x_continuous(breaks = unique(.$Breaks), labels = unique(.$C))}
Edit:
Another approach would be to use facets. Using space = "free_x"
allows to set the width proportional to the length of the x scale.
library(tidyverse) data %>% ggplot(aes(x = A, y = B, fill = A)) + geom_col(position = "dodge") + facet_grid(~C, scales = "free_x", space = "free_x")
You can also plot the facet labels on the bottom using switch
and remove x axis labels
data %>% ggplot(aes(x = A, y = B, fill = A)) + geom_col(position = "dodge") + facet_grid(~C, scales = "free_x", space = "free_x", switch = "x") + theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), strip.background = element_blank())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With