9

This is a follow-up on https://stackoverflow.com/questions/32275113

The problem is to tweak the legend elements to increase the space between legend keys without simultaneously extending the legend keys themselves. The solution is likely to be in tweaking the correct legend theme option.

Desired result: more vertical space between the legend key text labels, but without stretching the legend key lines.

d <- data.frame(x = mtcars$mpg, y = 0.10)
vlines <- rbind(aggregate(d[1], d[2], mean), 
                aggregate(d[1], d[2], median))
vlines$stat <- rep(c("mean", "median"), each = nrow(vlines)/2)
library("ggplot2")
ggplot(data = d, aes(x = x, y = ..density..)) + 
    geom_histogram(fill = "lightblue", color = "black") + 
    geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat), 
            show.legend = TRUE) +
    theme(legend.direction = "vertical", 
        legend.position = "right",
        #          legend.key = element_rect(size = 2),
        legend.key.size = unit(3, "cm"),
        #          legend.key.width = unit(2, "cm"),
        #          legend.key.height = unit(1, "cm")
        )

Increasing legend.key.size, as suggested in answers to the linked question (see above), has the undesired side effect of increasing the vertical lines as well.

enter image description here

Edit Based on PoGibas's clever workaround, here's a screenshot of the desired result, included here to make sure the purpose is clear:

enter image description here

Following PoGibas, I used: shape = 73, legend.key.height = unit(2, "cm") and size = 6 inside the color guide.

PatrickT
  • 10,037
  • 9
  • 76
  • 111
  • More vertical space between labels or more vertical space between boxes? – pogibas Apr 05 '18 at 09:03
  • @PoGibas: more white space between the legend labels "mean" and "median", shorter legend key lines as on my screenshot, and as for the grey boxes I don't mind as I will blank them out anyways. (Thus either reduce the gray boxes and their content or reduce the vertical lines inside the boxes) Thanks! – PatrickT Apr 05 '18 at 09:06
  • 1
    I don't see such an option in the docs. Text is usually moved about by justifying (left, right). But you would have to justify each label different directions. – Stephen Henderson Apr 05 '18 at 09:12
  • @StephenHenderson, that makes two of us! Sometimes I miss the obvious, but it looks like PoGibas also does not believe there's a built-in option for this. – PatrickT Apr 05 '18 at 09:50

1 Answers1

6

One solution is to replace lines with points (requires additional geom layer):

Create plot with invisible points (size = 0 and rectangle shape shape = 15).

p <- ggplot(d, aes(x, ..density..)) + 
    geom_histogram(fill = "lightblue", color = "black") + 
    geom_vline(data = vlines, mapping = aes(xintercept = x, colour = stat)) +
    geom_point(data = vlines, aes(0, 0, colour = stat), size = 0, shape = 15)

Add legend theme to:

  • Mask background color in legend (legend.key = element_rect(fill = "white"))
  • Create large legend (legend.key.height = unit(3, "cm"))
  • Remove lines (linetype = 0) and make large points (size = 5)

Code:

p + 
    theme(legend.direction = "vertical", 
          legend.position = "right",
          legend.key = element_rect(fill = "white"),
          legend.key.height = unit(3, "cm")) +
    guides(color = guide_legend(override.aes = list(linetype = 0, size = 5)))

enter image description here

PS.:

  • This is not a perfect solution as there's a gap between legend label and boxes.
  • If you want lines instead of rectangles use shape = 73
pogibas
  • 27,303
  • 19
  • 84
  • 117
  • That's nice thanks! I would prefer to have a line key, rather than a point key... I guess the square-looking point key can be made into a segment-looking line key by tweaking its width (the line legend shouldn't be a square, it should look like a line segment)... am I to believe there is no built-in ``ggplot`` option to control the length of the segments inside the boxes independently of the boxes? – PatrickT Apr 05 '18 at 09:47
  • 1
    Use shape 73 which is letter "I" :-) – pogibas Apr 05 '18 at 09:48
  • yep, ``shape = 73`` does it! – PatrickT Apr 05 '18 at 09:51