Skip to content

Commit e669482

Browse files
committed
Rename FlexibleGridSpec --> GridSpec (like Axes + Figure), update developer notes
1 parent 91d46cf commit e669482

File tree

1 file changed

+32
-66
lines changed

1 file changed

+32
-66
lines changed

proplot/subplots.py

Lines changed: 32 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,32 @@
33
The starting point for creating custom ProPlot figures and axes.
44
The `subplots` function is all you'll need to directly use here.
55
It 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
@@ -84,7 +50,7 @@
8450
from .utils import _notNone, _counter, units
8551
from . 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

Comments
 (0)