简体   繁体   中英

Change ggplot2::geom_line legend shape to a "dot" similar to ggplot2::geom_point's legend shape

The overriding effort here is to change the legend shape for geom_line to a geom_point "dot", but retain the geom_line in the plot. I would be grateful if someone could demonstrate how to create a cleaner geom_line2() function (see below) which shows the geom_point "dot" object in the legend.

I know that one could layer geom_point and effect guides(color = FALSE) for the geom_line . However, I'd like to understand how to do this in the ggproto code. I also know that with geom_point one can override the legend shape, but this approach does not work for geom_line .

I attempted to tinker with the GeomPath object to change the draw_key = draw_key_path to draw_key = draw_key_point , but that failed for many reasons.

I also thought I might be able to achieve the desired effect using guides(color = guide_geom()) but, as is broadly advertised, this is an undocumented function. I was unable to make progress even after looking at the source code on GitHub.

The code snippet at the bottom produces the desired effect but is hacky.

# this is the default
library(tidyverse)
library(grid)

mydf <- tibble(month = rep(seq(1, 10, 1), 4),
           olympian = sort(rep(c("apollo", "jove", "mercury", "minerva"), 10)),
           weight = c(seq(51, 60, 1), seq(60, 78, 2), 
                    seq(69.5, 56, -1.5), seq(55, 46, -1)))

ggplot(mydf, aes(month, weight, color = olympian)) +
  geom_line(size = 1) +
  theme_light() +
  labs(title = "Default geom_line legend shape")

在此处输入图片说明

# here is what worked to achieve the effect

GeomLine2 <- GeomPath

GeomLine2$draw_key <- function(data, params, size) {
  data$linetype[is.na(data$linetype)] <- 0

  segmentsGrob(0.5, 0.5, 0.5, 0.5, # NOTE CHG HERE
               gp = gpar(
                 col = alpha(data$colour, data$alpha),
                 lwd = 5, # NOTE CHG HERE
                 lty = data$linetype,
                 lineend = "round" # NOTE CHG HERE
               ),
               arrow = params$arrow
  )
}

geom_line2 <- function (mapping = NULL, data = NULL, 
                        stat = "identity", position = "identity", 
                        na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, 
...) 
{
  layer(data = data, mapping = mapping, stat = stat, geom = GeomLine2, 
        position = position, show.legend = show.legend, inherit.aes = 
inherit.aes, 
        params = list(na.rm = na.rm, ...))
}

ggplot(mydf, aes(month, weight, color = olympian)) +
  geom_line2(size = 1) +
  theme_light() +
  labs(subtitle = "Hacked geom_line legend shape")

在此处输入图片说明

This code also produces the undesirable side effect of setting all future calls to ggplot2::geom_line to this same legend effect.

PS ... this answer would be helpful but it is for old ggplot2

Option 1:

Don't do it! (NB This is my favourite and it is not intended to be facetious or unhelpful). ggplot tries to force you to do things in a specific way usually because there is a good reason. Representing lines with dots is less clear than using lines, so should typically be avoided. the most important aspect of a graph is how clearly does it convey information, not how pretty does it look. Don't compromise clarity for aesthetics.

But, if you really have a good reason why you are sure dots will be better then ...

Option 2

Don't use ggplot. ggplot, as mentioned, prefers to to use its own philosophy of how graphs should be. Other tools are more forgiving and can easily accomodate this. Eg this will be easy to do in base graphics

Option 3

If you really need ggplot, and you really need dots to represent lines, then you could create a graph that uses geom_point instead of geom_line, and then use gtable to replace the legend in your line graph with the one from the points graph

g = ggplot(mydf, aes(month, weight, color = olympian)) + theme_light()

gt.l = ggplot_gtable(ggplot_build(g + geom_line(size = 1)))
gt.p = ggplot_gtable(ggplot_build(g + geom_point(size = 2)))
gt.l$grobs[15] = gt.p$grobs[15]
grid.draw(gt.l)

在此处输入图片说明

Note: if you don't know which grob needs to be replaced, you can search for "guide" in the grob names to find the right one:

gt.l$grobs[grep('guide', gt.l$layout$name)] = gt.p$grobs[grep('guide', gt.p$layout$name)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM