698 lines
22 KiB
Python
698 lines
22 KiB
Python
|
import gc
|
||
|
import platform
|
||
|
|
||
|
import numpy as np
|
||
|
import pytest
|
||
|
|
||
|
import matplotlib as mpl
|
||
|
from matplotlib.testing.decorators import image_comparison
|
||
|
import matplotlib.pyplot as plt
|
||
|
import matplotlib.transforms as mtransforms
|
||
|
from matplotlib import gridspec, ticker
|
||
|
|
||
|
|
||
|
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(layout="constrained")
|
||
|
ax = fig.add_subplot()
|
||
|
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, layout="constrained")
|
||
|
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, layout="constrained")
|
||
|
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.png'])
|
||
|
def test_constrained_layout4():
|
||
|
"""Test constrained_layout for a single colorbar with subplots"""
|
||
|
|
||
|
fig, axs = plt.subplots(2, 2, layout="constrained")
|
||
|
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=0.002)
|
||
|
def test_constrained_layout5():
|
||
|
"""
|
||
|
Test constrained_layout for a single colorbar with subplots,
|
||
|
colorbar bottom
|
||
|
"""
|
||
|
|
||
|
fig, axs = plt.subplots(2, 2, layout="constrained")
|
||
|
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'], tol=0.002)
|
||
|
def test_constrained_layout6():
|
||
|
"""Test constrained_layout for nested gridspecs"""
|
||
|
# Remove this line when this test image is regenerated.
|
||
|
plt.rcParams['pcolormesh.snap'] = False
|
||
|
|
||
|
fig = plt.figure(layout="constrained")
|
||
|
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_identical_subgridspec():
|
||
|
|
||
|
fig = plt.figure(constrained_layout=True)
|
||
|
|
||
|
GS = fig.add_gridspec(2, 1)
|
||
|
|
||
|
GSA = GS[0].subgridspec(1, 3)
|
||
|
GSB = GS[1].subgridspec(1, 3)
|
||
|
|
||
|
axa = []
|
||
|
axb = []
|
||
|
for i in range(3):
|
||
|
axa += [fig.add_subplot(GSA[i])]
|
||
|
axb += [fig.add_subplot(GSB[i])]
|
||
|
|
||
|
fig.draw_without_rendering()
|
||
|
# check first row above second
|
||
|
assert axa[0].get_position().y0 > axb[0].get_position().y1
|
||
|
|
||
|
|
||
|
def test_constrained_layout7():
|
||
|
"""Test for proper warning if fig not set in GridSpec"""
|
||
|
with pytest.warns(
|
||
|
UserWarning, match=('There are no gridspecs with layoutgrids. '
|
||
|
'Possibly did not call parent GridSpec with '
|
||
|
'the "figure" keyword')):
|
||
|
fig = plt.figure(layout="constrained")
|
||
|
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_without_rendering()
|
||
|
|
||
|
|
||
|
@image_comparison(['constrained_layout8.png'])
|
||
|
def test_constrained_layout8():
|
||
|
"""Test for gridspecs that are not completely full"""
|
||
|
|
||
|
fig = plt.figure(figsize=(10, 5), layout="constrained")
|
||
|
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]
|
||
|
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, layout="constrained",
|
||
|
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'],
|
||
|
tol=0.032 if platform.machine() == 'arm64' else 0)
|
||
|
def test_constrained_layout10():
|
||
|
"""Test for handling legend outside axis"""
|
||
|
fig, axs = plt.subplots(2, 2, layout="constrained")
|
||
|
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(layout="constrained", 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(layout="constrained", 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(layout="constrained", figsize=(6, 8))
|
||
|
|
||
|
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=18)
|
||
|
example_plot(ax2, fontsize=18)
|
||
|
|
||
|
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, layout="constrained")
|
||
|
for ax in axs.flat:
|
||
|
pcm = example_pcolor(ax, fontsize=12)
|
||
|
fig.colorbar(pcm, ax=ax, shrink=0.6, aspect=20., pad=0.02)
|
||
|
with pytest.raises(TypeError):
|
||
|
fig.get_layout_engine().set(wpad=1, hpad=2)
|
||
|
fig.get_layout_engine().set(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, layout="constrained")
|
||
|
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.get_layout_engine().set(
|
||
|
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."""
|
||
|
mpl.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(layout="constrained")
|
||
|
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(layout="constrained")
|
||
|
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(layout="constrained")
|
||
|
ax2 = ax.twinx()
|
||
|
example_plot(ax)
|
||
|
example_plot(ax2, fontsize=24)
|
||
|
fig.draw_without_rendering()
|
||
|
assert all(ax.get_position().extents == ax2.get_position().extents)
|
||
|
|
||
|
|
||
|
def test_constrained_layout19():
|
||
|
"""Test twiny"""
|
||
|
fig, ax = plt.subplots(layout="constrained")
|
||
|
ax2 = ax.twiny()
|
||
|
example_plot(ax)
|
||
|
example_plot(ax2, fontsize=24)
|
||
|
ax2.set_title('')
|
||
|
ax.set_title('')
|
||
|
fig.draw_without_rendering()
|
||
|
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(layout="constrained")
|
||
|
|
||
|
fig.suptitle("Suptitle0")
|
||
|
fig.draw_without_rendering()
|
||
|
extents0 = np.copy(ax.get_position().extents)
|
||
|
|
||
|
fig.suptitle("Suptitle1")
|
||
|
fig.draw_without_rendering()
|
||
|
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(layout="constrained")
|
||
|
|
||
|
fig.draw_without_rendering()
|
||
|
extents0 = np.copy(ax.get_position().extents)
|
||
|
|
||
|
fig.suptitle("Suptitle", y=0.5)
|
||
|
fig.draw_without_rendering()
|
||
|
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 = plt.figure(layout="constrained", clear=True, num="123")
|
||
|
gs = fig.add_gridspec(1, 2)
|
||
|
sub = gs[0].subgridspec(2, 2)
|
||
|
fig.suptitle(f"Suptitle{i}")
|
||
|
|
||
|
|
||
|
@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...
|
||
|
"""
|
||
|
# Remove this line when this test image is regenerated.
|
||
|
plt.rcParams['pcolormesh.snap'] = False
|
||
|
|
||
|
fig, axs = plt.subplots(4, 5, layout="constrained")
|
||
|
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', pad=0.05)
|
||
|
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, layout="constrained")
|
||
|
axs[0, 1].set_visible(False)
|
||
|
fig.draw_without_rendering()
|
||
|
extents1 = np.copy(axs[0, 0].get_position().extents)
|
||
|
|
||
|
np.testing.assert_allclose(
|
||
|
extents1, [0.045552, 0.543288, 0.47819, 0.982638], rtol=1e-5)
|
||
|
|
||
|
|
||
|
def test_colorbar_align():
|
||
|
for location in ['right', 'left', 'top', 'bottom']:
|
||
|
fig, axs = plt.subplots(2, 2, layout="constrained")
|
||
|
cbs = []
|
||
|
for nn, ax in enumerate(axs.flat):
|
||
|
ax.tick_params(direction='in')
|
||
|
pc = example_pcolor(ax)
|
||
|
cb = fig.colorbar(pc, ax=ax, location=location, shrink=0.6,
|
||
|
pad=0.04)
|
||
|
cbs += [cb]
|
||
|
cb.ax.tick_params(direction='in')
|
||
|
if nn != 1:
|
||
|
cb.ax.xaxis.set_ticks([])
|
||
|
cb.ax.yaxis.set_ticks([])
|
||
|
ax.set_xticklabels([])
|
||
|
ax.set_yticklabels([])
|
||
|
fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72,
|
||
|
hspace=0.1, wspace=0.1)
|
||
|
|
||
|
fig.draw_without_rendering()
|
||
|
if location in ['left', 'right']:
|
||
|
np.testing.assert_allclose(cbs[0].ax.get_position().x0,
|
||
|
cbs[2].ax.get_position().x0)
|
||
|
np.testing.assert_allclose(cbs[1].ax.get_position().x0,
|
||
|
cbs[3].ax.get_position().x0)
|
||
|
else:
|
||
|
np.testing.assert_allclose(cbs[0].ax.get_position().y0,
|
||
|
cbs[1].ax.get_position().y0)
|
||
|
np.testing.assert_allclose(cbs[2].ax.get_position().y0,
|
||
|
cbs[3].ax.get_position().y0)
|
||
|
|
||
|
|
||
|
@image_comparison(['test_colorbars_no_overlapV.png'], style='mpl20')
|
||
|
def test_colorbars_no_overlapV():
|
||
|
fig = plt.figure(figsize=(2, 4), layout="constrained")
|
||
|
axs = fig.subplots(2, 1, sharex=True, sharey=True)
|
||
|
for ax in axs:
|
||
|
ax.yaxis.set_major_formatter(ticker.NullFormatter())
|
||
|
ax.tick_params(axis='both', direction='in')
|
||
|
im = ax.imshow([[1, 2], [3, 4]])
|
||
|
fig.colorbar(im, ax=ax, orientation="vertical")
|
||
|
fig.suptitle("foo")
|
||
|
|
||
|
|
||
|
@image_comparison(['test_colorbars_no_overlapH.png'], style='mpl20')
|
||
|
def test_colorbars_no_overlapH():
|
||
|
fig = plt.figure(figsize=(4, 2), layout="constrained")
|
||
|
fig.suptitle("foo")
|
||
|
axs = fig.subplots(1, 2, sharex=True, sharey=True)
|
||
|
for ax in axs:
|
||
|
ax.yaxis.set_major_formatter(ticker.NullFormatter())
|
||
|
ax.tick_params(axis='both', direction='in')
|
||
|
im = ax.imshow([[1, 2], [3, 4]])
|
||
|
fig.colorbar(im, ax=ax, orientation="horizontal")
|
||
|
|
||
|
|
||
|
def test_manually_set_position():
|
||
|
fig, axs = plt.subplots(1, 2, layout="constrained")
|
||
|
axs[0].set_position([0.2, 0.2, 0.3, 0.3])
|
||
|
fig.draw_without_rendering()
|
||
|
pp = axs[0].get_position()
|
||
|
np.testing.assert_allclose(pp, [[0.2, 0.2], [0.5, 0.5]])
|
||
|
|
||
|
fig, axs = plt.subplots(1, 2, layout="constrained")
|
||
|
axs[0].set_position([0.2, 0.2, 0.3, 0.3])
|
||
|
pc = axs[0].pcolormesh(np.random.rand(20, 20))
|
||
|
fig.colorbar(pc, ax=axs[0])
|
||
|
fig.draw_without_rendering()
|
||
|
pp = axs[0].get_position()
|
||
|
np.testing.assert_allclose(pp, [[0.2, 0.2], [0.44, 0.5]])
|
||
|
|
||
|
|
||
|
@image_comparison(['test_bboxtight.png'],
|
||
|
remove_text=True, style='mpl20',
|
||
|
savefig_kwarg={'bbox_inches': 'tight'})
|
||
|
def test_bboxtight():
|
||
|
fig, ax = plt.subplots(layout="constrained")
|
||
|
ax.set_aspect(1.)
|
||
|
|
||
|
|
||
|
@image_comparison(['test_bbox.png'],
|
||
|
remove_text=True, style='mpl20',
|
||
|
savefig_kwarg={'bbox_inches':
|
||
|
mtransforms.Bbox([[0.5, 0], [2.5, 2]])})
|
||
|
def test_bbox():
|
||
|
fig, ax = plt.subplots(layout="constrained")
|
||
|
ax.set_aspect(1.)
|
||
|
|
||
|
|
||
|
def test_align_labels():
|
||
|
"""
|
||
|
Tests for a bug in which constrained layout and align_ylabels on
|
||
|
three unevenly sized subplots, one of whose y tick labels include
|
||
|
negative numbers, drives the non-negative subplots' y labels off
|
||
|
the edge of the plot
|
||
|
"""
|
||
|
fig, (ax3, ax1, ax2) = plt.subplots(3, 1, layout="constrained",
|
||
|
figsize=(6.4, 8),
|
||
|
gridspec_kw={"height_ratios": (1, 1,
|
||
|
0.7)})
|
||
|
|
||
|
ax1.set_ylim(0, 1)
|
||
|
ax1.set_ylabel("Label")
|
||
|
|
||
|
ax2.set_ylim(-1.5, 1.5)
|
||
|
ax2.set_ylabel("Label")
|
||
|
|
||
|
ax3.set_ylim(0, 1)
|
||
|
ax3.set_ylabel("Label")
|
||
|
|
||
|
fig.align_ylabels(axs=(ax3, ax1, ax2))
|
||
|
|
||
|
fig.draw_without_rendering()
|
||
|
after_align = [ax1.yaxis.label.get_window_extent(),
|
||
|
ax2.yaxis.label.get_window_extent(),
|
||
|
ax3.yaxis.label.get_window_extent()]
|
||
|
# ensure labels are approximately aligned
|
||
|
np.testing.assert_allclose([after_align[0].x0, after_align[2].x0],
|
||
|
after_align[1].x0, rtol=0, atol=1e-05)
|
||
|
# ensure labels do not go off the edge
|
||
|
assert after_align[0].x0 >= 1
|
||
|
|
||
|
|
||
|
def test_suplabels():
|
||
|
fig, ax = plt.subplots(layout="constrained")
|
||
|
fig.draw_without_rendering()
|
||
|
pos0 = ax.get_tightbbox(fig.canvas.get_renderer())
|
||
|
fig.supxlabel('Boo')
|
||
|
fig.supylabel('Booy')
|
||
|
fig.draw_without_rendering()
|
||
|
pos = ax.get_tightbbox(fig.canvas.get_renderer())
|
||
|
assert pos.y0 > pos0.y0 + 10.0
|
||
|
assert pos.x0 > pos0.x0 + 10.0
|
||
|
|
||
|
fig, ax = plt.subplots(layout="constrained")
|
||
|
fig.draw_without_rendering()
|
||
|
pos0 = ax.get_tightbbox(fig.canvas.get_renderer())
|
||
|
# check that specifying x (y) doesn't ruin the layout
|
||
|
fig.supxlabel('Boo', x=0.5)
|
||
|
fig.supylabel('Boo', y=0.5)
|
||
|
fig.draw_without_rendering()
|
||
|
pos = ax.get_tightbbox(fig.canvas.get_renderer())
|
||
|
assert pos.y0 > pos0.y0 + 10.0
|
||
|
assert pos.x0 > pos0.x0 + 10.0
|
||
|
|
||
|
|
||
|
def test_gridspec_addressing():
|
||
|
fig = plt.figure()
|
||
|
gs = fig.add_gridspec(3, 3)
|
||
|
sp = fig.add_subplot(gs[0:, 1:])
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
|
||
|
def test_discouraged_api():
|
||
|
fig, ax = plt.subplots(constrained_layout=True)
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
with pytest.warns(PendingDeprecationWarning,
|
||
|
match="will be deprecated"):
|
||
|
fig, ax = plt.subplots()
|
||
|
fig.set_constrained_layout(True)
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
with pytest.warns(PendingDeprecationWarning,
|
||
|
match="will be deprecated"):
|
||
|
fig, ax = plt.subplots()
|
||
|
fig.set_constrained_layout({'w_pad': 0.02, 'h_pad': 0.02})
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
|
||
|
def test_kwargs():
|
||
|
fig, ax = plt.subplots(constrained_layout={'h_pad': 0.02})
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
|
||
|
def test_rect():
|
||
|
fig, ax = plt.subplots(layout='constrained')
|
||
|
fig.get_layout_engine().set(rect=[0, 0, 0.5, 0.5])
|
||
|
fig.draw_without_rendering()
|
||
|
ppos = ax.get_position()
|
||
|
assert ppos.x1 < 0.5
|
||
|
assert ppos.y1 < 0.5
|
||
|
|
||
|
fig, ax = plt.subplots(layout='constrained')
|
||
|
fig.get_layout_engine().set(rect=[0.2, 0.2, 0.3, 0.3])
|
||
|
fig.draw_without_rendering()
|
||
|
ppos = ax.get_position()
|
||
|
assert ppos.x1 < 0.5
|
||
|
assert ppos.y1 < 0.5
|
||
|
assert ppos.x0 > 0.2
|
||
|
assert ppos.y0 > 0.2
|
||
|
|
||
|
|
||
|
def test_compressed1():
|
||
|
fig, axs = plt.subplots(3, 2, layout='compressed',
|
||
|
sharex=True, sharey=True)
|
||
|
for ax in axs.flat:
|
||
|
pc = ax.imshow(np.random.randn(20, 20))
|
||
|
|
||
|
fig.colorbar(pc, ax=axs)
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
pos = axs[0, 0].get_position()
|
||
|
np.testing.assert_allclose(pos.x0, 0.2344, atol=1e-3)
|
||
|
pos = axs[0, 1].get_position()
|
||
|
np.testing.assert_allclose(pos.x1, 0.7024, atol=1e-3)
|
||
|
|
||
|
# wider than tall
|
||
|
fig, axs = plt.subplots(2, 3, layout='compressed',
|
||
|
sharex=True, sharey=True, figsize=(5, 4))
|
||
|
for ax in axs.flat:
|
||
|
pc = ax.imshow(np.random.randn(20, 20))
|
||
|
|
||
|
fig.colorbar(pc, ax=axs)
|
||
|
fig.draw_without_rendering()
|
||
|
|
||
|
pos = axs[0, 0].get_position()
|
||
|
np.testing.assert_allclose(pos.x0, 0.06195, atol=1e-3)
|
||
|
np.testing.assert_allclose(pos.y1, 0.8537, atol=1e-3)
|
||
|
pos = axs[1, 2].get_position()
|
||
|
np.testing.assert_allclose(pos.x1, 0.8618, atol=1e-3)
|
||
|
np.testing.assert_allclose(pos.y0, 0.1934, atol=1e-3)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize('arg, state', [
|
||
|
(True, True),
|
||
|
(False, False),
|
||
|
({}, True),
|
||
|
({'rect': None}, True)
|
||
|
])
|
||
|
def test_set_constrained_layout(arg, state):
|
||
|
fig, ax = plt.subplots(constrained_layout=arg)
|
||
|
assert fig.get_constrained_layout() is state
|
||
|
|
||
|
|
||
|
def test_constrained_toggle():
|
||
|
fig, ax = plt.subplots()
|
||
|
with pytest.warns(PendingDeprecationWarning):
|
||
|
fig.set_constrained_layout(True)
|
||
|
assert fig.get_constrained_layout()
|
||
|
fig.set_constrained_layout(False)
|
||
|
assert not fig.get_constrained_layout()
|
||
|
fig.set_constrained_layout(True)
|
||
|
assert fig.get_constrained_layout()
|
||
|
|
||
|
|
||
|
def test_layout_leak():
|
||
|
# Make sure there aren't any cyclic references when using LayoutGrid
|
||
|
# GH #25853
|
||
|
fig = plt.figure(constrained_layout=True, figsize=(10, 10))
|
||
|
fig.add_subplot()
|
||
|
fig.draw_without_rendering()
|
||
|
plt.close("all")
|
||
|
del fig
|
||
|
gc.collect()
|
||
|
assert not any(isinstance(obj, mpl._layoutgrid.LayoutGrid)
|
||
|
for obj in gc.get_objects())
|