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.
Related
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(...)
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')
I am new to R. I've been trying to work on my code but I am having trouble understanding which 'parts' go where. This is the code I was given:
df=10
boxplot(rt(1000,df),rnorm(1000),names=c(paste("t,df=",df),"Standard Normal"))
x=seq(0,1,length=150)
plot(qt(x,df),qnorm(x),xlab=paste("t, df=",df),ylab="standard
Normal",main="qq-plot")
abline(0,1)
curve(dnorm(x),-3.5,3.5,main="Density Comparison")
curve(dt(x,df),lty=2,add=TRUE)
legend("topright",legend=c("standard
normal",paste("t,df=",df)),lty=c(1,2))
I am supposed to create a user defined function that takes df as the input and output 3 types of plots. I need to use: df=5,10,25, and 50.
This is what I have so far. Please dumb it down for me since I'm not very familiar with R terminology and I am not sure I am placing things where they are supposed to go..:
my.plot = function(n, df) {
a = rt(n,df)
b=rnorm(1000)
x= seq(0,1,length=150)
qt=qt(x,df)
qn=qnorm(x)
dn=dnorm(x)
ledt=dt(x,df)
n=1000
}
thebox= boxplot(a,b,names=c(paste("t,df=",df),"Stand rd Normal")) #1boxplot.
theplot= plot(qt,qn,xlab=paste("t, df=",df),ylab="standard Normal",main="qq-plot")
abline(0,1)
onecurve= curve(dn,-3.5,3.5,main="Density Comparison") #density curve
twocurve= curve(ledt, lty=2,add=TRUE)
legend("topright",legend=c("standard normal",paste("t,df=",df)),lty=c(1,2)
}
return(thebox)
return(theplot)
return(oneplot)
return(twocurve)
}
par(mfrow=c(1,3))
my.plot(1000,5)
my.plot(1000,10)
my.plot(1000,25)
my.plot(1000,50)
It works like this:
1. Your only input parameter is df. So your function will have only one input variable.
2. Since you already have the remaining code functional (i.e. after defining df) that code can be used as it is.
Below is a simple implementation from your demo code. You can modify it to suite your needs.
my.plot <- function(df) {
par(mfrow=c(1,3))
boxplot(rt(1000,df),rnorm(1000),names=c(paste("t,df=",df),"Standard Normal"))
x=seq(0,1,length=150)
plot(qt(x,df),qnorm(x),xlab=paste("t, df=",df),ylab="standard
Normal",main="qq-plot")
abline(0,1)
curve(dnorm(x),-3.5,3.5,main="Density Comparison")
curve(dt(x,df),lty=2,add=TRUE)
legend("topright",legend=c("standard
normal",paste("t,df=",df)),lty=c(1,2))
par(mfrow=c(1,1))
}
my.plot(5)
for(df in c(5,10,15,25)) my.plot(df)
I have written a function that draws some plots, and returns a list, similar in style to the following format:
myfun <- function(x, y){
plot(x, y)
points(x+1, y+1)
abline(v=x[1])
mylist <- list(x=x,y=y,line=x[1])
return(mylist)
}
This works fine. However, in R, one generally plots from functions in the following way:
x <- rnorm(100)
y <- rnorm(100)
lin <- lm(x~y)
plot(lin)
i.e., one creates an object using the function, then uses plot(object) to get the plot. How can I set up my function to behave in this way? I've had a look at a few guides to writing R packages (including hadley's), but I couldn't find reference to this problem.
I would like to create this functionality so I can upload what I've created to CRAN or R-Forge.
You could create your own S3 class for it (
R provides a lot of object oriented systems (S3, S4, R5, R.oo, ...), see also: http://adv-r.had.co.nz/OO-essentials.html):
# create an object with an own class
lin = list(x=rnorm(100), y=rnorm(100))
class(lin) = "mylin"
# overload plotting function
plot.mylin = function(l) {
plot(l$x, l$y)
points(l$x+1, l$y+1, col=2)
abline(v=l$x[1])
}
# run it
plot(lin)
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.