简体   繁体   中英

Plotting multiple densities in ggplot2: How to add an extra variable with a different scale?

I will try to describe my problem using a simplified example. I am trying to plot several densities with ggplot2, something like:

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()

密度图

This works as expected. Now, I would like to add a new variable with a very different scale:

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

密度图与exrta变量

This produces the expected graph, but not the one I would like to make unfortunately. I would like to keep the original scales of both axes, so that the differences between the first five densities would still be visible, and the density of the new variable would appear as flat.

Is it possible to do this in a simple way? Like telling ggplot to overlay the new density without changing the scaling? Or telling ggplot to ignore a variable when computing the limits of the axes?

I could consider a manual solution that would save the limits of the axes in a first step, and then specify them when the graph is made with the new variable. But that might not be the most elegant solution and might require a lot of extra code. I would prefer avoiding this kind of solution if possible (especially because my case is actually much more complex and implies multiple graphs with facet_wrap() )

Any suggestions or hints would be most welcome. Many thanks in advance!

PS: To give you more background information, I am trying to plot several posterior distributions against their prior distribution (the flat one). I only have draws from the prior, not its exact density function - otherwise I would just have overlaid this prior with stat_function() .

Here's a cool way to change get a second Y axis:

First let's recreate your chart in a more generalized format. I'm going to create a data frame X (Note: it's Capitalized)

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

Which produces a the density chart

在此输入图像描述

OK, cool now let's recreate the issue in z you mentioned

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

Which gives

在此输入图像描述

OK, now here's we can subset a second axis by the difference given in

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

Namely, 50. but you can really make it whatever proportion you would like.

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

Which gives us the desired double y axis!

在此输入图像描述

You can also do a double x axis as well.

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

在此输入图像描述

Hope that helps!

Edit:

After clarification it looks like the desired result would simply to keep the original x-axis limits but to add the new larger density. We can do that both in my style and with the melt format you were using.

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)

在此输入图像描述

Edit 2: This gives us a plot with the right axis but it removes values from the density plot (as pointed out by Remek, and a solution in the comments which was correct from Jon Spring). Can we get a plot that leaves the density values unchanged? Yes! we need coord_cartesian() this will also us to preform a 'zoom in' rather than exude values outside of our limits.

Here's the solution in both styles:

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))

both of which will produce the desired results! 在此输入图像描述

How about using the pre-combined data to specify range?

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

or, we could use the same melt(z) but back out the data with the new variable:

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)))

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM