I am using do.call in building a function. but I met a problem like this:
z<-sample(1:3, 100, T)
y<-rnorm(100)
plot.list <- c(list(x=z,y=y))
do.call(plot, plot.list)
why the plot has included the y values?
Thanks!
This happens because plot.default attempts to create sensible labels for x and y if xlab and ylab are NULL
Using
deparse(substitute(y))
However, using do.call, the list is created, and the variable known as y is replaced by its contents thus this approach renders the label with the entire variable
foo <- function(y) deparse(substitute(y))
> do.call(foo, list(y=y))
[1] "c(1.19006018249756, -0.50627079218304, -0.103312348822805, 0.395028889714542, "
[2] "1.25258077222837, 2.63766225444435, 0.260296813253391, 0.280839960496168, "
[3] "-1.47428483557887, -0.585934600873922, 0.879979238185618, -0.0871689899965067, "
..... <truncated>
Setting xlab and ylab explicitly is the way to go.
do.call(plot, list(x=z,y=y, xlab = "x",ylab="y"))
To use do.call you'd need to pass z and y as names so they don't get evaluated ahead of time.
do.call("plot", list(x=as.name("z"), y=as.name("y")))
But the code sure feels like it would be clearer if you set xlab and ylab explicitly as #mnel recommends.
Related
I'm trying to make the legend of this plot pretty, so I need there the be an actual superscript, which is why I am using the pretty10exp() function from the sfsmisc library. It works when I use the c() function.
However, I am also trying to keep the string and the scientific notation number on the same line. The legend() is broken into two lines, which I think is due to c(). I thought I could use paste(), but for some reason the output is now incorrect.
plot(1:12)
pVal <- 4
legend("topright", legend = c("P value:", sfsmisc::pretty10exp(pVal)), cex = 1.5)
legend("topright", legend = paste("P value:", sfsmisc::pretty10exp(pVal)), cex = 1.5)
pVal being an arbitrary number represented in scientific notation. The second line results in output like this: "P value: (significand) %*% 10^-4". The first line also doesn't give me what I want. How can I fix this problem?
pretty10exp returns an expression which allows it to use the ?plotmath features for making nice looking numbers. When working with expressions, you can't just paste values in like strings. You need to manipulate them with a special set of functions. One such function is substitute. You can do
plot(1:12)
pVal <- 4
legend("topright", cex = 1.5,
legend = substitute("P value: "*x, list(x=sfsmisc::pretty10exp(pVal)[[1]])) )
We use substitute() to take the value contained in the expression from pretty10exp and prefix it with the label you want. (We use * to concatenate rather than paste() since plotmath allows it)
This is what I would do:
fun <- function(text, pVal) {
y <- floor(log10(pVal))
x <- pVal / 10^y
bquote(.(text)*":" ~ .(x) %.% 10 ^ .(y))
}
plot.new()
text(0.5,0.7,fun("P value", 0.4))
text(0.5, 0.3, fun("P value", signif(1/pi, 1)))
No package is needed.
My question is regarding the following code:
myfunc <- function(v1) {
deparse(substitute(v1))
}
myfunc(foo)
[1] "foo"
I typed in ?deparse and ?substitute into R and obtained the following:
deparse = Turn unevaluated expressions into character strings.
and
substitute = returns the parse tree for the (unevaluated) expression expr,
substituting any variables bound in env.
I don't seem to really understand this language. Would someone be able to simplify the technical aspect of these descriptions so that I could begin to appreciate how these two functions work together to allow us to do something cool like access the variable name of an object?
I struggle(d) with this too. The myplot() example from ?substitute is helpful. There, they define:
myplot <- function(x, y)
plot(x, y, xlab = deparse(substitute(x)),
ylab = deparse(substitute(y)))
calling
myplot(x=1:10, y = rnorm(10))
gives
whereas the alternative
x = 1:10
y = rnorm(10)
plot(x, y, xlab = x, ylab = y)
gives
Hopefully this shows what deparse(substitute()) is used for. In the plot version, the xlab and ylab arguments are the outputs of whatever was used to generate x and y. myplot knows to pass "character string versions of the actual arguments to the function" for xlab and ylab. (quotes from ?substitute)
I'm experiencing a strange error when using the function bquote for axis labeling. The error is only occurring when applying the label (the greek symbol "mu") to the y-axis:
df <- data.frame(x=1:10, y=1:10)
plot(y~x, df, t="l", xlab=bquote(.("Size [")*mu*m*.("]"))) # works
plot(y~x, df, t="l", ylab=bquote(.("Size [")*mu*m*.("]"))) # doesn't work
# Error in plot.default(1:10, 1:10, ylab = "Size [" * mu * m * "]", xlab = quote("x"), : object 'mu' not found
I know I could use expression as an alternative in this case, but I'm trying to understand the error.
This is due to subtleties of evaluation rules and the specifics of the implementation of this plotting function.
Note that this does not occur when not using the formula interface
plot(df$x,df$y, type="l", ylab=bquote(.("Size [")*mu*m*.("]"))) #works as you expect
To see what is happening, examine the source
getAnywhere("plot.formula")
and you'll see the equivalent of this simplified example
plotex<-function(x,y,type="l",ylab,...) {
m=match.call(expand.dots = FALSE)
dots <- lapply(m$..., eval)
dots$xlab <- enquote(dots$xlab)
do.call(plot,c(list(x=x,y=y,type=type,ylab=ylab),dots))
}
The xlab argument is in ... and protected against evaluation with an explicit enquote. The ylab is a named parameter and its evaluation is forced by inclusion in the list provided to do.call.
R's plotting is great for data exploration, as it often has very intelligent defaults. For example, when plotting with a formula the labels for the plot axes are derived from the formula. In other words, the following two calls produce the same output:
plot(x~y)
plot(x~y, xlab="x", ylab="y")
Is there any way to get a similar "intelligent auto-title"?
For example, I would like to call
plot(x~y, main=<something>)
And produce the same output as calling
plot(x~y, main="plot(x~y)")
Where the <something> inserts the call used using some kind of introspection.
Is there a facility for doing this in R, either through some standard mechanism or an external package?
edit: One suggestion was to specify the formula as a string, and supply that as the argument to a formula() call as well as main. This is useful, but it misses out on parameters than can affect a plot, such as using subsets of data. To elaborate, I'd like
x<-c(1,2,3)
y<-c(1,2,3)
z<-c(0,0,1)
d<-data.frame(x,y,z)
plot(x~y, subset(d, z==0), main=<something>)
To have the same effect as
plot(x~y, subset(d, z==0), main="plot(x~y, subset(d, z==0))")
I don't think this can be done without writing a thin wrapper around plot(). The reason is that R evaluates "supplied arguments" in the evaluation frame of the calling function, in which there's no way to access the current function call (see here for details).
By contrast, "default arguments" are evaluated in the evaluation frame of the function, from where introspection is possible. Here are a couple of possibilities (differing just in whether you want "myPlot" or "plot" to appear in the title:
## Function that reports actual call to itself (i.e. 'myPlot()') in plot title.
myPlot <- function(x,...) {
cl <- deparse(sys.call())
plot(x, main=cl, ...)
}
## Function that 'lies' and says that plot() (rather than myPlot2()) called it.
myPlot2 <- function(x,...) {
cl <- sys.call()
cl[[1]] <- as.symbol("plot")
cl <- deparse(cl)
plot(x, main=cl, ...)
}
## Try them out
x <- 1:10
y <- 1:10
par(mfcol=c(1,2))
myPlot(x,y)
myPlot2(y~x)
Here's a more general solution:
plotCaller <- function(plotCall, ...) {
main <- deparse(substitute(plotCall))
main <- paste(main, collapse="\n")
eval(as.call(c(as.list(substitute(plotCall)), main=main, ...)))
}
## Try _it_ out
plotCaller(hist(rnorm(9999), breaks=100, col="red"))
library(lattice)
plotCaller(xyplot(rnorm(10)~1:10, pch=16))
## plotCaller will also pass through additional arguments, so they take effect
## without being displayed
plotCaller(xyplot(rnorm(10)~1:10), pch=16)
deparse will attempt to break deparsed lines if they get too long (the default is 60 characters). When it does this, it returns a vector of strings. plot methods assume that 'main' is a single string, so the line main <- paste(main, collapse='\n') deals with this by concatenating all the strings returned by deparse, joining them using \n.
Here is an example of where this is necessary:
plotCaller(hist(rnorm(9999), breaks=100, col="red", xlab="a rather long label",
ylab="yet another long label"))
Of course there is! Here ya go:
x = rnorm(100)
y = sin(x)
something = "y~x"
plot(formula(something),main=something)
You might be thinking of the functionality of match.call. However that only really works when called inside of a function, not passed in as an argument. You could create your wrapper function that would call match.call then pass everything else on to plot or use substitute to capture the call then modify it with the call before evaluating:
x <- runif(25)
y <- rnorm(25, x, .1)
myplot <- function(...) {
tmp <- match.call()
plot(..., main=deparse(tmp))
}
myplot( y~x )
myplot( y~x, xlim=c(-.25,1.25) )
## or
myplot2 <- function(FUN) {
tmp1 <- substitute(FUN)
tmp2 <- deparse(tmp1)
tmp3 <- as.list(tmp1)
tmp4 <- as.call(c(tmp3, main=tmp2))
eval(tmp4)
}
myplot2( plot(y~x) )
myplot2( plot(y~x, xlim=c(-.25,1.25) ) )
I refer to my previous question, and want to know more about characteristics of factor in R.
Let say I have a dataset like this:
temp <- data.frame(x=letters[1:5],
y=1:5)
plot(temp)
I can change the label of x easily to another character:
levels(temp[,"x"]) <- letters[6:10]
But if I want to change it into some expression
levels(temp[,"x"]) <- c(expression(x>=1),
expression(x>=2),
expression(x>=3),
expression(x>=4),
expression(x>=5))
The >= sign will not change accordingly in the plot. And I found that class(levels(temp[,"x"])) is character, but expression(x>=1) is not.
If I want to add some mathematical annotation as factor, what can I do?
I do not see any levels arguments in ggplot and assigning levels to a character vector should not work. If you are trying to assign expression vectors you should just use one expression call and separate the arguments by commas and you should use the labels argument in a scale function:
p <- qplot(1:10, 10:1)+ scale_y_continuous( breaks= 1:10,
labels=expression( x>= 1, x>=2, x>=3, x>= 4,x>=5,
x>= 6, x>=7, x>= 8,x>=9, x>= 10) )
p
I would just leave them as character strings
levels(temp[,"x"]) <- paste("x>=", 1:5, sep="")
If you then want to include them as axis labels, you could do something like the following to convert them to expressions:
lev.as.expr <- parse(text=levels(temp[,"x"]))
For your plot, you could then do:
plot(temp, xaxt="n")
axis(side=1, at=1:5, labels=lev.as.expr)
Expression is used to generate text for plots and output but can't be the variable names per se. You'd have to use the axis() command to generate your own labels. Because it can evaluate expressions you could try...
plot(temp, xaxt = 'n')
s <- paste('x>', 1:5, sep = '=')
axis(1, 1:5, parse(text = s))