Disclaimer: I'm not particularly fond of plotting the density f(x | by) against x. In most situations I'm more interested in the probability f(by | x). So this is what the "conditional density plot" cdplot() (which has mostly been written by me) plots against x. And the trick is to compute f(by | x) = f(x | by) * f(by)/f(x). So I often feel that plotting f(x | by) against x is the wrong way around.
Concerns: Having said that, I see two potential problems. The first is easier to address than the second, I think.
- Bandwidth selection: Wouldn't it be the more natural default to use the same bandwidth for all subgroups? Otherwise the scaling of the densities might be harder to compare. In any case, this is what we decided to use for
cdplot(). Not sure what other "ridge lines" implementations are doing. (Note: If you decide to use the same bandwidth you could calldensity()directly rather than viaupdate(). - Environment handling: Both the
update(object, ...)method and youreval(str2lang(object$data), ...)will only work if the data is in the parent frame (or visible from there). (Note: Your evaluation should probably also useenvir = parent.frame()for consistency.). This may not be true and unfortunatelydensity()does not store the enclosing environment (as it would be done in aformula). That's why densities computed from auxiliary functions will not be compatible withplot2(). See the example below. Thus, the tradeoff is between the simple convenience ofplot2(density(x), by)vs. a more elaborate formula interface likeplot2(x ~ by, data = ..., type = "density")or something along those lines.
Example:
## convenience function returning a density
log_density <- function(x) density(log(x))
## example data
y <- 1:10
by <- rep(1:2, each = 5)
## set up density and try to plot
d <- log_density(y)
plot2(d, by = by) ## Error in log(x) : non-numeric argument to mathematical function
## or even worse: this would be completely misleading if you had eval(..., envir = parent.frame())
x <- by
plot2(d, by = x)