nibabel
nibabel copied to clipboard
Transposing ArrayProxies
For an ArrayProxy with contiguous data, it is possible to do something like:
class ArrayProxy:
@property
def T(self):
ret = copy(self)
ret.order = 'C' if self.order == 'F' else 'F'
ret.shape = self.shape[::-1]
return ret
This would permit gross manipulation of arrays without loading them into memory, and in particular would make it very cheap to flip a CIFTI-2 where the BrainModelAxis is dimension 1 to dimension 0 (typical for Connectome WB tools, but weird when you expect spatial axes first). However, it could not be implemented in all ArrayProxys.
We have already done something similar with reshape:
https://github.com/nipy/nibabel/blob/2838c06389165c9563551d35988df793fb15263d/nibabel/arrayproxy.py#L431-L435
I wonder if it's time to start thinking about a consistent interface:
class BaseArrayProxy(np.ArrayLike):
# Subclasses implement JIT loading, scaling, casting
def __array__(self, dtype=None) -> np.ndarray: ...
def __getitem__(self) -> np.ndarray: ...
# Generic properties like shape, dtype, ndim
@property
def T(self) -> np.ArrayLike:
return np.transpose(self)
def reshape(self, shape) -> np.ArrayLike:
return np.reshape(self, shape)
class ContiguousArrayProxy(BaseArrayProxy):
# Implements optimizations
# Requires order parameter
@property
def T(self): ...
def reshape(self, shape): ...
class ArrayProxy(ContiguousArrayProxy):
# Implement current ArrayProxy: (offset, shape, dtype, slope, inter)
I think, for instance, that AFNIArrayProxy might better fit as a subclass of ContiguousArrayProxy, since it can have different scale-factors per time point.