From 553bfab94660c51eebf0590233975faa30a97e58 Mon Sep 17 00:00:00 2001 From: ImportanceOfBeingErnest Date: Wed, 6 Jun 2018 20:59:38 +0200 Subject: [PATCH] Constrained layout tutorial improvements --- .../intermediate/constrainedlayout_guide.py | 119 ++++++++++-------- tutorials/intermediate/tight_layout_guide.py | 3 + tutorials/introductory/customizing.py | 2 + 3 files changed, 73 insertions(+), 51 deletions(-) diff --git a/tutorials/intermediate/constrainedlayout_guide.py b/tutorials/intermediate/constrainedlayout_guide.py index 3f32968105c5..74e5e13d4abf 100644 --- a/tutorials/intermediate/constrainedlayout_guide.py +++ b/tutorials/intermediate/constrainedlayout_guide.py @@ -9,8 +9,24 @@ legends and colorbars so that they fit in the figure window while still preserving, as best they can, the logical layout requested by the user. -*constrained_layout* is similar to *tight_layout*, but uses a constraint -solver to determine the size of axes that allows them to fit. +*constrained_layout* is similar to +:doc:`tight_layout`, +but uses a constraint solver to determine the size of axes that allows +them to fit. + +*constrained_layout* needs to be activated before any axes are added to +a figure. Two ways of doing so are + +* using the respective argument to :func:`~.pyplot.subplots` or + :func:`~.pyplot.figure`, e.g.:: + + plt.subplots(contrained_layout=True) + +* activate it via :ref:`rcParams`, like:: + + plt.rcParams['figure.constrained_layout.use'] = True + +Those are described in detail throughout the following sections. .. warning:: @@ -83,7 +99,7 @@ def example_plot(ax, fontsize=12, nodec=False): example_plot(ax) ############################################################################### -# Specifying `constrained_layout=True` in the call to `plt.subplots` +# Specifying ``constrained_layout=True`` in the call to ``plt.subplots`` # causes the layout to be properly constrained. fig, axs = plt.subplots(2, 2, constrained_layout=True) @@ -102,9 +118,9 @@ def example_plot(ax, fontsize=12, nodec=False): # # .. note:: # -# For the `pcolormesh` kwargs (``pc_kwargs``) we use a dictionary. +# For the `~.axes.Axes.pcolormesh` kwargs (``pc_kwargs``) we use a dictionary. # Below we will assign one colorbar to a number of axes each containing -# a `ScalarMappable`; specifying the norm and colormap ensures +# a `~.cm.ScalarMappable`; specifying the norm and colormap ensures # the colorbar is accurate for all the axes. arr = np.arange(100).reshape((10, 10)) @@ -117,7 +133,8 @@ def example_plot(ax, fontsize=12, nodec=False): ############################################################################ # If you specify a list of axes (or other iterable container) to the -# ``ax`` argument of ``colorbar``, constrained_layout will take space from all # axes that share the same gridspec. +# ``ax`` argument of ``colorbar``, constrained_layout will take space from all +# axes that share the same gridspec. fig, axs = plt.subplots(2, 2, figsize=(4, 4), constrained_layout=True) for ax in axs.flatten(): @@ -153,7 +170,7 @@ def example_plot(ax, fontsize=12, nodec=False): # Suptitle # ========= # -# ``constrained_layout`` can also make room for ``suptitle``. +# ``constrained_layout`` can also make room for `~.figure.Figure.suptitle`. fig, axs = plt.subplots(2, 2, figsize=(4, 4), constrained_layout=True) for ax in axs.flatten(): @@ -165,10 +182,10 @@ def example_plot(ax, fontsize=12, nodec=False): # Legends # ======= # -# Legends can be placed outside -# of their parent axis. Constrained-layout is designed to handle this. +# Legends can be placed outside of their parent axis. +# Constrained-layout is designed to handle this for :meth:`.Axes.legend`. # However, constrained-layout does *not* handle legends being created via -# ``fig.legend()`` (yet). +# :meth:`.Figure.legend` (yet). fig, ax = plt.subplots(constrained_layout=True) ax.plot(np.arange(10), label='This is a plot') @@ -190,8 +207,8 @@ def example_plot(ax, fontsize=12, nodec=False): # For constrained_layout, we have implemented a padding around the edge of # each axes. This padding sets the distance from the edge of the plot, # and the minimum distance between adjacent plots. It is specified in -# inches by the keyword arguments `w_pad` and `h_pad` to the function -# `fig.set_constrained_layout_pads`: +# inches by the keyword arguments ``w_pad`` and ``h_pad`` to the function +# `~.figure.Figure.set_constrained_layout_pads`: fig, axs = plt.subplots(2, 2, constrained_layout=True) for ax in axs.flatten(): @@ -210,7 +227,7 @@ def example_plot(ax, fontsize=12, nodec=False): hspace=0., wspace=0.) ########################################## -# Spacing between subplots is set by `wspace` and `hspace`. There are +# Spacing between subplots is set by ``wspace`` and ``hspace``. There are # specified as a fraction of the size of the subplot group as a whole. # If the size of the figure is changed, then these spaces change in # proportion. Note in the blow how the space at the edges doesn't change from @@ -229,10 +246,10 @@ def example_plot(ax, fontsize=12, nodec=False): # Spacing with colorbars # ----------------------- # -# Colorbars still respect the `w_pad` and `h_pad` values. However they will -# be `wspace` and `hsapce` apart from other subplots. Note the use of a `pad` -# kwarg here in the `colorbar` call. It defaults to 0.02 of the size of the -# axis it is attached to. +# Colorbars still respect the ``w_pad`` and ``h_pad`` values. However they will +# be ``wspace`` and ``hsapce`` apart from other subplots. Note the use of a +# ``pad`` kwarg here in the ``colorbar`` call. It defaults to 0.02 of the size +# of the axis it is attached to. fig, axs = plt.subplots(2, 2, constrained_layout=True) for ax in axs.flatten(): @@ -246,7 +263,7 @@ def example_plot(ax, fontsize=12, nodec=False): ########################################## # In the above example, the colorbar will not ever be closer than 2 pts to # the plot, but if we want it a bit further away, we can specify its value -# for `pad` to be non-zero. +# for ``pad`` to be non-zero. fig, axs = plt.subplots(2, 2, constrained_layout=True) for ax in axs.flatten(): @@ -259,16 +276,16 @@ def example_plot(ax, fontsize=12, nodec=False): ########################################## # rcParams -# -------- +# ======== # -# There are five `rcParams` that can be set, either in a script -# or in the `matplotlibrc` file. They all have the prefix -# `figure.constrained_layout`: +# There are five :ref:`rcParams` that can be set, +# either in a script or in the `matplotlibrc` file. +# They all have the prefix ``figure.constrained_layout``: # -# - `use`: Whether to use constrained_layout. Default is False -# - `w_pad`, `h_pad` Padding around axes objects. +# - ``use``: Whether to use constrained_layout. Default is False +# - ``w_pad``, ``h_pad``: Padding around axes objects. # Float representing inches. Default is 3./72. inches (3 pts) -# - `wspace`, `hspace` Space between subplot groups. +# - ``wspace``, ``hspace``: Space between subplot groups. # Float representing a fraction of the subplot widths being separated. # Default is 0.02. @@ -296,7 +313,7 @@ def example_plot(ax, fontsize=12, nodec=False): example_plot(ax2) ############################################################################### -# More complicated gridspec layouts are possible... +# More complicated gridspec layouts are possible. fig = plt.figure(constrained_layout=True) @@ -377,9 +394,9 @@ def docomplicated(suptitle=None): # ================================ # # There can be good reasons to manually set an axes position. A manual call -# to `ax.set_position()` will set the axes so constrained_layout has no -# effect on it anymore. (Note that constrained_layout still leaves the space -# for the axes that is moved). +# to `~.axes.Axes.set_position` will set the axes so constrained_layout has +# no effect on it anymore. (Note that constrained_layout still leaves the +# space for the axes that is moved). fig, axs = plt.subplots(1, 2, constrained_layout=True) example_plot(axs[0], fontsize=12) @@ -387,7 +404,7 @@ def docomplicated(suptitle=None): ############################################################################### # If you want an inset axes in data-space, you need to manually execute the -# layout using `fig.execute_constrained_layout()` call. The inset figure +# layout using ``fig.execute_constrained_layout()`` call. The inset figure # will then be properly positioned. However, it will not be properly # positioned if the size of the figure is subsequently changed. Similarly, # if the figure is printed to another backend, there may be slight changes @@ -414,7 +431,7 @@ def docomplicated(suptitle=None): # # ``constrained_layout`` will not work on subplots # created via the `subplot` command. The reason is that each of these -# commands creates a separate `GridSpec` instance and `constrained_layout` +# commands creates a separate `GridSpec` instance and ``constrained_layout`` # uses (nested) gridspecs to carry out the layout. So the following fails # to yield a nice layout: @@ -520,33 +537,33 @@ def docomplicated(suptitle=None): # # Figures are laid out in a hierarchy: # -# 1. Figure: `fig = plt.figure()` +# 1. Figure: ``fig = plt.figure()`` # -# a. Gridspec `gs0 = gridspec.GridSpec(1, 2, figure=fig)` +# a. Gridspec ``gs0 = gridspec.GridSpec(1, 2, figure=fig)`` # -# i. Subplotspec: `ss = gs[0, 0]` +# i. Subplotspec: ``ss = gs[0, 0]`` # -# 1. Axes: `ax0 = fig.add_subplot(ss)` +# 1. Axes: ``ax0 = fig.add_subplot(ss)`` # -# ii. Subplotspec: `ss = gs[0, 1]` +# ii. Subplotspec: ``ss = gs[0, 1]`` # -# 1. Gridspec: `gsR = gridspec.GridSpecFromSubplotSpec(2, 1, ss)` +# 1. Gridspec: ``gsR = gridspec.GridSpecFromSubplotSpec(2, 1, ss)`` # -# - Subplotspec: ss = gsR[0, 0] +# - Subplotspec: ``ss = gsR[0, 0]`` # -# - Axes: `axR0 = fig.add_subplot(ss)` +# - Axes: ``axR0 = fig.add_subplot(ss)`` # -# - Subplotspec: ss = gsR[1, 0] +# - Subplotspec: ``ss = gsR[1, 0]`` # -# - Axes: `axR1 = fig.add_subplot(ss)` +# - Axes: ``axR1 = fig.add_subplot(ss)`` # # Each item has a layoutbox associated with it. The nesting of gridspecs # created with `.GridSpecFromSubplotSpec` can be arbitrarily deep. # -# Each ``~matplotlib.axes.Axes` has *two* layoutboxes. The first one, +# Each `~matplotlib.axes.Axes` has *two* layoutboxes. The first one, # ``ax._layoutbox`` represents the outside of the Axes and all its # decorations (i.e. ticklabels,axis labels, etc.). -# The second layoutbox corresponds to the Axes' `ax.position`, which sets +# The second layoutbox corresponds to the Axes' ``ax.position``, which sets # where in the figure the spines are placed. # # Why so many stacked containers? Ideally, all that would be needed are the @@ -569,8 +586,8 @@ def docomplicated(suptitle=None): # the difference between the red ``pos`` box and the green ``ax`` box # is set by the size of the decorations around the Axes. # -# In the code, this is accomplished by the entries in `.do_constrained_layout` -# like:: +# In the code, this is accomplished by the entries in +# ``do_constrained_layout()`` like:: # # ax._poslayoutbox.edit_left_margin_min(-bbox.x0 + pos.x0 + w_padt) # @@ -589,7 +606,7 @@ def docomplicated(suptitle=None): # much smaller than the left-hand, so the right-hand layoutboxes are smaller. # # The Subplotspec boxes are laid out in the code in the subroutine -# `.arange_subplotspecs`, which simply checks the subplotspecs in the code +# ``arange_subplotspecs()``, which simply checks the subplotspecs in the code # against one another and stacks them appropriately. # # The two ``pos`` axes are lined up. Because they have the same @@ -627,10 +644,10 @@ def docomplicated(suptitle=None): # number of columns (one in this example). # # The colorbar layout logic is contained in `~matplotlib.colorbar.make_axes` -# which calls `._constrained_layout.layoutcolorbarsingle` +# which calls ``_constrained_layout.layoutcolorbarsingle()`` # for cbars attached to a single axes, and -# `._constrained_layout.layoutcolorbargridspec` if the colorbar is associated -# with a gridspec. +# ``_constrained_layout.layoutcolorbargridspec()`` if the colorbar is +# associated with a gridspec. fig, ax = plt.subplots(1, 2, constrained_layout=True) im = ax[0].pcolormesh(arr, **pc_kwargs) @@ -644,7 +661,7 @@ def docomplicated(suptitle=None): # # This example shows the Subplotspec layoutboxes being made smaller by # a colorbar layoutbox. The size of the colorbar layoutbox is -# set to be *shrink* smaller than the vertical extent of the ``pos`` +# set to be ``shrink`` smaller than the vertical extent of the ``pos`` # layoutboxes in the gridspec, and it is made to be centered between # those two points. @@ -713,7 +730,7 @@ def docomplicated(suptitle=None): # the axes position in made the same size as the occupied Axes positions. # # This is done at the start of -# `~._constrained_layout.do_constrained_layout` (``hassubplotspec``). +# ``_constrained_layout.do_constrained_layout()`` (``hassubplotspec``). fig = plt.figure(constrained_layout=True) gs = gridspec.GridSpec(1, 3, figure=fig) diff --git a/tutorials/intermediate/tight_layout_guide.py b/tutorials/intermediate/tight_layout_guide.py index 04d7a045fc2f..b31b65ae4788 100644 --- a/tutorials/intermediate/tight_layout_guide.py +++ b/tutorials/intermediate/tight_layout_guide.py @@ -10,6 +10,9 @@ feature and may not work for some cases. It only checks the extents of ticklabels, axis labels, and titles. +An alternative to *tight_layout* is +:doc:`constrained_layout`. + Simple Example ============== diff --git a/tutorials/introductory/customizing.py b/tutorials/introductory/customizing.py index e721f2df8712..142550b0638b 100644 --- a/tutorials/introductory/customizing.py +++ b/tutorials/introductory/customizing.py @@ -91,6 +91,8 @@ plt.show() ############################################################################### +# .. _matplotlib-rcparams: +# # matplotlib rcParams # =================== #