How to create a plot by two subgroups using interaction() in ggplot (combination of several plots)

Viewed 1164

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")
2 Answers

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

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)

Related