0

I am attempting to add a legend for two clustered bar graphs using ggplot2 and gridExtra packages. Both graphs have the same legend, which is Time (Pre-Post).

I can get two graphs the same size sitting next to each other, but if I simply leave out the legend.position = "none" argument on the right graph, the legend is included but it contracts the graph. Can anyone suggest a method of including a legend to the right of the right graph?

Cell means and column names for the first graph are as follows

Graph 1
    Time GroupDC1C0         CWSQTot
1   Pre  High Expectancy    43.54545
2   Post High Expectancy    28.81818
3   Pre  Low Expectancy     43.31111
4   Post Low Expectancy     36.55556

Graph 2
    Time  GroupDC1C0        CWSQCrav
1   Pre   High Expectancy   4.977273
2   Post  High Expectancy   1.659091
3   Pre   Low Expectancy    4.955556
4   Post  Low Expectancy    3.688889

The code for the two graphs in ggplot2 is as follows

    require(ggplot2)
clusteredBarsTot <- ggplot(cellMeansTot, aes(GroupDC1C0,CWSQTot)) + 
  geom_bar(aes(fill = Time), stat = "identity", position = "dodge", size = .5) +
  scale_fill_manual(values = c("#999999", "#666666")) +
  expand_limits(y = 50) +
  xlab("") + ylab("CWSQ Score") +
  theme_bw() 

clusteredBarsCrav <- ggplot(cellMeansCrav, aes(GroupDC1C0,CWSQCrav)) + 
  geom_bar(aes(fill = Time), stat = "identity", position = "dodge", size = .5) +
  scale_fill_manual(values = c("#999999", "#666666")) +
  expand_limits(y = 6) +
  xlab("") + ylab("CWSQ Craving Score") +
  theme_bw() 

titleFont <- element_text(face = "bold", color = "black", size = 16, vjust = 1.5)
titleFontX <- element_text(face = "bold", color = "black", size = 16, vjust = 0.01)
axisTextFont <- element_text(face = "plain", color = "black", size = 13) # y-axis numbers size
axisTextFontX <- element_text(face = "plain", color = "black", size = 11, angle = 45, hjust = 1, vjust = 1) #x-axis day labels
legendTitle <- element_text(face = "bold", color = "black", size = 14)
legendText <- element_text(face = "plain", color = "black", size = 13)


# add fix-ups to graph (fonts, angles on axis labels etc.) via theme argument
clusBarTot <- clusteredBarsTot + theme(title = titleFont, 
                      axis.title = titleFont,
                      axis.title.x = titleFontX,
                      axis.text  = axisTextFont,
                      axis.text.x = axisTextFontX,
                      legend.position = "none",
                      panel.grid.minor = element_blank(), 
                      panel.grid.major = element_blank()) 


clusBarCrav <- clusteredBarsCrav + theme(title = titleFont, 
                                       axis.title = titleFont,
                                       axis.title.x = titleFontX,
                                       axis.text  = axisTextFont,
                                       axis.text.x = axisTextFontX,
                                       legend.position = "none",
                                       panel.grid.minor = element_blank(),
                                       panel.grid.major = element_blank()) 

require(gridExtra)

#####side by side bar graphs
grid.arrange(clusBarTot, clusBarCrav, ncol=2)

##### draw lines on Totals graph
grid.lines(c(0.205, 0.365), c(0.87, 0.87))
grid.lines(c(0.205, 0.205), c(0.87, 0.855))
grid.lines(c(0.365, 0.365), c(0.87, 0.855))
####### draws a label on the Total graph
grid.text(expression(italic(p)==".006"),
          x= unit(0.29, "npc"), y = unit(0.9, "npc"), 
          gp=gpar(fontsize = 11))

##### draw lines on Craving graph
grid.lines(c(0.695, 0.861), c(0.845, 0.845))
grid.lines(c(0.695, 0.695), c(0.845, 0.83))
grid.lines(c(0.861, 0.861), c(0.845, 0.83))
####### draws a label on the Craving graph
grid.text(expression(italic(p)~"< .001"), x= unit(0.785, "npc"), y = unit(0.875, "npc"),
          gp=gpar(fontsize = 11))

I saw on stackexchange a post by someone who had written code for a method of laying out graphs with a common legend. However, these graphs appear in one column with the legend in a separate column. I tried playing around with this code and entering in my two graphs in the function but I don't understand R well enough to reverse engineer code like that. The code was as follows:

grid_arrange_shared_legend <- function(...) {
  plots <- list(...)
  g <- ggplotGrob(plots[[1]] + theme(legend.position="bottom"))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  grid.arrange(
    do.call(arrangeGrob, lapply(plots, function(x)
      x + theme(legend.position="none"))),
    legend,
    ncol = 2,
    heights = unit.c(unit(1, "npc") - lheight, lheight))
}

grid_arrange_shared_legend(clusBarTot, clusBarCrav)

As you can tell by my naff comments in the code I am still pretty new to R and programming.

Ruthger Righart
  • 4,799
  • 2
  • 28
  • 33
Llew Mills
  • 53
  • 4
  • 2
    It would be nicer to share your data in a [reproducible](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) format. Also it helps to provide the *minimal* code necessary to reproduce the issue. Is all the `element_text` stuff necessary? – MrFlick Jun 03 '15 at 05:32
  • As @MrFlick mentioned, your code above does not really generate any plots. I would recommend that you look into using the `legend()` function. It allows you to independently place a legend anywhere you want it. – Tim Biegeleisen Jun 03 '15 at 05:37
  • No you're right Mr Flick. It probably isn't necessary. I'm still learning how to use stackoverflow too it seems. I see what you mean Tim. I didn't assign the two cell mean plots I included to the objects clusteredBarsTot and clusteredBarsCrav. Had I done that then the grid.arrange call would have worked. Sorry for that. Still learning etiquette. – Llew Mills Jun 04 '15 at 03:51

1 Answers1

0

You are on the right way with this one. If you want to change the position of the legend from the bottom (as it was requested in the question that you refer to) to the right you change the code in a way that you say the legend position should be right (third line of code) and that you want to have 3 columns, the new code should be as follow:

grid_arrange_shared_legend <- function(...) {
  plots <- list(...)
  g <- ggplotGrob(plots[[1]] + theme(legend.position="right"))$grobs
  legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
  lheight <- sum(legend$height)
  grid.arrange(
    do.call(arrangeGrob, lapply(plots, function(x)
      x + theme(legend.position="none"))),
    legend,
    ncol = 3,
    heights = unit.c(unit(1, "npc") - lheight, lheight))
}

grid_arrange_shared_legend(clusBarTot, clusBarCrav)
Sarina
  • 548
  • 3
  • 10
  • Hi Sarina. Thanks you for the advice. That still comes out looking the same though, with the two graphs one on top of the other in one column and the legend by itself to the right and a lot of blank space to the right of the legend. I need 1st graph in one column, second graph in next column and legend in third column. – Llew Mills Jun 04 '15 at 03:38