Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib contour plot does not extract exact contours

I am having difficulties extracting the exact contour of the following data: (you can already see the contour by just looking at the data)

data = np.array(
      [[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])

If I plot it:

plt.imshow(data)

enter image description here

However, when I try to extract the contours using:

plt.contour(data, levels = np.unique(data))

enter image description here

As you can see the contour does not follow the sharp corner of the actual data. If I overlay both plots:

enter image description here

Here is the complete code:

import numpy as np
import matplotlib.pyplot as plt

data = np.array([[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])

plt.imshow(data)
plt.show()
plt.contour(data, levels=np.unique(data), cmap="jet")
plt.colorbar()
like image 558
james Avatar asked Jun 22 '26 21:06

james


1 Answers

The contours are drawn using a marching squares algorithm to compute contour locations, it interpolates between the grid points.

Maybe you're looking for the discrete region boundaries: these can be retrieved like this:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

data = np.array([[ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  1.        ,  1.        ],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277],
       [ 1.46184395,  1.46184395,  1.46184395,  4.24552277,  4.24552277]])


def region_borders(data, value, color, **kwargs):
    v = np.argwhere(np.diff((data == value).T, axis=0))
    vlines = np.array(list(zip(v + [.5, -.5], v + [.5, .5])))
    
    h = np.argwhere(np.diff((data == value).T, axis=1))
    hlines = np.array(list(zip(h + [-.5, .5], h + [.5, .5])))
    
    if len(vlines) and len(hlines):
        lines = np.vstack((vlines, hlines))
    elif len(vlines):
        lines = vlines
    else:
        lines = hlines
    return mpl.collections.LineCollection(lines, colors=color, **kwargs)


contours = np.unique(data)

fig, ax = plt.subplots(ncols=len(contours)+1, sharex=True, sharey=True, layout='constrained')
im = ax[0].matshow(data, cmap='jet', aspect='auto')
fig.colorbar(im, ax=ax[-1])

norm = mpl.colors.Normalize(data.min(), data.max())
for i, value in enumerate(contours, 1):
    ax[i].add_collection(region_borders(data, value, mpl.cm.jet(norm(value)), lw=2))
    ax[i].set_title(value)

enter image description here

like image 170
Stef Avatar answered Jun 25 '26 11:06

Stef



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!