matplotlib icon indicating copy to clipboard operation
matplotlib copied to clipboard

[Bug]: Contour segments changed after clabel

Open wei-lingfeng opened this issue 1 year ago • 1 comments

Bug summary

ax.clabel changes the contour segments itself as it removes the label part of the contours. image

Python 3.11.8 + Matplotlib 3.7.1 doesn't change the contour itself, where as Python 3.11.9 + Matplotlib 3.9.1 changes it. Is this an intended change?

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

size = 1000
sigma_x = 1.
sigma_y = 1.

x = np.linspace(-3, 3, size)
y = np.linspace(-3, 3, size)

xx, yy = np.meshgrid(x, y)
z = (1/(2*np.pi*sigma_x*sigma_y) * np.exp(-(xx**2/(2*sigma_x**2)
     + yy**2/(2*sigma_y**2))))

extent = [x[0], x[-1], y[0], y[-1]]
fig, ax = plt.subplots()
ax.imshow(z, extent=extent)
cs = ax.contour(z, extent=extent, colors='w')
seg1 = cs.allsegs[3][0]
ax.clabel(cs, cs.levels, fmt='%.5f%%', fontsize=15)
seg2 = cs.allsegs[3][0]
plt.show()

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3))
ax1.plot(seg1[:, 0], seg1[:, 1], marker='.', ms=1)
ax1.set_title('Before ax.clabel')
ax2.plot(seg2[:, 0], seg2[:, 1], marker='.', ms=1)
ax2.set_title('After ax.clabel')
plt.show()

Actual outcome

Contour segments changed after ax.clabel. The labeled part is removed from the contour

Expected outcome

Keep the contour segment unchanged

Additional information

Python 3.11.8 + Matplotlib 3.7.1 doesn't change the contour itself, where as Python 3.11.9 + Matplotlib 3.9.1 changes it. Is this an intended change?

Operating system

MacOS

Matplotlib Version

3.9.1

Matplotlib Backend

No response

Python version

3.11.9

Jupyter version

No response

Installation

None

wei-lingfeng avatar Aug 01 '24 00:08 wei-lingfeng

Thanks for the clear report @wei-lingfeng!

In v3.7 allsegs was an attribute that was defined once during the ContourSet's instantiation https://github.com/matplotlib/matplotlib/blob/6f10acc80b359d966c957773608bb84b733ee963/lib/matplotlib/contour.py#L822-L823

At v3.8.0 the ContourSet had a significant re-write and allsegs became a property that is calculated from the current state of the contour paths https://github.com/matplotlib/matplotlib/blob/8fb842c78f1b57b13a3d0fe63e83f3d31694f887/lib/matplotlib/contour.py#L948-L950

Usually the paths don't change so this difference shouldn't matter, but the contour labelling does work by creating gaps in them. While writing this I saw that @anntzer has some thoughts on that (https://github.com/matplotlib/matplotlib/issues/27081#issuecomment-2262401443) so I will stop here.

rcomer avatar Aug 01 '24 08:08 rcomer