在ggplot2中绘制多个密度:如何添加具有不同比例的额外变量?

时间:2018-10-24 15:45:13

标签: r ggplot2 scaling

我将尝试使用一个简化的示例来描述我的问题。我正在尝试用ggplot2绘制几种密度,例如:

library(reshape2)
library(ggplot2)

set.seed(1)
x <- replicate(5, rnorm(100)) 
colnames(x) <- paste0("x", 1:5)

ggplot(melt(x), aes(value, color = Var2)) + geom_density()

density plot

这按预期工作。现在,我想添加一个比例非常不同的新变量:

z <- cbind(x, y = rnorm(100) * 50)
ggplot(melt(z), aes(value, color = Var2)) + geom_density()

density plot with exrta variable

这将产生预期的图形,但不幸的是,我不想制作该图形。我想保留两个轴的原始比例,以便仍可以看到前五个密度之间的差异,并且新变量的密度将显示为平坦。

是否可以通过简单的方式执行此操作?就像告诉ggplot覆盖新密度而不更改缩放比例一样?还是让ggplot在计算轴的极限时忽略变量?

我可以考虑手动解决方案,该解决方案将首先保存轴的限制,然后在使用新变量创建图形时指定它们。但这可能不是最优雅的解决方案,并且可能需要大量额外的代码。如果可能的话,我宁愿避免这种解决方案(特别是因为我的情况实际上要复杂得多,并且包含多个带有facet_wrap()的图)

任何建议或提示都将受到欢迎。提前非常感谢!

PS:为了给您提供更多背景信息,我试图将几个后验分布与它们的先验分布(平坦的)作图。我只能从先验中提取数据,而不能从其确切的密度函数中提取数据;否则,我只会用stat_function()覆盖先验数据。

2 个答案:

答案 0 :(得分:2)

这是更改第二个Y轴的一种很酷的方法:

首先,让我们以更通用的格式重新创建图表。我将创建一个数据框X(注意:它是大写的)

X <- data.frame(x)

g <- ggplot()
g <- g + geom_density(data = X, aes(x1, colour= "X1"))
g <- g + geom_density(data = X, aes(x2, colour= "x2"))
g <- g + geom_density(data = X, aes(x3, colour= "x3"))
g <- g + geom_density(data = X, aes(x3, colour= "x4"))

g

哪个会生成一张密度图

enter image description here

好的,很酷,现在让我们在您提到的z中重新创建问题

Z <- data.frame(z)

g <- ggplot()
g <- g + geom_density(data = Z, aes(x1, colour= "X1"))
g <- g + geom_density(data = Z, aes(x2, colour= "x2"))
g <- g + geom_density(data = Z, aes(x3, colour= "x3"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(y, colour= "y"))
g

哪个给

enter image description here

好的,现在我们可以根据第二个轴的子集

z <- cbind(x, y = rnorm(100) * 50)

即50岁,但您可以按自己的意愿做任何事情。

Z <- data.frame(z)

g <- ggplot()
g <- g + geom_density(data = Z, aes(x1, colour= "x1"))
g <- g + geom_density(data = Z, aes(x2, colour= "x2"))
g <- g + geom_density(data = Z, aes(x3, colour= "x3"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(y/50, colour= "y"))
g <- g + scale_y_continuous(sec.axis = sec_axis(~.*50, name= "Y Second Axis"))
g

哪个可以给我们所需的双y轴!

enter image description here

您也可以做一个x轴的双轴操作。

g <- ggplot()
g <- g + geom_density(data = Z, aes(x1, colour= "x1"))
g <- g + geom_density(data = Z, aes(x2, colour= "x2"))
g <- g + geom_density(data = Z, aes(x3, colour= "x3"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(y/50, colour= "y"))
g <- g + scale_x_continuous(sec.axis = sec_axis(~.*50, name= "x Second Axis"))
g

enter image description here

希望有帮助!

编辑:

经过澄清,看起来想要的结果只是保持原始的x轴限制,而增加新的更大的密度。我们既可以使用我的样式,也可以使用您使用的融合格式来做到这一点。

g <- ggplot()
g <- g + geom_density(data = Z, aes(x1, colour= "x1"))
g <- g + geom_density(data = Z, aes(x2, colour= "x2"))
g <- g + geom_density(data = Z, aes(x3, colour= "x3"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(y, colour= "y"))
g <- g + xlim(range(-4:4))
g

OR

ggplot(melt(z), aes(value, color = Var2)) + geom_density() + xlim(range(-4, 4)

enter image description here

编辑2:这为我们提供了一个具有右轴的图,但它从密度图中删除了值(如Remek所指出的,以及Jon Spring的注释中的解决方案)。我们可以得到使密度值保持不变的图吗?是!我们需要coord_cartesian(),这还将使我们能够进行“放大”,而不是散发超出我们限制范围的值。

以下是两种样式的解决方案:

g <- ggplot()
g <- g + geom_density(data = Z, aes(x1, colour= "X1"))
g <- g + geom_density(data = Z, aes(x2, colour= "x2"))
g <- g + geom_density(data = Z, aes(x3, colour= "x3"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(x3, colour= "x4"))
g <- g + geom_density(data = Z, aes(y, colour= "y"))
g <- g + coord_cartesian(xlim=c(-4, 4))
g

ggplot(melt(z), aes(value, color = Var2)) + geom_density() + coord_cartesian(xlim=c(-4, 4))

两者都会产生预期的效果! enter image description here

答案 1 :(得分:1)

如何使用预合并的数据指定范围?

ggplot(melt(z), aes(value, color = Var2)) + 
  geom_density() +
  coord_cartesian(xlim = c(min(melt(x)$value),
                           max(melt(x)$value)))

或者,我们可以使用相同的melt(z),但使用新变量撤消数据:

ggplot(melt(z), aes(value, color = Var2)) + 
  geom_density() +
  coord_cartesian(xlim = c(min(subset(melt(z), Var2 != "y")$value),
                           max(subset(melt(z), Var2 != "y")$value)))

enter image description here