Got Plot? Legends

Advices on legend positions and labeling

In this example we’ll assume that we have some data that can be represented with some lines (e.g. some time series)

# generate some fake data
set.seed(434)
line1 = sort(runif(10, 0, 1))
line2 = sort(runif(10, 0, 1))
line3 = sort(runif(10, 0, 1))
some_data = rbind(line1, line2, line3)

The Basic Legend

Usually most of us will add a legend at one of the four corners of the chart. For instance, let’s add a legend at the bottom-right corner. The problem with this type of legends is that they require an extra effort from the reader switching between the label and the line when reading.

# legends
cols = paste("gray", seq(20, 80, length = 3), sep = "")
# line widths
lwds = c(2, 3.5, 5)
# plot
plot(0, xlab = "x axis", ylab = "y axis", xlim = c(0.5, 10), ylim = c(0, 1),
     type = "n", xaxs = "i", yaxs = "i", axes = FALSE)
axis(side = 1, pos = 0, at = 0:10, lwd.ticks = 0.2, col = "gray70")
axis(side = 2, pos = 0.6, las = 2, lwd.ticks = 0.2, col = "gray70")
title(c("Plot with a default legend"), cex.main = 0.9)
for (i in 1:3) {
    lines(1:10, some_data[i, ], col = cols[i], lwd = lwds[i])
}
# add legend
legend("bottomright", legend = rownames(some_data), col = cols, lwd = lwds)

Direct labeling

Instead of labeling at long distance, we can improve our chart by labeling the lines directly. In this way we don’t need to cross-reference between the key and the line. I would relegate the use of a box legend to those cases when space is tight and the lines crisscross extensively.

# legends
cols = paste("gray", seq(20,80,length=3), sep="")
# line widths
lwds = c(2, 3.5, 5)
# plot
plot(0, xlab="x axis", ylab="y axis", xlim=c(0.5,11), ylim=c(0,1),
     type="n", xaxs="i", yaxs="i", axes=FALSE)
axis(side=1, pos=0, at=0:10, lwd.ticks=0.2, col="gray70")
axis(side=2, pos=0.6, las=2, lwd.ticks=0.2, col="gray70")
title(c("Labeling the lines directly"), cex.main=0.9)
for (i in 1:3)
{
  lines(1:10, some_data[i,], col=cols[i], lwd=lwds[i])
}
# label lines directly
text(rep(10.4,3), some_data[,10], labels=rownames(some_data), cex=0.9)

Annotations

Closely related to long distance labeling is the use of long distance annotations in which marks are associated to the labels in the legend. Again, this use of annotations are very distracting for the eyes of the reader. It is difficult to focus on the patterns while your eyes go back and forth from the legend to the marks.

# generate some fake data
set.seed(208)
numbers = sort(runif(50, 0, 1))
noise = rbinom(50,1,.1) * rnorm(50, 0, 0.3)
y = numbers + noise

# plot
plot(0, xlab="x axis", ylab="y axis", xlim=c(0,51), ylim=c(-0.2,1.3),
     type="n", xaxs="i", yaxs="i", axes=FALSE)
axis(side=1, pos=-0.2, at=seq(0,50,5), lwd.ticks=0.2, col="gray70")
axis(side=2, pos=0, las=2, lwd.ticks=0.2, col="gray70")
lines(1:50, y, type="l", lwd=4, col="gray80")
title("Long distance annotations", cex.main=0.9)
# add connecting lines
lines(c(17,17), c(y[17],0.8), col="gray60")
lines(c(20,20), c(y[20],0.6), col="gray60")
lines(c(41,41), c(y[41],0.7), col="gray60")
# add symbols
points(c(17,20,41), c(0.8,0.6,0.7), pch=19, col="gray40", cex=3)
text(c(17,20,41), c(0.8,0.6,0.7), c(1,2,3), col="white")
# add legend
legend("bottomright", legend=c("there is a peak", "there is a sinking", "another peak"), pch=c("1","2","3"))

The solution to long distance annotations, whenever possible, is to use annotations directly so the reader identify the patterns quickly without getting lost in going back and forth with data and legends.

# plot
plot(0, xlab="x axis", ylab="y axis", xlim=c(0,51), ylim=c(-0.2,1.3),
     type="n", xaxs="i", yaxs="i", axes=FALSE)
axis(side=1, pos=-0.2, at=seq(0,50,5), lwd.ticks=0.2, col="gray70")
axis(side=2, pos=0, las=2, lwd.ticks=0.2, col="gray70")
lines(1:50, y, type="l", lwd=4, col="gray80")
title("Short distance annotations", cex.main=0.9)
# add connecting lines
lines(c(17,17), c(y[17],0.8), col="gray60")
lines(c(41,41), c(y[41],0.7), col="gray60")
# add annotations directly
text(c(17,20,41), c(0.85,-0.15,0.65), col="gray30",
     labels=c("a peak", "a sinking", "another peak"), cex=0.9)

Happy plotting

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s