9

I recently asked a question here which allowed me to add borders to geom_point()s in ggplot2 with customizable colors and thickness. Admittedly, it's a bit of a hack and I'm now having some trouble which may be a result of this. The borders are generated by layering two geom_point()s, one of which is the color of the border that I want and which is slightly larger than the geom_point() which provides the "fill". A reproducible example here:

require('ggplot2')

values <- rnorm(n = 10, mean = 1, sd = 0.5) + c(1:10)

df <- data.frame(id = rep(c('hq', 'lq'), each = 5),
                 values = values,
                 period = rep(c(1:5), 2))

plot <- 
    ggplot(df, aes(x = period,
                   y = values,
                   group = id,
                   shape = id,
                   color = id)) +
    geom_line(color = 'gray40') +
    geom_point(color = 'gray24',
               size = 4) +
    geom_point(size = 3) +
    guides(shape = guide_legend(override.aes = list(size = 5))) +
    scale_color_manual(values = c('lightskyblue1', 'lightpink'),
                       labels = c('HQ', 'LQ')) +
    scale_shape_manual(values = c(15, 17, 0, 2),
                       labels = c('HQ', 'LQ')) +
    theme_bw()

Because I would like the legend symbols to be larger than the plot symbols, I've used override.aes(). However, this means that the "borders" I've created do not appear in the legend:

enter image description here

Is there some way to give multiple size arguments to override.aes() so that the layering I've used in the plot is left intact in the legend (i.e. the legend symbols also contain the "borders")?

Community
  • 1
  • 1
thagzone
  • 355
  • 1
  • 3
  • 13

1 Answers1

13

You can do this with a single call to geom_point if you use a point-marker with both a border and a fill (pch values from 21 through 25; see ?pch). Then, you can set the size of the legend markers with override.aes and the borders and fill will always appear correctly. For example:

ggplot(dat, aes(x = period,
                y = values,
                group = id,
                shape = id,
                fill=id)) +
  geom_line(color = 'gray40') +
  geom_point(size=4) +
  guides(shape = guide_legend(override.aes = list(size = 5))) +
  scale_fill_manual(values = c('lightskyblue1', 'lightpink'),
                    labels = c('HQ', 'LQ')) +
  scale_shape_manual(values = c(22,24),   # These are the marker shapes
                     labels = c('HQ', 'LQ')) +
  theme_bw()

This results in a black border for the point markers (the default value, but you can change it) and the fill colour you specify.

enter image description here

UPDATE: In response to your comment, here's how to get the black border on the legend markers without any other changes to your original code:

  guides(shape = guide_legend(override.aes = 
                                list(size = 5, shape=c(22,24), 
                                     colour="black", 
                                     fill=c('lightskyblue1', 'lightpink')))) +
eipi10
  • 91,525
  • 24
  • 209
  • 285
  • Thanks for your reply. I am aware of the existence of `pch 21-25`. The issue is that, while in this small example the borders look fine, the actual plot I am generating has much smaller shapes and many more data points which render the `pch` borders far too thick. This is why I went with this "hack" fix. If you know how to alter the border size of the `pch 21-25` shapes, then that would be great! – thagzone Mar 27 '15 at 19:11
  • 1
    I don't know of a way to change the border on the point markers, but see the update to my answer for how to get the legend looking how you want without any other changes to your original code. – eipi10 Mar 27 '15 at 19:21
  • Bravo! Subtle difference matter. I was trying to adjust alpha with `alpha = list(1, 1, .5)`. Who knew it was as simple as using `c(1, 1, .5)` instead. – o_v Apr 12 '22 at 07:45
  • Just to update this old answer, you can use `stroke` to set border thickness of point markers (e.g., `stroke=0.3`). – eipi10 Apr 12 '22 at 15:49