401 lines
13 KiB
Python
401 lines
13 KiB
Python
import numpy as np
|
|
import pytest
|
|
|
|
from matplotlib.testing.decorators import image_comparison
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.gridspec as gridspec
|
|
from matplotlib import ticker, rcParams
|
|
|
|
|
|
def example_plot(ax, fontsize=12, nodec=False):
|
|
ax.plot([1, 2])
|
|
ax.locator_params(nbins=3)
|
|
if not nodec:
|
|
ax.set_xlabel('x-label', fontsize=fontsize)
|
|
ax.set_ylabel('y-label', fontsize=fontsize)
|
|
ax.set_title('Title', fontsize=fontsize)
|
|
else:
|
|
ax.set_xticklabels('')
|
|
ax.set_yticklabels('')
|
|
|
|
|
|
def example_pcolor(ax, fontsize=12):
|
|
dx, dy = 0.6, 0.6
|
|
y, x = np.mgrid[slice(-3, 3 + dy, dy),
|
|
slice(-3, 3 + dx, dx)]
|
|
z = (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)
|
|
pcm = ax.pcolormesh(x, y, z[:-1, :-1], cmap='RdBu_r', vmin=-1., vmax=1.,
|
|
rasterized=True)
|
|
ax.set_xlabel('x-label', fontsize=fontsize)
|
|
ax.set_ylabel('y-label', fontsize=fontsize)
|
|
ax.set_title('Title', fontsize=fontsize)
|
|
return pcm
|
|
|
|
|
|
@image_comparison(['constrained_layout1.png'])
|
|
def test_constrained_layout1():
|
|
"""Test constrained_layout for a single subplot"""
|
|
fig = plt.figure(constrained_layout=True)
|
|
ax = fig.add_subplot(111)
|
|
example_plot(ax, fontsize=24)
|
|
|
|
|
|
@image_comparison(['constrained_layout2.png'])
|
|
def test_constrained_layout2():
|
|
"""Test constrained_layout for 2x2 subplots"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
example_plot(ax, fontsize=24)
|
|
|
|
|
|
@image_comparison(['constrained_layout3.png'])
|
|
def test_constrained_layout3():
|
|
"""Test constrained_layout for colorbars with subplots"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for nn, ax in enumerate(axs.flat):
|
|
pcm = example_pcolor(ax, fontsize=24)
|
|
if nn == 3:
|
|
pad = 0.08
|
|
else:
|
|
pad = 0.02 # default
|
|
fig.colorbar(pcm, ax=ax, pad=pad)
|
|
|
|
|
|
@image_comparison(['constrained_layout4'])
|
|
def test_constrained_layout4():
|
|
"""Test constrained_layout for a single colorbar with subplots"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax, fontsize=24)
|
|
fig.colorbar(pcm, ax=axs, pad=0.01, shrink=0.6)
|
|
|
|
|
|
@image_comparison(['constrained_layout5.png'], tol=5.e-2)
|
|
def test_constrained_layout5():
|
|
"""
|
|
Test constrained_layout for a single colorbar with subplots,
|
|
colorbar bottom
|
|
"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax, fontsize=24)
|
|
fig.colorbar(pcm, ax=axs,
|
|
use_gridspec=False, pad=0.01, shrink=0.6,
|
|
location='bottom')
|
|
|
|
|
|
@image_comparison(['constrained_layout6.png'])
|
|
def test_constrained_layout6():
|
|
"""Test constrained_layout for nested gridspecs"""
|
|
fig = plt.figure(constrained_layout=True)
|
|
gs = fig.add_gridspec(1, 2, figure=fig)
|
|
gsl = gs[0].subgridspec(2, 2)
|
|
gsr = gs[1].subgridspec(1, 2)
|
|
axsl = []
|
|
for gs in gsl:
|
|
ax = fig.add_subplot(gs)
|
|
axsl += [ax]
|
|
example_plot(ax, fontsize=12)
|
|
ax.set_xlabel('x-label\nMultiLine')
|
|
axsr = []
|
|
for gs in gsr:
|
|
ax = fig.add_subplot(gs)
|
|
axsr += [ax]
|
|
pcm = example_pcolor(ax, fontsize=12)
|
|
|
|
fig.colorbar(pcm, ax=axsr,
|
|
pad=0.01, shrink=0.99, location='bottom',
|
|
ticks=ticker.MaxNLocator(nbins=5))
|
|
|
|
|
|
def test_constrained_layout7():
|
|
"""Test for proper warning if fig not set in GridSpec"""
|
|
with pytest.warns(
|
|
UserWarning, match=('Calling figure.constrained_layout, but figure '
|
|
'not setup to do constrained layout')):
|
|
fig = plt.figure(constrained_layout=True)
|
|
gs = gridspec.GridSpec(1, 2)
|
|
gsl = gridspec.GridSpecFromSubplotSpec(2, 2, gs[0])
|
|
gsr = gridspec.GridSpecFromSubplotSpec(1, 2, gs[1])
|
|
for gs in gsl:
|
|
fig.add_subplot(gs)
|
|
# need to trigger a draw to get warning
|
|
fig.draw(fig.canvas.get_renderer())
|
|
|
|
|
|
@image_comparison(['constrained_layout8.png'])
|
|
def test_constrained_layout8():
|
|
"""Test for gridspecs that are not completely full"""
|
|
fig = plt.figure(figsize=(10, 5), constrained_layout=True)
|
|
gs = gridspec.GridSpec(3, 5, figure=fig)
|
|
axs = []
|
|
for j in [0, 1]:
|
|
if j == 0:
|
|
ilist = [1]
|
|
else:
|
|
ilist = [0, 4]
|
|
for i in ilist:
|
|
ax = fig.add_subplot(gs[j, i])
|
|
axs += [ax]
|
|
pcm = example_pcolor(ax, fontsize=9)
|
|
if i > 0:
|
|
ax.set_ylabel('')
|
|
if j < 1:
|
|
ax.set_xlabel('')
|
|
ax.set_title('')
|
|
ax = fig.add_subplot(gs[2, :])
|
|
axs += [ax]
|
|
pcm = example_pcolor(ax, fontsize=9)
|
|
|
|
fig.colorbar(pcm, ax=axs, pad=0.01, shrink=0.6)
|
|
|
|
|
|
@image_comparison(['constrained_layout9.png'])
|
|
def test_constrained_layout9():
|
|
"""Test for handling suptitle and for sharex and sharey"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True,
|
|
sharex=False, sharey=False)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax, fontsize=24)
|
|
ax.set_xlabel('')
|
|
ax.set_ylabel('')
|
|
ax.set_aspect(2.)
|
|
fig.colorbar(pcm, ax=axs, pad=0.01, shrink=0.6)
|
|
fig.suptitle('Test Suptitle', fontsize=28)
|
|
|
|
|
|
@image_comparison(['constrained_layout10.png'])
|
|
def test_constrained_layout10():
|
|
"""Test for handling legend outside axis"""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
ax.plot(np.arange(12), label='This is a label')
|
|
ax.legend(loc='center left', bbox_to_anchor=(0.8, 0.5))
|
|
|
|
|
|
@image_comparison(['constrained_layout11.png'])
|
|
def test_constrained_layout11():
|
|
"""Test for multiple nested gridspecs"""
|
|
fig = plt.figure(constrained_layout=True, figsize=(13, 3))
|
|
gs0 = gridspec.GridSpec(1, 2, figure=fig)
|
|
gsl = gridspec.GridSpecFromSubplotSpec(1, 2, gs0[0])
|
|
gsl0 = gridspec.GridSpecFromSubplotSpec(2, 2, gsl[1])
|
|
ax = fig.add_subplot(gs0[1])
|
|
example_plot(ax, fontsize=9)
|
|
axs = []
|
|
for gs in gsl0:
|
|
ax = fig.add_subplot(gs)
|
|
axs += [ax]
|
|
pcm = example_pcolor(ax, fontsize=9)
|
|
fig.colorbar(pcm, ax=axs, shrink=0.6, aspect=70.)
|
|
ax = fig.add_subplot(gsl[0])
|
|
example_plot(ax, fontsize=9)
|
|
|
|
|
|
@image_comparison(['constrained_layout11rat.png'])
|
|
def test_constrained_layout11rat():
|
|
"""Test for multiple nested gridspecs with width_ratios"""
|
|
fig = plt.figure(constrained_layout=True, figsize=(10, 3))
|
|
gs0 = gridspec.GridSpec(1, 2, figure=fig, width_ratios=[6, 1])
|
|
gsl = gridspec.GridSpecFromSubplotSpec(1, 2, gs0[0])
|
|
gsl0 = gridspec.GridSpecFromSubplotSpec(2, 2, gsl[1], height_ratios=[2, 1])
|
|
ax = fig.add_subplot(gs0[1])
|
|
example_plot(ax, fontsize=9)
|
|
axs = []
|
|
for gs in gsl0:
|
|
ax = fig.add_subplot(gs)
|
|
axs += [ax]
|
|
pcm = example_pcolor(ax, fontsize=9)
|
|
fig.colorbar(pcm, ax=axs, shrink=0.6, aspect=70.)
|
|
ax = fig.add_subplot(gsl[0])
|
|
example_plot(ax, fontsize=9)
|
|
|
|
|
|
@image_comparison(['constrained_layout12.png'])
|
|
def test_constrained_layout12():
|
|
"""Test that very unbalanced labeling still works."""
|
|
fig = plt.figure(constrained_layout=True)
|
|
|
|
gs0 = gridspec.GridSpec(6, 2, figure=fig)
|
|
|
|
ax1 = fig.add_subplot(gs0[:3, 1])
|
|
ax2 = fig.add_subplot(gs0[3:, 1])
|
|
|
|
example_plot(ax1, fontsize=24)
|
|
example_plot(ax2, fontsize=24)
|
|
|
|
ax = fig.add_subplot(gs0[0:2, 0])
|
|
example_plot(ax, nodec=True)
|
|
ax = fig.add_subplot(gs0[2:4, 0])
|
|
example_plot(ax, nodec=True)
|
|
ax = fig.add_subplot(gs0[4:, 0])
|
|
example_plot(ax, nodec=True)
|
|
ax.set_xlabel('x-label')
|
|
|
|
|
|
@image_comparison(['constrained_layout13.png'], tol=2.e-2)
|
|
def test_constrained_layout13():
|
|
"""Test that padding works."""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax, fontsize=12)
|
|
fig.colorbar(pcm, ax=ax, shrink=0.6, aspect=20., pad=0.02)
|
|
fig.set_constrained_layout_pads(w_pad=24./72., h_pad=24./72.)
|
|
|
|
|
|
@image_comparison(['constrained_layout14.png'])
|
|
def test_constrained_layout14():
|
|
"""Test that padding works."""
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax, fontsize=12)
|
|
fig.colorbar(pcm, ax=ax, shrink=0.6, aspect=20., pad=0.02)
|
|
fig.set_constrained_layout_pads(
|
|
w_pad=3./72., h_pad=3./72.,
|
|
hspace=0.2, wspace=0.2)
|
|
|
|
|
|
@image_comparison(['constrained_layout15.png'])
|
|
def test_constrained_layout15():
|
|
"""Test that rcparams work."""
|
|
rcParams['figure.constrained_layout.use'] = True
|
|
fig, axs = plt.subplots(2, 2)
|
|
for ax in axs.flat:
|
|
example_plot(ax, fontsize=12)
|
|
|
|
|
|
@image_comparison(['constrained_layout16.png'])
|
|
def test_constrained_layout16():
|
|
"""Test ax.set_position."""
|
|
fig, ax = plt.subplots(constrained_layout=True)
|
|
example_plot(ax, fontsize=12)
|
|
ax2 = fig.add_axes([0.2, 0.2, 0.4, 0.4])
|
|
|
|
|
|
@image_comparison(['constrained_layout17.png'])
|
|
def test_constrained_layout17():
|
|
"""Test uneven gridspecs"""
|
|
fig = plt.figure(constrained_layout=True)
|
|
gs = gridspec.GridSpec(3, 3, figure=fig)
|
|
|
|
ax1 = fig.add_subplot(gs[0, 0])
|
|
ax2 = fig.add_subplot(gs[0, 1:])
|
|
ax3 = fig.add_subplot(gs[1:, 0:2])
|
|
ax4 = fig.add_subplot(gs[1:, -1])
|
|
|
|
example_plot(ax1)
|
|
example_plot(ax2)
|
|
example_plot(ax3)
|
|
example_plot(ax4)
|
|
|
|
|
|
def test_constrained_layout18():
|
|
"""Test twinx"""
|
|
fig, ax = plt.subplots(constrained_layout=True)
|
|
ax2 = ax.twinx()
|
|
example_plot(ax)
|
|
example_plot(ax2, fontsize=24)
|
|
fig.canvas.draw()
|
|
assert all(ax.get_position().extents == ax2.get_position().extents)
|
|
|
|
|
|
def test_constrained_layout19():
|
|
"""Test twiny"""
|
|
fig, ax = plt.subplots(constrained_layout=True)
|
|
ax2 = ax.twiny()
|
|
example_plot(ax)
|
|
example_plot(ax2, fontsize=24)
|
|
ax2.set_title('')
|
|
ax.set_title('')
|
|
fig.canvas.draw()
|
|
assert all(ax.get_position().extents == ax2.get_position().extents)
|
|
|
|
|
|
def test_constrained_layout20():
|
|
"""Smoke test cl does not mess up added axes"""
|
|
gx = np.linspace(-5, 5, 4)
|
|
img = np.hypot(gx, gx[:, None])
|
|
|
|
fig = plt.figure()
|
|
ax = fig.add_axes([0, 0, 1, 1])
|
|
mesh = ax.pcolormesh(gx, gx, img[:-1, :-1])
|
|
fig.colorbar(mesh)
|
|
|
|
|
|
def test_constrained_layout21():
|
|
"""#11035: repeated calls to suptitle should not alter the layout"""
|
|
fig, ax = plt.subplots(constrained_layout=True)
|
|
|
|
fig.suptitle("Suptitle0")
|
|
fig.canvas.draw()
|
|
extents0 = np.copy(ax.get_position().extents)
|
|
|
|
fig.suptitle("Suptitle1")
|
|
fig.canvas.draw()
|
|
extents1 = np.copy(ax.get_position().extents)
|
|
|
|
np.testing.assert_allclose(extents0, extents1)
|
|
|
|
|
|
def test_constrained_layout22():
|
|
"""#11035: suptitle should not be include in CL if manually positioned"""
|
|
fig, ax = plt.subplots(constrained_layout=True)
|
|
|
|
fig.canvas.draw()
|
|
extents0 = np.copy(ax.get_position().extents)
|
|
|
|
fig.suptitle("Suptitle", y=0.5)
|
|
fig.canvas.draw()
|
|
extents1 = np.copy(ax.get_position().extents)
|
|
|
|
np.testing.assert_allclose(extents0, extents1)
|
|
|
|
|
|
def test_constrained_layout23():
|
|
"""
|
|
Comment in #11035: suptitle used to cause an exception when
|
|
reusing a figure w/ CL with ``clear=True``.
|
|
"""
|
|
|
|
for i in range(2):
|
|
fig, ax = plt.subplots(num="123", constrained_layout=True, clear=True)
|
|
fig.suptitle("Suptitle{}".format(i))
|
|
|
|
|
|
# This test occasionally fails the image comparison tests, so we mark as
|
|
# flaky. Apparently the constraint solver occasionally doesn't fully
|
|
# optimize. Would be nice if this were more deterministic...
|
|
@pytest.mark.timeout(30)
|
|
@pytest.mark.flaky(reruns=3)
|
|
@image_comparison(['test_colorbar_location.png'],
|
|
remove_text=True, style='mpl20')
|
|
def test_colorbar_location():
|
|
"""
|
|
Test that colorbar handling is as expected for various complicated
|
|
cases...
|
|
"""
|
|
|
|
fig, axs = plt.subplots(4, 5, constrained_layout=True)
|
|
for ax in axs.flat:
|
|
pcm = example_pcolor(ax)
|
|
ax.set_xlabel('')
|
|
ax.set_ylabel('')
|
|
fig.colorbar(pcm, ax=axs[:, 1], shrink=0.4)
|
|
fig.colorbar(pcm, ax=axs[-1, :2], shrink=0.5, location='bottom')
|
|
fig.colorbar(pcm, ax=axs[0, 2:], shrink=0.5, location='bottom')
|
|
fig.colorbar(pcm, ax=axs[-2, 3:], shrink=0.5, location='top')
|
|
fig.colorbar(pcm, ax=axs[0, 0], shrink=0.5, location='left')
|
|
fig.colorbar(pcm, ax=axs[1:3, 2], shrink=0.5, location='right')
|
|
|
|
|
|
def test_hidden_axes():
|
|
# test that if we make an axes not visible that constrained_layout
|
|
# still works. Note the axes still takes space in the layout
|
|
# (as does a gridspec slot that is empty)
|
|
fig, axs = plt.subplots(2, 2, constrained_layout=True)
|
|
axs[0, 1].set_visible(False)
|
|
fig.canvas.draw()
|
|
extents1 = np.copy(axs[0, 0].get_position().extents)
|
|
|
|
np.testing.assert_allclose(
|
|
extents1, [0.045552, 0.548288, 0.47319, 0.982638], rtol=1e-5)
|