R function for plotting x number of variables - r

I am attempting to write a function that will be inserted into a larger script. The aim of this function is to accept any number of input variables and then plot them accordingly:
Plot_funct <- function(FigFolder,var1,var2,var3,...){
nargin <- length(as.list(match.call())) -1
}
This is where I'm starting from, here we have FigFolder which is the path of where the figures should be saved (as .pdf), I define 'nargin' which specifies the number of input arguments, and then I was planning on looping through each of the arguments (var1,var2, etc) and plot accordingly. The main concern I have is how do you set up a function to allow any number of inouts?

What is much easier is to just provide a list of these variables:
plot_funct = function(FigFolder, variable_list, ...) {
for(variable in variable_list) {
# Make plot here
}
})
or a bit more R like:
plot_variable = function(variable, ...) {
# Make plot here
})
plot_funct = function(FigFolder, variable_list, ...) {
lapply(variable_list, plot_variable, ...)
})
You could also stick to the separate variables, and use ...:
plot_function = function(..., FigFolder) {
variable_list = list(...)
# and use any of the two strategies given above, I'll use lapply
lapply(variable_list, plot_variable)
})
Note that this is more pseudo-code than real R code, but it illustrates the general strategy.

Related

Using global variables as input to R function

There are plenty of examples about updating global variables from the inside of R functions by using <<- or assign() (here is just one example), but I can't find any examples on how to use such variables as input for functions. For instance, consider this MATLAB function, which is just a complicated way of adding pi to a number:
function final = parentFun(why)
global pie
pie = pi;
final = childFun(why);
end
function y = childFun(x)
global pie
y = x + pie;
end
So that
>> parentFun(100)
ans =
103.1416
I would like to recreate this in R. The closest I got was by nesting childFun into parentFun like this:
parentFun <- function(why) {
pie <- pi
childFun <- function(x) {
x + pie
}
childFun(why)
}
And indeed
> parentFun(100)
[1] 103.1416
The problem is that in my real case parentFun is a couple hundred lines long and it contains several children which can be just as long. In other words, nesting is basically off the table.
Also, these are functions in a package, so pie is in fact acquired from within a function and isn't started by a script.
Of course, separating both functions doesn't work because childFun() can't see pie:
> parentFun <- function(why) {
pie <- pi
childFun(why)
}
> childFun <- function(x) {
x + pie
}
> parentFun(100)
Error in x + pie : non-numeric argument to binary operator
One possibility would be to change the environment of childfun
childFun <- function(x) {
x + pie
}
parentFun <- function(why) {
pie <- pi
environment(childFun) <- environment()
childFun(why)
}
parentFun(100)
[1] 103.1416
This has to do with lexical scoping of R. When you call a function R looks for the variables inside the function environment first. If it is not sucessful R continues the search in parent environments (in your case the global environment).
By writing environment(childFun) <- environment() you tell the function to look in the environment of parentFun for variables.
I recommend this book if you want to learn more about environments.

function as an argument of a function in R

