5

I have an array that I'd like to split into sub-arrays based on the obvious and non-overlapping rectangles:

>>> A = array([[  0.,  nan,   2.,  nan,   4.,  nan,    6,  nan],
               [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan],
               [ nan,  nan,  nan,  nan,   20,  nan,   22,  nan],
               [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan],
               [ 32.,  nan,  34.,  nan,  36.,  nan,  nan,  nan],
               [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan],
               [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan],
               [ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan]])

These locations are easily findable with np.argwhere, and it seems natural to do it the np.split. My desired output is

>>> np.split_2d(A)
    (array([[  0.,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]])
     array([[  2.,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]])
     array([[ 32.,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]])
     array([[ 34.,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]
            [ nan,  nan ]])
     array([[ 4.,  nan ]
            [ nan,  nan ]])
     array([[ 6.,  nan ]
            [ nan,  nan ]])
     array([[ 20,  nan ]
            [ nan,  nan ]])
     array([[ 22,  nan ]
            [ nan,  nan ]])
     array([[ 36.,  nan,  nan,  nan ]
            [ nan,  nan,  nan,  nan ]
            [ nan,  nan,  nan,  nan ]
            [ nan,  nan,  nan,  nan ]]))
     ...

np.split and the corresponding components vsplit, hsplit and dsplit and only work along a specified axis and an array of indices.

A question on binning answers a similar question, but in my case the bins are not regularly spaced and not the same size.

In my case, I'm trying to approximate an image from only a few samples. Hence, I want the image to be split up in the most obvious and intuitive way. I want the image to be divided up into quadrants essentially. For example, the lower right corner of this image would belong to the 36 term and not the 22 term.

Is there an easy way to do this, or do I have to parse it all myself?

Community
  • 1
  • 1
Scott
  • 2,568
  • 1
  • 27
  • 39
  • Hi Scott, will you please add an example of your desired output? – Jesuisme Dec 27 '13 at 04:33
  • It was included, but I made it more clear and fixed it up a bit. – Scott Dec 27 '13 at 20:33
  • The rectangles are not all that obvious, since this kind of tiling isn't unique. The bottom right could belong to either 22 or 36. There appears to be an implied hierarchy to the problem though. Would a recursive splitting in two along rows/columns, conditional on the non-nanness of the newly created corners achieve your goal? – Eelco Hoogendoorn Dec 29 '13 at 22:22
  • Right. I should clarify. This array is the output of the wavelet transform, meaning that it should be split up into more square shapes. 36 belongs to a more coarse term and 4,6,20 and 22 belong to a finer term. I added more detail to the question. – Scott Dec 30 '13 at 01:12

1 Answers1

2
def recurse(A):
    if A.shape[0]>A.shape[1]:   #split longest axis first
        if not np.isnan( A[0,A.shape[1]//2]):
            return [rect for part in np.split(A, 2, axis=1) for rect in recurse(part)]
        if not np.isnan( A[A.shape[0]//2,0]):
            return [rect for part in np.split(A, 2, axis=0) for rect in recurse(part)]
    else:
        if not np.isnan( A[A.shape[0]//2,0]):
            return [rect for part in np.split(A, 2, axis=0) for rect in recurse(part)]
        if not np.isnan( A[0,A.shape[1]//2]):
            return [rect for part in np.split(A, 2, axis=1) for rect in recurse(part)]
    return [A]

This produces the desired split for this dataset; but it hinges on several assumptions about the layout of the data, which you havnt specified, and which may not hold. But one could modify the general idea to accommodate a variety of circumstances.

Eelco Hoogendoorn
  • 10,459
  • 1
  • 44
  • 42