aseyffert aseyffert - 1 month ago 5x
Python Question

Building a tuple containing colons to be used to index a numpy array

I've created a class for dealing with multidimensional data of a specific type. This class has three attributes: A list containing the names of the axes (self.axisNames); a dictionary containing the parameter values along each axis (self.axes; keyd using the entries in axisNames); and a numpy array containing the data, with a dimension for each axis (self.intensityArr).

The class also has functions that dynamically add new axes depending on what I need for a specific case, which makes indexing the intensityArr a tricky proposition. To make indexing better I've started writing a function to build the index I need:

Inside class:

def indexIntensityArr(self,indexSpec):
# indexSpec is a dictionary containing axisName:indexVal entries (indexVal is an int)
# I want the function to return a tuple for use in indexing (see below def)
indexList = []
for axis in self.axisNames:
if axis in indexSpec:
# <do something to add : to index list (tuple)>
return tuple(indexList)

Outside class:

# ... create an instance of my class called myBlob with 4 dimensions ...

mySpec = {'axis1':10,'axis3':7}
mySlicedArr = myBlob.intensityArr[myBlob.indexIntensityArr(mySpec)]

I expect the above to result in mySlicedArr being a 2-dimensional array.

What do I need to put in the 'else' clause to get an : (or equivalent) in the tuple I use to index the intensityArr? Is this perhaps a bad way to solve the problem?


Inside indexing [], a : is translated to a slice, and the whole thing is passed to __getitem__ as a tuple

indexList = []
for axis in self.axisNames:
    if axis in indexSpec:

There are several numpy functions that use an indexing trick like this - that is build up a tuple of index values and slices. Or if they need to vary it, they'll start with a list, which can mutate, and convert it to a tuple right before use. (e.g. np.apply_along_axis)

Yes, the full spec for slice is slice(start, stop, step), with start and stop optional. Same as for np.arange or range. And None is equivalent to the unspecified values in a : expression.

A little custom class in translates the : notation into slices:

In [61]: np.s_[:,:1,0:,::3]
(slice(None, None, None),
 slice(None, 1, None),
 slice(0, None, None),
 slice(None, None, 3))