0

I have a grid. For each element of the grid, I'm drawing symbols depending on their contents. I did:

for (i in 1:nx) { # to each column
    x1 <- xmin + (i-1)*size #size is the lateral size of the quadricules = 0.5
    x2 <- xmin + i*size
    for (j in 1:ny) { # to each row
        y1 <- ymin + (j-1)*size
        y2 <- ymin + j*size
        nind <- nrow(mam[which(mam$LAT >= y1 & mam$LAT < y2 & mam$LON >= x1 & mam$LON < x2),]) # number of rows in table "mam" inside the given limits (x1,y1,x2,y2)
        if (nind == 1) {
            rect(x1+gap,y1+gap,x2-gap,y2-gap) # gap is about 0.1
            segments(x1+gap,y1+gap,x2-gap,y2-gap)
        } else if (nind == 2) {
            rect(x1+gap,y1+gap,x2-gap,y2-gap)
            segments(x1,y2,x2,y1)
        } else if (nind == 3) {
            rect(x1+gap,y1+gap,x2-gap,y2-gap)
            segments(x1,y1,x2,y2)
            segments(x1,y2,x2,y1)
        }
    }
}

It works ok, and produces map of cebid monkeys colleted in Amazon forest

forget about the colors. It's the small black squares that are being drawn here. But it takes too long, and for some operations apply seems faster (although some people say that's not true anymore... I'm not sure).

My question is: how can I do that using apply? I need the "i" parameter inside the function, so I know where the squares will be drawn. But haven't found how to get it. In other similar questions, the answers were always about using some other function, like outer() or R natural vectorization... but I don't think those will work here. Thanks in advance!

Rodrigo
  • 4,706
  • 6
  • 51
  • 94
  • 1
    You aren't going to speed up drawing by moving this to any apply function. Using the inherent vectorization present in `rect` and `segments` might buy you some speed, though. Typically, though, the bottleneck with creating graphics is the actual drawing, and there probably isn't a way to speed that up. – joran Jan 15 '14 at 19:58
  • I have to disagree with you, because I can see the symbols being drawn, and when there is a gap without symbols, anyway the function takes too long to cross that gap (without drawing anything). But I'll try that vectorization you mention. Thanks. – Rodrigo Jan 15 '14 at 20:03
  • No, the delay you're seeing has nothing to do with the differences between apply and a for loop. The apply version would still have to cycle through those indexes with nothing to draw, and it won't do that any faster. – joran Jan 15 '14 at 20:06
  • Some folks still say *apply is faster in some occasions. See, for instance: http://stackoverflow.com/a/3584290/1086511 – Rodrigo Jan 15 '14 at 20:21
  • I'm aware of that, but your case is nothing like that example. Trust me, the slow part of drawing graphics is the actual drawing of graphics, and that has to be done no matter what looping semantics you use. – joran Jan 15 '14 at 20:23
  • OK, thank you then! I'll post the results of vectorization. – Rodrigo Jan 15 '14 at 20:25
  • Possible alternatives: instead of all those `rect` and `segment` calls, try to turn your vertices into a matrix of `x` and `y` coordinates (in the right order) and just `plot(x,y,type='l')` . You can probably vectorize the calculation of the vertices as well. – Carl Witthoft Jan 15 '14 at 20:32
  • @John that was going to be my second suggestion :-) – Carl Witthoft Jan 15 '14 at 20:34
  • Sorry, Carl, withdrew it but here's a modified version. It's the little tiny squares that are taking awhile. So, use `points` and pick some good symbols in there (see `?points`) for drawing those little squares. All you need is a list of the locations and list of symbol values for the `pch` argument. You can also put the coloured squares up the same way using a larger symbol size (`cex`), the `col` argument, and `pch = 15`. – John Jan 15 '14 at 20:38
  • (when I said list of points I meant vector of x locations and vector of y locations for the centre of the symbols) – John Jan 15 '14 at 20:45
  • Thank you John and Carl, I need to try all those options to see the quality of the final image x speed. – Rodrigo Jan 15 '14 at 20:57
  • Actually, vectorizing the rect() and segments() speed up things a lot! – Rodrigo Jan 15 '14 at 21:59

1 Answers1

1

While I agree that you will likely not get any speed up from switching to *pply, here is how you would do it:

nx <- 1:10
ny <- 1:10

mapply(
  function(i, j) {
    x1 <- xmin + (i-1) * size #size is the lateral size of the quadricules = 0.5
    x2 <- xmin + i*size
    y1 <- ymin + (j-1)*size
    y2 <- ymin + j*size
    # do whatever
  },
  i=rep(nx, each=length(ny)), 
  j=rep(ny, length(nx))
)

The main thing to realize is that you can easily create every combination of i and j up front by using rep with and without the each argument.

Generally, the key speed advantage of *pply over other methods is pre-allocating the memory required to store the result so you don't have a growing object as you iterate. In your case, you're not writing to an object, so this doesn't apply.

The other benefits are clarity in code as well as simplicity in coding.

BrodieG
  • 51,669
  • 9
  • 93
  • 146