据我所知,使用override.aes
时,需要根据图例的顺序对list
参数中的值进行“硬编码”。
可以改用命名向量吗?
示例:
library(ggplot2)
set.seed(1)
df1 <- data.frame(x = 1:25, y_line = rnorm(25, 1, 0.01))
p <- ggplot(df1, aes(x, y_line)) +
geom_line(aes(colour = 'line')) +
geom_point(aes(y = 1, colour = 'point')) +
geom_line(aes(y = 1, color = 'point'), linetype = 'dotted')
# This specifies values by order:
p + guides(colour = guide_legend(override.aes = list(linetype = c('dotted', 'solid'), shape = c(NA, 16))))
# Attempt to use named vectors does not change the output
p + guides(colour = guide_legend(override.aes = list(linetype = c(point = 'dotted', line = 'solid'), shape = c(NA, 16))))
两个结果都相同:
使用带引号的名称时相同。
由reprex package(v0.2.1)于2019-05-07创建
答案 0 :(得分:1)
很抱歉,但是我想我可能确实错过了您要使用此功能的目的,因此,如果我的解决方法不能直接满足您的需要,我深表歉意。
我不确定是否可以在guides
函数中完成此操作,但是您可以做的是将guide_legend()
与scale_colour_*
结合使用来预先设置顺序breaks
。我认为这会模仿您的预期行为:
p <- ggplot(df1, aes(x, y_line)) +
geom_line(aes(colour = 'line')) +
geom_point(aes(y = 1, colour = 'point')) +
geom_line(aes(y = 1, colour = 'point'), linetype = 'dotted') +
scale_colour_discrete(
breaks = c("point", "line"),
guide = guide_legend(override.aes = list(linetype = c("dotted", "solid"),
shape = c(16, NA)))
)
答案 1 :(得分:1)
注意:我尚未对它进行彻底的测试,并且当hack与ggplot2中的其他未观察到的功能进行交互时,可能会出现无法预料的问题。程序包的内部工作原理可能很难理解,但是希望这可以提供一个起点...
图例构建部分位于ggplot2:::build_guides
(未导出的函数)内。如您所见,override.aes
中命名向量的名称在此过程中将被忽略。一种可能的解决方法是在函数中插入一些代码,以正确的顺序(基于图例标签)获得命名的矢量。我还添加了默认美学参数的检查,以便在某些情况下我们可能只希望覆盖一个或两个标签的美学,而其余参数保留默认值。
这是要插入的代码。我只尝试过线型,形状和大小。随便说一下,线型是我想到的唯一带有数字和分类值的情况,因此这是下面default.aes
涵盖的特定情况。
# define a function that completes each element in the override.aes list if
# it's a named vector, by arranging it in the order used by the legend labels,
# & replacing any unsupplied value with the latest (based on most recent layer)
# default aesthetic value for that specific element
complete.override.aes <- function(gdef, default.aes){
override.aes <- gdef$override.aes
if(!any(sapply(override.aes, function(x) !is.null(names(x))))){
return(gdef)
}
key.label <- gdef$key$.label
for(i in seq_along(override.aes)){
if(!is.null(names(override.aes[[i]]))){
x <- override.aes[[i]][key.label]
default.x <- default.aes[[names(override.aes)[[i]]]]
if(!is.na(default.x)){
x <- dplyr::coalesce(x,
rep(default.x,
times = length(key.label)))
}
names(x) <- NULL
override.aes[[i]] <- x
}
}
gdef$override.aes <- override.aes
gdef
}
# extract default aes associated with each layer in ggplot object,
# combine, & remove duplicates (keep latest where applicable)
default.aes <- sapply(layers, function(x) x$geom$default_aes)
default.aes <- purrr::flatten(default.aes)
default.aes <- default.aes[!duplicated(default.aes, fromLast = TRUE)]
# for linetype (if applicable), map from numeric to string
if(!is.null(default.aes[["linetype"]]) &
is.numeric(default.aes[["linetype"]])){
if(default.aes[["linetype"]] == 0) default.aes[["linetype"]] <- 7
default.aes[["linetype"]] <- c("solid", "dashed", "dotted",
"dotdash", "longdash", "twodash",
"blank")[default.aes[["linetype"]]]
}
gdefs <- lapply(gdefs, complete.override.aes, default.aes)
要使用此代码,请运行trace(ggplot2:::build_guides, edit = TRUE)
并将上面的代码插入第32行之后(即return(zeroGrob())
之后和gdefs <- guides_merge(gdefs)
之前)。
(或者,我们可以将代码插入上述函数的自己的版本中,并将其命名为build_guides2
,定义ggplot2:::ggplot_gtable.ggplot_built
的修改版本,而不是ggplot2:::build_guides
调用该代码,然后是ggplot2:::print.ggplot
的修改版本,它调用的是那个而不是ggplot_gtable
。但是,这种方法很快变得笨拙,占用了大量空间,并且与该主题相关在手边,所以我在这里不做详细介绍。)
结果:
# correct mapping for linetype
p + guides(colour = guide_legend(
override.aes = list(linetype = c(point = 'dotted', line = 'solid'),
shape = c(NA, 16))))
# both linetype & shape use named vectors, & specify one value each
# (otherwise linetype defaults to "solid" & shape to 19)
p + guides(colour = guide_legend(
override.aes = list(linetype = c(point = 'dotted'),
shape = c(line = 8))))