One of the annoyances in R is dealing with functions that don't evaluate one or more arguments that you pass, or who otherwise use the name of the variable passed. The problem appears when you try to write abstractly.
e.g.
However, it's hard to do something more abstract, e.g.
I am not happy with this, but there is NO OTHER WAY. I say this confidently because 'with' appears to completely discard the value of the variable passed, while only using its name, i.e. something like:
Having to call eval is the price we pay for the convenience of not using quotes.
And, guess what, I take the deal! Yesterday, I wrote 'violinPlot', which is like a 'boxplot' but with kernel density estimates instead of quantiles. The two basic arguments to violinPlot are 'datasets' and 'property': for each dataset, it extracts the property and plots a violin.

My code starts with:
You can see above that I also wanted to pass 'property' without quotes. Having essentially reimplemented 'with', I am in a position to modify it so that the syntax becomes
But here's what I might do: instead of
More pretty graphics:( Read more... )
e.g.
with(data, ZQ/Total.Z)
will compute data$ZQ / data$Total.Z
. What 'with' is doing is parsing that expression, figuring out which variable tokens are already present in the current environment, and putting "data$" in the front of the rest. Yesterday, in my naivety, I implemented just that (28 easy-to-read lines of R).However, it's hard to do something more abstract, e.g.
with(data, property)
will try to get a property named "property". To circumvent this, one can make a call to eval
:withExpr <- jPaste("with(x,",property,")") eval(parse(text=withExpr))
I am not happy with this, but there is NO OTHER WAY. I say this confidently because 'with' appears to completely discard the value of the variable passed, while only using its name, i.e. something like:
property <- deparse(substitute(property))
Having to call eval is the price we pay for the convenience of not using quotes.
And, guess what, I take the deal! Yesterday, I wrote 'violinPlot', which is like a 'boxplot' but with kernel density estimates instead of quantiles. The two basic arguments to violinPlot are 'datasets' and 'property': for each dataset, it extracts the property and plots a violin.
l <- list(mon, tue, wed, thu, fri, sat, sun) violinPlot(l, ZQ/Total.Z, col=c(rep("#AAAAFF",5), rep("orange", 2)), horizontal=FALSE)

My code starts with:
violinPlot <- function(datasets, property, labels=c("M", "T", "W", "R", "F", "Sa", "Su"), horizontal=TRUE, colors=NA){ property <- deparse(substitute(property)) colors <- rep(colors, length(datasets)/length(colors)+1) densities <- lapply(datasets, function(x) density(with2(x,property))) ... } with2 <- function(data, expr, ...) with(data, eval(parse(text=expr)), ...)
You can see above that I also wanted to pass 'property' without quotes. Having essentially reimplemented 'with', I am in a position to modify it so that the syntax becomes
with(data, "ZQ/Total.Z")
, and spare myself the eval next time... but I don't wanna.But here's what I might do: instead of
with(data,expr)
, make it with(data, exprLiteral=NULL, exprToEvaluate=NULL)
, and you would only pass one of these expr arguments. The difference is that 'exprToEvaluate' gets evaluated into a string (so it better be a string!); whereas 'exprLiteral' gets turned into a string directly, and corresponds to the current syntax of 'with'... and since 'exprLiteral' comes first (in the second position of the argument list), current calls to 'with' would continue working. Yay, backward-compatibility!More pretty graphics:( Read more... )