Adding arguments when creating a function in R - 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')

Related

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.

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.

R function for plotting x number of variables

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.

R functions with optional arguments to save file

I'm trying to create a user defined function in R with an optional argument to save the plot as a pdf. I have the required parameter to default to FALSE. If TRUE, then save to pdf with filename.pdf. Have I gotten some syntax wrong:
seeplot <-function (save=FALSE) {
x <- seq(1,10,1)
y <- x^2
plot (x,y,type="l")
if (save==TRUE) pdf(file="save")
}
Thanks.
I think it's from not reading ?pdf carefully that you're experiencing troubles. I'd let you struggle a bit (as struggle is good, shoot I often battle R) but I think maybe the logical save approach is not the best so I'll chime in. Here's 3 mistakes I see:
You call pdf but then never plot after that
You never say dev.off
There's no file extension to the pdf
Here is your function fixed:
seeplot <-function (save=FALSE) {
x <- seq(1,10,1)
y <- x^2
plot (x,y,type="l")
if (save) {
pdf(file="save.pdf")
plot (x,y,type="l")
dev.off()
}
}
But may I recommend supplying a file name instead of a logical save. This allows the user to name the file as they please:
seeplot <-function (file=NULL) {
x <- seq(1,10,1)
y <- x^2
plot (x,y,type="l")
if (!is.null(file)) {
pdf(file=file)
plot (x,y,type="l")
dev.off()
}
}

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