英文:
Legend that shows points vs lines in ggplot2
问题
我正在尝试在ggplot中生成一个图例,其中显示的点的名称与线的名称不同。我需要该图例与显示颜色、形状和线型的图例分开显示。
我最初有类似以下较小示例的代码,这个示例有效。基本上,我为点和线人为地设置了大小美学,然后覆盖了图例,只显示其中一个。据我所知,这是人们在绘图中添加回归线的方式。然而,在ggplot2版本3.4.0中,使用大小美学来表示线已经不推荐使用了。它仍然有效,但我认为行为稍微发生了变化。
# 以鸢尾花数据框作为示例,创建一个新的列用于水平线
data <- iris %>%
group_by(Species) %>%
mutate(AvgLength = mean(Petal.Length))
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Samples")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, size = "Average")) +
# 设置手动大小以获得正常的点和线宽
scale_size_manual(values = c("Average" = 0.5, "Samples" = 1.5)) +
# 覆盖大小图例,只显示第一个条目的线和第二个条目的点
guides(size = guide_legend(override.aes = list(linetype = c(1, 0), shape = c(NA, 16)), title = ""))
在我的实际应用中,线的名称按字母顺序排在点的名称之后(但应该在图例中首先显示),这会破坏图例,如下所示。我认为在我第一次编写代码时(在3.4.0之前),图例中来自大小比例的顺序是受到尊重的,但我不确定。
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, size = "Average")) +
scale_size_manual(values = c("Average" = 0.5, "Aa" = 1.5)) +
guides(size = guide_legend(override.aes = list(linetype = c(1, 0), shape = c(NA, 16)), title = ""))
我希望在新版本的ggplot中正确处理事情,而不使用大小美学,但我不确定如何在具有不同美学的情况下在同一个图例中同时显示点和线,因为我已经在其他方面使用了颜色。我能够获得的最接近的是将它们显示为两个单独的图例,如下所示,然后以某种方式手动更改间距。但是,如果必须将其应用于在不同位置显示图例的多种类型的绘图中,这个解决方案并不理想,而且我不确定如何手动调整大小和线宽图例之间的间距,同时保持其他图例不变。
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, linewidth = "Average")) +
scale_size_manual(values = c("Average" = 0.5, "Aa" = 1.5)) +
scale_linewidth_manual(values = c("Average" = 0.5)) +
guides(size = guide_legend(title = "", order = 1),
linewidth = guide_legend(title = "", order = 2))
我知道通常ggplot不太适用于手动设置图例,因为应该如何设置您的绘图和数据框的方式。然而,我认为在这个应用中,由于数据框的设置方式,要找到一个干净的解决方案可能会很困难。是否有人有这个问题的干净解决方案?
英文:
I am trying to generate a legend in ggplot that shows points with a different name than lines. I need that legend to show up separately from the legend that is showing color, shape, and linetype.
I originally had code similar to this smaller example, which works. Basically, I artificially set a size aesthetic for both the points and lines, then override the legend to only show one or the other. From what I can tell, this is how people have been adding regression lines to their plots. However, using the size aesthetic for lines was deprecated in ggplot2 version 3.4.0. It still works, but I think the behavior has changed slightly.
# Use iris dataframe as example and create new column for horizontal lines
data <- iris %>%
group_by(Species) %>%
mutate(AvgLength = mean(Petal.Length))
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Samples")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, size = "Average")) +
# Set manual size to get normal points and linewidths
scale_size_manual(values = c("Average" = .5, "Samples" = 1.5)) +
# Override the size legend to show only a line for the first entry and only a point for the second
guides(size = guide_legend(override.aes = list(linetype = c(1,0), shape = c(NA, 16)), title = ""))
In my actual application, the line name comes alphabetically after the points name (but should show up first in the legend), which breaks the legend, as shown here. I think the order from the size_scale was respected in the legend when I first wrote the code (pre 3.4.0), but I'm not sure.
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, size = "Average")) +
scale_size_manual(values = c("Average" = .5, "Aa" = 1.5)) +
guides(size = guide_legend(override.aes = list(linetype = c(1,0), shape = c(NA, 16)), title = ""))
Plot with legend messed up by name order
I would like to do things right with the new version of ggplot, and not use the size aesthetic, but I'm not sure how to have both points and lines on the same legend with a different aesthetic since I'm already using color for something else. The closest I can get is showing them as two separate legends like below, then somehow manually changing the spacing. However, this solution isn't great if you have to apply it to multiple types of plots where the legends are being shown in different places, and I'm not sure how to manually fix the spacing between the size and linewidth legends, while leaving the other legend alone.
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, linewidth = "Average")) +
scale_size_manual(values = c("Average" = .5, "Aa" = 1.5)) +
scale_linewidth_manual(values = c("Average" = .5)) +
guides(size = guide_legend(title = "", order = 1),
linewidth = guide_legend(title = "", order = 2))
Plot that doesn't use the size aesthetic for lines, but the legends look weird
I'm aware that ggplot generally doesn't play well with manual legend specification because of how you should be setting up your plots and dataframes. However, I think in this application, it would be hard to set up the dataframe differently. Does anyone have a clean solution for this problem?
答案1
得分: 3
现在我们需要处理两种美学,我们必须确保图例通过“复制”比例尺的规范进行合并,即在两个比例尺中的两个类别分别设置一个值,并且在每个图例中都将limits
设置为实际包括每个类别。通过这样做,size
和lindwidth
的图例将被合并,通过limits
,您还可以设置图例中类别的顺序,最后,我们可以使用override.aes
来完善图例,即去掉“线”类别的shape
和“点”类别的linetype
。
library(ggplot2)
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, linewidth = "Average")) +
scale_size_manual(values = c("Average" = .5, "Aa" = 1.5), limits = c("Average", "Aa")) +
scale_linewidth_manual(values = c("Average" = .5, "Aa" = 1.5), limits = c("Average", "Aa")) +
labs(size = NULL, linewidth = NULL) +
guides(
size = guide_legend(
override.aes = list(linetype = c("solid", "blank"), shape = c(NA, 16))
)
)
英文:
As we now have to deal with two aesthetics we have to ensure that the legends get merged by "duplicating" the specification of the scale, i.e. set a value for both categories in both scales and also set the limits
to actually include both categories in each legend. Doing so the size
and lindwidth
legends get merged, via the limits you could also set the order of the categories in the legend and finally we can use override.aes
to polish the legend, i.e. get rid of the shape
for the "line" category and the linetype
for the "point" category.
library(ggplot2)
ggplot(data) +
geom_point(aes(x = Petal.Width, y = Petal.Length, color = Species, shape = Species, size = "Aa")) +
geom_hline(aes(yintercept = AvgLength, color = Species, linetype = Species, linewidth = "Average")) +
scale_size_manual(values = c("Average" = .5, "Aa" = 1.5), limits = c("Average", "Aa")) +
scale_linewidth_manual(values = c("Average" = .5, "Aa" = 1.5), limits = c("Average", "Aa")) +
labs(size = NULL, linewidth = NULL) +
guides(
size = guide_legend(
override.aes = list(linetype = c("solid", "blank"), shape = c(NA, 16))
)
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论