[SOLVED] how does the np.index_exp[] work in the 3D voxel / volumetric plot with rgb colors example

Issue

I am reading the example: https://matplotlib.org/stable/gallery/mplot3d/voxels_rgb.html#sphx-glr-gallery-mplot3d-voxels-rgb-py about creating a 3d sphere.
But I don’t understand how the indexing works in the example. Can any one help me to understand. Thanks

> def midpoints(x):
> sl = ()
> for i in range(x.ndim):
>>    x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]])
>>    sl += np.index_exp[:]
>>    print(np.index_exp[:-1])
>>    print(x[np.index_exp[:-1]])
I know the "index_exp[:-1]" returns (slice(None,None,-1),) and "x[index_exp[:-1]]" will give result like this:
[[[0 0 0],
  [0 0 0],
  [0 0 0]],
[[1 1 1],
  [1 1 1],
  [1 1 1]]]

But I don't understand how the ```x[index_exp[:-1]]``` in the for loop only shows:
[[[1 1 1],
  [1 1 1],
  [1 1 1]]]

Solution

In the example, x, is one of the (17,17,17) arrays produced by

In [208]: r, g, b = np.indices((17, 17, 17)) / 16.0
     ...: rc = midpoints(r)
     ...: gc = midpoints(g)
     ...: bc = midpoints(b)

indices is like meshgrid and mgrid, creating grid arrays.

I haven’t used np.index_exp, but I see it’s the same as np.s_, except it always returns a tuple

In [225]: x = r.copy()
In [226]: ()+np.index_exp[:-1]    # so this tuple can joined with sl
Out[226]: (slice(None, -1, None),)
In [227]: x[()+np.index_exp[:-1]].shape
Out[227]: (16, 17, 17)
In [228]: x[:-1].shape
Out[228]: (16, 17, 17)

so

x = (x[sl + np.index_exp[:-1]] + x[sl + np.index_exp[1:]])/2.0

for the initial sl, this is

x = (x[:-1] + x[1:])/2.0

x[1:]-x[:-1] is widely used to take the difference between adjacent elements, np.diff. Here it just acts on the first dimension (of 3). So this is just the mean of adjacent points. Note both x[:-1] and x[1:] are (16,17,17) arrays.

The next bit just adds a [:] slice to sl:

In [230]: sl += np.index_exp[:]
In [231]: sl
Out[231]: (slice(None, None, None),)
In [232]: sl + np.index_exp[:-1]
Out[232]: (slice(None, None, None), slice(None, -1, None))

So this is doing

 x[:, :-1]     # which should be a (17,16,17) array

and the next iteration x[:,:, :-1] # (17,17,16)

This r varies only in the first dimension, so can compare its values with the midpoints with:

In [249]: r1 = midpoints(r)
In [250]: r[:5,0,0]
Out[250]: array([0.    , 0.0625, 0.125 , 0.1875, 0.25  ])
In [251]: r1[:4,0,0]
Out[251]: array([0.03125, 0.09375, 0.15625, 0.21875])

So the use index_exp just allows them to write the (x[:-1]+x[1:])/2 averaging in a general way that applies to all 3 dimensions the r, g.b arraus/

Answered By – hpaulj

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *