33The starting point for creating custom ProPlot figures and axes.
44The `subplots` function is all you'll need to directly use here.
55It returns a `Figure` instance and an `axes_grid` container of
6- `~proplot.axes.Axes` axes, whose positions are controlled by the
7- `FlexibleGridSpec ` class.
6+ `~proplot.axes.Axes` axes, whose positions are controlled by the new
7+ `GridSpec ` class.
88
99.. raw:: html
1010
1111 <h1>Developer notes</h1>
1212
13- Matplotlib permits arbitrarily many gridspecs per figure, and
14- encourages serial calls to `~matplotlib.figure.Figure.add_subplot`. By
15- contrast, ProPlot permits only *one* `~matplotlib.gridspec.GridSpec` per
16- figure, and forces the user to construct axes and figures with `subplots`. On
17- the whole, matplotlib's approach is fairly cumbersome, but necessary owing to
18- certain design limitations. The following describes how ProPlot addresses
19- these limitations.
20-
21- * Matplotlib's `~matplotlib.gridspec.GridSpec` can only implement *uniform*
22- spacing between rows and columns of subplots. This seems to be the main
23- reason the `~matplotlib.gridspec.GridSpecFromSubplotSpec` class was
24- invented. To get variable spacing, users have to build their own nested
25- `~matplotlib.gridspec.GridSpec` objects and manually pass
26- `~matplotlib.gridspec.SubplotSpec` objects to
27- `~matplotlib.figure.Figure.add_subplot`.
28-
29- ProPlot's `FlexibleGridSpec` class permits *variable* spacing between
30- rows and columns of subplots. This largely eliminates the need for
31- `~matplotlib.gridspec.GridSpecFromSubplotSpec`, and prevents users
32- from having to pass their own `~matplotlib.gridspec.SubplotSpec` objects
33- to `~matplotlib.figure.Figure.add_subplot`.
34-
35- * Matplotlib's `~matplotlib.pyplot.subplots` can only draw simple 2D
36- arrangements of subplots. To make complex arrangements, the user must
37- generate their own `~matplotlib.gridspec.SubplotSpec` instances, or serially
38- pass 3-digit integers or 3 positional arguments
39- `~matplotlib.figure.Figure.add_subplot`. And to simplify this workflow, the
40- gridspec geometry must be allowed to vary. For example, to draw a simple
41- grid with two subplots on the top and one subplot on the bottom, the user
42- can serially pass ``221``, ``222``, and ``212`` to
43- `~matplotlib.figure.Figure.add_subplot`. But if the gridspec geometry
44- was required to remain the same, instead of ``212``, the user would have to
45- use ``2, 2, (3,4)``, which is much more cumbersome. So, the figure
46- must support multiple gridspec geometries -- i.e. it must support multiple
47- gridspecs!
48-
49- With ProPlot, users can build complex subplot grids using the ``array``
50- `subplots` argument. This means that serial calls to
51- `~matplotlib.figure.Figure.add_subplot` are no longer necessary, and we can
52- use just *one* gridspec for the whole figure without imposing any new
53- limitations. Among other things, this simplifies the "tight layout"
54- algorithm.
55-
56-
57- Also note that ProPlot's `subplots` returns an `axes_grid` of axes, while
58- matplotlib's `~matplotlib.pyplot.subplots` returns a 2D `~numpy.ndarray`,
59- a 1D `~numpy.ndarray`, or the axes itself. `axes_grid` was invented in
60- part because `subplots` can draw arbitrarily complex arrangements of
61- subplots, not just simple grids. `axes_grid` is a `list` subclass supporting
62- 1D indexing (e.g. ``axs[0]``), but permits 2D indexing (e.g. ``axs[1,0]``)
63- *just in case* the user *happened* to draw a clean 2D matrix of subplots.
64- The `~axes_grid.__getattr__` override also means it no longer matters
65- whether you are calling a method on an axes or a singleton `axes_grid` of axes.
13+ While matplotlib permits arbitrarily many gridspecs per figure, ProPlot
14+ permits only *one*. When `subplots` is used, this is trivial to enforce. When
15+ `~Figure.add_subplot` is used, the figure geometry is "locked" after the
16+ first call -- although `~Figure.add_subplot` calls that divide into the
17+ existing geometry are also acceptable (for example, two square subplots above
18+ a longer rectangle subplots with the integers ``221``, ``222``, and ``212``).
19+ This choice is not a major imposition on the user, and *considerably*
20+ simplifies gridspec adjustments, e.g. the "tight layout" adjustments.
21+
22+ While matplotlib's `~matplotlib.pyplot.subplots` returns a 2D `~numpy.ndarray`,
23+ a 1D `~numpy.ndarray`, or the axes itself, ProPlot's `subplots` returns an
24+ `axes_grid` of axes, meant to unify these three possible return values.
25+ `axes_grid` is a `list` subclass supporting 1D indexing (e.g. ``axs[0]``), but
26+ permits 2D indexing (e.g. ``axs[1,0]``) *just in case* the user *happened*
27+ to draw a clean 2D matrix of subplots. The `~axes_grid.__getattr__` override
28+ also means it no longer matters whether you are calling a method on an axes
29+ or a singleton `axes_grid` of axes. Finally, `axes_grid` lets `subplots`
30+ support complex arrangements of subplots -- just use 1D indexing when they
31+ don't look like a 2D matrix.
6632"""
6733# NOTE: Importing backend causes issues with sphinx, and anyway not sure it's
6834# always included, so make it optional
8450from .utils import _notNone , _counter , units
8551from . import projs , axes
8652__all__ = [
87- 'axes_grid' , 'close' , 'show' , 'subplots' , 'Figure' , 'FlexibleGridSpec ' ,
53+ 'axes_grid' , 'close' , 'show' , 'subplots' , 'Figure' , 'GridSpec ' ,
8854 ]
8955
9056# Translation
@@ -346,7 +312,7 @@ def get_active_rows_columns(self):
346312 col2 = col1
347313 return nrows // 2 , ncols // 2 , row1 // 2 , row2 // 2 , col1 // 2 , col2 // 2
348314
349- class FlexibleGridSpec (mgridspec .GridSpec ):
315+ class GridSpec (mgridspec .GridSpec ):
350316 """
351317 `~matplotlib.gridspec.GridSpec` generalization that allows for grids with
352318 *variable spacing* between successive rows and columns of axes.
@@ -371,7 +337,7 @@ def __init__(self, figure, nrows=1, ncols=1, **kwargs):
371337 The vertical and horizontal spacing between rows and columns of
372338 subplots, respectively. In `~proplot.subplots.subplots`, ``wspace``
373339 and ``hspace`` are in physical units. When calling
374- `FlexibleGridSpec ` directly, values are scaled relative to
340+ `GridSpec ` directly, values are scaled relative to
375341 the average subplot height or width.
376342
377343 If float, the spacing is identical between all rows and columns. If
@@ -446,7 +412,7 @@ def _spaces_as_ratios(self,
446412 hspace = None , wspace = None , # spacing between axes
447413 height_ratios = None , width_ratios = None ,
448414 ** kwargs ):
449- """For keyword arg usage, see `FlexibleGridSpec `."""
415+ """For keyword arg usage, see `GridSpec `."""
450416 # Parse flexible input
451417 nrows , ncols = self .get_active_geometry ()
452418 hratios = np .atleast_1d (_notNone (height_ratios , 1 ))
@@ -508,7 +474,7 @@ def get_active_width_ratios(self):
508474
509475 def get_active_geometry (self ):
510476 """Returns the number of active rows and columns, i.e. the rows and
511- columns that aren't skipped by `~FlexibleGridSpec .__getitem__`."""
477+ columns that aren't skipped by `~GridSpec .__getitem__`."""
512478 return self ._nrows_active , self ._ncols_active
513479
514480 def update (self , ** kwargs ):
@@ -814,7 +780,7 @@ def __init__(self,
814780 self ._tpanels = []
815781 self ._lpanels = []
816782 self ._rpanels = []
817- gridspec = FlexibleGridSpec (self , ** (gridspec_kw or {}))
783+ gridspec = GridSpec (self , ** (gridspec_kw or {}))
818784 nrows , ncols = gridspec .get_active_geometry ()
819785 self ._barray = np .empty ((0 , ncols ), dtype = bool )
820786 self ._tarray = np .empty ((0 , ncols ), dtype = bool )
@@ -1308,7 +1274,7 @@ def _insert_row_column(self, side, idx,
13081274 gridspec .update (** gridspec_kw )
13091275 else :
13101276 # New gridspec
1311- gridspec = FlexibleGridSpec (self , ** gridspec_kw )
1277+ gridspec = GridSpec (self , ** gridspec_kw )
13121278 self ._gridspec_main = gridspec
13131279 # Reassign subplotspecs to all axes and update positions
13141280 # May seem inefficient but it literally just assigns a hidden,
@@ -1873,12 +1839,12 @@ def subplots(array=None, ncols=1, nrows=1,
18731839 hratios, wratios
18741840 Aliases for `height_ratios`, `width_ratios`.
18751841 width_ratios, height_ratios : float or list thereof, optional
1876- Passed to `FlexibleGridSpec `. The width
1842+ Passed to `GridSpec `. The width
18771843 and height ratios for the subplot grid. Length of `width_ratios`
18781844 must match the number of rows, and length of `height_ratios` must
18791845 match the number of columns.
18801846 wspace, hspace, space : float or str or list thereof, optional
1881- Passed to `FlexibleGridSpec `, denotes the
1847+ Passed to `GridSpec `, denotes the
18821848 spacing between grid columns, rows, and both, respectively. If float
18831849 or string, expanded into lists of length ``ncols-1`` (for `wspace`)
18841850 or length ``nrows-1`` (for `hspace`).
@@ -1887,9 +1853,9 @@ def subplots(array=None, ncols=1, nrows=1,
18871853 the list. By default, these are determined by the "tight
18881854 layout" algorithm.
18891855 left, right, top, bottom : float or str, optional
1890- Passed to `FlexibleGridSpec`, denote the width of padding between the
1856+ Passed to `GridSpec`. Denotes the width of padding between the
18911857 subplots and the figure edge. Units are interpreted by
1892- `~proplot.utils.units`. By default, these are determined by the
1858+ `~proplot.utils.units`. By default, padding is determined by the
18931859 "tight layout" algorithm.
18941860
18951861 sharex, sharey, share : {3, 2, 1, 0}, optional
0 commit comments