1

Referring to this previous question:

Remove all-zero rows in a 2D matrix

import numpy as np

data = np.array([[4, 1, 1, 2, 0, 4],
                 [3, 4, 3, 1, 4, 4],
                 [1, 4, 3, 1, 0, 0],
                 [0, 4, 4, 0, 4, 3],
                 [0, 0, 0, 0, 0, 0]])

data = data[~(data==0).all(1)]
print(data)

Output :

    [[4 1 1 2 0 4]
     [3 4 3 1 4 4]
     [1 4 3 1 0 0]
     [0 4 4 0 4 3]]

ok so far so good but what if i add null column?

 data = np.array([[0, 4, 1, 1, 2, 0, 4],
                  [0, 3, 4, 3, 1, 4, 4],
                  [0, 0, 1, 4, 3, 1, 0],
                  [0, 0, 4, 4, 0, 4, 3],
                  [0, 0, 0, 0, 0, 0, 0]])

Output is

          [[0 4 1 1 2 0 4]
           [0 3 4 3 1 4 4]
           [0 1 4 3 1 0 0]
           [0 0 4 4 0 4 3]]

which is not what i want.

Basically if my matrix is :

            [[0, 0, 0, 0, 0, 0, 0, 0, 0],
             [0, 0, 4, 1, 1, 2, 0, 4, 0],
             [0, 0, 3, 4, 3, 1, 4, 4, 0],
             [0, 0, 1, 4, 3, 1, 0, 0, 0],
             [0, 0, 0, 4, 4, 0, 4, 3, 0],
             [0, 0, 0, 0, 0, 0, 0, 0, 0]]

The output i'll be expecting is

        [[4 1 1 2 0 4]
         [3 4 3 1 4 4]
         [1 4 3 1 0 0]
         [0 4 4 0 4 3]]
Nelly
  • 81
  • 6

2 Answers2

2

Here's one approach -

def reduced_box(a):
    # Store shape info
    M,N = a.shape

    # Mask of valid places in the array
    mask = a!=0

    # Get boolean array with at least a valid one per row
    m_col = mask.any(1)

    # Get the starting and ending valid rows with argmax.
    # More info : https://stackoverflow.com/a/47269413/
    r0,r1 = m_col.argmax(), M-m_col[::-1].argmax()

    # Repeat for cols
    m_row = mask.any(0)
    c0,c1 = m_row.argmax(), N-m_row[::-1].argmax()

    # Finally slice with the valid indices as the bounding box limits
    return a[r0:r1,c0:c1]

Sample run -

In [210]: a
Out[210]: 
array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 4, 1, 0, 2, 0, 4, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 4, 0, 1, 0, 0, 0],
       [0, 0, 0, 4, 0, 0, 4, 3, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0]])

In [211]: reduced_box(a)
Out[211]: 
array([[4, 1, 0, 2, 0, 4],
       [0, 0, 0, 0, 0, 0],
       [1, 4, 0, 1, 0, 0],
       [0, 4, 0, 0, 4, 3]])
Divakar
  • 218,885
  • 19
  • 262
  • 358
1

You can use scipy.ndimage.measurements.find_objects:

import numpy as np
from scipy.ndimage.measurements import find_objects

data = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0],
                 [0, 0, 4, 1, 1, 2, 0, 4, 0],
                 [0, 0, 3, 4, 3, 1, 4, 4, 0],
                 [0, 0, 1, 4, 3, 1, 0, 0, 0],
                 [0, 0, 0, 4, 4, 0, 4, 3, 0],
                 [0, 0, 0, 0, 0, 0, 0, 0, 0]])
data[find_objects(data.astype(bool))[0]]
#array([[4, 1, 1, 2, 0, 4],
#       [3, 4, 3, 1, 4, 4],
#       [1, 4, 3, 1, 0, 0],
#       [0, 4, 4, 0, 4, 3]])
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99