14

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

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
Tiberius
  • 331
  • 1
  • 9
  • Link 1: http://stackoverflow.com/questions/11366964/is-there-a-way-to-change-the-spacing-between-legend-items-in-ggplot2 Link 2: http://www.cookbook-r.com/Graphs/Bar_and_line_graphs_%28ggplot2%29/ – Tiberius Jan 07 '16 at 13:22
  • 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 Jan 07 '16 at 13:25
  • 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 Jan 07 '16 at 13:52
  • I don't think ggplot2 is "pixel perfect", but I would have to dive deep into the code to be sure. – Mike Wise Jan 07 '16 at 13:55
  • Btw, you can see that there is a gap when you remove the following code line: "theme(legend.key = element_rect(colour = 'black', size=.01))". The legend keys should then be clearly separated by a thin white line. I'd like to know how to remove that line/gap ... I don't think that it's to do with pixels as I was able to create Figure 2 using ggplot before. It's just that having updated ggplot recently this "old" script no longer works. The main difference between the old and the new script is that I added "geom_bar()+" in the second code line - now I get an error message for that ... – Tiberius Jan 07 '16 at 16:35
  • Well there are quite a few regression bugs in ggplot 2.0.0 right now. So I am not surprised things have changed. – Mike Wise Jan 07 '16 at 17:09
  • Could you reformulate your question as a bug, and mentioned that you think ggplot used to behave differently? That will get more attention. – Mike Wise Jan 07 '16 at 17:10
  • Link 3: http://www.cookbook-r.com/Graphs/Plotting_means_and_error_bars_%28ggplot2%29/ Thanks, Mike. I have edited the question accordingly - hope it's a bit clearer now. – Tiberius Jan 07 '16 at 17:55
  • I wouldn't expect this to be perfect using raster graphics - there's anti-aliasing and such going on that has little to do with `ggplot`. I'd be much more convinced this is something worth taking seriously if you demonstrated using vector graphics like PDF or SVG. – Gregor Thomas Jan 10 '16 at 06:10
  • @Gregor Unfortunately such a test goes beyond my current programming capabilities. I have provided data and the script to create Figure 1. If you or someone else knows how to do the relevant test, this is more than welcome here. Indeed, I am not sure if it is a ggplot bug, but in view of the discrepancy between Fig. 1 and 2 (both of which were created with different versions of ggplot) it is a possibility. My main interest here is to find a way to reduce the gap between the legend keys (see Figure 1). So, if you have any ideas on how to go about that, that would be great. – Tiberius Jan 10 '16 at 16:02
  • 1
    Just replace the `.jpg` in your `ggsave` with `.pdf` or `.svg`. to change the type of file you are saving. – Gregor Thomas Jan 10 '16 at 17:15
  • @Gregor Thanks for the explanation, that's easy enough. I have just done that. The problem is the same, however, regardless of whether the image type is .jpg, .pdf, .svg or .tiff. Basically, the midline looks thicker and when you zoom in you will find that this is because there two lines are drawn in the centre (with a small gap in between) instead of just one. – Tiberius Jan 10 '16 at 17:43
  • 1
    Related https://github.com/tidyverse/ggplot2/issues/2844 – Tung Oct 22 '18 at 00:06
  • When saving 40x40 I even get two black rectangles with a line of white pixels inside, on top of both colors. – Nakx Apr 21 '20 at 13:15

1 Answers1

3

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.

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104