【问题标题】:How to have two different size legends in one ggplot?如何在一个ggplot中有两个不同大小的图例?
【发布时间】:2017-10-11 18:58:03
【问题描述】:

想象一下我绘制了这个玩具数据:

lev <- c("A", "B", "C", "D")

nodes <- data.frame(ord=c(1,1,1,2,2,3,3,4), brand=
  factor(c("A", "B", "C","B", "C","D", "B","D"), levels=lev), 
  thick=c(16,9,9,16,4,1,4,1))

edge <-  data.frame(ord1=c(1,1,2,3), brand1=factor(c("C","A","B","B"), 
  levels=lev),ord2=c(2,2,3,4), brand2=c("C","B","B","D"),
  N1=c(2,1,2,1), N2=c(5,5,2,1))

ggplot() +
  geom_point(data = nodes,
    aes(x = ord, y = brand, size = sqrt(thick)),
    color = "black", shape = 16, show.legend = T) + 
  scale_x_continuous(limits=c(1, 4), breaks=seq(0,4,1),
    minor_breaks = NULL) + 
  geom_segment(data = edge,
    aes(x = ord1, y = brand1, xend = ord2, yend = brand2), 
    color = "blue", size = edge$N2/edge$N1) +
  ylim(lev) +
  theme_bw()

正如预期的那样,我得到了这个情节。

我想添加另一个与线段宽度和 N2/N1 相关的图例(在节点下方)。

PD: 根据您的一些建议...

ggplot() + 
  geom_segment(data = edge,
    aes(x = ord1, y = brand1, xend = ord2, yend = brand2, size = N2/N1), 
    color = "blue", show.legend = T) +
  geom_point(data = nodes,
    aes(x = ord, y = brand, size = thick),
    color = "black", shape = 16, show.legend = T) + 
  scale_x_continuous(limits = c(1, 4), breaks = 0:4,
    minor_breaks = NULL) +
  scale_size_continuous(trans = "sqrt", breaks = c(1,4,9,16))  + 
  ylim(lev) +  theme_bw()

我得到了图例,但它与另一个重叠。

我可以尝试使用颜色而不是宽度:

ggplot()+ geom_segment(data=edge, aes(x=ord1, y=brand1, xend=ord2, yend=brand2, alpha=N2/N1) , size=1 ,show.legend = T) +
  geom_point(data=nodes,aes(x=ord, y=brand, size=thick), color="black", shape=16,show.legend = T) + 
  scale_x_continuous(limits=c(1, 4), breaks=seq(0,4,1), minor_breaks = NULL) + scale_size_continuous(trans = "sqrt", breaks=c(1,4,9,16))  + 
   ylim(lev) + theme_bw()

或变化的阿尔法

虽然我更喜欢原始的宽度方法,因为在我的真实情节中,我会有很多线交叉。

PD:任何具有 lattice 的解决方案或任何能够导出为 svg 或矢量 pdf 的替代方案?

PD2:我发现了另一个问题,细点没有正确缩放,有时无法强制 ggplot 显示正确的图例: How can I force ggplot to show more levels on the legend?

【问题讨论】:

  • 不要对数据的大小进行平方根,而是按比例计算:scale_size_continuous(trans = "sqrt")。这将解决您的标签问题(第一个项目符号)。为线条粗细添加单独的图例会更加困难......当他们关注单个问题而不是很多东西时,问题会更好。
  • 1) 2) 要获得图例,您需要使用 aes 来映射宽度 3) 最后绘制点,以便它们位于段的顶部。
  • 1) Gregor 的答案的替代方法是使用scale_size_area(),它将数据映射到点的区域而不是默认情况下的直径,2) 段厚度的关键将需要在非常至少要使用aes() 来映射段的大小 3) 最后绘制点,使它们位于段的顶部。我怀疑你的一些问题一定已经得到了回答。第一个和第三个是微不足道的,关于段大小的,可能对其他人有用。检查答案是否存在,如果不存在,请为它写一个新问题,并带有描述性标题。
  • @Gregor 如果有多个变量,我在哪里指定要转换的变量?我如何指定这些数字的限制?因为我试过了,只能看到4到16,我想要1到16
  • @PedroAphalo 我更喜欢转换它,因为我也可以使用对数或平方。

标签: r ggplot2 lattice


【解决方案1】:

使用我整理的高度实验包:

library(ggplot2) # >= 2.3.0
library(dplyr)
library(relayer) # install.github("clauswilke/relayer")

# make aesthetics aware size scale, also use better scaling
scale_size_c <- function(name = waiver(), breaks = waiver(), labels = waiver(), 
          limits = NULL, range = c(1, 6), trans = "identity", guide = "legend", aesthetics = "size") 
{
  continuous_scale(aesthetics, "area", scales::rescale_pal(range), name = name, 
                   breaks = breaks, labels = labels, limits = limits, trans = trans, 
                   guide = guide)
}


lev <- c("A", "B", "C", "D")

nodes <- data.frame(
  ord = c(1,1,1,2,2,3,3,4),
  brand = factor(c("A", "B", "C", "B", "C", "D", "B", "D"), levels=lev), 
  thick = c(16, 9, 9, 16, 4, 1, 4, 1)
)

