1

I'm wondering if there is a better of writing array cropping/slicing from the end, but in a programmatic way. This means, that the crop size can actually be 0, and I have multiple dimension e.g. a 5D Tensor.

Here a simple example in 2D:

# This is just to have some dummy data
import numpy as np
A = np.random.rand( 10,5)

# The easy standard case:
ix = 1
iy = 1
B = A [ ix:-ix , iy:-iy]   # This works

# Now the trickier case, where I'm looking for a pythonic way of doing it.
iy = 0
# Using the code from above, does not what I want => 2nd dim ==0 
C1 = A [ ix:-ix , iy:-iy]

# The next line gives the result that I want but hard coded
C2 = A [ ix:-ix ,   :   ]

# The next line also gives me what I want, but gets completely unreadable
# for real variable names and multiple dimensions
C3 = A [ ix:A.shape[0]-ix : iy:A.shape[1]-iy] 


# Is there something like this in numpy, similar to Matlab?
C4 = A [ ix:end-ix     , iy:end-iy ]
C5 = A [ ix:np.end-ix  , iy : np.end-iy ]

I know it doesn't look so bad for 2D but if you have multiple dimensions and real variable names, the code easily messes up. So is there something like "end" from Matlab here in python, or some other more pythonic way?

1
  • Indexing can always be done with a tuple, x[idx]. A number of the numpy functions construct a such a tuple from lists or even arrays. Look also at the np.lib.indextricks.py to see the clever tricks behind objects like np.r_ and np.ogrid. Commented May 24, 2018 at 17:08

2 Answers 2

1

You should use slice(None). For readability, you can wrap this in a simple function:

def s(k):
    return slice(None) if k==0 else slice(k, -k)

C1 = A [ s(ix) , s(iy) ]
Sign up to request clarification or add additional context in comments.

2 Comments

Having the helper handle building a single slice object looks like a cleaner design than what I picked, but your (grace-period) edit makes s(1, -0) produce 1:0 instead of 1:.
@user2357112, True. I've made my example more specific. Obviously your solution is more generic.
0

There's no end. The best you can do is wrap things up in a helper function:

def crop(arr, *crop_lengths):
    if len(crop_lengths) > arr.ndim:
        raise TypeError('Not enough dimensions to crop.')
    slices = [slice(i, axis_len-i) for (i, axis_len) in zip(crop_lengths, arr.shape)]
    return arr[tuple(slices)]

Usage example:

ix = 1
iy = 0
cropped = crop(A, ix, iy)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.