Coverage for /usr/lib/python3/dist-packages/matplotlib/gridspec.py: 22%
279 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-06-14 15:25 +0200
« prev ^ index » next coverage.py v7.4.4, created at 2025-06-14 15:25 +0200
1r"""
2:mod:`~matplotlib.gridspec` contains classes that help to layout multiple
3`~.axes.Axes` in a grid-like pattern within a figure.
5The `GridSpec` specifies the overall grid structure. Individual cells within
6the grid are referenced by `SubplotSpec`\s.
8Often, users need not access this module directly, and can use higher-level
9methods like `~.pyplot.subplots`, `~.pyplot.subplot_mosaic` and
10`~.Figure.subfigures`. See the tutorial
11:doc:`/tutorials/intermediate/arranging_axes` for a guide.
12"""
14import copy
15import logging
16from numbers import Integral
18import numpy as np
20import matplotlib as mpl
21from matplotlib import _api, _pylab_helpers, _tight_layout
22from matplotlib.transforms import Bbox
24_log = logging.getLogger(__name__)
27class GridSpecBase:
28 """
29 A base class of GridSpec that specifies the geometry of the grid
30 that a subplot will be placed.
31 """
33 def __init__(self, nrows, ncols, height_ratios=None, width_ratios=None):
34 """
35 Parameters
36 ----------
37 nrows, ncols : int
38 The number of rows and columns of the grid.
39 width_ratios : array-like of length *ncols*, optional
40 Defines the relative widths of the columns. Each column gets a
41 relative width of ``width_ratios[i] / sum(width_ratios)``.
42 If not given, all columns will have the same width.
43 height_ratios : array-like of length *nrows*, optional
44 Defines the relative heights of the rows. Each row gets a
45 relative height of ``height_ratios[i] / sum(height_ratios)``.
46 If not given, all rows will have the same height.
47 """
48 if not isinstance(nrows, Integral) or nrows <= 0:
49 raise ValueError(
50 f"Number of rows must be a positive integer, not {nrows!r}")
51 if not isinstance(ncols, Integral) or ncols <= 0:
52 raise ValueError(
53 f"Number of columns must be a positive integer, not {ncols!r}")
54 self._nrows, self._ncols = nrows, ncols
55 self.set_height_ratios(height_ratios)
56 self.set_width_ratios(width_ratios)
58 def __repr__(self):
59 height_arg = (', height_ratios=%r' % (self._row_height_ratios,)
60 if len(set(self._row_height_ratios)) != 1 else '')
61 width_arg = (', width_ratios=%r' % (self._col_width_ratios,)
62 if len(set(self._col_width_ratios)) != 1 else '')
63 return '{clsname}({nrows}, {ncols}{optionals})'.format(
64 clsname=self.__class__.__name__,
65 nrows=self._nrows,
66 ncols=self._ncols,
67 optionals=height_arg + width_arg,
68 )
70 nrows = property(lambda self: self._nrows,
71 doc="The number of rows in the grid.")
72 ncols = property(lambda self: self._ncols,
73 doc="The number of columns in the grid.")
75 def get_geometry(self):
76 """
77 Return a tuple containing the number of rows and columns in the grid.
78 """
79 return self._nrows, self._ncols
81 def get_subplot_params(self, figure=None):
82 # Must be implemented in subclasses
83 pass
85 def new_subplotspec(self, loc, rowspan=1, colspan=1):
86 """
87 Create and return a `.SubplotSpec` instance.
89 Parameters
90 ----------
91 loc : (int, int)
92 The position of the subplot in the grid as
93 ``(row_index, column_index)``.
94 rowspan, colspan : int, default: 1
95 The number of rows and columns the subplot should span in the grid.
96 """
97 loc1, loc2 = loc
98 subplotspec = self[loc1:loc1+rowspan, loc2:loc2+colspan]
99 return subplotspec
101 def set_width_ratios(self, width_ratios):
102 """
103 Set the relative widths of the columns.
105 *width_ratios* must be of length *ncols*. Each column gets a relative
106 width of ``width_ratios[i] / sum(width_ratios)``.
107 """
108 if width_ratios is None:
109 width_ratios = [1] * self._ncols
110 elif len(width_ratios) != self._ncols:
111 raise ValueError('Expected the given number of width ratios to '
112 'match the number of columns of the grid')
113 self._col_width_ratios = width_ratios
115 def get_width_ratios(self):
116 """
117 Return the width ratios.
119 This is *None* if no width ratios have been set explicitly.
120 """
121 return self._col_width_ratios
123 def set_height_ratios(self, height_ratios):
124 """
125 Set the relative heights of the rows.
127 *height_ratios* must be of length *nrows*. Each row gets a relative
128 height of ``height_ratios[i] / sum(height_ratios)``.
129 """
130 if height_ratios is None:
131 height_ratios = [1] * self._nrows
132 elif len(height_ratios) != self._nrows:
133 raise ValueError('Expected the given number of height ratios to '
134 'match the number of rows of the grid')
135 self._row_height_ratios = height_ratios
137 def get_height_ratios(self):
138 """
139 Return the height ratios.
141 This is *None* if no height ratios have been set explicitly.
142 """
143 return self._row_height_ratios
145 @_api.delete_parameter("3.7", "raw")
146 def get_grid_positions(self, fig, raw=False):
147 """
148 Return the positions of the grid cells in figure coordinates.
150 Parameters
151 ----------
152 fig : `~matplotlib.figure.Figure`
153 The figure the grid should be applied to. The subplot parameters
154 (margins and spacing between subplots) are taken from *fig*.
155 raw : bool, default: False
156 If *True*, the subplot parameters of the figure are not taken
157 into account. The grid spans the range [0, 1] in both directions
158 without margins and there is no space between grid cells. This is
159 used for constrained_layout.
161 Returns
162 -------
163 bottoms, tops, lefts, rights : array
164 The bottom, top, left, right positions of the grid cells in
165 figure coordinates.
166 """
167 nrows, ncols = self.get_geometry()
169 if raw:
170 left = 0.
171 right = 1.
172 bottom = 0.
173 top = 1.
174 wspace = 0.
175 hspace = 0.
176 else:
177 subplot_params = self.get_subplot_params(fig)
178 left = subplot_params.left
179 right = subplot_params.right
180 bottom = subplot_params.bottom
181 top = subplot_params.top
182 wspace = subplot_params.wspace
183 hspace = subplot_params.hspace
184 tot_width = right - left
185 tot_height = top - bottom
187 # calculate accumulated heights of columns
188 cell_h = tot_height / (nrows + hspace*(nrows-1))
189 sep_h = hspace * cell_h
190 norm = cell_h * nrows / sum(self._row_height_ratios)
191 cell_heights = [r * norm for r in self._row_height_ratios]
192 sep_heights = [0] + ([sep_h] * (nrows-1))
193 cell_hs = np.cumsum(np.column_stack([sep_heights, cell_heights]).flat)
195 # calculate accumulated widths of rows
196 cell_w = tot_width / (ncols + wspace*(ncols-1))
197 sep_w = wspace * cell_w
198 norm = cell_w * ncols / sum(self._col_width_ratios)
199 cell_widths = [r * norm for r in self._col_width_ratios]
200 sep_widths = [0] + ([sep_w] * (ncols-1))
201 cell_ws = np.cumsum(np.column_stack([sep_widths, cell_widths]).flat)
203 fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T
204 fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T
205 return fig_bottoms, fig_tops, fig_lefts, fig_rights
207 @staticmethod
208 def _check_gridspec_exists(figure, nrows, ncols):
209 """
210 Check if the figure already has a gridspec with these dimensions,
211 or create a new one
212 """
213 for ax in figure.get_axes():
214 if hasattr(ax, 'get_subplotspec'):
215 gs = ax.get_subplotspec().get_gridspec()
216 if hasattr(gs, 'get_topmost_subplotspec'):
217 # This is needed for colorbar gridspec layouts.
218 # This is probably OK because this whole logic tree
219 # is for when the user is doing simple things with the
220 # add_subplot command. For complicated layouts
221 # like subgridspecs the proper gridspec is passed in...
222 gs = gs.get_topmost_subplotspec().get_gridspec()
223 if gs.get_geometry() == (nrows, ncols):
224 return gs
225 # else gridspec not found:
226 return GridSpec(nrows, ncols, figure=figure)
228 def __getitem__(self, key):
229 """Create and return a `.SubplotSpec` instance."""
230 nrows, ncols = self.get_geometry()
232 def _normalize(key, size, axis): # Includes last index.
233 orig_key = key
234 if isinstance(key, slice):
235 start, stop, _ = key.indices(size)
236 if stop > start:
237 return start, stop - 1
238 raise IndexError("GridSpec slice would result in no space "
239 "allocated for subplot")
240 else:
241 if key < 0:
242 key = key + size
243 if 0 <= key < size:
244 return key, key
245 elif axis is not None:
246 raise IndexError(f"index {orig_key} is out of bounds for "
247 f"axis {axis} with size {size}")
248 else: # flat index
249 raise IndexError(f"index {orig_key} is out of bounds for "
250 f"GridSpec with size {size}")
252 if isinstance(key, tuple):
253 try:
254 k1, k2 = key
255 except ValueError as err:
256 raise ValueError("Unrecognized subplot spec") from err
257 num1, num2 = np.ravel_multi_index(
258 [_normalize(k1, nrows, 0), _normalize(k2, ncols, 1)],
259 (nrows, ncols))
260 else: # Single key
261 num1, num2 = _normalize(key, nrows * ncols, None)
263 return SubplotSpec(self, num1, num2)
265 def subplots(self, *, sharex=False, sharey=False, squeeze=True,
266 subplot_kw=None):
267 """
268 Add all subplots specified by this `GridSpec` to its parent figure.
270 See `.Figure.subplots` for detailed documentation.
271 """
273 figure = self.figure
275 if figure is None:
276 raise ValueError("GridSpec.subplots() only works for GridSpecs "
277 "created with a parent figure")
279 if isinstance(sharex, bool):
280 sharex = "all" if sharex else "none"
281 if isinstance(sharey, bool):
282 sharey = "all" if sharey else "none"
283 # This check was added because it is very easy to type
284 # `subplots(1, 2, 1)` when `subplot(1, 2, 1)` was intended.
285 # In most cases, no error will ever occur, but mysterious behavior
286 # will result because what was intended to be the subplot index is
287 # instead treated as a bool for sharex. This check should go away
288 # once sharex becomes kwonly.
289 if isinstance(sharex, Integral):
290 _api.warn_external(
291 "sharex argument to subplots() was an integer. Did you "
292 "intend to use subplot() (without 's')?")
293 _api.check_in_list(["all", "row", "col", "none"],
294 sharex=sharex, sharey=sharey)
295 if subplot_kw is None:
296 subplot_kw = {}
297 # don't mutate kwargs passed by user...
298 subplot_kw = subplot_kw.copy()
300 # Create array to hold all axes.
301 axarr = np.empty((self._nrows, self._ncols), dtype=object)
302 for row in range(self._nrows):
303 for col in range(self._ncols):
304 shared_with = {"none": None, "all": axarr[0, 0],
305 "row": axarr[row, 0], "col": axarr[0, col]}
306 subplot_kw["sharex"] = shared_with[sharex]
307 subplot_kw["sharey"] = shared_with[sharey]
308 axarr[row, col] = figure.add_subplot(
309 self[row, col], **subplot_kw)
311 # turn off redundant tick labeling
312 if sharex in ["col", "all"]:
313 for ax in axarr.flat:
314 ax._label_outer_xaxis(check_patch=True)
315 if sharey in ["row", "all"]:
316 for ax in axarr.flat:
317 ax._label_outer_yaxis(check_patch=True)
319 if squeeze:
320 # Discarding unneeded dimensions that equal 1. If we only have one
321 # subplot, just return it instead of a 1-element array.
322 return axarr.item() if axarr.size == 1 else axarr.squeeze()
323 else:
324 # Returned axis array will be always 2-d, even if nrows=ncols=1.
325 return axarr
328class GridSpec(GridSpecBase):
329 """
330 A grid layout to place subplots within a figure.
332 The location of the grid cells is determined in a similar way to
333 `~.figure.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace*
334 and *hspace*.
336 Indexing a GridSpec instance returns a `.SubplotSpec`.
337 """
338 def __init__(self, nrows, ncols, figure=None,
339 left=None, bottom=None, right=None, top=None,
340 wspace=None, hspace=None,
341 width_ratios=None, height_ratios=None):
342 """
343 Parameters
344 ----------
345 nrows, ncols : int
346 The number of rows and columns of the grid.
348 figure : `.Figure`, optional
349 Only used for constrained layout to create a proper layoutgrid.
351 left, right, top, bottom : float, optional
352 Extent of the subplots as a fraction of figure width or height.
353 Left cannot be larger than right, and bottom cannot be larger than
354 top. If not given, the values will be inferred from a figure or
355 rcParams at draw time. See also `GridSpec.get_subplot_params`.
357 wspace : float, optional
358 The amount of width reserved for space between subplots,
359 expressed as a fraction of the average axis width.
360 If not given, the values will be inferred from a figure or
361 rcParams when necessary. See also `GridSpec.get_subplot_params`.
363 hspace : float, optional
364 The amount of height reserved for space between subplots,
365 expressed as a fraction of the average axis height.
366 If not given, the values will be inferred from a figure or
367 rcParams when necessary. See also `GridSpec.get_subplot_params`.
369 width_ratios : array-like of length *ncols*, optional
370 Defines the relative widths of the columns. Each column gets a
371 relative width of ``width_ratios[i] / sum(width_ratios)``.
372 If not given, all columns will have the same width.
374 height_ratios : array-like of length *nrows*, optional
375 Defines the relative heights of the rows. Each row gets a
376 relative height of ``height_ratios[i] / sum(height_ratios)``.
377 If not given, all rows will have the same height.
379 """
380 self.left = left
381 self.bottom = bottom
382 self.right = right
383 self.top = top
384 self.wspace = wspace
385 self.hspace = hspace
386 self.figure = figure
388 super().__init__(nrows, ncols,
389 width_ratios=width_ratios,
390 height_ratios=height_ratios)
392 _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"]
394 def update(self, **kwargs):
395 """
396 Update the subplot parameters of the grid.
398 Parameters that are not explicitly given are not changed. Setting a
399 parameter to *None* resets it to :rc:`figure.subplot.*`.
401 Parameters
402 ----------
403 left, right, top, bottom : float or None, optional
404 Extent of the subplots as a fraction of figure width or height.
405 wspace, hspace : float, optional
406 Spacing between the subplots as a fraction of the average subplot
407 width / height.
408 """
409 for k, v in kwargs.items():
410 if k in self._AllowedKeys:
411 setattr(self, k, v)
412 else:
413 raise AttributeError(f"{k} is an unknown keyword")
414 for figmanager in _pylab_helpers.Gcf.figs.values():
415 for ax in figmanager.canvas.figure.axes:
416 if isinstance(ax, mpl.axes.SubplotBase):
417 ss = ax.get_subplotspec().get_topmost_subplotspec()
418 if ss.get_gridspec() == self:
419 ax._set_position(
420 ax.get_subplotspec().get_position(ax.figure))
422 def get_subplot_params(self, figure=None):
423 """
424 Return the `.SubplotParams` for the GridSpec.
426 In order of precedence the values are taken from
428 - non-*None* attributes of the GridSpec
429 - the provided *figure*
430 - :rc:`figure.subplot.*`
431 """
432 if figure is None:
433 kw = {k: mpl.rcParams["figure.subplot."+k]
434 for k in self._AllowedKeys}
435 subplotpars = mpl.figure.SubplotParams(**kw)
436 else:
437 subplotpars = copy.copy(figure.subplotpars)
439 subplotpars.update(**{k: getattr(self, k) for k in self._AllowedKeys})
441 return subplotpars
443 def locally_modified_subplot_params(self):
444 """
445 Return a list of the names of the subplot parameters explicitly set
446 in the GridSpec.
448 This is a subset of the attributes of `.SubplotParams`.
449 """
450 return [k for k in self._AllowedKeys if getattr(self, k)]
452 def tight_layout(self, figure, renderer=None,
453 pad=1.08, h_pad=None, w_pad=None, rect=None):
454 """
455 Adjust subplot parameters to give specified padding.
457 Parameters
458 ----------
459 pad : float
460 Padding between the figure edge and the edges of subplots, as a
461 fraction of the font-size.
462 h_pad, w_pad : float, optional
463 Padding (height/width) between edges of adjacent subplots.
464 Defaults to *pad*.
465 rect : tuple (left, bottom, right, top), default: None
466 (left, bottom, right, top) rectangle in normalized figure
467 coordinates that the whole subplots area (including labels) will
468 fit into. Default (None) is the whole figure.
469 """
470 if renderer is None:
471 renderer = figure._get_renderer()
472 kwargs = _tight_layout.get_tight_layout_figure(
473 figure, figure.axes,
474 _tight_layout.get_subplotspec_list(figure.axes, grid_spec=self),
475 renderer, pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
476 if kwargs:
477 self.update(**kwargs)
480class GridSpecFromSubplotSpec(GridSpecBase):
481 """
482 GridSpec whose subplot layout parameters are inherited from the
483 location specified by a given SubplotSpec.
484 """
485 def __init__(self, nrows, ncols,
486 subplot_spec,
487 wspace=None, hspace=None,
488 height_ratios=None, width_ratios=None):
489 """
490 Parameters
491 ----------
492 nrows, ncols : int
493 Number of rows and number of columns of the grid.
494 subplot_spec : SubplotSpec
495 Spec from which the layout parameters are inherited.
496 wspace, hspace : float, optional
497 See `GridSpec` for more details. If not specified default values
498 (from the figure or rcParams) are used.
499 height_ratios : array-like of length *nrows*, optional
500 See `GridSpecBase` for details.
501 width_ratios : array-like of length *ncols*, optional
502 See `GridSpecBase` for details.
503 """
504 self._wspace = wspace
505 self._hspace = hspace
506 self._subplot_spec = subplot_spec
507 self.figure = self._subplot_spec.get_gridspec().figure
508 super().__init__(nrows, ncols,
509 width_ratios=width_ratios,
510 height_ratios=height_ratios)
512 def get_subplot_params(self, figure=None):
513 """Return a dictionary of subplot layout parameters."""
514 hspace = (self._hspace if self._hspace is not None
515 else figure.subplotpars.hspace if figure is not None
516 else mpl.rcParams["figure.subplot.hspace"])
517 wspace = (self._wspace if self._wspace is not None
518 else figure.subplotpars.wspace if figure is not None
519 else mpl.rcParams["figure.subplot.wspace"])
521 figbox = self._subplot_spec.get_position(figure)
522 left, bottom, right, top = figbox.extents
524 return mpl.figure.SubplotParams(left=left, right=right,
525 bottom=bottom, top=top,
526 wspace=wspace, hspace=hspace)
528 def get_topmost_subplotspec(self):
529 """
530 Return the topmost `.SubplotSpec` instance associated with the subplot.
531 """
532 return self._subplot_spec.get_topmost_subplotspec()
535class SubplotSpec:
536 """
537 The location of a subplot in a `GridSpec`.
539 .. note::
541 Likely, you will never instantiate a `SubplotSpec` yourself. Instead,
542 you will typically obtain one from a `GridSpec` using item-access.
544 Parameters
545 ----------
546 gridspec : `~matplotlib.gridspec.GridSpec`
547 The GridSpec, which the subplot is referencing.
548 num1, num2 : int
549 The subplot will occupy the *num1*-th cell of the given
550 *gridspec*. If *num2* is provided, the subplot will span between
551 *num1*-th cell and *num2*-th cell **inclusive**.
553 The index starts from 0.
554 """
555 def __init__(self, gridspec, num1, num2=None):
556 self._gridspec = gridspec
557 self.num1 = num1
558 self.num2 = num2
560 def __repr__(self):
561 return (f"{self.get_gridspec()}["
562 f"{self.rowspan.start}:{self.rowspan.stop}, "
563 f"{self.colspan.start}:{self.colspan.stop}]")
565 @staticmethod
566 def _from_subplot_args(figure, args):
567 """
568 Construct a `.SubplotSpec` from a parent `.Figure` and either
570 - a `.SubplotSpec` -- returned as is;
571 - one or three numbers -- a MATLAB-style subplot specifier.
572 """
573 if len(args) == 1:
574 arg, = args
575 if isinstance(arg, SubplotSpec):
576 return arg
577 elif not isinstance(arg, Integral):
578 raise ValueError(
579 f"Single argument to subplot must be a three-digit "
580 f"integer, not {arg!r}")
581 try:
582 rows, cols, num = map(int, str(arg))
583 except ValueError:
584 raise ValueError(
585 f"Single argument to subplot must be a three-digit "
586 f"integer, not {arg!r}") from None
587 elif len(args) == 3:
588 rows, cols, num = args
589 else:
590 raise TypeError(f"subplot() takes 1 or 3 positional arguments but "
591 f"{len(args)} were given")
593 gs = GridSpec._check_gridspec_exists(figure, rows, cols)
594 if gs is None:
595 gs = GridSpec(rows, cols, figure=figure)
596 if isinstance(num, tuple) and len(num) == 2:
597 if not all(isinstance(n, Integral) for n in num):
598 raise ValueError(
599 f"Subplot specifier tuple must contain integers, not {num}"
600 )
601 i, j = num
602 else:
603 if not isinstance(num, Integral) or num < 1 or num > rows*cols:
604 raise ValueError(
605 f"num must be 1 <= num <= {rows*cols}, not {num!r}")
606 i = j = num
607 return gs[i-1:j]
609 # num2 is a property only to handle the case where it is None and someone
610 # mutates num1.
612 @property
613 def num2(self):
614 return self.num1 if self._num2 is None else self._num2
616 @num2.setter
617 def num2(self, value):
618 self._num2 = value
620 def get_gridspec(self):
621 return self._gridspec
623 def get_geometry(self):
624 """
625 Return the subplot geometry as tuple ``(n_rows, n_cols, start, stop)``.
627 The indices *start* and *stop* define the range of the subplot within
628 the `GridSpec`. *stop* is inclusive (i.e. for a single cell
629 ``start == stop``).
630 """
631 rows, cols = self.get_gridspec().get_geometry()
632 return rows, cols, self.num1, self.num2
634 @property
635 def rowspan(self):
636 """The rows spanned by this subplot, as a `range` object."""
637 ncols = self.get_gridspec().ncols
638 return range(self.num1 // ncols, self.num2 // ncols + 1)
640 @property
641 def colspan(self):
642 """The columns spanned by this subplot, as a `range` object."""
643 ncols = self.get_gridspec().ncols
644 # We explicitly support num2 referring to a column on num1's *left*, so
645 # we must sort the column indices here so that the range makes sense.
646 c1, c2 = sorted([self.num1 % ncols, self.num2 % ncols])
647 return range(c1, c2 + 1)
649 def is_first_row(self):
650 return self.rowspan.start == 0
652 def is_last_row(self):
653 return self.rowspan.stop == self.get_gridspec().nrows
655 def is_first_col(self):
656 return self.colspan.start == 0
658 def is_last_col(self):
659 return self.colspan.stop == self.get_gridspec().ncols
661 def get_position(self, figure):
662 """
663 Update the subplot position from ``figure.subplotpars``.
664 """
665 gridspec = self.get_gridspec()
666 nrows, ncols = gridspec.get_geometry()
667 rows, cols = np.unravel_index([self.num1, self.num2], (nrows, ncols))
668 fig_bottoms, fig_tops, fig_lefts, fig_rights = \
669 gridspec.get_grid_positions(figure)
671 fig_bottom = fig_bottoms[rows].min()
672 fig_top = fig_tops[rows].max()
673 fig_left = fig_lefts[cols].min()
674 fig_right = fig_rights[cols].max()
675 return Bbox.from_extents(fig_left, fig_bottom, fig_right, fig_top)
677 def get_topmost_subplotspec(self):
678 """
679 Return the topmost `SubplotSpec` instance associated with the subplot.
680 """
681 gridspec = self.get_gridspec()
682 if hasattr(gridspec, "get_topmost_subplotspec"):
683 return gridspec.get_topmost_subplotspec()
684 else:
685 return self
687 def __eq__(self, other):
688 """
689 Two SubplotSpecs are considered equal if they refer to the same
690 position(s) in the same `GridSpec`.
691 """
692 # other may not even have the attributes we are checking.
693 return ((self._gridspec, self.num1, self.num2)
694 == (getattr(other, "_gridspec", object()),
695 getattr(other, "num1", object()),
696 getattr(other, "num2", object())))
698 def __hash__(self):
699 return hash((self._gridspec, self.num1, self.num2))
701 def subgridspec(self, nrows, ncols, **kwargs):
702 """
703 Create a GridSpec within this subplot.
705 The created `.GridSpecFromSubplotSpec` will have this `SubplotSpec` as
706 a parent.
708 Parameters
709 ----------
710 nrows : int
711 Number of rows in grid.
713 ncols : int
714 Number of columns in grid.
716 Returns
717 -------
718 `.GridSpecFromSubplotSpec`
720 Other Parameters
721 ----------------
722 **kwargs
723 All other parameters are passed to `.GridSpecFromSubplotSpec`.
725 See Also
726 --------
727 matplotlib.pyplot.subplots
729 Examples
730 --------
731 Adding three subplots in the space occupied by a single subplot::
733 fig = plt.figure()
734 gs0 = fig.add_gridspec(3, 1)
735 ax1 = fig.add_subplot(gs0[0])
736 ax2 = fig.add_subplot(gs0[1])
737 gssub = gs0[2].subgridspec(1, 3)
738 for i in range(3):
739 fig.add_subplot(gssub[0, i])
740 """
741 return GridSpecFromSubplotSpec(nrows, ncols, self, **kwargs)