edge <- data.frame(
  ord1 = c(1, 1, 2, 3),
  brand1 = factor(c("C", "A", "B", "B"), levels = lev),
  ord2 = c(2, 2, 3, 4),
  brand2 = c("C", "B", "B", "D"),
  N1 = c(2, 1, 2, 1),
  N2 = c(5, 5, 2, 1)
)

ggplot() + 
  (geom_segment(
    data = edge,
    aes(x = ord1, y = brand1, xend = ord2, yend = brand2, edge_size = N2/N1), 
    color = "blue"
  ) %>% rename_geom_aes(new_aes = c("size" = "edge_size"))) +
  (geom_point(
    data = nodes,
    aes(x = ord, y = brand, node_size = thick),
    color = "black", shape = 16
  ) %>% rename_geom_aes(new_aes = c("size" = "node_size"))) + 
  scale_x_continuous(
    limits = c(1, 4),
    breaks = 0:4,
    minor_breaks = NULL
  ) +
  scale_size_c(
    aesthetics = "edge_size",
    breaks = 1:5,
    name = "edge size",
    guide = guide_legend(keywidth = grid::unit(1.2, "cm"))
  )  + 
  scale_size_c(
    aesthetics = "node_size",
    trans = "sqrt",
    breaks = c(1, 4, 9, 16),
    name = "node size"
  )  + 
  ylim(lev) + theme_bw()

reprex package (v0.2.0) 于 2018 年 5 月 16 日创建。

【讨论】:

  • 这很棒。我现在不需要它,但我会测试它。谢谢。
  • 感谢您的选择。我几乎得到了我需要的东西,唯一的问题是我失去了 geom_segment() 中的箭头
【解决方案2】:

有时 ggplot 可能不是这项工作的最佳工具。熟悉这些实例的其他一些绘图选项是值得的,R 的基本图形系统相当通用。

您可以在基本图形中执行以下操作:

lev <- c("A", "B", "C", "D")    
nodes <- data.frame(ord=c(1,1,1,2,2,3,3,4), brand=
    factor(c("A", "B", "C","B", "C","D", "B","D"), levels=lev), 
  thick=c(16,9,9,16,4,1,4,1))   
edge <-  data.frame(ord1=c(1,1,2,3), 
  brand1=factor(c("C","A","B","B"), levels=lev),
  ord2=c(2,2,3,4), 
  brand2=factor(c("C","B","B","D"), levels=lev),
  N1=c(2,1,2,1), N2=c(5,5,2,1))

png(width = 6, height = 4, units = 'in',res=300)
par(xpd=FALSE, mar = c(5, 4, 4, 15) + 0.1)
plot(NULL, NULL,  xaxt = "n", yaxt = "n",
  xlim = c(1,4), ylim = c(1,4), 
  xlab = 'ord', ylab = 'brand')
axis(side = 1, at = 1:4)
axis(side = 2, at = 1:4, labels = LETTERS[1:4])
grid()
par(xpd=TRUE)
segments(edge$ord1, as.integer(edge$brand1), 
  edge$ord2, as.integer(edge$brand2), 
  lwd = 4*edge$N2/edge$N1,
  col='blue')

points(nodes$ord, nodes$brand, cex=sqrt(nodes$thick), pch=16)
legend(4.5,4,
  legend = as.character(c(1,2,4,8,16)), 
  pch = 16, 
  cex = 1.5,
  pt.cex = sqrt(c(1,2,4,8,16)))
legend(6,4,
  legend = as.character(1:5), 
  lwd = 4*(1:5), 
  col = 'blue',
  cex = 1.5)
dev.off()

【讨论】:

  • @skan 我更改了您对edge 的定义,因为您忘记将edge$ord2 作为OP 中的一个因素。所以 edge2 得到与 edge1 不同的级别。尝试运行我的整个代码,包括变量定义
  • PD:任何带有格子的解决方案或任何能够导出为 svg 或矢量 pdf 的替代方案?
  • 此方法适用于矢量图形格式。只需使用svg()pdf() 代替png() 命令
  • 你怎么知道在 cex 和 pt.cex 上写什么?我想使用 NP=c(0.375 0.250 0.125 0.125 0.125) 的点。然后我将它们绘制为点(nodosord,因子(nodosord,因子(nodosord,因子(nodosevent),cex = 10 *(nodos $ NP),pch = 16))。我应该用什么来做图例?我试过了legend(4.5,4, legend = as.character(c(5,10,20,40)), pch = 16, cex = 1, pt.cex = (c(5,10,20,40))) 但是图例点的宽度与绘图点的宽度不匹配。
  • @skan 很难按照您在评论格式中提出的要求。基本上图中的cex 应该对应于图例中pt.cex 的值。与 1.25 到 3.75 的点相比,您的 pt.cex 向量似乎太大(从 5 到 40)。
猜你喜欢
  • 2019-04-10
  • 2021-10-03
  • 2013-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-03
  • 2012-12-15
  • 2011-10-18
相关资源
最近更新 更多