arataj
arataj

Reputation: 373

ggplot - a custom legend

I want to draw a custom legend in ggplot2. I tried, as suggested in other questions here on a similar topic, scale_colour_manual, guide=legend, etc., yet the default legend is immovable so far. The default legend ignores two plots, and needlessly draws size levels for the third plot. I would want a legend like that:

[light gray line] graph 1
[black circle of size=1] graph 2
[gray rectangle of size=1] graph 3

Here is the code, with example data frames. Custom legend modifications, like these from this question, appear to do nothing.

cloud2 <- data.frame(x = c(0, 1, 2), y = c(0.3, 0.4, 0.5))
sandwich3 <- data.frame(x = c(1, 2, 3), y = c(0.4, 0.5, 0.6), p = c(0.1, 0.6, 0.3))
sandwich4 <- data.frame(x = c(3, 4, 5), y = c(0.6, 0.3, 0.5), p = c(0.1, 0.7, 0.2))
ggplot(cloud2, aes(x=x, y=y)) + geom_line(size=0.1,colour="gray70") +
  aes(x=x, y=y, size=sqrt(p)) +
  geom_point(data=sandwich3,colour="gray40",shape=15) + scale_size(range=c(0,2)) +
  geom_point(data=sandwich4,colour="black",shape=16) +
  theme(legend.position=c(0.905, 0.14), legend.title=element_blank(),
  axis.ticks = element_line(colour = "black"), axis.text = element_text(colour = "black")) +
  scale_x_continuous(limits = c(-5, 5), breaks=c(-2, 0, 2)) +
  scale_y_continuous(limits = c(-1.1, 1.2))

The resulting plot, using the original data frames: enter image description here

Upvotes: 2

Views: 1317

Answers (1)

tonytonov
tonytonov

Reputation: 25608

First, it's better to keep all data in one place. I used rbind to make a single data frame with several extra columns. This way, mapping to aes is also much simpler since it is declared once across all geoms:

df_plot
  x   y   p series line
1 0 0.3  NA      1    1
2 1 0.4  NA      1    1
3 2 0.5  NA      1    1
4 1 0.4 0.1      2    2
5 2 0.5 0.6      2    2
6 3 0.6 0.3      2    2
7 3 0.6 0.1      3    2
8 4 0.3 0.7      3    2
9 5 0.5 0.2      3    2

Note the use of factors:

str(df_plot)
'data.frame':   9 obs. of  5 variables:
 $ x     : num  0 1 2 1 2 3 3 4 5
 $ y     : num  0.3 0.4 0.5 0.4 0.5 0.6 0.6 0.3 0.5
 $ p     : num  NA NA NA 0.1 0.6 0.3 0.1 0.7 0.2
 $ series: Factor w/ 3 levels "1","2","3": 1 1 1 2 2 2 3 3 3
 $ line  : Factor w/ 2 levels "1","2": 1 1 1 2 2 2 2 2 2

Now, just be accurate in mapping and override all scales:

ggplot(df_plot, aes(x = x, y = y, size = sqrt(p), 
                    linetype = series, shape = series, colour = series)) + 
    geom_line(size = 0.1) + 
    geom_point() + 
    scale_x_continuous(limits = c(-5, 5), breaks=c(-2, 0, 2)) +
    scale_y_continuous(limits = c(-1.1, 1.2)) +
    scale_shape_manual(values = c(NA, 15, 16)) + 
    scale_linetype_manual(values = c(1, 0, 0)) +
    scale_colour_manual(values = c("gray70", "gray40", "black")) + 
    scale_size(range = c(0,2)) +
    theme(legend.position = c(0.905, 0.14), legend.title = element_blank(),
          axis.ticks = element_line(colour = "black"), 
          axis.text = element_text(colour = "black")) +
    guides(size = F)

With that, your initial picture is untouched, but the legend is (automatically) correct:

enter image description here enter image description here

Upvotes: 1

Related Questions