I have this function which I have saved in the database.
runifrect <- function(n,a,b,z,d) {
else(print("Check if the x and y coordinates lie as such: 0<=a<b<=1 and 0<=z<d<=1"))}
Now I am trying to define this function with the use of the old one:
plotrectpoints<- function(runifrect(n,a,b,z,d),a,b,z,d) {
However I am getting an error I dont understand what is wrong with the function, I want it to work for any arbitrary values n,a,b,z,d.
When a function is defined in R it cannot evaluate the values in parenthesis. It rather creates dummy objects which get the values when the function is called. These dummy object names follow the same rules that are applied to all variables names. Since you cannot have a variable name contained parenthesis, you cannot include it into the list of arguments when you define the function.
First function definition
runifrect <- function(n,a,b,z,d) {
if(a<1&a>=0&b>0&b<=1&z<1&z>=0&d<=1&d>0) {
x <- runif(n,a,b)
y <- runif(n,z,d)
k<-c(x,y)
matrix(k,nrow = n,ncol = 2)}
else(print("Check if the x and y coordinates lie as such: 0<=a<b<=1 and 0<=z<d<=1"))}
Second function definition
plotrectpoints<- function(x,a,b,z,d) {
plot(x,
xlim=c(0,1),
ylim=c(0,1),
main = "Plot of rectangle and randomly generated points")
rect(a,z,b,d, border='red',lty='dotted')}
Call to the function
plotrectpoints( runifrect(n,a,b,z,d), a,b,z,d)
This is my first answer on this platform. Please bear with me.
If your end goal is to call the 'runifrect()' function from the 'plotrectpoints()' function, we can remove the 'runifrect(n,a,b,z,d)' parameter and replace that with 'n'.
The code should look as follows:
runifrect <- function(n,a,b,z,d) {
if(a<1&a>=0&b>0&b<=1&z<1&z>=0&d<=1&d>0) {
x <- runif(n,a,b)
y <- runif(n,z,d)
k<-c(x,y)
matrix(k,nrow = n,ncol = 2)}
else(print("Check if the x and y coordinates lie as such: 0<=a<b<=1 and 0<=z<d<=1"))}
plotrectpoints<- function(n,a,b,z,d) {
plot(runifrect(n,a,b,z,d),
xlim=c(0,1),
ylim=c(0,1),
main = "Plot of rectangle and randomly generated points")
rect(a,z,b,d, border='red',lty='dotted')}
and I have used the following parameters to test.
plotrectpoints(10,0.5,0.8,0.3,0.7)
I have also attached the plot the above code generated.
enter image description herePlease let me know if the above code is what you are looking for.

Adding points after the fact with ggplot2; user defined function

I believe the answer to this is that I cannot, but rather than give in utterly to depraved desperation, I will turn to this lovely community.
How can I add points (or any additional layer) to a ggplot after already plotting it? Generally I would save the plot to a variable and then just tack on + geom_point(...), but I am trying to include this in a function I am writing. I would like the function to make a new plot if plot=T, and add points to the existing plot if plot=F. I can do this with the basic plotting package:
fun <- function(df,plot=TRUE,...) {
...
if (!plot) { points(dYdX~Time.Dec,data=df2,col=col) }
else { plot(dYdX~Time.Dec,data=df2,...) }}
I would like to run this function numerous times with different dataframes, resulting in a plot with multiple series plotted.
For example,
fun(df.a,plot=T)
fun(df.b,plot=F)
fun(df.c,plot=F)
fun(df.d,plot=F)
The problem is that because functions in R don't have side-effects, I cannot access the plot made in the first command. I cannot save the plot to -> p, and then recall p in the later functions. At least, I don't think I can.
have a ggplot plot object be returned from your function that you can feed to your next function call like this:
ggfun = function(df, oldplot, plot=T){
...
if(plot){
outplot = ggplot(df, ...) + geom_point(df, ...)
}else{
outplot = oldplot + geom_point(data=df, ...)
}
print(outplot)
return(outplot)
}
remember to assign the plot object returned to a variable:
cur.plot = ggfun(...)

Adding arguments when creating a function in R

I am a beginner in R. For example i have a function called w whose code is listed below:
w<-function(x){
a<-x+2
plot(a)
}
How can i add these arguments in the function so that
Export: a number equal to 0 if result should be allowed on screen and to 1 if the result should be printed in a text file.
Tfile: name of the text file where the results will be written to;
Gfile:name of the pdf file where the graph will be written to.
To include further arguments in a function, simply list them in function().
w <- function(x, export, tfile, gfile) {
a <- x + 2
if (export == 1) {
write.csv(a, file = tfile)
} else if (export == 0) {
pdf(file = gfile)
plot(a)
dev.off()
}
}
For more information on writing and debugging functions in R, see this article.
As the others have pointed out, just separate additional arguments with commas. You can have as many as you want.
w <- function(x, export, tfile, gfile)
Assigning values within the function definition allows them to have default arguments, so you can choose not to include them
w <- function(x, export = 0, tfile = "w.csv", gfile = "w.pdf")
I will add that a handy thing for plot functions (and many other functions) is the ellipsis ... construct, which basically means "any other relevant arguments". For instance, doing something like this allows you to optionally pass further graphical parameters to your plot (e.g. label names, title).
w <- function(x, ...){
a <- x + 2
plot(a, ...)
}
w(10, main="Main title")
w(15, type='l', col='red')

Change of colors in compare.matrix command in r

I'm trying to change the colors for the compare.matrix command in r, but the error is always the same:
Error in image.default(x = mids, y = mids, z = mdata, col = c(heat.colors(10)[10:1]), :
formal argument "col" matched by multiple actual arguments
My code is very simple:
compare.matrix(current,ech_b1,nbins=40)
and some of my attempts are:
compare.matrix(current,ech_b1,nbins=40,col=c(grey.colors(5)))
compare.matrix(current,ech_b1,nbins=40,col=c(grey.colors(10)[10:1]))
Assuming you're using compare.matrix() from the SDMTools package, the color arguments appear to be hard-coded into the function, so you'll need to redefine the function in order to make them flexible:
# this shows you the code in the console
SDMTools::compare.matrix
function(x,y,nbins,...){
#---- preceding code snipped ----#
suppressWarnings(image(x=mids, y=mids, z=mdata, col=c(heat.colors(10)[10:1]),...))
#overlay contours
contour(x=mids, y=mids, z=mdata, col="black", lty="solid", add=TRUE,...)
}
So you can make a new one like so, but bummer, there are two functions using the ellipsis that have a col argument predefined. If you'll only be using extra args to image() and not to contour(), this is cheap and easy.
my.compare.matrix <- function(x,y,nbins,...){
#---- preceding code snipped ----#
suppressWarnings(image(x=mids, y=mids, z=mdata,...))
#overlay contours
contour(x=mids, y=mids, z=mdata, col="black", lty="solid", add=TRUE)
}
If, however, you want to use ... for both internal calls, then the only way I know of to avoid confusion about redundant argument names is to do something like:
my.compare.matrix <- function(x,y,nbins,
image.args = list(col=c(heat.colors(10)[10:1])),
contour.args = list(col="black", lty="solid")){
#---- preceding code snipped ----#
contour.args[[x]] <- contour.args[[y]] <- image.args[[x]] <- image.args[[y]] <- mids
contour.args[[z]] <- image.args[[z]] <- mdata
suppressWarnings(do.call(image, image.args))
#overlay contours
do.call(contour, contour.args)
}
Decomposing this change: instead of ... make a named list of arguments, where the previous hard codes are now defaults. You can then change these items by renaming them in the list or adding to the list. This could be more elegant on the user side, but it gets the job done. Both of the above modifications are untested, but should get you there, and this is all prefaced by my above comment. There may be some other problem that cannot be detected by SO Samaritans because you didn't specify the package or the data.

Resources