Skip to content

negative_linestyles kwarg in contour.py #23266

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions lib/matplotlib/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ def __init__(self, ax, *args,
hatches=(None,), alpha=None, origin=None, extent=None,
cmap=None, colors=None, norm=None, vmin=None, vmax=None,
extend='neither', antialiased=None, nchunk=0, locator=None,
transform=None,
transform=None, negative_linestyles=None,
**kwargs):
"""
Draw contour lines or filled regions, depending on
Expand Down Expand Up @@ -786,6 +786,13 @@ def __init__(self, ax, *args,

self._transform = transform

self.negative_linestyles = negative_linestyles
# If negative_linestyles was not defined as a kwarg,
# define negative_linestyles with rcParams
if self.negative_linestyles is None:
self.negative_linestyles = \
mpl.rcParams['contour.negative_linestyle']

kwargs = self._process_args(*args, **kwargs)
self._process_levels()

Expand Down Expand Up @@ -1276,11 +1283,10 @@ def _process_linestyles(self):
if linestyles is None:
tlinestyles = ['solid'] * Nlev
if self.monochrome:
neg_ls = mpl.rcParams['contour.negative_linestyle']
eps = - (self.zmax - self.zmin) * 1e-15
for i, lev in enumerate(self.levels):
if lev < eps:
tlinestyles[i] = neg_ls
tlinestyles[i] = self.negative_linestyles
else:
if isinstance(linestyles, str):
tlinestyles = [linestyles] * Nlev
Expand Down Expand Up @@ -1751,6 +1757,18 @@ def _initialize_x_y(self, z):
iterable is shorter than the number of contour levels
it will be repeated as necessary.

negative_linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, \
optional
*Only applies to* `.contour`.

If *negative_linestyles* is None, the default is 'dashed' for
negative contours.

*negative_linestyles* can also be an iterable of the above
strings specifying a set of linestyles to be used. If this
iterable is shorter than the number of contour levels
it will be repeated as necessary.

hatches : list[str], optional
*Only applies to* `.contourf`.

Expand Down
77 changes: 77 additions & 0 deletions lib/matplotlib/tests/test_contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,80 @@ def test_subfigure_clabel():
CS = ax.contour(X, Y, Z)
ax.clabel(CS, inline=True, fontsize=10)
ax.set_title("Simplest default with labels")


@pytest.mark.parametrize(
"style", ['solid', 'dashed', 'dashdot', 'dotted'])
def test_linestyles(style):
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

# Positive contour defaults to solid
fig1, ax1 = plt.subplots()
CS1 = ax1.contour(X, Y, Z, 6, colors='k')
ax1.clabel(CS1, fontsize=9, inline=True)
ax1.set_title('Single color - positive contours solid (default)')
assert CS1.linestyles is None # default

# Change linestyles using linestyles kwarg
fig2, ax2 = plt.subplots()
CS2 = ax2.contour(X, Y, Z, 6, colors='k', linestyles=style)
ax2.clabel(CS2, fontsize=9, inline=True)
ax2.set_title(f'Single color - positive contours {style}')
assert CS2.linestyles == style

# Ensure linestyles do not change when negative_linestyles is defined
fig3, ax3 = plt.subplots()
CS3 = ax3.contour(X, Y, Z, 6, colors='k', linestyles=style,
negative_linestyles='dashdot')
ax3.clabel(CS3, fontsize=9, inline=True)
ax3.set_title(f'Single color - positive contours {style}')
assert CS3.linestyles == style


@pytest.mark.parametrize(
"style", ['solid', 'dashed', 'dashdot', 'dotted'])
def test_negative_linestyles(style):
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

# Negative contour defaults to dashed
fig1, ax1 = plt.subplots()
CS1 = ax1.contour(X, Y, Z, 6, colors='k')
ax1.clabel(CS1, fontsize=9, inline=True)
ax1.set_title('Single color - negative contours dashed (default)')
assert CS1.negative_linestyles == 'dashed' # default

# Change negative_linestyles using rcParams
plt.rcParams['contour.negative_linestyle'] = style
fig2, ax2 = plt.subplots()
CS2 = ax2.contour(X, Y, Z, 6, colors='k')
ax2.clabel(CS2, fontsize=9, inline=True)
ax2.set_title(f'Single color - negative contours {style}'
'(using rcParams)')
assert CS2.negative_linestyles == style

# Change negative_linestyles using negative_linestyles kwarg
fig3, ax3 = plt.subplots()
CS3 = ax3.contour(X, Y, Z, 6, colors='k', negative_linestyles=style)
ax3.clabel(CS3, fontsize=9, inline=True)
ax3.set_title(f'Single color - negative contours {style}')
assert CS3.negative_linestyles == style

# Ensure negative_linestyles do not change when linestyles is defined
fig4, ax4 = plt.subplots()
CS4 = ax4.contour(X, Y, Z, 6, colors='k', linestyles='dashdot',
negative_linestyles=style)
ax4.clabel(CS4, fontsize=9, inline=True)
ax4.set_title(f'Single color - negative contours {style}')
assert CS4.negative_linestyles == style