0

I want to produce a grouped bar graph from my data which contains seven different conditions (two factors) with three replicates per treatment. The reference group ('Water') is ungrouped, because it contains only one conditition and is shown as a single bar, the other treatments are grouped. I used position_dodge2 with preserve = "single" to keep all bars at the same width, but then the single bar has a lot of space around it which I would like to get rid of while keeping the same width as the other bars. How is that possible?

I tried to add width and padding in position_dodge2, but it did not work for me. I would like to avoid facetting, and keep the width of the other bars and the "lonely" one centred on its x-axis label.

My data (data2):

structure(list(glue = structure(c(2L, 2L, 2L, 1L, 1L, 1L, 3L, 
3L, 3L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Methylcellulose", 
"Water", "Xanthan"), class = "factor"), sug = structure(c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 2L, 2L, 
2L, 3L, 3L, 3L), .Label = c("Control", "Mannitol", "Sorbitol"
), class = "factor"), sg = c(85, 91.76470588, 89.79591837, 69.76744186, 
93.82716049, 92.59259259, 52.94117647, 77.21518987, 84.81012658, 
87.5, 87.05882353, 83.13253012, 68.6746988, 55.55555556, 73, 
68.6746988, 82.71604938, 93.75, 34.52380952, 83.52941176, 86.9047619
)), class = "data.frame", row.names = c(NA, -21L))

And this is my plot after sorting the levels in the desired order:

ggplot(data = data2, aes(x =glue, y = sg, fill = sug)) + 
  stat_summary(geom = "bar", position = position_dodge2(width = 2, preserve = "single"), color = "black") +
  stat_summary(fun.data = mean_se, geom = "errorbar", position = position_dodge2( preserve = "single", padding = 0.7)) +
  theme_classic() +
  ylab("Germination rate [%]") +
  theme(legend.position = "bottom",
        text = element_text(size = 12, color = "black"),
        axis.text = element_text(size = 12, color = "black"),
        axis.title = element_text(face = "bold", vjust = 3),
        legend.title = element_text(face = "bold"),
        axis.line = element_line(size=1),
        axis.ticks.x = element_line (size = 1)) + 
  scale_x_discrete("Seed coat") +
  scale_fill_manual(name = "Sugar",values = c("White", "LightGrey", "#838B8B")) +
  scale_y_continuous(limits = c(0,100)) 

Thanks!

2 Answers2

0

you can do this with geom_bar(position = position_dodge(width = 0.9))like so:

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar(position = position_dodge(width = 0.9))

would this be an option:

library(ggplot2)
ggplot(mtcars, aes(x=as.factor(vs),fill = as.factor(cyl))) +
  geom_bar(position = 'dodge')+
  facet_grid(~cyl,scales = "free_x", space = "free_x")

Created on 2020-06-11 by the reprex package (v0.3.0)


Here is another way. Convert a table of the cyl and vs into a data.frame. After renaming the columns accordingly create a dummy with a very low count for cyl == 8 and vs == 1; so small that the bar can not be seen and create ggplot.

The result is bars of equal size at the right position.

library(tidyverse)
df <- data.frame(table(mtcars$cyl, mtcars$vs))

df %>% 
  rename('cyl' = 'Var1', 'vs' = 'Var2') %>% 
  mutate(Freq = ifelse(cyl == 8 & vs == 1, 0.001, Freq)) %>% #glimpse()
  ggplot() + geom_col(aes(cyl, Freq, fill =vs), position = 'dodge')

Created on 2020-06-11 by the reprex package (v0.3.0)

