1

Say we have this toy data:

temp <- data.frame(A=1:6, gr=c("A","A","A","B","B","B"))

I can easily create a plot as

lev <- c("A", "B")
ggplot()+geom_point(data=temp,aes(x=A, y=gr))+ylim(lev)

I get this enter image description here

But I would like to convert it to a function in order to easily change the input parameters

myplot <- function(lev=lev) {ggplot()+geom_point(data=temp,aes(x=A, y=gr))+ylim(lev)}

But when I run

lev <- c("B","A")
myplot()

I get this error:

Error in limits(c(...), "y") : promise already under evaluation: recursive default argument reference or earlier problems?

I've tried converting ylim to a factor, and using eval, but it doesn't work either.

I've tried parametrizing other things such as the input dataset and they work well, but I don't understand why ylim doesn't.

There is a question that speaks about a related problem with aes parameters
Pass function argument to ggplot label

but its solution uses aes_string and doesn't apply here.

skan
  • 7,423
  • 14
  • 59
  • 96

3 Answers3

3

Change how you define your function:

myplot <- function(lev) { #I think setting lev in the definition is causing problems
  ggplot(data=temp, aes(x=A, y=gr))+
  geom_point()+
  ylim(lev)
}

Then set up a new variable for the set of levels:

args=c("B", "A") #can reorder these however you want
myplot(lev=args)
Matt
  • 954
  • 1
  • 9
  • 24
  • I use lev=lev because I want a default argument. But it's strange because I don't have the same problem if I use myplot(temp=temp) in the definition – skan Jul 03 '17 at 20:30
2

you're not calling your function with the argument!

myplot() 

throws the error because you're not giving it its argument. If you call it like you're supposed to call it (as defined by your own definition), it works.

myplot(lev) 

edit: You probably wanted to set the defaults of argument lev with lev? As far as I understand you get the error because of the way R evaluates function arguments. I didn't find any further info on that (in this short time), so I'd be happy to see answers going more in depth on that. You can directly set the defaults like that

myplot <- function(lev = c("A", "B)) {...}

Then you can also call your function without the argument, i.e. myplot() will work.

friep
  • 321
  • 1
  • 8
  • I use lev=lev because I want a default argument. But it's strange because I don't have the same problem if I use myplot(temp=temp) in the definition – skan Jul 03 '17 at 20:30
  • I'm not really understanding it right now (it's quite late where I am and I can't think anymore) but it definitely has to do something with the fact that you define lev outside your function as well. That's why you don't have the problem when you rename your argument to `temp`. See https://stackoverflow.com/questions/14982223/an-error-i-cant-understand-promise-already-under-evaluation and the page linked in the response and https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Argument-evaluation . Something with evaluation frames, calling environments etc. Sorry that I can't explain it – friep Jul 03 '17 at 21:50
  • I expected that the names wouldn't conflict because one is local and the other global – skan Jul 03 '17 at 22:45
0

I've found that strangely just calling the function's parameter with a different name than the input data works.

temp <- data.frame(A=1:6, gr=c("A","A","A","B","B","B"))
mylev <- c("A", "B")

myplot <- function(lev=mylev) {ggplot()+geom_point(data=temp,aes(x=A, y=gr))+ylim(lev)}

myplot() works

That way I can have the default parameter pointing to a given definition.

PD: Still doesn't work well. It's strange. THe first time you run it works. But If I run the it again I get this error:

Error: length(lims) == 2 is not TRUE

skan
  • 7,423
  • 14
  • 59
  • 96