1

I have a list of three two-dimensional arrays that contains x, y and z coordinates of some points (to draw a surface from them, I store them in two-dimensional arrays, like surface plots in MATLAB).

Example:

points <- list(x=matrix(c(1, 2, 3, 4), nrow=2), 
               y=matrix(c(5, 6, 1, 4), nrow=2), 
               z=matrix(c(1, 9, 2, 3), nrow=2))

This is a representation of points with coordinates (1, 5, 1), (2, 6, 9) and so on (4 points total).

Now I have to multiply every (x, y, z) point with some fixed matrix C (to rotate my surface) and return the result in the same form of list of two-dimensional matrixes.

I can do it in this way with loops:

apply_matrix <- function(C, points) {
  x <- points$x
  y <- points$y
  z <- points$z
  n <- nrow(x)
  m <- ncol(x)
  outx <- matrix(rep(0, n*m), nrow = n)
  outy <- matrix(rep(0, n*m), nrow = n)
  outz <- matrix(rep(0, n*m), nrow = n)

  for (i in 1:nrow(x)) {
    for (j in 1:ncol(x)) {
      out <- C %*% c(x[i, j], y[i, j], z[i, j])
      outx[i,j] <- out[1,]
      outy[i,j] <- out[2,]
      outz[i,j] <- out[3,]
    }
  }
  list(x=outx,y=outy,z=outz)
}

However, I'm looking for more efficient loop-free solution.

I believe it is possible to convert the list to three-dimensional matrix and then ask R to multiply my matrix C to this three-dimensional matrix using appropriate dimensions, but cannot figure out how to do it.

Ilya V. Schurov
  • 7,687
  • 2
  • 40
  • 78
  • It's unclear to me why you would store xyz data in a set of matrices. Why not just `points <- list(x= c(1, 2, 3, 4) , y=c(5, 6, 1, 4), z=c(1, 9, 2, 3) )`. The matrix form does not seem to add any information. I do know how to perform the requested transformation in the structure that I suggest. – IRTFM Mar 07 '16 at 01:31
  • Parametric surface plotters like plotly (see e.g. the last solution we discussed here: http://stackoverflow.com/a/35821700/3025981) require points to be presented in 2D array/matrix form. This form adds information on which points are neighbors that allow to construct appropriate meshes. – Ilya V. Schurov Mar 07 '16 at 11:21

1 Answers1

1

Here I first convert the list to a three-dimensional array and then also return one:

C <- matrix(rnorm(3 * 3), 3)
ar <- array(unlist(points), c(dim(points[[1]]), 3))
aperm(apply(ar, 1:2, `%*%`, x = t(C)), c(2, 3, 1))
Julius Vainora
  • 47,421
  • 9
  • 90
  • 102
  • Thanks! I guessed that I need one of that `apply` functions, but it is virtually impossible to remember which one is correct :) Actually, I need to get the same data structure as I have initally (list of x, y, z), so I changed your code a little bit: `out <- apply(ar, 1:2, `%*%`, x = t(C)); list(x=out[1,,],y=out[2,,],z=out[3,,])`. I'm not sure how to do the last conversion more elegant, but it works. – Ilya V. Schurov Mar 07 '16 at 15:32
  • @IlyaV.Schurov, you could also do `unlist(apply(out, 1, list), rec = FALSE)`. – Julius Vainora Mar 07 '16 at 15:58