2

My question is an exact duplicate of this one [1], but the provided answer isn't working on my system.

Question: How can I add geom_segment() layers within a for loop? If I use aes, as the OP of the referenced question does, I also get only the last layer. If, as the answerer suggests, I don't use aes, I don't get any segments at all.

Here is a minimal example:

  ga <- 2.39996322972865332
  p <- ggplot()
  p <- p + scale_y_continuous(limits = c(-1, 1))
  p <- p + scale_x_continuous(limits = c(-1, 1))
  for (i in 0:2) {
    #     p <- p + geom_segment(x = -cos(i*ga), y = -sin(i*ga), xend = cos(i*ga), yend = sin(i*ga)) # No segments
    p <- p + geom_segment(aes(x = -cos(i*ga), y = -sin(i*ga), xend = cos(i*ga), yend = sin(i*ga))) # Only last segment
  }
  p

I'm using R version 3.1.2 and (apparently) ggplot2 version 1.0.0 on Ubuntu.

(Note: I get the same result if I use repeat or while.)

[1] Enriching a ggplot2 plot with multiple geom_segment in a loop?

Community
  • 1
  • 1
sudo make install
  • 5,629
  • 3
  • 36
  • 48

3 Answers3

4

Skip the loop. Pass a vector to the i variable:

 p <- p + geom_segment(
                aes(x = -cos((0:2)*ga), y = -sin((0:2)*ga),
                    xend = cos((0:2)*ga), yend = sin((0:2)*ga))
                       )

Just a check to see that you can use a variable as well as a numeric constant:

 i <- 0:2
 p <- p + geom_segment(aes(x = -cos(i*ga), y = -sin(i*ga), 
                           xend = cos(i*ga), yend = sin(i*ga)) )

enter image description here

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Ahhh brilliant! I need to start vectorizing things in my head by default. Thanks so much! – sudo make install Mar 13 '15 at 17:26
  • This the cleanest and useful solution. I found so many melting and data.frame "casting" and they were always suboptimal and often broken (e.g. if you use a different `data` for the main plotting). – Garini May 03 '17 at 14:39
1

I had a very similar problem, but could not avoid using a for loop. I solved it by

adding inherit.aes = TRUE

after the aes() statement within the geom_segment() statement.

Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Hanne
  • 13
  • 2
-1

I just wanted to add one point to @BondedDust's answer.

If you try to put this into a function, something like this...

  draw.golden.angle <- function(n) {

  ga <- 2.39996322972865332
  p <- ggplot()
  p <- p + scale_y_continuous(limits = c(-1, 1))
  p <- p + scale_x_continuous(limits = c(-1, 1))
  i <- 0:n
  p <- p + geom_segment(aes(x = -cos(i*ga), y = -sin(i*ga), xend = cos(i*ga), yend = sin(i*ga))) # Only last segment
  p

  }

  draw.golden.angle(7)

...you will get an error saying that the variable i isn't recognized. You can fix this by assigning i to a global variable as follows:

i <<- 0:n
sudo make install
  • 5,629
  • 3
  • 36
  • 48
  • Assigning to a global variable is a very dangerous way to go about this. – Gregor Thomas Mar 13 '15 at 19:22
  • Thanks for the warning, @Gregor--I will read up on global variables. Is there another way you can think to do this? If you'd like I can make it a separate question. – sudo make install Mar 13 '15 at 19:39
  • I can't think of a really easy way. The robust solution would be to add new data columns for each value of `i`, `melt`, and use `geom_segment` with a grouping variable, `aes(group = i)`. It's quite a bit more work, but that's the price we pay to have stable and reliable functions. – Gregor Thomas Mar 13 '15 at 19:44
  • Also, `fortunes::fortune(236)` – Gregor Thomas Mar 13 '15 at 19:46
  • And Circle 6 of [The R Inferno](http://www.burns-stat.com/pages/Tutor/R_inferno.pdf) is about global assignment (and why you should never do it). – Gregor Thomas Mar 13 '15 at 19:48
  • It is true that assignment to the enclosing frame is generally deprecated, but in this instance the "risk" would be external in a sense because the function would always succeed in the manner intended but any `i`-object in the enclosing frame would get clobbered. It's a bit different risk than one usually takes when using the super-assign. The term global-variable does not really apply here. The `<<-` function only makes an assignment to a named-object one level up. It's not guaranteed to be "global". – IRTFM Mar 13 '15 at 20:02