fr/fr_env/lib/python3.8/site-packages/matplotlib/tests/test_contour.py

399 lines
14 KiB
Python

import datetime
import platform
import re
import numpy as np
from numpy.testing import assert_array_almost_equal
import matplotlib as mpl
from matplotlib.testing.decorators import image_comparison
from matplotlib import pyplot as plt, rc_context
from matplotlib.colors import LogNorm
import pytest
def test_contour_shape_1d_valid():
x = np.arange(10)
y = np.arange(9)
z = np.random.random((9, 10))
fig, ax = plt.subplots()
ax.contour(x, y, z)
def test_contour_shape_2d_valid():
x = np.arange(10)
y = np.arange(9)
xg, yg = np.meshgrid(x, y)
z = np.random.random((9, 10))
fig, ax = plt.subplots()
ax.contour(xg, yg, z)
@pytest.mark.parametrize("args, message", [
((np.arange(9), np.arange(9), np.empty((9, 10))),
'Length of x (9) must match number of columns in z (10)'),
((np.arange(10), np.arange(10), np.empty((9, 10))),
'Length of y (10) must match number of rows in z (9)'),
((np.empty((10, 10)), np.arange(10), np.empty((9, 10))),
'Number of dimensions of x (2) and y (1) do not match'),
((np.arange(10), np.empty((10, 10)), np.empty((9, 10))),
'Number of dimensions of x (1) and y (2) do not match'),
((np.empty((9, 9)), np.empty((9, 10)), np.empty((9, 10))),
'Shapes of x (9, 9) and z (9, 10) do not match'),
((np.empty((9, 10)), np.empty((9, 9)), np.empty((9, 10))),
'Shapes of y (9, 9) and z (9, 10) do not match'),
((np.empty((3, 3, 3)), np.empty((3, 3, 3)), np.empty((9, 10))),
'Inputs x and y must be 1D or 2D, not 3D'),
((np.empty((3, 3, 3)), np.empty((3, 3, 3)), np.empty((3, 3, 3))),
'Input z must be 2D, not 3D'),
(([[0]],), # github issue 8197
'Input z must be at least a (2, 2) shaped array, but has shape (1, 1)'),
(([0], [0], [[0]]),
'Input z must be at least a (2, 2) shaped array, but has shape (1, 1)'),
])
def test_contour_shape_error(args, message):
fig, ax = plt.subplots()
with pytest.raises(TypeError, match=re.escape(message)):
ax.contour(*args)
def test_contour_empty_levels():
x = np.arange(9)
z = np.random.random((9, 9))
fig, ax = plt.subplots()
with pytest.warns(UserWarning) as record:
ax.contour(x, x, z, levels=[])
assert len(record) == 1
def test_contour_Nlevels():
# A scalar levels arg or kwarg should trigger auto level generation.
# https://github.com/matplotlib/matplotlib/issues/11913
z = np.arange(12).reshape((3, 4))
fig, ax = plt.subplots()
cs1 = ax.contour(z, 5)
assert len(cs1.levels) > 1
cs2 = ax.contour(z, levels=5)
assert (cs1.levels == cs2.levels).all()
def test_contour_badlevel_fmt():
# Test edge case from https://github.com/matplotlib/matplotlib/issues/9742
# User supplied fmt for each level as a dictionary, but Matplotlib changed
# the level to the minimum data value because no contours possible.
# This was fixed in https://github.com/matplotlib/matplotlib/pull/9743
x = np.arange(9)
z = np.zeros((9, 9))
fig, ax = plt.subplots()
fmt = {1.: '%1.2f'}
with pytest.warns(UserWarning) as record:
cs = ax.contour(x, x, z, levels=[1.])
ax.clabel(cs, fmt=fmt)
assert len(record) == 1
def test_contour_uniform_z():
x = np.arange(9)
z = np.ones((9, 9))
fig, ax = plt.subplots()
with pytest.warns(UserWarning) as record:
ax.contour(x, x, z)
assert len(record) == 1
@image_comparison(['contour_manual_labels'],
savefig_kwarg={'dpi': 200}, remove_text=True, style='mpl20')
def test_contour_manual_labels():
x, y = np.meshgrid(np.arange(0, 10), np.arange(0, 10))
z = np.max(np.dstack([abs(x), abs(y)]), 2)
plt.figure(figsize=(6, 2), dpi=200)
cs = plt.contour(x, y, z)
pts = np.array([(1.5, 3.0), (1.5, 4.4), (1.5, 6.0)])
plt.clabel(cs, manual=pts)
@image_comparison(['contour_labels_size_color.png'],
remove_text=True, style='mpl20')
def test_contour_labels_size_color():
x, y = np.meshgrid(np.arange(0, 10), np.arange(0, 10))
z = np.max(np.dstack([abs(x), abs(y)]), 2)
plt.figure(figsize=(6, 2))
cs = plt.contour(x, y, z)
pts = np.array([(1.5, 3.0), (1.5, 4.4), (1.5, 6.0)])
plt.clabel(cs, manual=pts, fontsize='small', colors=('r', 'g'))
@image_comparison(['contour_manual_colors_and_levels.png'], remove_text=True)
def test_given_colors_levels_and_extends():
_, axs = plt.subplots(2, 4)
data = np.arange(12).reshape(3, 4)
colors = ['red', 'yellow', 'pink', 'blue', 'black']
levels = [2, 4, 8, 10]
for i, ax in enumerate(axs.flat):
filled = i % 2 == 0.
extend = ['neither', 'min', 'max', 'both'][i // 2]
if filled:
# If filled, we have 3 colors with no extension,
# 4 colors with one extension, and 5 colors with both extensions
first_color = 1 if extend in ['max', 'neither'] else None
last_color = -1 if extend in ['min', 'neither'] else None
c = ax.contourf(data, colors=colors[first_color:last_color],
levels=levels, extend=extend)
else:
# If not filled, we have 4 levels and 4 colors
c = ax.contour(data, colors=colors[:-1],
levels=levels, extend=extend)
plt.colorbar(c, ax=ax)
@image_comparison(['contour_datetime_axis.png'],
remove_text=False, style='mpl20')
def test_contour_datetime_axis():
fig = plt.figure()
fig.subplots_adjust(hspace=0.4, top=0.98, bottom=.15)
base = datetime.datetime(2013, 1, 1)
x = np.array([base + datetime.timedelta(days=d) for d in range(20)])
y = np.arange(20)
z1, z2 = np.meshgrid(np.arange(20), np.arange(20))
z = z1 * z2
plt.subplot(221)
plt.contour(x, y, z)
plt.subplot(222)
plt.contourf(x, y, z)
x = np.repeat(x[np.newaxis], 20, axis=0)
y = np.repeat(y[:, np.newaxis], 20, axis=1)
plt.subplot(223)
plt.contour(x, y, z)
plt.subplot(224)
plt.contourf(x, y, z)
for ax in fig.get_axes():
for label in ax.get_xticklabels():
label.set_ha('right')
label.set_rotation(30)
@image_comparison(['contour_test_label_transforms.png'],
remove_text=True, style='mpl20',
tol=0 if platform.machine() == 'x86_64' else 0.08)
def test_labels():
# Adapted from pylab_examples example code: contour_demo.py
# see issues #2475, #2843, and #2818 for explanation
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) / 2) / (2 * np.pi)
Z2 = (np.exp(-(((X - 1) / 1.5)**2 + ((Y - 1) / 0.5)**2) / 2) /
(2 * np.pi * 0.5 * 1.5))
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)
fig, ax = plt.subplots(1, 1)
CS = ax.contour(X, Y, Z)
disp_units = [(216, 177), (359, 290), (521, 406)]
data_units = [(-2, .5), (0, -1.5), (2.8, 1)]
CS.clabel()
for x, y in data_units:
CS.add_label_near(x, y, inline=True, transform=None)
for x, y in disp_units:
CS.add_label_near(x, y, inline=True, transform=False)
@image_comparison(['contour_corner_mask_False.png',
'contour_corner_mask_True.png'],
remove_text=True)
def test_corner_mask():
n = 60
mask_level = 0.95
noise_amp = 1.0
np.random.seed([1])
x, y = np.meshgrid(np.linspace(0, 2.0, n), np.linspace(0, 2.0, n))
z = np.cos(7*x)*np.sin(8*y) + noise_amp*np.random.rand(n, n)
mask = np.random.rand(n, n) >= mask_level
z = np.ma.array(z, mask=mask)
for corner_mask in [False, True]:
plt.figure()
plt.contourf(z, corner_mask=corner_mask)
def test_contourf_decreasing_levels():
# github issue 5477.
z = [[0.1, 0.3], [0.5, 0.7]]
plt.figure()
with pytest.raises(ValueError):
plt.contourf(z, [1.0, 0.0])
def test_contourf_symmetric_locator():
# github issue 7271
z = np.arange(12).reshape((3, 4))
locator = plt.MaxNLocator(nbins=4, symmetric=True)
cs = plt.contourf(z, locator=locator)
assert_array_almost_equal(cs.levels, np.linspace(-12, 12, 5))
@pytest.mark.parametrize("args, cls, message", [
((), TypeError,
'function takes exactly 6 arguments (0 given)'),
((1, 2, 3, 4, 5, 6), ValueError,
'Expected 2-dimensional array, got 0'),
(([[0]], [[0]], [[]], None, True, 0), ValueError,
'x, y and z must all be 2D arrays with the same dimensions'),
(([[0]], [[0]], [[0]], None, True, 0), ValueError,
'x, y and z must all be at least 2x2 arrays'),
((*[np.arange(4).reshape((2, 2))] * 3, [[0]], True, 0), ValueError,
'If mask is set it must be a 2D array with the same dimensions as x.'),
])
def test_internal_cpp_api(args, cls, message): # Github issue 8197.
from matplotlib import _contour # noqa: ensure lazy-loaded module *is* loaded.
with pytest.raises(cls, match=re.escape(message)):
mpl._contour.QuadContourGenerator(*args)
def test_internal_cpp_api_2():
from matplotlib import _contour # noqa: ensure lazy-loaded module *is* loaded.
arr = [[0, 1], [2, 3]]
qcg = mpl._contour.QuadContourGenerator(arr, arr, arr, None, True, 0)
with pytest.raises(
ValueError, match=r'filled contour levels must be increasing'):
qcg.create_filled_contour(1, 0)
def test_circular_contour_warning():
# Check that almost circular contours don't throw a warning
x, y = np.meshgrid(np.linspace(-2, 2, 4), np.linspace(-2, 2, 4))
r = np.hypot(x, y)
plt.figure()
cs = plt.contour(x, y, r)
plt.clabel(cs)
@pytest.mark.parametrize("use_clabeltext, contour_zorder, clabel_zorder",
[(True, 123, 1234), (False, 123, 1234),
(True, 123, None), (False, 123, None)])
def test_clabel_zorder(use_clabeltext, contour_zorder, clabel_zorder):
x, y = np.meshgrid(np.arange(0, 10), np.arange(0, 10))
z = np.max(np.dstack([abs(x), abs(y)]), 2)
fig, (ax1, ax2) = plt.subplots(ncols=2)
cs = ax1.contour(x, y, z, zorder=contour_zorder)
cs_filled = ax2.contourf(x, y, z, zorder=contour_zorder)
clabels1 = cs.clabel(zorder=clabel_zorder, use_clabeltext=use_clabeltext)
clabels2 = cs_filled.clabel(zorder=clabel_zorder,
use_clabeltext=use_clabeltext)
if clabel_zorder is None:
expected_clabel_zorder = 2+contour_zorder
else:
expected_clabel_zorder = clabel_zorder
for clabel in clabels1:
assert clabel.get_zorder() == expected_clabel_zorder
for clabel in clabels2:
assert clabel.get_zorder() == expected_clabel_zorder
@image_comparison(['contour_log_extension.png'],
remove_text=True, style='mpl20')
def test_contourf_log_extension():
# Test that contourf with lognorm is extended correctly
fig = plt.figure(figsize=(10, 5))
fig.subplots_adjust(left=0.05, right=0.95)
ax1 = fig.add_subplot(131)
ax2 = fig.add_subplot(132)
ax3 = fig.add_subplot(133)
# make data set with large range e.g. between 1e-8 and 1e10
data_exp = np.linspace(-7.5, 9.5, 1200)
data = np.power(10, data_exp).reshape(30, 40)
# make manual levels e.g. between 1e-4 and 1e-6
levels_exp = np.arange(-4., 7.)
levels = np.power(10., levels_exp)
# original data
c1 = ax1.contourf(data,
norm=LogNorm(vmin=data.min(), vmax=data.max()))
# just show data in levels
c2 = ax2.contourf(data, levels=levels,
norm=LogNorm(vmin=levels.min(), vmax=levels.max()),
extend='neither')
# extend data from levels
c3 = ax3.contourf(data, levels=levels,
norm=LogNorm(vmin=levels.min(), vmax=levels.max()),
extend='both')
cb = plt.colorbar(c1, ax=ax1)
assert cb.ax.get_ylim() == (1e-8, 1e10)
cb = plt.colorbar(c2, ax=ax2)
assert cb.ax.get_ylim() == (1e-4, 1e6)
cb = plt.colorbar(c3, ax=ax3)
assert_array_almost_equal(
cb.ax.get_ylim(), [3.162277660168379e-05, 3162277.660168383], 2)
@image_comparison(['contour_addlines.png'],
remove_text=True, style='mpl20', tol=0.03)
# tolerance is because image changed minutely when tick finding on
# colorbars was cleaned up...
def test_contour_addlines():
fig, ax = plt.subplots()
np.random.seed(19680812)
X = np.random.rand(10, 10)*10000
pcm = ax.pcolormesh(X)
# add 1000 to make colors visible...
cont = ax.contour(X+1000)
cb = fig.colorbar(pcm)
cb.add_lines(cont)
assert_array_almost_equal(cb.ax.get_ylim(), [114.3091, 9972.30735], 3)
@image_comparison(baseline_images=['contour_uneven'],
extensions=['png'], remove_text=True, style='mpl20')
def test_contour_uneven():
z = np.arange(24).reshape(4, 6)
fig, axs = plt.subplots(1, 2)
ax = axs[0]
cs = ax.contourf(z, levels=[2, 4, 6, 10, 20])
fig.colorbar(cs, ax=ax, spacing='proportional')
ax = axs[1]
cs = ax.contourf(z, levels=[2, 4, 6, 10, 20])
fig.colorbar(cs, ax=ax, spacing='uniform')
@pytest.mark.parametrize(
"rc_lines_linewidth, rc_contour_linewidth, call_linewidths, expected", [
(1.23, None, None, 1.23),
(1.23, 4.24, None, 4.24),
(1.23, 4.24, 5.02, 5.02)
])
def test_contour_linewidth(
rc_lines_linewidth, rc_contour_linewidth, call_linewidths, expected):
with rc_context(rc={"lines.linewidth": rc_lines_linewidth,
"contour.linewidth": rc_contour_linewidth}):
fig, ax = plt.subplots()
X = np.arange(4*3).reshape(4, 3)
cs = ax.contour(X, linewidths=call_linewidths)
assert cs.tlinewidths[0][0] == expected