13

I would like to create a bar plot with ggplot2 in which the discrete values of the x axis would be grouped into subgroups (see picture attached - the picture is from the web I do not have a code for the plot yet).

enter image description here

Thanks for your help !

lqdo2000
  • 351
  • 2
  • 5
  • 16

2 Answers2

18

Two approaches:

Example data:

dat <- data.frame(value=runif(26)*10,
                  grouping=c(rep("Group 1",10),
                             rep("Group 2",10),
                             rep("Group 3",6)),
                  letters=LETTERS[1:26])

head(dat)
     value grouping letters
1 8.316451  Group 1       A
2 9.768578  Group 1       B
3 4.896294  Group 1       C
4 2.004545  Group 1       D
5 4.905058  Group 1       E
6 8.997713  Group 1       F

Without facetting:

ggplot(dat, aes(grouping, value, fill=letters, label = letters)) + 
     geom_bar(position="dodge", stat="identity") + 
     geom_text(position = position_dodge(width = 1), aes(x=grouping, y=0))

With facetting:

ggplot(dat, aes(letters,value, label = letters)) + 
     geom_bar(stat="identity") + 
     facet_wrap(~grouping, scales="free")

Facetting has the obvious advantage of not having to muck about with the positioning of the labels.

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
  • Thanks ! It looks pretty good with facetting. However, is it possible to get the same width for all the bars independently of the numbers of values I have for each group?(when using scales="free_x", the width of the groups is the same but not the bars. When using scales="free_y", that's the opposite). – lqdo2000 Apr 22 '14 at 01:01
  • 4
    Found it. I used `facet_grid` with the argument 'space="free_x"` ! – lqdo2000 Apr 22 '14 at 01:37
  • 3
    How would you do this on the y axis with discrete, non-numberical values ? – Katie S Nov 19 '19 at 15:33
5

To pile on an alternative, there is also ggh4x::guide_axis_nested(), which solves a similar issue. Disclaimer: I'm the author of ggh4x.

library(ggplot2)

df <- data.frame(
  x = LETTERS[1:16],
  group = rep(c("Group 1", "Group 2", "Group 3"), c(5, 3, 8)),
  value = rpois(16, 10)
)

ggplot(df, aes(paste0(x, "&", group), value)) +
  geom_col() +
  guides(x = ggh4x::guide_axis_nested(delim = "&"))

Created on 2023-02-24 by the reprex package (v2.0.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • I get an unexpected cluster behavior if I use your exact example but set: x= LETTERS[1:2]. I would LIKE for it to look identical to what you have above but every group just has letters A and B. Unfortuntely, when I do that it no longer groups by "group" and instead spits by groups across A and B. Any way to fix that? – Nathan Mar 22 '23 at 06:11
  • You can do `factor(paste(...), levels = ...)` to set the levels in the order that you want. – teunbrand Mar 22 '23 at 07:26
  • I'll create a new post :) Still having trouble making it look like above.the "Group" still isn't visually looking like what you have above. – Nathan Mar 22 '23 at 14:07