diff --git a/.flake8 b/.flake8 index ca1d8f2d4bdc..ee00a5b98ab6 100644 --- a/.flake8 +++ b/.flake8 @@ -94,6 +94,7 @@ per-file-ignores = tutorials/colors/colormap-manipulation.py: E402 tutorials/intermediate/artists.py: E402 tutorials/intermediate/constrainedlayout_guide.py: E402 + tutorials/intermediate/gridspec.py: E402 tutorials/intermediate/legend_guide.py: E402 tutorials/intermediate/tight_layout_guide.py: E402 tutorials/introductory/customizing.py: E501 diff --git a/doc/users/prev_whats_new/whats_new_1.0.rst b/doc/users/prev_whats_new/whats_new_1.0.rst index af078f2a734d..bce014e5e4e2 100644 --- a/doc/users/prev_whats_new/whats_new_1.0.rst +++ b/doc/users/prev_whats_new/whats_new_1.0.rst @@ -23,8 +23,7 @@ Sophisticated subplot grid layout Jae-Joon Lee has written :mod:`~matplotlib.gridspec`, a new module for doing complex subplot layouts, featuring row and column spans and -more. See :doc:`/tutorials/intermediate/arranging_axes` for a tutorial -overview. +more. See :doc:`/tutorials/intermediate/gridspec` for a tutorial overview. .. figure:: ../../gallery/userdemo/images/sphx_glr_demo_gridspec01_001.png :target: ../../gallery/userdemo/demo_gridspec01.html diff --git a/examples/lines_bars_and_markers/scatter_hist.py b/examples/lines_bars_and_markers/scatter_hist.py index 395b413ceb6a..1ad5d8ac1c8b 100644 --- a/examples/lines_bars_and_markers/scatter_hist.py +++ b/examples/lines_bars_and_markers/scatter_hist.py @@ -88,8 +88,8 @@ def scatter_hist(x, y, ax, ax_histx, ax_histy): # ---------------- # # We may equally define a gridspec with unequal width- and height-ratios to -# achieve desired layout. Also see the -# :doc:`/tutorials/intermediate/arranging_axes` tutorial. +# achieve desired layout. Also see the :doc:`/tutorials/intermediate/gridspec` +# tutorial. # start with a square Figure fig = plt.figure(figsize=(8, 8)) diff --git a/examples/subplots_axes_and_figures/gridspec_and_subplots.py b/examples/subplots_axes_and_figures/gridspec_and_subplots.py index 133fd37b5d71..fbb7ebd013a0 100644 --- a/examples/subplots_axes_and_figures/gridspec_and_subplots.py +++ b/examples/subplots_axes_and_figures/gridspec_and_subplots.py @@ -8,10 +8,7 @@ and then remove the covered axes and fill the gap with a new bigger axes. Here we create a layout with the bottom two axes in the last column combined. -To start with this layout (rather than removing the overlapping axes) use -`~.pyplot.subplot_mosaic`. - -See also :doc:`/tutorials/intermediate/arranging_axes`. +See also :doc:`/tutorials/intermediate/gridspec`. """ import matplotlib.pyplot as plt diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index cbe6532c1265..bbd6fe846650 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -5,10 +5,8 @@ The `GridSpec` specifies the overall grid structure. Individual cells within the grid are referenced by `SubplotSpec`\s. -Often, users need not access this module directly, and can use higher-level -methods like `~.pyplot.subplots`, `~.pyplot.subplot_mosaic` and -`~.Figure.subfigures`. See the tutorial -:doc:`/tutorials/intermediate/arranging_axes` for a guide. +See the tutorial :doc:`/tutorials/intermediate/gridspec` for a comprehensive +usage guide. """ import copy diff --git a/tutorials/intermediate/arranging_axes.py b/tutorials/intermediate/arranging_axes.py deleted file mode 100644 index a266843f77aa..000000000000 --- a/tutorials/intermediate/arranging_axes.py +++ /dev/null @@ -1,382 +0,0 @@ -""" -===================================== -Arranging multiple Axes in a Figure -===================================== - -Often more than one Axes is wanted on a figure at a time, usually -organized into a regular grid. Matplotlib has a variety of tools for -working with grids of Axes that have evolved over the history of the library. -Here we will discuss the tools we think users should use most often, the tools -that underpin how Axes are organized, and mention some of the older tools. - -.. note:: - - Matplotlib uses *Axes* to refer to the drawing area that contains - data, x- and y-axis, ticks, labels, title, etc. See :ref:`figure_parts` - for more details. Another term that is often used is "subplot", which - refers to an Axes that is in a grid with other Axes objects. - -Overview -======== - -Create grid-shaped combinations of Axes ---------------------------------------- - -`~matplotlib.pyplot.subplots` - The primary function used to create figures and a grid of Axes. It - creates and places all Axes on the figure at once, and returns an - object array with handles for the Axes in the grid. See - `.Figure.subplots`. - -or - -`~matplotlib.pyplot.subplot_mosaic` - A simple way to create figures and a grid of Axes, with the added - flexibility that Axes can also span rows or columns. The Axes - are returned in a labelled dictionary instead of an array. See also - `.Figure.subplot_mosaic` and :doc:`/tutorials/provisional/mosaic`. - -Sometimes it is natural to have more than one distinct group of Axes grids, -in which case Matplotlib has the concept of `~.figure.SubFigure`: - -`~matplotlib.figure.SubFigure` - A virtual figure within a figure. - -Underlying tools ----------------- - -Underlying these are the concept of a `~.gridspec.GridSpec` and -a `~.SubplotSpec`: - -`~matplotlib.gridspec.GridSpec` - Specifies the geometry of the grid that a subplot will be - placed. The number of rows and number of columns of the grid - need to be set. Optionally, the subplot layout parameters - (e.g., left, right, etc.) can be tuned. - -`~matplotlib.gridspec.SubplotSpec` - Specifies the location of the subplot in the given `.GridSpec`. - -Adding single Axes at a time ----------------------------- - -The above functions create all Axes in a single function call. It is also -possible to add Axes one at a time, and this was originally how Matplotlib -used to work. Doing so is generally less elegant and flexible, though -sometimes useful for interactive work or to place an Axes in a custom -location: - -`~matplotlib.figure.Figure.add_axes` - Adds a single axes at a location specified by - ``[left, bottom, width, height]`` in fractions of figure width or height. - -`~matplotlib.pyplot.subplot` or `.Figure.add_subplot` - Adds a single subplot on a figure, with 1-based indexing (inherited from - Matlab). Columns and rows can be spanned by specifying a range of grid - cells. - -`~matplotlib.pyplot.subplot2grid` - Similar to `.pyplot.subplot`, but uses 0-based indexing and two-d python - slicing to choose cells. - -.. redirect-from:: /tutorials/intermediate/gridspec - -""" -############################################################################ -# High-level methods for making grids -# =================================== -# -# Basic 2x2 grid -# -------------- -# -# We can create a basic 2-by-2 grid of Axes using -# `~matplotlib.pyplot.subplots`. It returns a `~matplotlib.figure.Figure` -# instance and an array of `~matplotlib.axes.Axes` objects. The Axes -# objects can be used to access methods to place artists on the Axes; here -# we use `~.Axes.annotate`, but other examples could be `~.Axes.plot`, -# `~.Axes.pcolormesh`, etc. - -import matplotlib.pyplot as plt -import numpy as np - -fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(5.5, 3.5), - constrained_layout=True) -# add an artist, in this case a nice label in the middle... -for row in range(2): - for col in range(2): - axs[row, col].annotate(f'axs[{row}, {col}]', (0.5, 0.5), - transform=axs[row, col].transAxes, - ha='center', va='center', fontsize=18, - color='darkgrey') -fig.suptitle('plt.subplots()') - -############################################################################## -# We will annotate a lot of Axes, so lets encapsulate the annotation, rather -# than having that large piece of annotation code every time we need it: - - -def annotate_axes(ax, text, fontsize=18): - ax.text(0.5, 0.5, text, transform=ax.transAxes, - ha="center", va="center", fontsize=fontsize, color="darkgrey") - - -############################################################################## -# The same effect can be achieved with `~.pyplot.subplot_mosaic`, -# but the return type is a dictionary instead of an array, where the user -# can give the keys useful meanings. Here we provide two lists, each list -# representing a row, and each element in the list a key representing the -# column. - -fig, axd = plt.subplot_mosaic([['upper left', 'upper right'], - ['lower left', 'lower right']], - figsize=(5.5, 3.5), constrained_layout=True) -for k in axd: - annotate_axes(axd[k], f'axd["{k}"]', fontsize=14) -fig.suptitle('plt.subplot_mosaic()') - -############################################################################ -# Axes spanning rows or columns in a grid -# --------------------------------------- -# -# Sometimes we want Axes to span rows or columns of the grid. -# There are actually multiple ways to accomplish this, but the most -# convenient is probably to use `~.pyplot.subplot_mosaic` by repeating one -# of the keys: - -fig, axd = plt.subplot_mosaic([['upper left', 'right'], - ['lower left', 'right']], - figsize=(5.5, 3.5), constrained_layout=True) -for k in axd: - annotate_axes(axd[k], f'axd["{k}"]', fontsize=14) -fig.suptitle('plt.subplot_mosaic()') - -############################################################################ -# See below for the description of how to do the same thing using -# `~matplotlib.gridspec.GridSpec` or `~matplotlib.pyplot.subplot2grid`. -# -# Variable widths or heights in a grid -# ------------------------------------ -# -# Both `~.pyplot.subplots` and `~.pyplot.subplot_mosaic` allow the rows -# in the grid to be different heights, and the columns to be different -# widths using the *gridspec_kw* keyword argument. -# Spacing parameters accepted by `~matplotlib.gridspec.GridSpec` -# can be passed to `~matplotlib.pyplot.subplots` and -# `~matplotlib.pyplot.subplot_mosaic`: - -gs_kw = dict(width_ratios=[1.4, 1], height_ratios=[1, 2]) -fig, axd = plt.subplot_mosaic([['upper left', 'right'], - ['lower left', 'right']], - gridspec_kw=gs_kw, figsize=(5.5, 3.5), - constrained_layout=True) -for k in axd: - annotate_axes(axd[k], f'axd["{k}"]', fontsize=14) -fig.suptitle('plt.subplot_mosaic()') - -############################################################################ -# Nested Axes layouts -# ------------------- -# -# Sometimes it is helpful to have two or more grids of Axes that -# may not need to be related to one another. The most simple way toin -# accomplish this is to use `.Figure.subfigures`. Note that the subfigure -# layouts are independent, so the Axes spines in each subfigure are not -# necessarily aligned. See below for a more verbose way to achieve the same -# effect with `~.gridspec.GridSpecFromSubplotSpec`. - -fig = plt.figure(constrained_layout=True) -subfigs = fig.subfigures(1, 2, wspace=0.07, width_ratios=[1.5, 1.]) -axs0 = subfigs[0].subplots(2, 2) -subfigs[0].set_facecolor('0.9') -subfigs[0].suptitle('subfigs[0]\nLeft side') -subfigs[0].supxlabel('xlabel for subfigs[0]') - -axs1 = subfigs[1].subplots(3, 1) -subfigs[1].suptitle('subfigs[1]') -subfigs[1].supylabel('ylabel for subfigs[1]') - -############################################################################ -# It is also possible to nest Axes using `~.pyplot.subplot_mosaic` using -# nested lists. This method does not use subfigures, like above, so lacks -# the ability to add per-subfigure ``suptitle`` and ``supxlabel``, etc. -# Rather it is a convenience wrapper around the `~.SubplotSpec.subgridspec` -# method described below. - -inner = [['innerA'], - ['innerB']] -outer = [['upper left', inner], - ['lower left', 'lower right']] - -fig, axd = plt.subplot_mosaic(outer, constrained_layout=True) -for k in axd: - annotate_axes(axd[k], f'axd["{k}"]') - -############################################################################ -# Low-level and advanced grid methods -# =================================== -# -# Internally, the arrangement of a grid of Axes is controlled by creating -# instances of `~.GridSpec` and `~.SubplotSpec`. *GridSpec* defines a -# (possibly non-uniform) grid of cells. Indexing into the *GridSpec* returns -# a SubplotSpec that covers one or more grid cells, and can be used to -# specify the location of an Axes. -# -# The following examples show how to use low-level methods to arrange Axes -# using *GridSpec* objects. -# -# Basic 2x2 grid -# -------------- -# -# We can accopmplish a 2x2 grid in the same manner as -# ``plt.subplots(2, 2)``: - -fig = plt.figure(figsize=(5.5, 3.5), constrained_layout=True) -spec = fig.add_gridspec(ncols=2, nrows=2) - -ax0 = fig.add_subplot(spec[0, 0]) -annotate_axes(ax0, 'ax0') - -ax1 = fig.add_subplot(spec[0, 1]) -annotate_axes(ax1, 'ax1') - -ax2 = fig.add_subplot(spec[1, 0]) -annotate_axes(ax2, 'ax2') - -ax3 = fig.add_subplot(spec[1, 1]) -annotate_axes(ax3, 'ax3') - -fig.suptitle('Manually added subplots using add_gridspec') - -############################################################################## -# Axes spanning rows or grids in a grid -# ------------------------------------- -# -# We can index the *spec* array using `NumPy slice syntax -# `_ -# and the new Axes will span the slice. This would be the same -# as ``fig, axd = plt.subplot_mosaic([['ax0', 'ax0'], ['ax1', 'ax2']], ...)``: - -fig = plt.figure(figsize=(5.5, 3.5), constrained_layout=True) -spec = fig.add_gridspec(2, 2) - -ax0 = fig.add_subplot(spec[0, :]) -annotate_axes(ax0, 'ax0') - -ax10 = fig.add_subplot(spec[1, 0]) -annotate_axes(ax10, 'ax10') - -ax11 = fig.add_subplot(spec[1, 1]) -annotate_axes(ax11, 'ax11') - -fig.suptitle('Manually added subplots, spanning a column') - -############################################################################### -# Manual adjustments to a *GridSpec* layout -# ----------------------------------------- -# -# When a *GridSpec* is explicitly used, you can adjust the layout -# parameters of subplots that are created from the *GridSpec*. Note this -# option is not compatible with ``constrained_layout`` or -# `.Figure.tight_layout` which both ignore *left* and *right* and adjust -# subplot sizes to fill the figure. Usually such manual placement -# requires iterations to make the Axes tick labels not overlap the Axes. -# -# These spacing parameters can also be passed to `~.pyplot.subplots` and -# `~.pyplot.subplot_mosaic` as the *gridspec_kw* argument. - -fig = plt.figure(constrained_layout=False, facecolor='0.9') -gs = fig.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.75, - hspace=0.1, wspace=0.05) -ax0 = fig.add_subplot(gs[:-1, :]) -annotate_axes(ax0, 'ax0') -ax1 = fig.add_subplot(gs[-1, :-1]) -annotate_axes(ax1, 'ax1') -ax2 = fig.add_subplot(gs[-1, -1]) -annotate_axes(ax2, 'ax2') -fig.suptitle('Manual gridspec with right=0.75') - -############################################################################### -# Nested layouts with SubplotSpec -# ------------------------------- -# -# You can create nested layout similar to `~.Figure.subfigures` using -# `~.gridspec.SubplotSpec.subgridspec`. Here the Axes spines *are* -# aligned. -# -# Note this is also available from the more verbose -# `.gridspec.GridSpecFromSubplotSpec`. - -fig = plt.figure(constrained_layout=True) -gs0 = fig.add_gridspec(1, 2) - -gs00 = gs0[0].subgridspec(2, 2) -gs01 = gs0[1].subgridspec(3, 1) - -for a in range(2): - for b in range(2): - ax = fig.add_subplot(gs00[a, b]) - annotate_axes(ax, f'axLeft[{a}, {b}]', fontsize=10) - if a == 1 and b == 1: - ax.set_xlabel('xlabel') -for a in range(3): - ax = fig.add_subplot(gs01[a]) - annotate_axes(ax, f'axRight[{a}, {b}]') - if a == 2: - ax.set_ylabel('ylabel') - -fig.suptitle('nested gridspecs') - -############################################################################### -# Here's a more sophisticated example of nested *GridSpec*: We create an outer -# 4x4 grid with each cell containing an inner 3x3 grid of Axes. We outline -# the outer 4x4 grid by hiding appropriate spines in each of the inner 3x3 -# grids. - - -def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): - return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) - -fig = plt.figure(figsize=(8, 8), constrained_layout=False) -outer_grid = fig.add_gridspec(4, 4, wspace=0, hspace=0) - -for a in range(4): - for b in range(4): - # gridspec inside gridspec - inner_grid = outer_grid[a, b].subgridspec(3, 3, wspace=0, hspace=0) - axs = inner_grid.subplots() # Create all subplots for the inner grid. - for (c, d), ax in np.ndenumerate(axs): - ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1)) - ax.set(xticks=[], yticks=[]) - -# show only the outside spines -for ax in fig.get_axes(): - ss = ax.get_subplotspec() - ax.spines.top.set_visible(ss.is_first_row()) - ax.spines.bottom.set_visible(ss.is_last_row()) - ax.spines.left.set_visible(ss.is_first_col()) - ax.spines.right.set_visible(ss.is_last_col()) - -plt.show() - -############################################################################# -# -# More reading -# ============ -# -# - More details about :doc:`subplot mosaic `. -# - More details about :doc:`constrained layout -# `, used to align -# spacing in most of these examples. -# -# .. admonition:: References -# -# The use of the following functions, methods, classes and modules is shown -# in this example: -# -# - `matplotlib.pyplot.subplots` -# - `matplotlib.pyplot.subplot_mosaic` -# - `matplotlib.figure.Figure.add_gridspec` -# - `matplotlib.figure.Figure.add_subplot` -# - `matplotlib.gridspec.GridSpec` -# - `matplotlib.gridspec.SubplotSpec.subgridspec` -# - `matplotlib.gridspec.GridSpecFromSubplotSpec` diff --git a/tutorials/intermediate/gridspec.py b/tutorials/intermediate/gridspec.py new file mode 100644 index 000000000000..d9c5f10bd49e --- /dev/null +++ b/tutorials/intermediate/gridspec.py @@ -0,0 +1,265 @@ +""" +============================================================= +Customizing Figure Layouts Using GridSpec and Other Functions +============================================================= + +How to create grid-shaped combinations of axes. + +`~matplotlib.pyplot.subplots` + The primary function used to create figures and axes. It is similar to + `.pyplot.subplot`, but creates and places all axes on the figure at once. + See also `.Figure.subplots`. + +`~matplotlib.gridspec.GridSpec` + Specifies the geometry of the grid that a subplot will be + placed. The number of rows and number of columns of the grid + need to be set. Optionally, the subplot layout parameters + (e.g., left, right, etc.) can be tuned. + +`~matplotlib.gridspec.SubplotSpec` + Specifies the location of the subplot in the given `.GridSpec`. + +`~matplotlib.pyplot.subplot2grid` + A helper function that is similar to `.pyplot.subplot`, + but uses 0-based indexing and let subplot to occupy multiple cells. + This function is not covered in this tutorial. +""" + +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec + +############################################################################ +# Basic Quickstart Guide +# ====================== +# +# These first two examples show how to create a basic 2-by-2 grid using +# both :func:`~matplotlib.pyplot.subplots` and :mod:`~matplotlib.gridspec`. +# +# Using :func:`~matplotlib.pyplot.subplots` is quite simple. +# It returns a :class:`~matplotlib.figure.Figure` instance and an array of +# :class:`~matplotlib.axes.Axes` objects. + +fig1, f1_axes = plt.subplots(ncols=2, nrows=2, constrained_layout=True) + +############################################################################ +# For a simple use case such as this, :mod:`~matplotlib.gridspec` is +# perhaps overly verbose. +# You have to create the figure and :class:`~matplotlib.gridspec.GridSpec` +# instance separately, then pass elements of gridspec instance to the +# :func:`~matplotlib.figure.Figure.add_subplot` method to create the axes +# objects. +# The elements of the gridspec are accessed in generally the same manner as +# numpy arrays. + +fig2 = plt.figure(constrained_layout=True) +spec2 = gridspec.GridSpec(ncols=2, nrows=2, figure=fig2) +f2_ax1 = fig2.add_subplot(spec2[0, 0]) +f2_ax2 = fig2.add_subplot(spec2[0, 1]) +f2_ax3 = fig2.add_subplot(spec2[1, 0]) +f2_ax4 = fig2.add_subplot(spec2[1, 1]) + +############################################################################# +# The power of gridspec comes in being able to create subplots that span +# rows and columns. Note the `NumPy slice syntax +# `_ +# for selecting the part of the gridspec each subplot will occupy. +# +# Note that we have also used the convenience method `.Figure.add_gridspec` +# instead of `.gridspec.GridSpec`, potentially saving the user an import, +# and keeping the namespace cleaner. + +fig3 = plt.figure(constrained_layout=True) +gs = fig3.add_gridspec(3, 3) +f3_ax1 = fig3.add_subplot(gs[0, :]) +f3_ax1.set_title('gs[0, :]') +f3_ax2 = fig3.add_subplot(gs[1, :-1]) +f3_ax2.set_title('gs[1, :-1]') +f3_ax3 = fig3.add_subplot(gs[1:, -1]) +f3_ax3.set_title('gs[1:, -1]') +f3_ax4 = fig3.add_subplot(gs[-1, 0]) +f3_ax4.set_title('gs[-1, 0]') +f3_ax5 = fig3.add_subplot(gs[-1, -2]) +f3_ax5.set_title('gs[-1, -2]') + +############################################################################# +# :mod:`~matplotlib.gridspec` is also indispensable for creating subplots +# of different widths via a couple of methods. +# +# The method shown here is similar to the one above and initializes a +# uniform grid specification, +# and then uses numpy indexing and slices to allocate multiple +# "cells" for a given subplot. + +fig4 = plt.figure(constrained_layout=True) +spec4 = fig4.add_gridspec(ncols=2, nrows=2) +anno_opts = dict(xy=(0.5, 0.5), xycoords='axes fraction', + va='center', ha='center') + +f4_ax1 = fig4.add_subplot(spec4[0, 0]) +f4_ax1.annotate('GridSpec[0, 0]', **anno_opts) +fig4.add_subplot(spec4[0, 1]).annotate('GridSpec[0, 1:]', **anno_opts) +fig4.add_subplot(spec4[1, 0]).annotate('GridSpec[1:, 0]', **anno_opts) +fig4.add_subplot(spec4[1, 1]).annotate('GridSpec[1:, 1:]', **anno_opts) + +############################################################################ +# Another option is to use the ``width_ratios`` and ``height_ratios`` +# parameters. These keyword arguments are lists of numbers. +# Note that absolute values are meaningless, only their relative ratios +# matter. That means that ``width_ratios=[2, 4, 8]`` is equivalent to +# ``width_ratios=[1, 2, 4]`` within equally wide figures. +# For the sake of demonstration, we'll blindly create the axes within +# ``for`` loops since we won't need them later. + +fig5 = plt.figure(constrained_layout=True) +widths = [2, 3, 1.5] +heights = [1, 3, 2] +spec5 = fig5.add_gridspec(ncols=3, nrows=3, width_ratios=widths, + height_ratios=heights) +for row in range(3): + for col in range(3): + ax = fig5.add_subplot(spec5[row, col]) + label = 'Width: {}\nHeight: {}'.format(widths[col], heights[row]) + ax.annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center') + +############################################################################ +# Learning to use ``width_ratios`` and ``height_ratios`` is particularly +# useful since the top-level function :func:`~matplotlib.pyplot.subplots` +# accepts them within the ``gridspec_kw`` parameter. +# For that matter, any parameter accepted by +# :class:`~matplotlib.gridspec.GridSpec` can be passed to +# :func:`~matplotlib.pyplot.subplots` via the ``gridspec_kw`` parameter. +# This example recreates the previous figure without directly using a +# gridspec instance. + +gs_kw = dict(width_ratios=widths, height_ratios=heights) +fig6, f6_axes = plt.subplots(ncols=3, nrows=3, constrained_layout=True, + gridspec_kw=gs_kw) +for r, row in enumerate(f6_axes): + for c, ax in enumerate(row): + label = 'Width: {}\nHeight: {}'.format(widths[c], heights[r]) + ax.annotate(label, (0.1, 0.5), xycoords='axes fraction', va='center') + +############################################################################ +# The ``subplots`` and ``get_gridspec`` methods can be combined since it is +# sometimes more convenient to make most of the subplots using ``subplots`` +# and then remove some and combine them. Here we create a layout with +# the bottom two axes in the last column combined. + +fig7, f7_axs = plt.subplots(ncols=3, nrows=3) +gs = f7_axs[1, 2].get_gridspec() +# remove the underlying axes +for ax in f7_axs[1:, -1]: + ax.remove() +axbig = fig7.add_subplot(gs[1:, -1]) +axbig.annotate('Big Axes \nGridSpec[1:, -1]', (0.1, 0.5), + xycoords='axes fraction', va='center') + +fig7.tight_layout() + +############################################################################### +# Fine Adjustments to a Gridspec Layout +# ===================================== +# +# When a GridSpec is explicitly used, you can adjust the layout +# parameters of subplots that are created from the GridSpec. Note this +# option is not compatible with ``constrained_layout`` or +# `.Figure.tight_layout` which both adjust subplot sizes to fill the +# figure. + +fig8 = plt.figure(constrained_layout=False) +gs1 = fig8.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.48, wspace=0.05) +f8_ax1 = fig8.add_subplot(gs1[:-1, :]) +f8_ax2 = fig8.add_subplot(gs1[-1, :-1]) +f8_ax3 = fig8.add_subplot(gs1[-1, -1]) + +############################################################################### +# This is similar to :func:`~matplotlib.pyplot.subplots_adjust`, but it only +# affects the subplots that are created from the given GridSpec. +# +# For example, compare the left and right sides of this figure: + +fig9 = plt.figure(constrained_layout=False) +gs1 = fig9.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.48, + wspace=0.05) +f9_ax1 = fig9.add_subplot(gs1[:-1, :]) +f9_ax2 = fig9.add_subplot(gs1[-1, :-1]) +f9_ax3 = fig9.add_subplot(gs1[-1, -1]) + +gs2 = fig9.add_gridspec(nrows=3, ncols=3, left=0.55, right=0.98, + hspace=0.05) +f9_ax4 = fig9.add_subplot(gs2[:, :-1]) +f9_ax5 = fig9.add_subplot(gs2[:-1, -1]) +f9_ax6 = fig9.add_subplot(gs2[-1, -1]) + +############################################################################### +# GridSpec using SubplotSpec +# ========================== +# +# You can create GridSpec from the :class:`~matplotlib.gridspec.SubplotSpec`, +# in which case its layout parameters are set to that of the location of +# the given SubplotSpec. +# +# Note this is also available from the more verbose +# `.gridspec.GridSpecFromSubplotSpec`. + +fig10 = plt.figure(constrained_layout=True) +gs0 = fig10.add_gridspec(1, 2) + +gs00 = gs0[0].subgridspec(2, 3) +gs01 = gs0[1].subgridspec(3, 2) + +for a in range(2): + for b in range(3): + fig10.add_subplot(gs00[a, b]) + fig10.add_subplot(gs01[b, a]) + +############################################################################### +# A Complex Nested GridSpec using SubplotSpec +# =========================================== +# +# Here's a more sophisticated example of nested GridSpec where we put +# a box around each cell of the outer 4x4 grid, by hiding appropriate +# spines in each of the inner 3x3 grids. + +import numpy as np + + +def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): + return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) + + +fig11 = plt.figure(figsize=(8, 8), constrained_layout=False) +outer_grid = fig11.add_gridspec(4, 4, wspace=0, hspace=0) + +for a in range(4): + for b in range(4): + # gridspec inside gridspec + inner_grid = outer_grid[a, b].subgridspec(3, 3, wspace=0, hspace=0) + axs = inner_grid.subplots() # Create all subplots for the inner grid. + for (c, d), ax in np.ndenumerate(axs): + ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1)) + ax.set(xticks=[], yticks=[]) + +# show only the outside spines +for ax in fig11.get_axes(): + ss = ax.get_subplotspec() + ax.spines.top.set_visible(ss.is_first_row()) + ax.spines.bottom.set_visible(ss.is_last_row()) + ax.spines.left.set_visible(ss.is_first_col()) + ax.spines.right.set_visible(ss.is_last_col()) + +plt.show() + +############################################################################# +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.pyplot.subplots` +# - `matplotlib.figure.Figure.add_gridspec` +# - `matplotlib.figure.Figure.add_subplot` +# - `matplotlib.gridspec.GridSpec` +# - `matplotlib.gridspec.SubplotSpec.subgridspec` +# - `matplotlib.gridspec.GridSpecFromSubplotSpec` diff --git a/tutorials/intermediate/tight_layout_guide.py b/tutorials/intermediate/tight_layout_guide.py index 976fd511a516..4bc92b49c122 100644 --- a/tutorials/intermediate/tight_layout_guide.py +++ b/tutorials/intermediate/tight_layout_guide.py @@ -117,7 +117,7 @@ def example_plot(ax, fontsize=12): ############################################################################### # It works with subplots created with # :func:`~matplotlib.pyplot.subplot2grid`. In general, subplots created -# from the gridspec (:doc:`/tutorials/intermediate/arranging_axes`) will work. +# from the gridspec (:doc:`/tutorials/intermediate/gridspec`) will work. plt.close('all') fig = plt.figure() diff --git a/tutorials/introductory/usage.py b/tutorials/introductory/usage.py index e578d9b7d44d..0d31712752b4 100644 --- a/tutorials/introductory/usage.py +++ b/tutorials/introductory/usage.py @@ -559,7 +559,7 @@ def my_plotter(ax, data1, data2, param_dict): ############################################################################### # Matplotlib has quite sophisticated tools for arranging Axes: See -# :doc:`/tutorials/intermediate/arranging_axes` and +# :doc:`/tutorials/intermediate/gridspec` and # :doc:`/tutorials/provisional/mosaic`. # # diff --git a/tutorials/provisional/mosaic.py b/tutorials/provisional/mosaic.py index 9aa06c9520e1..120e80d97d5d 100644 --- a/tutorials/provisional/mosaic.py +++ b/tutorials/provisional/mosaic.py @@ -14,7 +14,7 @@ and verbose. For dense, even grids we have `.Figure.subplots` but for more complex layouts, such as Axes that span multiple columns / rows of the layout or leave some areas of the Figure blank, you can use -`.gridspec.GridSpec` (see :doc:`/tutorials/intermediate/arranging_axes`) or +`.gridspec.GridSpec` (see :doc:`/tutorials/intermediate/gridspec`) or manually place your axes. `.Figure.subplot_mosaic` aims to provide an interface to visually lay out your axes (as either ASCII art or nested lists) to streamline this process.