Reputation: 492
I am working on some data in R that consist of four-dimensional arrays composed of three spatial dimensions and a time dimension: x, y, z, t. For some of my analyses, I would like to obtain all of the data in the time dimension for a set of spatial coordinates x, y, z. Thus far, I have used the which function to obtain the indices of the spatial locations of interest. But when I go to obtain all relevant data in the time dimension corresponding to the spatial locations, I cannot find an elegant R solution and have resorted to using repmat, a ported MATLAB function.
a4d <- array(rnorm(10000), rep(10,4)) #x, y, z, t
#arbitrary set of 3d spatial indices x, y, z (here, using high values at first timepoint)
indices <- which(a4d[,,,1] > 2, arr.ind=TRUE)
str(indices)
# int [1:20, 1:3] 10 2 6 5 8 2 6 8 2 10 ...
# - attr(*, "dimnames")=List of 2
# ..$ : NULL
# ..$ : chr [1:3] "dim1" "dim2" "dim3"
#Now, I would like to use these indices to get data x, y, z for all t
#Intuitive, but invalid, syntax (also not clear what the structure of the data would be)
#a4d[indices,]
#Ugly, but working, syntax
library(pracma)
#number of timepoints
nt <- dim(a4d)[4]
#create a 4d lookup matrix
lookup <- cbind(repmat(indices, nt, 1), rep(1:nt, each=nrow(indices)))
#obtain values at each timepoint for indices x, y, z
result <- cbind(lookup, a4d[lookup])
This solution works okay for the stated purpose, but seems ugly conceptually. Ideally, I would like a 2-dimensional matrix at the end: index x time. So, in this case, with 20 x, y, z coordinates in the lookup, and 10 timepoints, a 20 x 10 matrix would be ideal where rows represent each row of indices (don't need to preserve the x, y, z, values necessarily) and each column is a timepoint.
Is there is a good way to do this in R? I have played around with do.call("[", list ... etc. and using outer and prod, but these haven't worked as I had hoped.
Thanks for any suggestions! Michael
Upvotes: 4
Views: 2886
Reputation: 1313
Accessing by each dimension individually does not work as @tilo-wiklund or I expect. Instead of 23 rows across 10 time steps, the result is a 23x23x23 cube across the 10 time steps.
r.idvdim <- a4d[indices[,1],indices[,2],indices[,3],]
r.apply <- apply(a4d, 4, `[`, indices)
r.cbind <- matrix(a4d[lookup],ncol=nt)
dim(r.idvdim) # [1] 23 23 23 10
dim(r.apply) # [1] 23 10
dim(r.cbind) # [1] 23 10
Upvotes: 1
Reputation: 89057
I think you are looking for:
apply(a4d, 4, `[`, indices)
And to check that our results match:
result1 <- matrix(result[,5], ncol = 10)
result2 <- apply(a4d, 4, `[`, indices)
identical(result1, result2)
# [1] TRUE
Upvotes: 7
Reputation: 821
I'm probably missing something, but don't you simply want a4d[indices[,1],indices[,2],indices[,3],]
?
Upvotes: 1