7
votes

Using pch I can plot any symbol and assign any label to in the legend. But how can I plot two symbols for each legend label? For example, in the plot below, I would like to have ■ ▲ ● paired with red versions of those so I have only three labels 'a', 'b', 'c' displayed in the legend, for those six symbols. At the moment, it seems that basic plot legend allows me to only plot one symbol for each label:

plot(rnorm(50),pch=c(15:17),col=1:2)
legend('topleft',pch=c(15:17),col=1:2,legend=c("a","b","c"),cex=1.5)

enter image description here

2
What prevent you from constructing a legend yourself with a combination of points() and text()? (or would this be an 'acceptable' solution?) Another idea would be to use ggplot2 with a discrete and color scale. - chl
@chl: Your first point - I thought that more robust/automatic solution would be possible. Your second point - I honestly dislike ggplot2, because it adds to much chartjunk by default, so I avoid it. Maybe you have similar idea for lattice/grid? - Geek On Acid
Hmm. I wonder if ggplot2 themes can be tweaked to make you happier. What do you consider chartjunky other than the backgrounds and grid lines? Although I think the lattice solution provided by @Josh O'Brien below should suit you nicely. - Ben Bolker
I have to ask: is this really the best way to present data? You still need to present the meaning of different colors for each of "a" "b" "c", so why not use non-filled characters next to abc in the legend, followed there or elsewhere with an explanation of the difference between black and red. - Carl Witthoft
This is absolutely valid question @Carl, and I have to admit that empty point was my initial strategy. But I have quite problematic collaborator who has different views on that, and for this person the legend should EXACTLY represent the points on the plot. My other choice would be to have separate legends for each condition. Bugger... - Geek On Acid

2 Answers

9
votes

This isn't too hard with lattice, as its key = argument takes an arbitrary number of columns to be included in the legend.

library(lattice)

myPCH <- 15:17
Data  <- rnorm(50)
Index <- seq(length(Data))

xyplot(Data ~ Index, 
       pch = myPCH, col=1:2,
       key = list(space = "right", adj=1,
                  text = list(c("a", "b", "c"), cex=1.5),
                  points = list(pch = myPCH),
                  points = list(pch = myPCH,col=2)))

I don't know off the top of my head how to include the legend inside the plotting area, but with this kind of plot it seems better to have it outside anyway. (Edit: @chl in comments kindly points out a couple of ways to do this. To plot the key in the lower-left of the figure, for instance, replace space = "right" in the above with either corner = c(0,0) or x = 0, y=0.2)

enter image description here

5
votes

Like chl pointed out, it is also possible to build a customized legend. The function 'legend' invisibly returns boundaries of the legend box as well as the coordinates of the legend text. One could plot the legend text without symbols, and then add the symbols manually with 'points' to the returned coordinates. This would not require any additional graphics packages:

plot(rnorm(50), pch=c(15:17), col=1:2)
# Plot legend text, inset could be used to shift legend text to the right
pos <- legend('topleft', legend=c("a","b","c"), cex=1.5)
# Plot symbols in two columns, shifted to the left by 3 and 1 respectively
points(x=rep(pos$text$x, times=2) - c(3,1), 
    y=rep(pos$text$y, times=2), 
    pch=rep(c(15:17), times=2), col=rep(1:2, times=3))

The image produced by the code