pythonnumpy

Python Slicing using tuples and : slice operator


I want a generic way to get each column from an ndarray so I can write them one at a time to another file. The file only accepts 1 column at a time. I also need to know the index numbers for the yz coordinates to construct new names for column.

The input file contains many ndarrays which are mostly 1 dimensional. But, some are 2D or 3D arrays. I am trying to find a generic way to handle n dimensions. The code below works for a 3D array (x = rows, y = cols, z = depth).

import numpy as np
    
curve = np.arange(5000).reshape(10, 4,125)

if len(curve.shape) > 1:
  for i, x in np.ndenumerate(curve[0,...]):
    d = curve[:, i[0], i[1]]
    s = '_' + '_'.join(str(e) for e in i)
    print("Vp" + s)

Slicing the "top" row off gives an object that preserves the yz indices in an order to iterate columns.

For a tuple of indices, such as i = (y,z), I have to reference the values of i for indices to use with the : operator. This returns 500 (4 x 125) ndarrays with shape (10,). Success.

    d = curve[:, i[0], i[1]]

If I could combine the tuple i with the slice operator I could process any ndarray shape. Substituting the following line instead

    d = curve[:, i]

This sort of works but stops with the error below.

So,

Error using curve[:, i]

(10, 4, 125) <- Shape of input 3D ndarray

Index tuple: (0, 0) extracted ndarray of shape(10, 2, 125)

Vp_0_0

Index tuple: (0, 1) extracted ndarray of shape(10, 2, 125)

Vp_0_1
Index tuple: (0, 2) extracted ndarray of shape(10, 2, 125)

Vp_0_2

Index tuple: (0, 3) extracted ndarray of shape(10, 2, 125)

Vp_0_3

---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-84-2aa0e9bae9df> in <cell line: 0>()

      6 if len(curve.shape) > 1:
      
      7   for i, x in np.ndenumerate(curve[0,...]):
      
----> 8     d = curve[:, i]

      9     print("Index tuple: " + str(i) + " extracted ndarray of shape" + str(d.shape))
      
     10     s = '_' + '_'.join(str(e) for e in i)
     

IndexError: index 4 is out of bounds for axis 1 with size 4

Solution

  • When you do

    curve[:, i]
    

    you are indexing with a tuple where the first element is a slice, and the second element is a tuple. This will invoke advanced indexing.

    You could do

    curve[:, *i]
    

    to “explode” i at the current level.

    To build such an indexing tuple programatically, you cannot say, for example

    i = (1, :, 2) # won’t work
    

    because : only works at the top level of a slicing. Instead, you can use the built-in slice() function to create a slice object:

    A = np.arange(27).reshape(3, 3, 3)
    i = (1, slice(None), 1)
    A[i] # => 10, 13, 16