14
votes

NOTE: I have updated this post following discussion with Mike, as my question might be indicative a bug in ggplot. Basically, previously I was able to create a bar plot using ggplot without space between the legend keys (Figure 2 is an example output of that, as is Link 2). Now, however, ggplot seems to be automatically adding space between the legend keys ...

Original post
I would like to create a barplot with a legend. An example of what I am doing would be the following:

b <- c("A","A","A","B","B","B", "A","A","A","B","B","B", "A","A","A","B","B","B")
c <- c(11,22,33,99,88,77, 44,55,66,61,62,63, 83,85, 87, 84,86, 88)

dft <- data.frame(b,c)

ggplot(dft, aes(b,c, fill=b))+
  stat_summary(fun.y=mean, geom="bar", position="dodge", colour="black", size=.2)+
  scale_fill_manual(values=c("grey", "white"))+
  theme(legend.key = element_rect(colour = 'black', size=.01)) 
ggsave("T3.jpg")

The problem I have with this is that ggplot seems to automatically create space in between the two legend keys.

Figure 1

enter image description here

Is there a way to remove this space between the legend keys. See Figure 2 below for an example of what I would like to do.

Figure 2

enter image description here

A similar question has already been asked see Link 1, where the aim was to create more space between the legend keys, but unfortunately none of the answers helped me in resolving my question (i.e., to remove the space between the legend keys).

I also came across a link where the bar plots suggest that it seems to be possible to remove the space between the legend keys: Link 2. When adapting the script to my example, however, exactly the same problem arose (space between legend keys).

How come the bar plots at this link show no space, whereas when I try to replicate this space is added between the legend keys? I should perhaps also add that I have recently updated ggplot. Could this have to do with that?

dft2<-ddply(dft,.(b),plyr::summarize, meanc = mean(c))

ggplot(data=dft2, aes(x=b, y=meanc, fill=b)) + 
   geom_bar(stat="identity",position=position_dodge(), colour="black", size=.3) +
   scale_fill_manual(values=c("grey", "white")) +
   theme(legend.key = element_rect(colour = 'black', size=.01)) 
ggsave("T2.jpg")

Any suggestions for how to resolve this would be most welcome. Btw, adding more space could also be a potential solution for me, but as can be seen by the previous post (Link 1), this may not be easy to implement in ggplot.


Start edit

For the sake of completeness, I am pasting in my original ggplot script that used to generate a legend without space between the legend keys (Figure 2 was created with this script - the bars etc. have been omitted from Figure 2, as this question is concerned with the legend only):

For the summarySE function, see Link 3:

slc <- summarySE(sl, measurevar="EStroop.ART", groupvars=c("Etarget","Econgruency"), na.rm=T)

ggplot(data=slc, aes(x=Etarget, y=EStroop.ART, fill=Econgruency))+ 
  geom_bar()+
  geom_bar(stat="identity", position=position_dodge(), colour="black",     show_guide=FALSE, size=0.15)+
  geom_errorbar(aes(ymin=EStroop.ART-ci, ymax=EStroop.ART+ci),
                width=0.2, # Width of the error bars
                position=position_dodge(.9), size=0.15)+
  labs(x="Target", y="Adjusted Reaction Time (milliseconds)")+ #set other    titles 
  scale_fill_manual(values=c("grey", "white"))+
  theme(axis.title.x = element_text(face="bold", vjust=0.1, size =6),
        axis.title.y = element_text(face="bold", vjust=1.0, size =6),
        axis.text.x = element_text(size = 5, colour="black"),
        axis.text.y = element_text(size = 5, colour="black"),
        legend.key = element_rect(colour = 'black', size=.2), # to change border of the legend box
        legend.text=element_text(size = 4),
        legend.title=element_blank(),
        panel.grid.major = element_line(size=.20),
        panel.grid.minor = element_line(size=.1),
        axis.ticks=element_line(size=.2),
        axis.line=element_line(colour="black", size=0.15),
        legend.key.size = unit(.3, "cm"))+ # size of legend box
  coord_cartesian(ylim=c(500,700)) # to "zoom" in on the graph 
ggsave("ES_cong.tiff", width=86, height=60, units='mm', dpi=1200)  

End edit

1
I blew it way up, your example plotted 2600 pixels high, and I can't see a gap. The left line of the key is a bit thick though. That should not be.Mike Wise
For Figure 1 there should be a gap: a thin grey line in between the black borders of the legend keys. For Figure 2 there should not be a gap (this is what I want to achieve). Which figure are you referring to? Also, you should be able to produce the legend of Figure 1 with the example script above - again, this should produce this gap. It's a minimal gap, mind you, but still clearly visible to me. I hadn't spotted that the border lines have varying degrees of thickness, ideally this should not be the case though. Any suggestions for how to resolve this as well would be welcome.Tiberius
Just replace the .jpg in your ggsave with .pdf or .svg. to change the type of file you are saving.Gregor Thomas

1 Answers

3
votes

This can be resolved with the rectangle_key_glyph() function from the cowplot package. It has an option to set the exact padding you want, which can be positive or negative.

By default, there is no gap. This causes the two lines around the boxes to be drawn side-by-side, which means they appear thicker. This may not be what you want.

library(ggplot2)
library(cowplot)

b <- c(
  "A", "A", "A", "B", "B", "B", "A", "A", "A",
  "B", "B", "B", "A", "A", "A", "B", "B", "B"
)
c <- c(
  11, 22, 33, 99, 88, 77, 44, 55, 66,
  61, 62, 63, 83, 85, 87, 84, 86, 88
)

dft <- data.frame(b, c)

ggplot(dft, aes(b, c, fill = b))+
  stat_summary(
    fun = mean, geom = "bar", position = "dodge", 
    colour = "black", size = 0.2,
    key_glyph = rectangle_key_glyph(
      colour = "black"
    )
  ) +
  scale_fill_manual(values = c("grey", "white")) +
  theme(legend.key = element_blank()) 

My preferred solution is to make the gap bigger, so it's clearly there.

ggplot(dft, aes(b, c, fill = b))+
  stat_summary(
    fun = mean, geom = "bar", position = "dodge", 
    colour = "black", size = 0.2,
    key_glyph = rectangle_key_glyph(
      colour = "black",
      padding = margin(3, 3, 3, 3)
    )
  ) +
  scale_fill_manual(values = c("grey", "white")) +
  theme(legend.key = element_blank())

But you can also use negative padding to have the lines lie exactly on top of each other in the middle. Here done with size = 2 to exaggerate the effect.

ggplot(dft, aes(b, c, fill = b))+
  stat_summary(
    fun = mean, geom = "bar", position = "dodge", 
    colour = "black", size = 2,
    key_glyph = rectangle_key_glyph(
      colour = "black",
      padding = margin(-2, -2, -2, -2)
    )
  ) +
  scale_fill_manual(values = c("grey", "white")) +
  theme(legend.key = element_blank())

Note that in all these cases, I've set legend.key = element_blank(). We don't want anything to be drawn underneath our legend key. This is particularly important when you use a positive padding.