420 lines
13 KiB
Python
420 lines
13 KiB
Python
import datetime
|
|
|
|
import numpy as np
|
|
from matplotlib.testing.decorators import image_comparison
|
|
from matplotlib import pyplot as plt
|
|
from numpy.testing import assert_array_almost_equal
|
|
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)
|
|
|
|
|
|
def test_contour_shape_mismatch_1():
|
|
|
|
x = np.arange(9)
|
|
y = np.arange(9)
|
|
z = np.random.random((9, 10))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(x, y, z)
|
|
excinfo.match(r'Length of x must be number of columns in z.')
|
|
|
|
|
|
def test_contour_shape_mismatch_2():
|
|
|
|
x = np.arange(10)
|
|
y = np.arange(10)
|
|
z = np.random.random((9, 10))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(x, y, z)
|
|
excinfo.match(r'Length of y must be number of rows in z.')
|
|
|
|
|
|
def test_contour_shape_mismatch_3():
|
|
|
|
x = np.arange(10)
|
|
y = np.arange(10)
|
|
xg, yg = np.meshgrid(x, y)
|
|
z = np.random.random((9, 10))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(xg, y, z)
|
|
excinfo.match(r'Number of dimensions of x and y should match.')
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(x, yg, z)
|
|
excinfo.match(r'Number of dimensions of x and y should match.')
|
|
|
|
|
|
def test_contour_shape_mismatch_4():
|
|
|
|
g = np.random.random((9, 10))
|
|
b = np.random.random((9, 9))
|
|
z = np.random.random((9, 10))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(b, g, z)
|
|
excinfo.match(r'Shape of x does not match that of z: found \(9L?, 9L?\) ' +
|
|
r'instead of \(9L?, 10L?\)')
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(g, b, z)
|
|
excinfo.match(r'Shape of y does not match that of z: found \(9L?, 9L?\) ' +
|
|
r'instead of \(9L?, 10L?\)')
|
|
|
|
|
|
def test_contour_shape_invalid_1():
|
|
|
|
x = np.random.random((3, 3, 3))
|
|
y = np.random.random((3, 3, 3))
|
|
z = np.random.random((9, 10))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(x, y, z)
|
|
excinfo.match(r'Inputs x and y must be 1D or 2D.')
|
|
|
|
|
|
def test_contour_shape_invalid_2():
|
|
|
|
x = np.random.random((3, 3, 3))
|
|
y = np.random.random((3, 3, 3))
|
|
z = np.random.random((3, 3, 3))
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
ax.contour(x, y, z)
|
|
excinfo.match(r'Input z must be a 2D array.')
|
|
|
|
|
|
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 funny edge case from
|
|
# https://github.com/matplotlib/matplotlib/issues/9742
|
|
# User supplied fmt for each level as a dictionary, but
|
|
# MPL changed the level to the minimum data value because
|
|
# no contours possible.
|
|
# This would error out pre
|
|
# 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(baseline_images=['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(baseline_images=['contour_labels_size_color'],
|
|
extensions=['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(baseline_images=['contour_manual_colors_and_levels'],
|
|
extensions=['png'], remove_text=True)
|
|
def test_given_colors_levels_and_extends():
|
|
_, axes = 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(axes.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(baseline_images=['contour_datetime_axis'],
|
|
extensions=['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(baseline_images=['contour_test_label_transforms'],
|
|
extensions=['png'], remove_text=True, style='mpl20')
|
|
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(baseline_images=['contour_corner_mask_False',
|
|
'contour_corner_mask_True'],
|
|
extensions=['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]:
|
|
fig = 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))
|
|
|
|
|
|
def test_contour_1x1_array():
|
|
# github issue 8197
|
|
with pytest.raises(TypeError) as excinfo:
|
|
plt.contour([[0]])
|
|
excinfo.match(r'Input z must be at least a 2x2 array.')
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
plt.contour([0], [0], [[0]])
|
|
excinfo.match(r'Input z must be at least a 2x2 array.')
|
|
|
|
|
|
def test_internal_cpp_api():
|
|
# Following github issue 8197.
|
|
import matplotlib._contour as _contour
|
|
|
|
with pytest.raises(TypeError) as excinfo:
|
|
qcg = _contour.QuadContourGenerator()
|
|
excinfo.match(r'function takes exactly 6 arguments \(0 given\)')
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
qcg = _contour.QuadContourGenerator(1, 2, 3, 4, 5, 6)
|
|
excinfo.match(r'Expected 2-dimensional array, got 0')
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
qcg = _contour.QuadContourGenerator([[0]], [[0]], [[]], None, True, 0)
|
|
excinfo.match(r'x, y and z must all be 2D arrays with the same dimensions')
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
qcg = _contour.QuadContourGenerator([[0]], [[0]], [[0]], None, True, 0)
|
|
excinfo.match(r'x, y and z must all be at least 2x2 arrays')
|
|
|
|
arr = [[0, 1], [2, 3]]
|
|
with pytest.raises(ValueError) as excinfo:
|
|
qcg = _contour.QuadContourGenerator(arr, arr, arr, [[0]], True, 0)
|
|
excinfo.match(r'If mask is set it must be a 2D array with the same ' +
|
|
r'dimensions as x.')
|
|
|
|
qcg = _contour.QuadContourGenerator(arr, arr, arr, None, True, 0)
|
|
with pytest.raises(ValueError) as excinfo:
|
|
qcg.create_filled_contour(1, 0)
|
|
excinfo.match(r'filled contour levels must be increasing')
|
|
|
|
|
|
def test_circular_contour_warning():
|
|
# Check that almost circular contours don't throw a warning
|
|
with pytest.warns(None) as record:
|
|
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)
|
|
assert len(record) == 0
|
|
|
|
|
|
@image_comparison(baseline_images=['contour_log_extension'],
|
|
extensions=['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')
|
|
plt.colorbar(c1, ax=ax1)
|
|
plt.colorbar(c2, ax=ax2)
|
|
plt.colorbar(c3, ax=ax3)
|
|
|
|
|
|
@image_comparison(baseline_images=['contour_addlines'],
|
|
extensions=['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)
|