MarBlo
  • 4,195
  • 1
  • 13
  • 27
  • Thanks, but then the single bar has the double width of the grouped onse, I would like to keep them all the same width (therefore using position_dodge2 with preserve ="single"). When I add both, the bar jumps to the left, but I would like to keep it centred on the x-mark – Mimi Seele Jun 11 '20 at 11:29
  • @Mimi Seele I have made a new edit. Maybe this comes closer; bars have equal width – MarBlo Jun 11 '20 at 12:17
  • thank you very much, but is there an option without facet wrap? I tried that too, but would like to avoid splitting the graph – Mimi Seele Jun 11 '20 at 12:25
  • @Mimi Seele, have a look to the next trial. This should be what you want. – MarBlo Jun 11 '20 at 13:50
  • Not quite, I would like to have the bar still centred on the x-axis label, is that possible? – Mimi Seele Jun 11 '20 at 17:07
  • @Mimi Seele, that would not make sense to me, vs is a factor with two levels. Even from aesthetic point of view I would say the red bar belongs to left. BTW you get the same result, if you leave the rename and mutate line out. – MarBlo Jun 11 '20 at 17:42
  • That's true. I guess the problem lies in my plot (which I did not provide because i don't know how to share the data), because here the single-bar (no. 8 in the example) is in first position and therefore the space is more obvious. – Mimi Seele Jun 12 '20 at 11:41
  • Have a look at [SO](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) – MarBlo Jun 12 '20 at 17:54
0

It is a bit difficult to follow for me. The question has changed so much over the time, that people who land on this page later will have diffulties to follow. The question has started without your sample data but with data from mtcars. So I think you should edit your question and delete the beginning with mtcars. I probably will delete my first answer, later.

Your explanation is also not absolutely clear to me. But what I understand is considered in the following. I am still not sure, if that is what you are looking for, but hope never ends. Further explanation can be found in the reprex.

library(ggplot2)
# Your data
df <- structure(list(glue = structure(c(
  2L, 2L, 2L, 1L, 1L, 1L, 3L,
  3L, 3L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L, 3L
), .Label = c(
  "Methylcellulose",
  "Water", "Xanthan"
), class = "factor"), sug = structure(c(
  1L,
  1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 2L, 2L,
  2L, 3L, 3L, 3L
), .Label = c("Control", "Mannitol", "Sorbitol"), class = "factor"), sg = c(
  85, 91.76470588, 89.79591837, 69.76744186,
  93.82716049, 92.59259259, 52.94117647, 77.21518987, 84.81012658,
  87.5, 87.05882353, 83.13253012, 68.6746988, 55.55555556, 73,
  68.6746988, 82.71604938, 93.75, 34.52380952, 83.52941176, 86.9047619
)), class = "data.frame", row.names = c(NA, -21L))


# you said you wanted the lonely bar in first position. You can therefore change the 
# order of factor levels like this
df$glue <- factor(df$glue, levels = c('Water', 'Methylcellulose', 'Xanthan'))

# you also want to reduce space between the reference bar (the lonely bar?) and the
# grouped bar. You also said you wanted the plot to look like the second or last plot
# on the webpage you are referencing to. But those plots look different. The difference
# is the width of the reference bar. If you want the bar to use the same width as 
# the grouped bar, which I believe, you need to change preserve to total.


ggplot(data = df, aes(x = glue, y = sg, fill = sug)) +
  stat_summary(geom = "col", position = position_dodge2(width = 2, preserve = "total"), color = "black") +
  stat_summary(fun.data = mean_se, geom = "errorbar", position = position_dodge2(preserve = "single", padding = 0.7)) +
  theme_classic() +
  ylab("Germination rate [%]") +
  theme(
    legend.position = "bottom",
    text = element_text(size = 12, color = "black"),
    axis.text = element_text(size = 12, color = "black"),
    axis.title = element_text(face = "bold", vjust = 3),
    legend.title = element_text(face = "bold"),
    axis.line = element_line(size = 1),
    axis.ticks.x = element_line(size = 1)
  ) +
  scale_x_discrete("Seed coat") +
  scale_fill_manual(name = "Sugar", values = c("White", "LightGrey", "#838B8B")) +
  scale_y_continuous(limits = c(0, 100))
#> No summary function supplied, defaulting to `mean_se()`

Created on 2020-06-13 by the reprex package (v0.3.0)

MarBlo
  • 4,195
  • 1
  • 13
  • 27
  • I'm very sorry for being complicated here, it's my first question and I'm learning a lot! I edited the question again (sorry!), hopefully more clear this time? So I would like to keep the bars at the same width, that's my problem. – Mimi Seele Jun 14 '20 at 14:08
  • I also deleted the car-example, because you are right, it is confusing. So I guess you can delete your first answer. – Mimi Seele Jun 14 '20 at 14:09