1

I have a very simple loop trying to draw four curves on the same graph using ggplot. Here is the code:

  df = data.frame(x=0:10/10)
  gg = ggplot(df)
  for (t in 4:1/4)
      gg = gg + geom_path(aes(x,x^t))
  gg  

When I run it, it only shows the last graph. If I add them one at a time, eg:

  df = data.frame(x=0:10/10)
  gg = ggplot(df)
  gg = gg + geom_path(aes(x,x^1.00))
  gg = gg + geom_path(aes(x,x^0.75))
  gg = gg + geom_path(aes(x,x^0.50))
  gg = gg + geom_path(aes(x,x^0.25))
  gg

it works just fine. Can someone explain the magic?

Roobie Nuby
  • 1,379
  • 12
  • 19
  • 1
    you need to capture the environment (current value of t at each stage) otherwise only the last one will exist by the time ggplot2 actually builds the plot – baptiste Feb 14 '17 at 05:46
  • Have you checked out this [solution](http://stackoverflow.com/questions/26235825/for-loop-only-adds-the-final-ggplot-layer)? – Gene Burinsky Feb 14 '17 at 05:47

3 Answers3

4

you could substitute the value explicitly,

eval(substitute(expr = {gg = gg + geom_path(aes(x,x^t))}, env = list(t=t)))

but a better solution would be to create the entire data.frame with all variables first, and then plot it (preferably in long format).

Community
  • 1
  • 1
baptiste
  • 75,767
  • 19
  • 198
  • 294
4

Baptiste suggested to create the entire data.frame with all variables first, and then plot it (preferably in long format). The answer provided by Gene creates the data in wide format requiring to loop over the columns.

The code below creates the data in long format and plots all curves in one call:

# create data in long format
df <- expand.grid(x = 0:10/10, exp = 1:4/4)
df$y <- df$x^df$exp

# plot
library(ggplot2)
gg <- ggplot(df, aes(x, y, group = exp)) + geom_line()
gg

enter image description here

Note that geom_line() is used here because it connects the observations in order of the variable on the x axis. geom_path() connects the observations in the order in which they appear in the data.

The different curves can be colour-coded as well:

# continous scale
gg + aes(colour = exp)

enter image description here

# discrete scale
gg + aes(colour = factor(exp))

enter image description here

Note that by including the colour aesthetic in the call to aes() an appropriate legend is created by default.

Community
  • 1
  • 1
Uwe
  • 41,420
  • 11
  • 90
  • 134
  • I accepted this, even though the answer by @baptiste is short and says more. It was so terse that I could not understand what what meant by long format vs wide, until I saw the other this answer. – Roobie Nuby Feb 16 '17 at 18:57
1

As alluded to by baptise and the aforementioned solution, the for loop doesn't work because of lazy evaluation. Here's a working for loop approach that works by updating the supplied data in every loop. As mentioned elsewhere, there are more efficient ways to plot this

#make the data and put it all into a single df
df = data.frame(x=0:10/10)
df = cbind(df,sapply(4:1/4, function(t) df$x^t))

# initiate ggplot
g <- ggplot(df)

# make some colours
cols = colorRampPalette(c("blue",'green'))(ncol(df))

# loop over columns
for (j in 2:ncol(df)){

  # update the data within the loop
  gg.data <- data.frame(x = df[,1], y = df[,j])

  # add the line
  g <- g + geom_path(data = gg.data, aes(x,y), col = cols[j])
}
g

g plot

Community
  • 1
  • 1
Gene Burinsky
  • 9,478
  • 2
  • 21
  • 28
  • 3
    @Baptiste suggested to create the data in _long format_. Your answer creates the data in _wide format_ which is less preferable for `ggplot2` and requires to loop over the columns unnecessarily. Therefore, your statement _Here's the right approach_ is quite strong. – Uwe Feb 14 '17 at 08:05
  • 1
    @UweBlock, in some instances, such as the solution link, the for loop is inevitable. Moreover, the OP was concerned for why the for loop wasn't working hence the response. If it were my code, I would put the data into a long format and let ggplot take care of the details too. – Gene Burinsky Feb 14 '17 at 17:21
  • I agree that for loops can't be avoided some times. But they are not the proper solution neither in this case nor the in the linked solution because the whole approach in both cases was misguided. To me, both cases are [_XY problems_](http://xyproblem.info/). Both OP experienced an issue with adding layers to a ggplot object within a for loop because they hadn't created the data in the format that ggplot prefers. A better question would have been, e.g., "How to prepare the data to plot parameterized curves with ggplot?". – Uwe Feb 15 '17 at 09:22