4

I have a data frame, df, representing a correlation matrix, with this heatmap with example extrema. Every point has, obviously, (x,y,value): Heatmap

I am looking into getting the local extrema. I looked into argrelextrema, I tried it on individual rows and the results were as expected, but that didn't work for 2D. I have also looked into scipy.signal.find_peaks, but this is for a 1D array.

Is there anything in Python that will return the local extrema over/under certain values(threshold)? Something like an array of (x, y, value)? If not then can you point me in the right direction?

Adam
  • 3,407
  • 2
  • 29
  • 52

1 Answers1

1

This is a tricky question, because you need to carefully define the notion of how "big" a maximum or minimum needs to be before it is relevant. For example, imagine that you have a patch containing the following 5x5 grid of pixels:

im = np.array([[ 0 0 0 0 0
                 0 5 5 5 0
                 0 5 4 5 0
                 0 5 5 5 0
                 0 0 0 0 0. ]])

This might be looked at as a local minimum, because 4 is less than the surrounding 5s. OTOH, it might be looked at as a local maximum, where the single lone 4 pixel is just "noise", and the 3x3 patch of average 4.89-intensity pixels is actually a single local maximum. This is commonly known as the "scale" at which you are viewing the image.

In any case, you can estimate the local derivative in one direction by using a finite difference in that direction. The x direction might be something like:

k = np.array([[ -1 0 1 
                -1 0 1
                -1 0 1. ]])

Applying this filter to the image patch defined above gives:

>>> cv2.filter2D(im, cv2.CV_64F, k)[1:-1,1:-1]
array([[  9.,   0.,  -9.],
       [ 14.,   0., -14.],
       [  9.,   0.,  -9.]])

Applying a similar filter in the y direction will transpose this. The only point in here with a 0 in both the x and the y directions is the very middle, which is the 4 that we decided was a local minimum. This is tantamount to checking that the gradient is 0 in both x and y.

This whole process can be extended to find the larger single local maximum that we have identified. You'll use a larger filter, e.g.

k = np.array([[ -2, -1, 0,  1,  2],
              [ -2, -1, 0,  1,  2], ...

Since the 4 makes the local maximum an approximate thing, you'll need to use some "approximate" logic. i.e. you'll look for values that are "close" to 0. Just how close depends on just how fudgy you are willing to allow the local extrema to be. To sum up, the two fudge factors here are 1. filter size and 2. ~=0 fudge factor.

Him
  • 4,322
  • 2
  • 17
  • 57