8

Working in NumPy, I understand how to slice 2D arrays from a 3D array using this article.

Depending on the axis I'd want to slice in:

array = [[[0  1  2]
          [3  4  5]
          [6  7  8]]

         [[9  10 11]
          [12 13 14]
          [15 16 17]]

         [[18 19 20]
          [21 22 23]
          [24 25 26]]]

Slicing would give me:

i_slice = array[0]

    [[0  1  2]
     [3  4  5]
     [6  7  8]]

j_slice = array[:, 0]

    [[0  1  2]
     [9  10 11]
     [18 19 20]]

k_slice = array[:, :, 0]

    [[0  3  6]
     [9  12 15]
     [18 21 24]]

But is it possible to slice at a 45 degree angle? such as:

j_slice_down = array[slice going down starting from index 0]

    [[0  1  2]
     [12 13 14]
     [24 25 26]]

I was able to achieve this in all 3 axis's going up or down, and even wrapping all the way around... in the dark list days with many for loops... but I'm sure there must be a better way in NumPy.

Update, chosen answer:

I chose hpaulj's answer creating two coordinate arrays with np.arrange. With a little work, I was able to make it fit my needs of returning a slice at any angle, on any axis, asymmetric dimension of 3D array, and at any position, including wrapping all the way around so that it is the same dimension as the axis.

My method using np.arrange

Two np.arrange arrays were made for an x and y.

Different methods such as np.roll, incrementing, np.hstack and np.concatenate were done on the np.arrange array x axis array. y = y[::-1] for the alternate angle.

if axis is 'z': #i
    slice_notation = np.index_exp[x, y, :] 

elif axis is 'y': #k
    slice_notation = np.index_exp[x, :, y]

else: #j 
    slice_notation = np.index_exp[:, x, y]

Creates the slice expression, then I use the slice_notation to perform my needed operations in place.

The other proposed methods: np.diagonal and np.eye may be more suitable for others though as they may have different requirements than me.

2 Answers2

3
In [145]: arr[np.arange(3), np.arange(3),:]
Out[145]: 
array([[ 0,  1,  2],
       [12, 13, 14],
       [24, 25, 26]])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • 3
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Vasilisa Feb 18 '19 at 08:26
  • 1
    for small slice ranges, I like this the arrange, since you can arrange the slicing to suit if expanded … eg. a[[0,1,2],[0,1,2],:] or … a[[2,1,0],[0,1,2],:] – NaN Feb 18 '19 at 10:43
  • @hpaulj - This seems to be what I'm looking for. So for I can apply this to all axis's by placing np.arange in other placements than your example. Also, reversing the output of np.arange allows me to select in the other direction and starting in the negatives allows me to creating wrapping selections. – Enger Bewza Feb 18 '19 at 23:56
  • This is most useful for my use as I'd like to perform actions on the 3D array with the slice instead of extracting the slice out of the array. I'll play a bit further and if it's successful, I'll provide some examples and accept this answer. – Enger Bewza Feb 19 '19 at 00:00
  • 1
    `np.where(np.eye(3))` produces these same two ranges, so my answer is related to @Divakar's `eye` comment. – hpaulj Feb 19 '19 at 00:11
2

You can try with np.diagonal:

arr = np.array([[[0  ,1  ,2],
          [3  ,4  ,5],
          [6  ,7  ,8]],
         [[9  ,10 ,11],
          [12 ,13 ,14],
          [15 ,16 ,17]],
         [[18 ,19 ,20],
          [21 ,22 ,23],
          [24 ,25 ,26]]])

np.diagonal(arr).T
array([[ 0,  1,  2],
       [12, 13, 14],
       [24, 25, 26]])
Chris
  • 29,127
  • 3
  • 28
  • 51
  • 1
    np.diagonal has axis1 and axis2 as kwargs. They let you choose which diagonal slice of arr is returned. – Tls Chris Feb 18 '19 at 16:46