1

Here's a silly data.frame:

df <- read.table(textConnection(
"pole medal  bag     x     y
north gold   paper   0.852 0.423
north gold   plastic 0.277 0.055
north silver paper   0.257 0.211
north silver plastic 0.457 0.614
north bronze paper   0.825 0.299
north bronze plastic 0.672 0.126
south gold   paper   0.482 0.764
south gold   plastic 0.603 0.869
south silver paper   0.327 0.451
south silver plastic 0.147 0.672
south bronze paper   0.140 0.466
south bronze plastic 0.833 0.325
"), header = TRUE)

I know how to plot a scatterplot for these data in a way that uses color and shape to indicate two of the factor attributes; for example:

library(ggplot2)
ggplot(data = df, aes(x = x, y = y)) +
geom_point(size = 4, aes(shape = pole, color = bag))

enter image description here

I would like to add one more point feature to indicate a third factor attribute (in this case medal). The one possibility that comes to mind is a colored outline.

Is there a convenient way to do this? (One tricky aspect of the problem is that the color palette for the outlines must be distinct from that used for the point fills, because, for each point, the outline and the fill must be visually distinguishable.)

UPDATE:

When I try Gregor's suggestion, the points look right, but the legend is messed up:

enter image description here

kjo
  • 33,683
  • 52
  • 148
  • 265
  • 1
    You will likely need to establish your own color schemes for the fill vs color to make this look OK. Plus some legend work. Such as: `scale_fill_manual(values = c("pink", "white")) + scale_color_manual(values = c("brown", "gold", "grey74")) + guides(fill = guide_legend(override.aes = list(color = c("pink", "white"))), color = guide_legend(override.aes = list(shape = 21)))` – aosmith Aug 17 '16 at 16:58
  • Why was this question downvoted? – kjo Aug 17 '16 at 17:13
  • @kjo, probably because this is discussed at some length in the docs of `geom_point`. Also [see for example here](http://stackoverflow.com/questions/15965870/fill-and-border-colour-in-geom-point-scale-colour-manual-in-ggplot) and – Axeman Aug 17 '16 at 19:14
  • The discussion in the examples [here](http://docs.ggplot2.org/current/geom_point.html) says: "For shapes that have a border (like 21), you can colour the inside and outside separately. Use the stroke aesthetic to modify the width of the border" – Axeman Aug 18 '16 at 15:00
  • 1
    @Axeman: OK, we differ in what we consider to be "discussed at some length". The necessary `scale_*` and `guide` modifications given by aosmith and Gregor are not explicitly mentioned in the docs. Those are all part of the answer I was looking for. But, hey, that's OK: it's not the first time that a question of mine gets downvoted by someone who did not bother to understand the question in the first place. – kjo Aug 18 '16 at 15:37
  • You're assuming it was my vote. But thanks anyways. – Axeman Aug 18 '16 at 15:45
  • @Axeman: no I am not assuming it was your vote. I am only assuming that you are right in your guess as to why the question had been downvoted. IOW: If your guess is right, then the down-voter did not understand the question. – kjo Aug 18 '16 at 19:53

1 Answers1

7

Yes you can! There is an example in the help for ?geom_point:

# For shapes that have a border (like 21), you can colour the inside and
# outside separately. Use the stroke aesthetic to modify the width of the
# border
ggplot(mtcars, aes(wt, mpg)) +
  geom_point(shape = 21, colour = "black", fill = "white", size = 5, stroke = 5)

In your case you'll want to use shapes 21 (circles with outline) and 24 (triangles with outline) like this:

ggplot(data = df, aes(x = x, y = y)) +
  geom_point(aes(shape = pole, color = medal, fill = bag),
             size = 4, stroke = 2) + 
  scale_shape_manual(values = c(21, 24))

Notice that, when using both, fill corresponds to the center of the points and color to the outline. You can change the weight of the outline by setting stroke.

As noted in the comments, you'll have to do some extra tweaking to get the legend right. Adding to the above plot:

fill_col = c("pink", "white")
outline_col = c("brown", "gold", "grey74")

scale_fill_manual(values = fill_col) + 
scale_color_manual(values = outline_col) +
guides(fill = guide_legend(override.aes = list(color = fill_col)),
       color = guide_legend(override.aes = list(shape = 21)))
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294