【问题标题】:Change ggplot2::geom_line legend shape to a "dot" similar to ggplot2::geom_point's legend shape将 ggplot2::geom_line 图例形状更改为类似于 ggplot2::geom_point 的图例形状的“点”
【发布时间】:2019-01-07 01:37:39
【问题描述】:

这里最重要的工作是将geom_line 的图例形状更改为geom_point“点”,但在图中保留geom_line。如果有人可以演示如何创建一个更简洁的 geom_line2() 函数(见下文),该函数在图例中显示 geom_point“点”对象,我将不胜感激。

我知道可以将geom_point 分层并为geom_line 影响guides(color = FALSE)。但是,我想了解如何在ggproto 代码中执行此操作。我也知道geom_point 可以覆盖图例形状,但这种方法不适用于geom_line

我尝试修改 GeomPath 对象以将 draw_key = draw_key_path 更改为 draw_key = draw_key_point,但由于多种原因失败了。

我还认为使用guides(color = guide_geom()) 可能能够达到预期的效果,但正如广泛宣传的那样,这是一个未记录的功能。看了 GitHub 上的源代码,还是没进步。

底部的代码 sn-p 产生了想要的效果,但是很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")

此代码还会产生不良副作用,即将所有未来对ggplot2::geom_line 的调用设置为相同的图例效果。

PS ... this answer 会有所帮助,但它适用于旧的ggplot2

【问题讨论】:

  • 修改GeomPath 会如何产生问题?我曾想过在 environment(GeomPath$draw_key)$f &lt;- [your customised function above]environment(GeomPath$draw_key)$f &lt;- draw_key_path 之间切换可以让您在两种图例类型之间切换?
  • 我会给出重点,因为我同意下面的 dww。 . .通过从GeomPoint 移植到draw_key 进行更改将引发由于未指定大小和笔划而导致的错误。此外,如果没有像 keep_mid_true 这样的函数,自定义函数也会失败。最后,奇怪的曲折(比如找到Kmisc::dapply)在这个过程中引发了一致的扳手。

标签: r ggplot2


【解决方案1】:

选项 1:

别这样! (注意这是我最喜欢的,它不是为了搞笑或无益)。 ggplot 试图强迫你以特定的方式做事,通常是因为有充分的理由。用点表示线条不如使用线条清晰,因此通常应避免使用。图表最重要的方面是它传达信息的清晰程度,而不是它看起来有多漂亮。不要为了美观而牺牲清晰度。

但是,如果你真的有充分的理由确信点会更好,那么......

选项 2

不要使用 ggplot。如前所述,ggplot 更喜欢使用自己的图表应该如何的哲学。其他工具更宽容,可以轻松适应这一点。例如。这在基础图形中很容易做到

选项 3

如果您真的需要 ggplot,并且确实需要点来表示线条,那么您可以创建一个使用 geom_point 而不是 geom_line 的图形,然后使用 gtable 将折线图中的图例替换为点图中的图例

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)

注意:如果您不知道需要更换哪个 grob,可以在 grob 名称中搜索 "guide" 找到正确的:

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

【讨论】:

  • 谢谢 dww...是的,我对此最感兴趣,因为它可以更好地理解 ggplot2 的内部结构。鉴于预期的效果,您的解决方案更清洁、更安全。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 2022-09-27
  • 2022-11-27
  • 2022-01-16
相关资源
最近更新 更多