Reputation: 745
I would like to add additional geoms to a ggplot density plot, but without changing the displayed limits of the data and without having to compute the desired limits by custom code. To give an example:
set.seed(12345)
N = 1000
d = data.frame(measured = ifelse(rbernoulli(N, 0.5), rpois(N, 100), rpois(N,1)))
d$fit = dgeom(d$measured, 0.6)
ggplot(d, aes(x = measured)) + geom_density() + geom_line(aes(y = fit), color = "blue")
ggplot(d, aes(x = measured)) + geom_density() + geom_line(aes(y = fit), color = "blue") + coord_cartesian(ylim = c(0,0.025))
In the first plot, the fit curve (which fits the "measured" data quite badly) obscures the shape of the measured data:
I would like to crop the plot to include all data from the first geom, but crop the fit curve, as in the second plot:
While I can produce the second plot with coord_cartesian
, this has two disadvantages:
coord_cartesian
. I however need to combine the plot with facet_wrap(scales = "free")
The desired output would be achieved, if the second geom was not considered when computing coordinate limits - is that possible without computing the limits in custom R code?
The question R: How do I use coord_cartesian on facet_grid with free-ranging axis is related, but does not have a satisfactory answer.
Upvotes: 6
Views: 1128
Reputation: 6813
One thing you could try is to scale fit
and use geom_density(aes(y = ..scaled..)
Scaling fit
between 0
and 1
:
d$fit_scaled <- (d$fit - min(d$fit)) / (max(d$fit) - min(d$fit))
Use fit_scaled
and ..scaled..
:
ggplot(d, aes(x = measured)) +
geom_density(aes(y = ..scaled..)) +
geom_line(aes(y = fit_scaled), color = "blue")
This can be combined with facet_wrap()
:
d$group <- rep(letters[1:2], 500) #fake group
ggplot(d, aes(x = measured)) +
geom_density(aes(y = ..scaled..)) +
geom_line(aes(y = fit_scaled), color = "blue") +
facet_wrap(~ group, scales = "free")
An option that does not scale the data:
You can use the function multiplot()
from http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
library(grid)
plots <- c(list(...), plotlist)
numPlots = length(plots)
if (is.null(layout)) {
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
for (i in 1:numPlots) {
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
With this function you can combine the two plots, which makes it easier to read them:
multiplot(
ggplot(d, aes(x = measured)) +
geom_density() +
facet_wrap(~ group, scales = "free"),
ggplot(d, aes(x = measured)) +
geom_line(aes(y = fit), color = "blue") +
facet_wrap(~ group, scales = "free")
)
This will give you:
And if you want to compare groups next to each other, you can use facet_grid()
instead of facet_wrap()
with cols = 2
in multiplot()
:
multiplot(
ggplot(d, aes(x = measured)) +
geom_density() +
facet_grid(group ~ ., scales = "free"),
ggplot(d, aes(x = measured)) +
geom_line(aes(y = fit), color = "blue") +
facet_grid(group ~ ., scales = "free"),
cols = 2
)
And it looks like this:
Upvotes: 2
Reputation: 17668
You can try to calculate the max y-limit first. Then plot.
d1 <- d %>%
mutate(max_dens=round(max(density(measured)$y), 2))
ggplot(d1, aes(x=measured)) +
geom_line(aes(y=fit), color = "blue") +
geom_density() +
coord_cartesian(ylim = c(0, unique(d1$max_dens)))
Upvotes: 0