7

I have a number off ggplot objects created based off dichotomous count data. I have combined them together using ggarrange. In this function, there is an option to create a shared legend, but as far as I can see no way to create shared x and y axis labels. In addition, the spacing of the figures is very weird - there is a huge gap between the two figure columns, and in addition a large amount of vertical space before the shared legend. So in sum I would like to be able to create shared x and y axes and minimise the unnecessary vertical and horizontal space.

I checked out the following threads: ggplot2 grid_arrange_shared_legend share axis labels

ggplot: align plots together and add common labels and legend

Add common axis titles with lines/arrows for multiple plots in ggplot

ggplot: how to add common x and y labels to a grid of plots

But I think what I want to do is quite a bit simpler, and I don't know how to combine ggarrange with facet.grid which was suggested a few times.

I have copied a reproducible example below.

require(tidyverse)
require(ggpubr)
require(reshape2) 

condition <- c("a", "a", "a", "b", "b", "b", "c", "c", "c", "c")
binary_1 <- c(0,0,0,0,0,1,1,1,1,1)
binary_2 <- c(1,1,1,1,1,1,0,0,0,0)
binary_3 <- c(0,1,1,1,1,1,1,1,0,0)
binary_4 <- c(1,1,1,0,0,0,0,0,0,0)


df <- data.frame(condition, binary_1, binary_2, binary_3, binary_4)
df

gg_df <- df %>%
  mutate(binary_1 = as.factor(binary_1), binary_2 = as.factor(binary_2), binary_3 = as.factor(binary_3), binary_4 = as.factor(binary_4))

gg_melt <- melt(gg_df)

gg_1 <- ggplot(gg_melt, aes(x=condition, fill = binary_1)) +
  geom_bar(stat="count") +
  scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
  scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
  xlab("Condition") + 
  ylab("Number of Participants") +
  ggtitle("Binary 1") +
  theme(plot.title = element_text(size = 10, face="bold", hjust = 0.5)) +
  theme(aspect.ratio = 1) +
  theme(legend.title=element_text(size=10, face = "bold"), axis.title = element_text(size=10, face = "bold"), axis.text = element_text(size=10))+
  theme(legend.box.just = "center")

gg_2 <- ggplot(gg_melt, aes(x=condition, fill = binary_2)) +
  geom_bar(stat="count") +
  scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
  scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
  xlab("Condition") + 
  ylab("Number of Participants") +
  ggtitle("Binary 2") +
  theme(plot.title = element_text(size = 10, face="bold", hjust = 0.5)) +
  theme(aspect.ratio = 1) +
  theme(legend.title=element_text(size=10, face = "bold"), axis.title = element_text(size=10, face = "bold"), axis.text = element_text(size=10))+
  theme(legend.box.just = "center")

gg_3 <- ggplot(gg_melt, aes(x=condition, fill = binary_3)) +
  geom_bar(stat="count") +
  scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
  scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
  xlab("Condition") + 
  ylab("Number of Participants") +
  ggtitle("Binary 3") +
  theme(plot.title = element_text(size = 10, face="bold", hjust = 0.5)) +
  theme(aspect.ratio = 1) +
  theme(legend.title=element_text(size=10, face = "bold"), axis.title = element_text(size=10, face = "bold"), axis.text = element_text(size=10))+
  theme(legend.box.just = "center")

gg_4 <- ggplot(gg_melt, aes(x=condition, fill = binary_4)) +
  geom_bar(stat="count") +
  scale_fill_manual(values = c("#FDAE61", "#9E0142"), name = "Behaviour Observed", labels = c("0" = "Absent", "1" = "Present")) +
  scale_x_discrete(labels = c(a = "Condition A", b = "Condition B", c = "Condition C")) + 
  xlab("Condition") + 
  ylab("Number of Participants") +
  ggtitle("Binary 4") +
  theme(plot.title = element_text(size = 10, face="bold", hjust = 0.5)) +
  theme(aspect.ratio = 1) +
  theme(legend.title=element_text(size=10, face = "bold"), axis.title = element_text(size=10, face = "bold"), axis.text = element_text(size=10))+
  theme(legend.box.just = "center")

figure <- ggarrange(gg_1, gg_2, gg_3, gg_4,
                    labels = NULL,
                    ncol = 2, nrow = 4,
                    common.legend = TRUE, legend = "bottom",
                    align = "hv",
                    font.label = list(size = 10, color = "black", face = "bold", family = NULL, position = "top"))

pdf("figure.pdf")
figure
dev.off()
 
becbot
  • 151
  • 1
  • 2
  • 9
  • Try using `pdf("figure.pdf", width=7, height=14)`. Remember that in your plot there are 2 empty rows (`nrow = 2` would be the right choice in `ggarrange`). – Marco Sandri Nov 09 '20 at 19:05

1 Answers1

13

For common axes using ggarrange, you could try changing to:

require(grid)   # for the textGrob() function

figure <- ggarrange(gg_1 + rremove("ylab") + rremove("xlab"), gg_2 + rremove("ylab") + rremove("xlab"), gg_3 + rremove("ylab") + rremove("xlab"), gg_4+ rremove("ylab") + rremove("xlab"), # remove axis labels from plots
                    labels = NULL,
                    ncol = 2, nrow = 2,
                    common.legend = TRUE, legend = "bottom",
                    align = "hv", 
                    font.label = list(size = 10, color = "black", face = "bold", family = NULL, position = "top"))

annotate_figure(figure, left = textGrob("Common y-axis", rot = 90, vjust = 1, gp = gpar(cex = 1.3)),
                    bottom = textGrob("Common x-axis", gp = gpar(cex = 1.3)))

The gp = gpar(cex = 1.3) part changes the font size. The reason there was so much space before the common legend is because you specified nrow = 4 in ggarrange, but the last 2 rows were not populated. The reason there is a gap between figure columns is because you included theme(aspect.ratio = 1) for each plot, so to reduce this gap you have to decreases the width of the ggarrange figure, or else comment out/delete the aspect ratio bit.

maycca
  • 3,848
  • 5
  • 36
  • 67
alessandra
  • 135
  • 1
  • 5
  • the function `textGrob` seems to be from `grid` library. include `require(grid)` to run the code and display the plots – maycca Jan 13 '22 at 12:18