nibabel icon indicating copy to clipboard operation
nibabel copied to clipboard

Transposing ArrayProxies

Open effigies opened this issue 3 years ago • 0 comments

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.

effigies avatar Sep 07 '22 14:09 effigies