8

I'm trying to plot from a rather complex array in R. I want to produce an image with 3 by 3 graphs, each with red and blue points on it.

I've got a structure of apply loops which works, but I'd like to change the y maximum value by each row.

I would normally do this using a counter, like i, in other languages. But the apply thing in R is completely baffling me!

par(mfrow=c(3,3),pty="s")             # a 3 by 3 graphic
set.seed(1001)

x <- 1:54                             # with 1 to 54 along the x axis

y <- array(rexp(20), dim=c(54,6,3,2)) # and the y axis coming 
                                      # from an array with dimensions as shown.

ymax <- c(1,0.1,0.3)                  # three different y maximum values I want 
                                      # on the graphic, one for each row of graphs

counter <- 1                          # a counter, starting at 1, 
                                      # as I would use in a traditional loop

apply(y[,3:5,,], 2, function(i)       # my first apply, which only considers
                                      # the 3rd, 4th and 5th columns
    {

    yy <- ymax[counter]               # using the counter to select my ylimit maximum

    apply(i, 2, function (ii)         # my second apply, considering the 3rd 
                                      # dimension of y
        {
            plot(x,ii[,1], col="blue", ylim=c(0,yy)) 

                                      # plotting the 4th dimension

                points(x,ii[,2], col="red") 

                                      # adding points in a different 
                                      # colour from the 4th dim. 

    })
})

Thank you in advance for your thoughts, they are very much appreciated!

Cheers Kate

Kate2808
  • 129
  • 2
  • 7
  • You shouln't use `apply` if you only want side efects such as plotting. Use `for` loops or reshape your data and use ggplot2 or lattice. – Roland Jan 09 '14 at 20:09

3 Answers3

16

I think it might be easier to use loops in this case. Also, your code does not have a line to update the counter, like counter <- counter + 1. From inside apply you will need to assign to the global environment using <<-, note the doubled smaller < sign. An example using lapply, e.g.

Single lapply usage

counter <- 0
lapply(1:3, function(x) {
  counter <<- counter + 1
  cat("outer", counter, "\n")
  plot(1:10, main=counter)
})

Or nested usage of lapply

counter <- 0
lapply(1:3, function(x) {
  counter <<- counter + 1
  cat("outer", counter, "\n")
  lapply(1:3, function(x) {
    counter <<- counter + 1
    cat("inner", counter, "\n") 
    plot(1:10, main=counter)     
  })
})
Mark Heckmann
  • 10,943
  • 4
  • 56
  • 88
  • Hey, thanks, I've never used lapply before, but I will give it a try. I was using loops before, but it was so incredibly slow I swapped to apply. Thanks for the hints though. Very much appreciated. – Kate2808 Jan 13 '14 at 09:30
9

The key thing here is to use lapply on the index rather than on the array itself, so then you can use the index to subset both your y limits and the array ahead of the inner loop. This also avoids having to use the <<- construct.

Simplified your data a bit:

par(mfrow=c(3,3),pty="s")             # a 3 by 3 graphic
set.seed(1001)
x <- 1:10                             # with 1 to 54 along the x axis
dims <- c(10,6,3,2)
y <- array(rexp(prod(dims)), dim=c(10,6,3,2)) # and the y axis coming 
ymax <- c(1,0.1,0.3)

lapply(1:3, function(counter, arr) {
  apply(
    arr[ ,counter + 2, , ], 2, 
    function(ii) {
      plot(x, ii[,1], col="blue", ylim=c(0,ymax[counter]))
      points(x, ii[,2], col="red") 
    } )
  },
  arr=y
)

enter image description here

BrodieG
  • 51,669
  • 9
  • 93
  • 146
  • Wicked, thanks for that. Still getting my head around the different apply variations, this illustrates the difference really nicely. Thanks again – Kate2808 Jan 13 '14 at 09:32
  • @Kate2808, see previous comment, forgot you wouldn't be notified unless I referenced you. – BrodieG Jan 13 '14 at 13:54
2

I am not going to rewrite your code as I must say it is difficult to comprehend, but this will help: you can update a variable outside of the scope of apply by using <<- assignment, e.g. to update some external "counter"

Oleg Sklyar
  • 9,834
  • 6
  • 39
  • 62
  • Hey, thanks for the tip about the <<- symbol. I'm not a natural programmer, although I enjoy it in an odd way. So thanks for answering, one day I'm sure my code with be clearer to others :-) Cheers – Kate2808 Jan 13 '14 at 09:29