Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can ggplot2 control point size and line size (lineweight) separately in one legend?

An example using ggplot2 to graph groups of data points and lines connecting the means for each group, mapped with the same aes for shape and for linetype:

p <- ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 2) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19))

Problem is that point symbols in the legend appear a bit too small to see, relative to the line symbols:

p

Trying to enlarge point size in legend also enlarges lineweight, so that is not useful here.

p1 <- p + guides(shape = guide_legend(override.aes = list(size = 4)))

p1

It would be nice if lineweight were a distinct aesthetic from size. I tried adding

+ guides(linetype = guide_legend(override.aes = list(size = 1)))

which just gives a warning.

> Warning message:
In guide_merge.legend(init, x[[i]]) : Duplicated override.aes is ignored.

It seems to make no difference either if I move the linetype aes out of ggplot() and into stat_summary(). If I wanted only the point symbols, I could eliminate lines from the legend this way.

p2 <- p + guides(shape = guide_legend(override.aes = list(size = 4, linetype = 0)))

p2

Instead, (keeping small point symbols in the graph itself) I want one single legend with both big point symbols as in this last image and thin line symbols as in the first image. Is there a way to do this?

like image 802
Scott Avatar asked Jul 29 '14 02:07

Scott


People also ask

How do I change the size of a legend key in R?

To change the Size of Legend, we have to add guides() and guide_legend() functions to the geom_point() function. Inside guides() function, we take parameter color, which calls guide_legend() guide function as value. Inside guide_legend() function, we take an argument called override.

How do I change the legend value in ggplot2?

You can use the following syntax to change the legend labels in ggplot2: p + scale_fill_discrete(labels=c('label1', 'label2', 'label3', ...))

How do I add a legend in ggplot2?

You can place the legend literally anywhere. To put it around the chart, use the legend. position option and specify top , right , bottom , or left . To put it inside the plot area, specify a vector of length 2, both values going between 0 and 1 and giving the x and y coordinates.


2 Answers

It sure does seem to be difficult to set those properties independently. I was only kind of able to come up with a hack. If your real data is much different it will likely have to be adjusted. But what i did was used the override.aes to set the size of the point. Then I went in and built the plot, and then manually changed the line width settings in the actual low-level grid objects. Here's the code

pp<-ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 3) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19)) +
  guides(shape=guide_legend(override.aes=list(size=5)))

build <- ggplot_build(pp)
gt <- ggplot_gtable(build)

segs <- grepl("geom_path.segments", sapply(gt$grobs[[8]][[1]][[1]]$grobs, '[[', "name"))
gt$grobs[[8]][[1]][[1]]$grobs[segs]<-lapply(gt$grobs[[8]][[1]][[1]]$grobs[segs], 
    function(x) {x$gp$lwd<-2; x})
grid.draw(gt)

The magic number "8" was where gt$grobs[[8]]$name=="guide-box" so i knew I was working the legend. I'm not the best with grid graphics and gtables yet, so perhaps someone might be able to suggest a more elegant way.

like image 84
MrFlick Avatar answered Sep 21 '22 14:09

MrFlick


Using the grid function grid.force(), all the grobs in the ggplot become visible to grid's editing functions, including the legend keys. Thus, grid.gedit can be applied, and the required edit to the plot can be achieved using one line of code. In addition, I increase the width of the legend keys so that the different line types for line segments are clear.

library(ggplot2)
library(grid)
p <- ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 2) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19)) +
  theme(legend.key.width = unit(1, "cm"))

p

grid.ls(grid.force())    # To get the names of all the grobs in the ggplot

# The edit - to set the size of the point in the legend to 4 mm
grid.gedit("key-[-0-9]-1-1", size = unit(4, "mm"))    

enter image description here

To save the modified plot

  g <- grid.grab()
  ggsave(plot=g, file="test.pdf")
like image 39
Sandy Muspratt Avatar answered Sep 21 '22 14:09

Sandy Muspratt