5

I am trying to create a function that takes in 2 parameters & outputs the appropriate ggplot for them. The code works perfectly manually, but somehow I cannot make it work inside a function wrapper.

The error returned is

Error in eval(expr, envir, enclos) : object 'TimeVector' not found

I try to correct for that by coercing the objects not found, which are added to ggplot, as strings. This in turn creates different trouble in form of

Error: Discrete value supplied to continuous scale

Removing the scale_x_continuous(breaks=0:24) fixes that second error, but outputs an empty graph, suggesting that ggplot is not fed with any data at all.

The data is a large data frame of observations of traffic density grouped by time. It looks like this:

ID                   Road Status                Time Statusint Day  Months Year Weekday

1 Me7war To Sheikh Zayid Orange 2012-10-01 00:03:00         3   1 October   12  Monday
1 Me7war To Sheikh Zayid  Green 2012-10-01 05:00:00         2   1 October   12  Monday
1 Me7war To Sheikh Zayid Yellow 2012-10-01 05:24:00         5   1 October   12  Monday

I am trying to plot the "Statusint" variable, short for status integer ranging from 1 (good traffic) to 5 (Terrible traffic) against the "Time" variable. "Time" is formatted as Posix, so I create a numeric vector called "TimeVector" for the sole purpose of plotting against in ggplot.

The function is as follows:

Plotroad <- function( roadID , Day ) {

  *** Working Code ***

  else { 

  ### THE PROBLEM CODE: Everything below works manually, but returns an error in the function

    Roadsubset <- October[October$ID == as.numeric(roadID), ] 
    Timesubset <- subset(Roadsubset, format(Roadsubset$Time,'%d') == "Day" )
    TimeVector <- as.numeric(gsub(":" , "." , strftime(Timesubset$Time, format="%H:%M")))

    ggplot(Timesubset, aes( x = "TimeVector", y = "Timesubset$Statusint")) + geom_point() +  
        stat_smooth() + scale_x_continuous(breaks=0:24) 


    ### The working code: 
    Roadsubset <- October[October$ID == as.numeric(roadID), ] 
    Timesubset <- subset(Roadsubset, subset = Roadsubset$Day == as.integer(Date) )
    TimeVector <- as.numeric(gsub(":" , "." , strftime(Timesubset$Time, format="%H:%M")))
    Timesubset$timevector <- TimeVector

    print(ggplot( data = Timesubset, aes_string( x = "timevector" , y = "Statusint" )) + geom_point() + stat_smooth()  + scale_x_continuous(breaks=0:24) + labs(list(title = as.character(Timesubset$Road[1]) , x = "Time of Day", y = "Status")))  

  }
}

I have seen some advice suggesting using print, as ggplot is invoked not in the command line. This, however does not fix the aforementioned errors.

This is my first post to stack overflow, so please point out how I can better format questions for the future, if in need. Thanks.

M. Momtaz Hegazy
  • 173
  • 1
  • 12
  • 1
    tl;dr, but it seems like you are looking for `aes_string`? – Roland Dec 30 '13 at 19:04
  • @Roland Danke, aber That in turn creates a new error: `Error in parse(text = x)[[1]] : subscript out of bounds` – M. Momtaz Hegazy Dec 30 '13 at 19:09
  • Try changing this ```aes( x = "TimeVector", y = "Timesubset$Statusint"))``` into ```aes_string( x = "TimeVector", y = "Statusint"))``` I believe you shouldn't keep adding the data reference inside the aes() call. [Here is a similar question](http://stackoverflow.com/questions/19016007/metaprogramming-with-ggplot2) – marbel Dec 31 '13 at 00:57
  • Try using just one ```data.frame``` that includes all the data, with a [long format](http://vita.had.co.nz/papers/tidy-data.pdf). Check this [Question](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) out also to see how to make a reproducible example. – marbel Dec 31 '13 at 01:06
  • 1
    @MartínBel Doing both these things helped immensely, Thank you – M. Momtaz Hegazy Dec 31 '13 at 12:35

1 Answers1

7

Aside from using variable names, there is an issue with scope. GGPlot carries out non-standard evaluation in the global environment, so anything defined in your function is not directly accessible, except for the "data" argument since that one is passed explicitly and not through non-standard evaluation. So one work around to this problem is to add your variable to the data argument. I've created an example that I think mimics your problem, but since I don't have your data it's not identical:

gg_fun <- function() {
  data <- data.frame(a=1:10, b=1:10)
  clr <- rep(c("a", "b"), 5)
  ggplot(data, aes(x=a, y=b, color=clr)) + geom_point()
}
gg_fun()
# Error in eval(expr, envir, enclos) : object 'clr' not found
gg_fun <- function() {
  data <- data.frame(a=1:10, b=1:10)
  clr <- rep(c("a", "b"), 5)
  data$clr <- clr
  ggplot(data, aes(x=a, y=b, color=clr)) + geom_point()
}
gg_fun() # works

In your case, you need to add TimeVector to Timesubset (trivial), and then use the unquoted aes syntax:

ggplot(Timesubset, aes(x=TimeVector, y=Statusint)) ...
BrodieG
  • 51,669
  • 9
  • 93
  • 146
  • Yep, that seemed to be the thing. Thank you – M. Momtaz Hegazy Dec 31 '13 at 12:35
  • I have a similar issue with ggplot not finding my color vector, but my color vector has four values matching four factors in my data.frame, which has 1200 observations. My data.frame does not allow my to add a four-item vector as a column. Any edit for this scenario? Or would this be a separate question? – mightypile Mar 06 '15 at 01:42
  • @mightypile, just make a vector the same length as your data frame with the color that you want for each row. `match` may help with that task. – BrodieG Mar 06 '15 at 01:44
  • @BrodieG, Doing that yields "Error: Incompatible lengths for set aesthetics: colour, size, hjust, vjust, x, y, label". I've messed with colors and labels a dozen different ways. I think I just need to refactor and clean things up. A more elegant solution awaits my efforts. Thanks! – mightypile Mar 06 '15 at 02:12
  • 1
    @BrodieG I think using the phrase "same length as your dataframe" is potentially misleading. Almost always you would want to make a vector of the same length as the number of rows of a dataframe. – IRTFM Jun 05 '21 at 01:37
  • 0-1 (circumventing comment nanny) for pedantics ;), but yes, you're right of course @IRTFM. Nice handle BTW. – BrodieG Jun 05 '21 at 23:59