Question

I'm encountering a problem when trying to make a density plot with ggplot. The data look a bit like in the example here.

require(ggplot2)
require(plyr)
mms <- data.frame(deliciousness = rnorm(100),
                  type=sample(as.factor(c("peanut", "regular")), 100, replace=TRUE),
                  color=sample(as.factor(c("red", "green", "yellow", "brown")), 100, replace=TRUE))


mms.cor <- ddply(.data=mms, .(type, color), summarize, n=paste("n =", length(deliciousness)))

plot <- ggplot(data=mms, aes(x=deliciousness)) + geom_density() + facet_grid(type ~ color) + geom_text(data=mms.cor, aes(x=1.8, y=5, label=n), colour="black", inherit.aes=FALSE, parse=FALSE)

Labelling each facet with the labels work quite well unless the scales for each facet vary. Does anyone have an idea how I could achieve putting the labels at the same location when the scales per facet differ?

Best, daniel

Was it helpful?

Solution

Something like this?

plot <- ggplot(data=mms, aes(x=deliciousness)) +
  geom_density(aes(y=..scaled..)) + facet_grid(type ~ color) +
  geom_text(data=mms.cor, aes(x=1.2, y=1.2, label=n), colour="black")
plot

There is a way to get the limits set internally by ggplot with scales="free", but it involves hacking the grob (graphics object). Since you seem to want the density plots to have equal height (???), you can do that with aes(y=..scaled...). Then setting the location for the labels is straightforward.

EDIT (Response to OP's comment)

This is what I meant by hacking the grob. Note that this takes advantage of the internal structure used by gglpot. The problem is that this could change at any time with a new version (and in fact it is already different from older versions). So there is no guarantee this code will work in the future.

plot <- ggplot(data=mms, aes(x=deliciousness)) +
  geom_density() + 
  facet_grid(type ~ color, scales="free")
panels <- ggplot_build(plot)[["panel"]]
limits <- do.call(rbind,lapply(panels$ranges,
                               function(range)c(range$x.range,range$y.range)))
colnames(limits) <- c("x.lo","x.hi","y.lo","y.hi")
mms.cor <- cbind(mms.cor,limits)
plot + 
  geom_text(data=mms.cor, aes(x=x.hi, y=y.hi, label=n), hjust=1,colour="black")

The basic idea is to generate plot without the text, then build the graphics object using ggplot_build(plot). From this we can extract the x- and y-limits, and bind those to the labels in your mms.cor data frame. Now render the plot with the text, using these limits.

Note that the plots are different from my earlier answer because you did not use set.seed(...) in your code to generate the dataset (and I forgot to add it...).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top