Yesterday, I asked a question regarding how to plot multiple (horizontal-ish) lines, each with a user-specified color, without using a loop.
I tried to use the suggested function matplot() to plot the short vertical lines shown in the plot below with the relevant code.
ci = matrix(1:30, nrow=3, byrow=T)
ci=list(rbind(ci[1,], ci[1,]+2),
rbind(ci[2,], ci[2,]+2),
rbind(ci[3,], ci[3,]+2))
x = rbind(1:10, 1:10)
plot(-5, xlim=c(1,10), ylim=c(1,32))
invisible(mapply(matlines, x=list(x), y=ci,
col=c("red","blue","black"),
lty = 1))
This is all good. However, I am trying to wrap this code inside a function, and I would like to be able to input a list of optional arguments, which can then be passed to mapply/matlines. I tried to use the argument MoreArgs in mapply() to no avail. It seems that arguments that MoreArgs takes are not treated the same as others. As you can see in the first code, each item of the list gets a different color, but when I put col inside the list args.ci, the 3 colors are recycled within each item of the list. I wonder if there is anyway to resolve this issue so that if I have multiple values for an argument, each value gets applied to one item of a list. Thanks!
args.ci = list(col=c("red","blue","black"), lty=1:3)
plot(-5, xlim=c(1,10), ylim=c(1,32))
invisible(mapply(matlines, x=list(x), y=ci,
MoreArgs = args.ci))
Here's a general approach to this sort of problem. You should be able to adapt it to do more exactly what you want:
myFun <- function(...) {
fixedArgs <- list(matlines, x=list(x), y=ci)
dots <- list(...)
allArgs <- c(fixedArgs, dots)
plot(-5, xlim=c(1,10), ylim=c(1,32))
invisible(do.call(mapply, allArgs))
}
myFun(col=c("red","blue","black"), lty=1)
Related
here is the problem. I have two lists of vectors, sorted (i hope, but i thing i can sort them if they arent) where ith vector in first list has as many numbers as ith vector in the second list. I just want to plot them. But I fear R cant plot elements of lists. Any ideas how to fix that? Thx a lot. Here is the code i tried.
a<-c(2,1,5)
b<-c(2,2,2)
f<-c(4)
g<-c(1)
k<-list(a,f)
l<-list(b,g)
for(i in 1:2){
plot(l[i],k[i])}
and the issue is
Error in xy.coords(x, y, xlabel, ylabel, log) :
(list) object cannot be coerced to type 'double'
The best way to do it is to avoid the for-loop and unlist the lists in order to plot them.
This is a way using unlist:
plot(unlist(l),unlist(k))
The way to do it with a for-loop would be the following:
for (i in 1:2) {
par(new=T)
plot(l[[i]], k[[i]], xlim=c(0,2), ylim=c(0,5))
}
But it is totally unnecessary as you can get the same result simply by unlisting. You would also have to use par(new=T) so that the second (or any other) plot won't overwrite the previous ones and you would have to specify x and y limits so that the two plots would have the same scales. Also, you would have to use double square brackets [[]] as #HubertL mentions in his answer to access the lists. The result would be the same as above (with the labels in a bolder format since labels would be plotted twice on top of each other).
You can try to use double brackets[[]]:
plot(l[[i]],k[[i]])
Almost there, as #HubertL, just two brackets
a<-c(2,1,5)
b<-c(2,2,2)
f<-c(4)
g<-c(1)
k<-list(a,f)
l<-list(b,g)
for(i in 1:2){
plot(l[[i]],k[[i]])
}
Some of spatstat functions, such as crossing.psp do not allow to assign marks within the function. I am making a complicated function with for loops and lapply commands, which calls for marks in ppp and psp objects. I am experiencing problems when trying to assign marks to these objects when I use get() functions. Typically I would use assign function in these cases, but cannot get it to work. Here is an example:
library(spatstat)
win <- owin(c(0,1), c(0,1))
p1 <- ppp(0.1, 0.3, window = win)
p2 <- ppp(0.2, 0.4, window = win)
p3 <- ppp(0.4, 0.7, window = win)
points <- c("p1", "p2", "p3")
For those who are not familiar with the package, marks works followingly:
marks(p1) <- "p1"
What I want to do is (or something similar, which gives the desired result):
for(i in length(points)){
marks(get(points[i])) <- points[i]}
This, of course, does not work because I am using the assignment operator for get function. If I try assign function, I get an error
for(i in 1:length(points)) assign(marks(get(points[i])), points[i])
#Error in assign(marks(get(points[i])), points[i]) :
# invalid first argument
# Or following also gives the same error:
for(i in 1:length(points)) assign(x = marks, value = points[i], envir = get(points[i]))
I have also tried:
setmarks(mget(points), points)
sapply(seq_along(points), function(i) marks(get(points[i])) <- points[i])
How can I assign marks to spatspat objects within loops or using apply commands?
This will do the trick:
for(i in points) {
assign(i, do.call(`marks<-`, list(x=as.symbol(i), value=i)))
}
## Check a point patter to see that it works
marks(p3)
# [1] "p3"
If the need for a pair of nested function calls (the inner one to marks<-() and the outer one to assign()) seems mysterious, have a look at the "subset assignment" section of R-lang.
There is a data.frame() for which's columns I'd like to calculate quantiles:
tert <- c(0:3)/3
data <- dbGetQuery(dbCon, "SELECT * FROM tablename")
quans <- mapply(quantile, data, probs=tert, name=FALSE)
But the result only contains the last element of quantiles return list and not the whole result. I also get a warning longer argument not a multiple of length of shorter. How can I modify my code to make it work?
PS: The function alone works like a charme, so I could use a for loop:
quans <- quantile(a$fileName, probs=tert, name=FALSE)
PPS: What also works is not specifying probs
quans <- mapply(quantile, data, name=FALSE)
The problem is that mapply is trying to apply the given function to each of the elements of all of the specified arguments in sequence. Since you only want to do this for one argument, you should use lapply, not mapply:
lapply(data, quantile, probs=tert, name=FALSE)
Alternatively, you can still use mapply but specify the arguments that are not to be looped over in the MoreArgs argument.
mapply(quantile, data, MoreArgs=list(probs=tert, name=FALSE))
I finally found a workaround which I don't like but kinda works. Perhaps someone can tell the right way to do it:
q <- function(x) { quantile(x, probs=c(0:3)/3, names=FALSE) }
mapply(q, data)
works, no Idea where the difference is.
I want to create a series of x-y scatter charts, where y is always the same variable and x are the variables I want to check if they are correlated with. As an example lets use the mtcars dataset.
I am relatively new to R but getting better.
The code below works, the list charts contains all the charts, except that the X axis shows as "x", and I want it to be the name of the variable. I tried numerous combinations of xlab= and I do not seem to get it
if I use names(data) I see the names I want to use. I guess I want to reference the first of names(data) the first iteration of apply, the second the second time, etc. How can I do that?
Th next step would be to print them in a lattice together, I assume an lapply or sapply will do the trick with the print function - I appreciate idea for this too, just pointers I do not need a solution.
load(mtcars)
mypanel <- function(x,y,...) {
panel.xyplot(x,data[,y],...)
panel.grid(x=-1,y=-1)
panel.lmline(x,y,col="red",lwd=1,lty=1)
}
data <- mtcars[,2:11]
charts <- apply(data,2,function(x) xyplot (mtcars[,1] ~ x, panel=mypanel,ylab="MPG"))
This all started because I was not able to use the panel function to cycle.
I did not find that this code "worked". Modified it to do so:
mypanel <- function(x,y,...) {
panel.xyplot(x, y, ...)
panel.grid(x=-1, y=-1)
panel.lmline(x,y,col="red",lwd=1,lty=1)
}
data <- mtcars[,2:11]
charts <- lapply(names(data), function(x) { xyplot (mtcars[,1] ~ mtcars[,x],
panel=mypanel,ylab="MPG", xlab=x)})
Needed to remove the 'data[,y]' from the panel function and pass names instead of column vectors so there was something to use for a x-label.
I was wondering if anyone could help me use a variable name within a function.
I've put together a dot plot that sorts variables and then produces a bitmap, but I can't get R to pass the variable name to the plot title.
Example data
id<-c(1,2,3)
blood<-c(1,2,10)
weight<-c(1,2,13)
mydata<-as.data.frame(cbind(id,blood,weight))
mydata$blood
#######SORTED DOT PLOT####
Dplotter<-function (id,x,Title=""){
if (is.null(Title)) {Title=""} else {Title=Title}
DIR<-paste("C:/temp/WholePlots/New/",Title,".bmp",sep="")
D<-as.data.frame(cbind(id,x))
x1<-as.data.frame(D[order(x),])
bmp(DIR)
dotchart(x1$x,labels=id,main=Title,pch=16)
dev.off()
}
###############
Dplotter(mydata$id,mydata$blood,"Blood")
Dplotter(mydata$id,mydata$weight,"Weight")
In the second line of the function, I'd like to pass on the variable
name, something like
`if (is.null(Title)) {Title=varname(x)} else {Title=Title}`
so that I don't have to put "Blood" in the function Title field
(e.g. Dplotter(mydata$id,mydata$blood)
Basically, how does one paste in the variable name in a function? It
would be even better if one could take out the dataset name from the
Title (without attaching the dataset, which I've been told is bad
practice), so that instead of getting mydata$blood, you just get
"blood" in the title.
I've failed to find an easy solution to paste in a variable name in
a function. As you can guess, putting the variable name in a
paste() function returns the values of the variable (so that the
plot title is filled with values rather the variable name).
I'd also like to automate the function even further, so that I can
just put the dataset and the ID,and then have the function repeated
for each variable in the dataset. Obviously this requires solving
question 1 first, otherwise both title and filenames will encounter
problems.
The general answer is deparse(substitute(x)). E.g.
fooPlot <- function(x, main, ...) {
if(missing(main))
main <- deparse(substitute(x))
plot(x, main = main, ...)
}
Here it is in use:
set.seed(42)
dat <- data.frame(x = rnorm(1:10), y = rnorm(1:10))
fooPlot(dat, col = "red")
Which produces:
In your particular example though, this won't work because you don't want dat$x as the title, you want just x. We could do a little more manipulation however:
fooPlot <- function(x, main, ...) {
if(missing(main)) {
main <- deparse(substitute(x))
if(grepl("\\$", main)) {
main <- strsplit(main, "\\$")[[1]][2]
}
}
plot(x, main = main, ...)
}
Which for fooPlot(dat$x, col = "red") gives:
Note this code makes some assumptions, that main is not a vector, that there will only ever be one $ in the object passed to plot (i.e. you couldn't use a nested list for example with the above code).
You need to retrieve a set of strings, the variable names, and use them for the title of your plots and filenames as well.
I will use the longley dataset to illustrate the trick.
data(longley, package="datasets")
#return a vector with variable names
colnames(longley)
names(longley) #equivalent
#get the name of a specific variable (column number):
names(longley)[1]
To plot each variable, get two sets of strings: variable names and filenames:
var.names=names(longley)
file.names=paste(var.names, "bmp", sep=".")
#with an extra step to prefix a directory to those filenames
for (i in 1:ncol(longley) ) {
bmp(file=file.names[i])
plot(longley[[i]], main=var.names[i], ylab="")
dev.off()
}
ylab="", since otherwise it gives a silly "longley[[i]]" as y-label, and if I use var.name[i] as ylab, it would be redundant.