4

I am trying to create plots by two subgroups, just like in the picture below (ggplot2 multiple sub groups of a bar chart). However, I would like to do that for a combination of plots.

enter image description here

When I tried to do that, instead of having the categories clearly separated (like in the example with Irrigated/Dry and Variety1/Variety 2), my variables "growth" and "year" are being collapsed together.

I am having trouble incorporating into my code this tiny modification. I would like for my variable year to be just like "Irrigated/Dry", and the variable growth as "Variety1/Variety2" Right now, this is how the plot looks like:

enter image description here

Here is my code:

library(ggplot2)

#Creates the data

d <- expand.grid(c(.3, .8), c(.3, 0.8), c(0, 0.5), c(1, 2), c("Oregon"," California"), c("2010","2011"))
colnames(d) <- c("gamma1", "gamma2", "growth",  "store", "state", "year")
d$sells <- rnorm(64)

d$gamma_plot <- as.factor(paste(d$gamma1, d$gamma2, sep = "_"))
d$store <- as.factor(d$store)

d$growth <- factor(d$growth)
d$gamma_plot = factor(d$gamma_plot,
                              labels=c(expression(paste(gamma[1],"=", gamma[2]," = 0.3")),
                                       expression(paste(gamma[1], " = 0.3 ", gamma[2], " = 0.8")),
                                       expression(paste(gamma[1], " = 0.8 ", gamma[2], " = 0.3")),
                                       expression(paste(gamma[1],"=", gamma[2]," = 0.8"))
                              )
)

d$store = factor(d$store,
                          labels = c(expression(paste(store[1], " = 1")),
                                     expression(paste(store[2], " = 2"))
                          )
)

#Creates the plot
p = ggplot(data=d, aes(x=interaction(year, growth), y=sells, fill=state)) + 
  geom_col(position="dodge") +
  theme_bw() +
  facet_grid(store ~ gamma_plot, labeller = label_parsed) + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm")) + 
  guides(fill = guide_legend(nrow = 1)) +
  labs(x=expression(growth), y = "Sells")

EDITED:

The two solutions given to my question were great and I really appreciate it. I have decided to alter the plot a little and have an interaction between gamma_plot and growth instead. I could not make R understand that gamma_plot was an expression. Any ideas?

enter image description here

#Creates the plot using teunbrand's code :)

ggplot(data=d, aes(x=interaction(growth, gamma_plot, sep = "&"), y=sells, fill=year)) + 
  geom_col(position="dodge") +
  theme_bw() +
  facet_grid(store ~ state, labeller = label_parsed) + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm"),
        axis.text.x = element_text(margin = margin(2,2,2,2))) +
  scale_x_discrete(guide = guide_axis_nested(delim = "&")) +
  guides(fill = guide_legend(nrow = 1)) +
  labs(x=expression(growth), y = "Sells")
Miranda
  • 148
  • 13
  • 1
    Is you code missing `data_plot`? – Peter Jul 10 '20 at 19:22
  • So sorry. Just fix it. – Miranda Jul 10 '20 at 19:27
  • For nested axis labels see [ggplot2 multiple sub groups of a bar chart](https://stackoverflow.com/questions/20060949/ggplot2-multiple-sub-groups-of-a-bar-chart) (does the figure look familiar?); [Multi-row x-axis labels in ggplot line chart](https://stackoverflow.com/questions/20571306/multi-row-x-axis-labels-in-ggplot-line-chart); [Axis labels on two lines with nested x variables (year below months)](https://stackoverflow.com/questions/44616530/axis-labels-on-two-lines-with-nested-x-variables-year-below-months) – Henrik Jul 10 '20 at 23:42
  • Yes, I tried to use the code in that post, but that did not work for me with the combination of plots. – Miranda Jul 10 '20 at 23:44

2 Answers2

2

As far as I'm aware there is no axis hierarchy in ggplot2. Normally, one would use facets to seperate the year from growth, but it seems like you're already using the facets to seperate out something else.

Example how one would use facets in this case:

ggplot(data=d, aes(x=interaction(growth), y=sells, fill=state)) + 
  geom_col(position="dodge") +
  theme_bw() +
  facet_grid(store ~ gamma_plot + year, labeller = label_parsed, switch = "x") + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        strip.placement = "outside",
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm")) + 
  guides(fill = guide_legend(nrow = 1)) +
  labs(x=expression(growth), y = "Sells")

enter image description here

Seeing as the above is not really a good option, I recommend looking for extention packages that offer what you seek. If you'll allow me to be so bold, there is a function in a github package I wrote that formats axes in a nested fashion. Example below:

library(ggh4x)
ggplot(data=d, aes(x=interaction(growth, year, sep = "&"), y=sells, fill=state)) + 
  geom_col(position="dodge") +
  theme_bw() +
  facet_grid(store ~ gamma_plot, labeller = label_parsed) + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm"),
        axis.text.x = element_text(margin = margin(2,2,2,2))) +
  scale_x_discrete(guide = guide_axis_nested(delim = "&")) +
  guides(fill = guide_legend(nrow = 1)) +
  labs(x=expression(growth), y = "Sells")

enter image description here

Edit: With regards to the follow up question about the spacing between years; I can't think of an elegant solution but the following would get the job done. It converts the discrete axis to a continuous one.

# Precalculate interaction
d$interaction <- interaction(d$growth, d$year, sep = "&")
nudge <- 1 # How much you want to nudge

# Use ifelse to nudge position and use factor as integer
ggplot(data=d, aes(x=ifelse(as.numeric(interaction) > 2, 
                            as.numeric(interaction) + nudge, 
                            as.numeric(interaction)),
                   y=sells, fill=state)) + 
  geom_col(position="dodge") +
  theme_bw() +
  facet_grid(store ~ gamma_plot, labeller = label_parsed) + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm"),
        axis.text.x = element_text(margin = margin(2,2,2,2))) +
  # Using a continuous axis here
  scale_x_continuous(breaks = c(1,2,3 + nudge, 4 + nudge),
                     labels = levels(d$interaction),
                     guide = guide_axis_nested(delim = "&")) +
  guides(fill = guide_legend(nrow = 1)) +
  labs(x=expression(growth), y = "Sells")

enter image description here

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Great, that worked perfectly! Just a follow-up question: would it be possible to add more horizontal spacing/padding between the years within each plot? In a way that the bars for 2010 and the bars for 2011 are more distinguishable? – Miranda Jul 10 '20 at 19:51
  • 1
    Yes but couldn't come up with an elegant solution. See edit above – teunbrand Jul 10 '20 at 20:04
  • The solution was great. I decided to change the plot's organization and now I am having trouble making ggplot2 understand that one of the labels is an expression. Thank you for all the help! – Miranda Jul 11 '20 at 00:05
2

How about this option:



library(ggplot2)


ggplot(data=d, aes(x = interaction(year, growth), y=sells, fill = state)) + 
  geom_col(position="dodge") +
  scale_x_discrete(labels = unique(interaction(d$year, factor(d$growth), sep = "\n")))+
  theme_bw() +
  facet_grid(store ~ gamma_plot, labeller = label_parsed) + 
  theme(legend.title = element_blank(), legend.position="bottom",
        panel.grid.major = element_blank(), 
        legend.key.size = unit(0.10, "cm"),
        legend.key.width = unit(0.15,"cm")) + 
  guides(fill = guide_legend(nrow = 1)) +
  labs(x = expression(Year~growth), y = "Sells")

Created on 2020-07-10 by the reprex package (v0.3.0)

Peter
  • 11,500
  • 5
  • 21
  • 31