Passing a list of arguments to plot in R - r

I would like to use the same arguments for several calls to plot.
I tried to use a list (which can serve as a dictionary) :
a <- list(type="o",ylab="")
plot(x,y, a)
But it does not work :
Error in plot.xy(xy, type, ...) : invalid plot type
Any suggestion ?

Extending #baptiste's answer, you can use do.call like this:
x <- 1:10 # some data
y <- 10:1
do.call("plot", list(x,y, type="o", ylab=""))
Or setting the arguments in a list and call it a
a <- list(x,y, type="o", ylab="")
do.call(plot, a)

Another option is to create a function wrapper:
myplot <- function(...) plot(...,type="o",ylab="")
myplot(x,y)

Related

Passing object to lines function ifor plot data

My issue is the following. I use ROCR package to plot data. performance function returns an object that I pass to plot the data like this:
example <- performance(prediction1,"tpr","fpr")
plot(example,col="red")
I want to add another performance object to this plot, but lines function accepts x and y coords and not an object. In fact if I do: lines(example2, col="blue") this error appears:
Error in as.double(y) :
cannot coerce type 'S4' to vector of type 'double'**
You can add new line with add = TRUE as plot argument:
library(ROCR)
data(ROCR.simple)
prediction1 <- prediction( ROCR.simple$predictions, ROCR.simple$labels)
example1 <- performance(prediction1,"tpr","fpr")
plot(example1, col="red")
example2 <- performance(prediction1, "sens", "spec")
plot(example2, col="blue", add = TRUE)

Modifying dots (...) inside a function

I'm trying to modify the dots (...) inside a custom function. Here's a simplified example of my plot2 function, which displays a plot onscreen with type="p" (the default) and saves an svg with type="l". The problem surfaces when one of the ... plot options is already in the function. In this example, "type" is matched by multiple actual arguments.
plot2 <-function(...){
plot(...) #visible on screen
svg("c:/temp/out.svg") #saved to file
plot(...,type="l")
dev.off()
}
#This works
plot2(1:10)
#This does not work because type is redefined
plot2(1:10, type="o")
I have tried to put the dots in a list inside the function and modify it, but plot does not accept a list as an input.
#Does not work
plot2 <-function(...){
plot(...)
dots <<-list(...)
print(dots)
if("type" %in% names(dots)) dots$type="l"
print(dots)
svg("c:/temp/out.svg")
plot(dots)
dev.off()
}
plot2(1:10, type="o")
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' is a list, but does not have components 'x' and 'y'
In cases where you want to forward a modified version of ..., you need to do two things:
Capture the dots
Forward the captured dots via do.call.
This works as follows:
plot2 = function (...) {
# capture:
dots = list(...)
# modify:
dots$type = 'l'
# forward call:
do.call(plot, dots)
}
In general, do.call(f, list(‹…›)) is equivalent to f(‹…›).
For what you want, there is a simpler (and better) way, and you do not need to touch to .... By explicitly defining the arguments that need a special treatment, you take them out of the catch all .... This is also a sane approach that is more explicit about what the function does (in its formal arguments). Here is how to do it:
plot2 <- function(x, type = "p", ...) {
plot(x, type = type, ...) #visible on screen
svg("out.svg") #saved to file
plot(x, ..., type = "l")
dev.off()
}
plot2(1:10)
plot2(1:10, type = "o")

How can I suppress the creation of a plot while calling a function in R?

I am using a function in R (specifically limma::plotMDS) that produces a plot and also returns a useful value. I want to get the returned value without producing the plot. Is there an easy way to call the function but suppress the plot that it creates?
You can wrap the function call like this :
plotMDS.invisible <- function(...){
ff <- tempfile()
png(filename=ff)
res <- plotMDS(...)
dev.off()
unlink(ff)
res
}
An example of call :
x <- matrix(rnorm(1000*6,sd=0.5),1000,6)
rownames(x) <- paste("Gene",1:1000)
x[1:50,4:6] <- x[1:50,4:6] + 2
# without labels, indexes of samples are plotted.
mds <- plotMDS.invisible(x, col=c(rep("black",3), rep("red",3)) )

Obtain names of variable arguments based on dot dot dot in function R (deparse)

I am creating an automated plotter, based on some dummy variables. I set it up such that:
plotter <- function(...) { }
will plot all the dummies I feed it.
However, I would like it to be able to add labels to the plot, namely the variable names.
I do know that
deparse(substitute(variablename))
will yield
"variablename"
which is a start, but how do I do this in the case of multiple arguments? Is it at possible? Is there a workaround?
names(list(...)) will get you a character vector containing the names of the supplied arguments that have been absorbed by ...:
plotter <- function(...) {names(list(...))}
plotter(x=1:4, y=11:14)
# [1] "x" "y"
Alternatively, if you want to pass in unnamed arguments, try this (which extends #baptiste's now-deleted answer):
plotter <- function(..., pch=16, col="red") {
nms <- setdiff(as.character(match.call(expand.dots=TRUE)),
as.character(match.call(expand.dots=FALSE)))
nms
}
x <- 1:4
y <- 1:14
plotter(x, y, col="green")
# [1] "x" "y"

How can I auto-title a plot with the R call that produced it?

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) ) )

Resources