Place a border around different shape varieties in

2019-06-14 01:36发布

In attempting to place a border around geom_point()s in ggplot2, this question was an extremely helpful starting point. I ended up opting for the approach outlined by @joran (the second answer) because it allows me to get smaller outlines (this is preferable since these points will end up being quite small in the final product).

However, I am having trouble employing a slight variation of this technique. I have two different shape varieties to outline and this is causing me some problems. Here is a reproducible example:

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)) +
    geom_line(color = 'gray40') +
    geom_point(aes(shape = id,
                   color = id),
               size = 3) +
    geom_point(aes(shape = id),
               color = 'gray70',
               size = 3,
               show_guide = FALSE) +
    scale_color_manual(values = c('lightskyblue1', 'lightpink'),
                       labels = c('HQ', 'LQ')) +
    scale_shape_manual(values = c(15, 16, 0, 1),
                       labels = c('HQ', 'LQ')) +
    theme_bw()

This ends up giving a plot that looks like this:

enter image description here

I cannot understand why the points become solid gray (this is the color I'd like the border around the blue and pink points to be). Any help in retaining the blue and pink fill with a gray border matching the shape type would be greatly appreciated!

EDIT: In case it was not clear, I know that I can use pch 21-25 to achieve a border. However, these borders are too large and their thickness is not modifiable (as far as I know). As a result I am trying to layer two geom_points()s, one filled and the other unfilled, to achieve the appearance of a border. I can sort of accomplish this by layering another set of geom_point()s like this:

plot <- 
    ggplot(df, aes(x = period,
                   y = values,
                   group = id)) +
    geom_line(color = 'gray40') +
    geom_point(aes(shape = id,
                   color = id),
               size = 3) +
    geom_point(shape = 1,
               color = 'gray70',
               size = 3,
               show_guide = FALSE) +
    scale_color_manual(values = c('lightskyblue1', 'lightpink'),
                       labels = c('HQ', 'LQ')) +
    scale_shape_manual(values = c(15, 16),
                       labels = c('HQ', 'LQ')) +
    theme_bw()

The problem here is that each "border" does not match the corresponding shape, and the resulting image looks like this:

enter image description here

标签: r ggplot2
3条回答
Fickle 薄情
2楼-- · 2019-06-14 01:49

Just saw that @mucio has updated his answer - I think his answer is a little bit more elegant, though this way may give you thin borders that you want.


Since you're using id for the shape legend both times, both the colorful shapes and the grey shapes are both filled. One way around this (admittedly a hack, but that doesn't seem to have stopped you so far), is to create a new variable with new levels and use that for the shape in the grey shapes. (Also note that I had to rearrange the order of the shape specifications).

df$id2 <- ifelse(df$id == 'hq', 'hq_alt', 'lq_alt')
plot <- 
    ggplot(df, aes(x = period,
                   y = values,
                   group = id)) +
    geom_line(color = 'gray40') +

     geom_point(aes(shape = id,
                   color = id),
               size = 3) +
    geom_point(aes(shape = id2),
               color = 'gray70',
               size = 3,
               show_guide = FALSE) +
    scale_color_manual(values = c('lightskyblue1', 'lightpink'),
                       labels = c('HQ', 'LQ')) +
    scale_shape_manual(values = c(15, 0, 16, 1),
                       labels = c('HQ', 'LQ'), guide=F) +
    theme_bw()
查看更多
神经病院院长
3楼-- · 2019-06-14 01:52

Edited

I missread your question. Anyway the solution is in the order of the geom_point:

  1. the first one goes in the background, so I use it to draw bigger gray shapes (size 5)

    geom_point(aes(shape = id),
               color = 'gray70',
               size = 5,
               show_guide = FALSE)
    
  2. the second one draws the colored shapes:

    geom_point(aes(shape = id,
                   color = id),
               size = 3)
    

Whit this:

plot <- 
  ggplot(df, aes(x = period,
                 y = values,
                 group = id)) +
  geom_line(color = 'gray40') +
  geom_point(aes(shape = id),
             color = 'gray70',
             size = 5,
             show_guide = FALSE) + 
  geom_point(aes(shape = id,
                 color = id),
             size = 3) +
  scale_color_manual(values = c('lightskyblue1', 'lightpink'),
                     labels = c('HQ', 'LQ')) +
  scale_shape_manual(values = c(15, 16, 0, 1),
                     labels = c('HQ', 'LQ')) +
  theme_bw()

Whit this code I can achieve this result: enter image description here

查看更多
放荡不羁爱自由
4楼-- · 2019-06-14 02:01

Actually, you don't have to use so many aes's. Only one aes in ggplot is sufficient. The aes will automatically be applied to the other geom_.. unless it is overrided.

plot <- 
  ggplot(df, aes(x = period, y = values, group = id, shape = id, color=id)) +
  geom_line(color = 'gray40') +
  geom_point(color = 'gray70', size = 5, show_guide = FALSE) +
  geom_point(size = 3) +
  scale_color_manual(values = c('lightskyblue1', 'lightpink'), labels = c('HQ', 'LQ')) +
  scale_shape_manual(values = c(15, 16, 0, 1), labels = c('HQ', 'LQ')) +
  theme_bw()

enter image description here

查看更多
登录 后发表回答