4

I'm an R/ggplot newbie switching over from MatLab.

I would like to create a function using ggplot with linear regression equation printed on the graph (which is discussed in Adding Regression Line Equation and R2 on graph). But here, I am trying to build a function with it but wasn't successful.

I kept getting an error - "Error in eval(expr, envir, enclos) : object 'label' not found".

One workaround is to define "label" variable outside of the function but I just don't understand why this doesn't work.

Can anyone explain why?

df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)

f <- function(DS, x, y, z) {
    label <- z
    print(label)

    ggplot(DS, aes(x=x, y=y)) + 
        geom_point() +
        labs(y=y) +
        labs(title=y) +
        xlim(0,5)+
        ylim(0,5)+
        geom_smooth(method="lm", se=FALSE)+
        geom_text (aes(x=1, y=4, label=label))
}

f(df, x, y, "aaa") #execution line  
Community
  • 1
  • 1
JJ Shin
  • 41
  • 3

1 Answers1

5

See the following code:

library(ggplot2)
df <- data.frame(x = c(1:100))
df$y <- 2 + 3 * df$x + rnorm(100, sd = 40)
f <- function(DS, x, y, z) {
  label.df = data.frame(x=1, y=4, label=z)
  ggplot(DS, aes_string(x=x, y=y)) + 
    geom_point() +
    labs(y=y) +
    labs(title=y) +
    geom_smooth(method="lm", se=FALSE)+
    geom_text (aes(x=x, y=y, label=label), label.df)
}

f(df, "x", "y", "aaa") 

There were a few fixes about your code:

  • The data you are using in geom_text is the same you have defined in ggplot() unless you change it. Here I have created a temporary data.frame for this purpose called label.df.
  • The xlim() and ylim() functions were filtering most of your data points, since the range of x and y are much larger than the limits you defined in the original code.
  • When you want to pass the names of the columns of your data.frame to be used for displaying the graph it would be easier to pass their names as strings (i.e. "x"). This way, the aes() function is also changed to aes_string().

Here is the result: enter image description here

Edit Thanks to @Gregor, a simpler version would be:

f <- function(DS, x, y, z) {
   ggplot(DS, aes_string(x=x, y=y)) + 
    geom_point() +
    labs(y=y) +
    labs(title=y) +
    geom_smooth(method="lm", se=FALSE)+
    annotate(geom="text", x=1, y=4, label=z)
}
Ali
  • 9,440
  • 12
  • 62
  • 92
  • Could you explain what was the problem? – Soheil May 15 '15 at 22:38
  • 6
    I'd recommend `annotate(geom = "text", ...)` rather than `geom_text`. Avoids the hassle of creating a new data frame. – Gregor Thomas May 15 '15 at 22:39
  • Also, you don't need to pass x and y in the function. You just pass the data frame and ggplot gets x and y from DS. – eipi10 May 15 '15 at 22:46
  • 1
    @eipi10 passing those arguments makes the function more flexible. Just think that the columns have different names than "x" and "y". – Ali May 15 '15 at 23:31
  • Thanks @Gregor. I was able to reproduce the plot using "annotate". Thanks Ali. I corrected my x and ylimit which was used for old df and I also noted use of "" in the function execution. – JJ Shin May 17 '15 at 05:18