Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/matplotlib/gridspec.py: 22%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

293 statements  

1r""" 

2:mod:`~matplotlib.gridspec` contains classes that help to layout multiple 

3`~.axes.Axes` in a grid-like pattern within a figure. 

4 

5The `GridSpec` specifies the overall grid structure. Individual cells within 

6the grid are referenced by `SubplotSpec`\s. 

7 

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 :ref:`arranging_axes` for a guide. 

11""" 

12 

13import copy 

14import logging 

15from numbers import Integral 

16 

17import numpy as np 

18 

19import matplotlib as mpl 

20from matplotlib import _api, _pylab_helpers, _tight_layout 

21from matplotlib.transforms import Bbox 

22 

23_log = logging.getLogger(__name__) 

24 

25 

26class GridSpecBase: 

27 """ 

28 A base class of GridSpec that specifies the geometry of the grid 

29 that a subplot will be placed. 

30 """ 

31 

32 def __init__(self, nrows, ncols, height_ratios=None, width_ratios=None): 

33 """ 

34 Parameters 

35 ---------- 

36 nrows, ncols : int 

37 The number of rows and columns of the grid. 

38 width_ratios : array-like of length *ncols*, optional 

39 Defines the relative widths of the columns. Each column gets a 

40 relative width of ``width_ratios[i] / sum(width_ratios)``. 

41 If not given, all columns will have the same width. 

42 height_ratios : array-like of length *nrows*, optional 

43 Defines the relative heights of the rows. Each row gets a 

44 relative height of ``height_ratios[i] / sum(height_ratios)``. 

45 If not given, all rows will have the same height. 

46 """ 

47 if not isinstance(nrows, Integral) or nrows <= 0: 

48 raise ValueError( 

49 f"Number of rows must be a positive integer, not {nrows!r}") 

50 if not isinstance(ncols, Integral) or ncols <= 0: 

51 raise ValueError( 

52 f"Number of columns must be a positive integer, not {ncols!r}") 

53 self._nrows, self._ncols = nrows, ncols 

54 self.set_height_ratios(height_ratios) 

55 self.set_width_ratios(width_ratios) 

56 

57 def __repr__(self): 

58 height_arg = (f', height_ratios={self._row_height_ratios!r}' 

59 if len(set(self._row_height_ratios)) != 1 else '') 

60 width_arg = (f', width_ratios={self._col_width_ratios!r}' 

61 if len(set(self._col_width_ratios)) != 1 else '') 

62 return '{clsname}({nrows}, {ncols}{optionals})'.format( 

63 clsname=self.__class__.__name__, 

64 nrows=self._nrows, 

65 ncols=self._ncols, 

66 optionals=height_arg + width_arg, 

67 ) 

68 

69 nrows = property(lambda self: self._nrows, 

70 doc="The number of rows in the grid.") 

71 ncols = property(lambda self: self._ncols, 

72 doc="The number of columns in the grid.") 

73 

74 def get_geometry(self): 

75 """ 

76 Return a tuple containing the number of rows and columns in the grid. 

77 """ 

78 return self._nrows, self._ncols 

79 

80 def get_subplot_params(self, figure=None): 

81 # Must be implemented in subclasses 

82 pass 

83 

84 def new_subplotspec(self, loc, rowspan=1, colspan=1): 

85 """ 

86 Create and return a `.SubplotSpec` instance. 

87 

88 Parameters 

89 ---------- 

90 loc : (int, int) 

91 The position of the subplot in the grid as 

92 ``(row_index, column_index)``. 

93 rowspan, colspan : int, default: 1 

94 The number of rows and columns the subplot should span in the grid. 

95 """ 

96 loc1, loc2 = loc 

97 subplotspec = self[loc1:loc1+rowspan, loc2:loc2+colspan] 

98 return subplotspec 

99 

100 def set_width_ratios(self, width_ratios): 

101 """ 

102 Set the relative widths of the columns. 

103 

104 *width_ratios* must be of length *ncols*. Each column gets a relative 

105 width of ``width_ratios[i] / sum(width_ratios)``. 

106 """ 

107 if width_ratios is None: 

108 width_ratios = [1] * self._ncols 

109 elif len(width_ratios) != self._ncols: 

110 raise ValueError('Expected the given number of width ratios to ' 

111 'match the number of columns of the grid') 

112 self._col_width_ratios = width_ratios 

113 

114 def get_width_ratios(self): 

115 """ 

116 Return the width ratios. 

117 

118 This is *None* if no width ratios have been set explicitly. 

119 """ 

120 return self._col_width_ratios 

121 

122 def set_height_ratios(self, height_ratios): 

123 """ 

124 Set the relative heights of the rows. 

125 

126 *height_ratios* must be of length *nrows*. Each row gets a relative 

127 height of ``height_ratios[i] / sum(height_ratios)``. 

128 """ 

129 if height_ratios is None: 

130 height_ratios = [1] * self._nrows 

131 elif len(height_ratios) != self._nrows: 

132 raise ValueError('Expected the given number of height ratios to ' 

133 'match the number of rows of the grid') 

134 self._row_height_ratios = height_ratios 

135 

136 def get_height_ratios(self): 

137 """ 

138 Return the height ratios. 

139 

140 This is *None* if no height ratios have been set explicitly. 

141 """ 

142 return self._row_height_ratios 

143 

144 def get_grid_positions(self, fig): 

145 """ 

146 Return the positions of the grid cells in figure coordinates. 

147 

148 Parameters 

149 ---------- 

150 fig : `~matplotlib.figure.Figure` 

151 The figure the grid should be applied to. The subplot parameters 

152 (margins and spacing between subplots) are taken from *fig*. 

153 

154 Returns 

155 ------- 

156 bottoms, tops, lefts, rights : array 

157 The bottom, top, left, right positions of the grid cells in 

158 figure coordinates. 

159 """ 

160 nrows, ncols = self.get_geometry() 

161 subplot_params = self.get_subplot_params(fig) 

162 left = subplot_params.left 

163 right = subplot_params.right 

164 bottom = subplot_params.bottom 

165 top = subplot_params.top 

166 wspace = subplot_params.wspace 

167 hspace = subplot_params.hspace 

168 tot_width = right - left 

169 tot_height = top - bottom 

170 

171 # calculate accumulated heights of columns 

172 cell_h = tot_height / (nrows + hspace*(nrows-1)) 

173 sep_h = hspace * cell_h 

174 norm = cell_h * nrows / sum(self._row_height_ratios) 

175 cell_heights = [r * norm for r in self._row_height_ratios] 

176 sep_heights = [0] + ([sep_h] * (nrows-1)) 

177 cell_hs = np.cumsum(np.column_stack([sep_heights, cell_heights]).flat) 

178 

179 # calculate accumulated widths of rows 

180 cell_w = tot_width / (ncols + wspace*(ncols-1)) 

181 sep_w = wspace * cell_w 

182 norm = cell_w * ncols / sum(self._col_width_ratios) 

183 cell_widths = [r * norm for r in self._col_width_ratios] 

184 sep_widths = [0] + ([sep_w] * (ncols-1)) 

185 cell_ws = np.cumsum(np.column_stack([sep_widths, cell_widths]).flat) 

186 

187 fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T 

188 fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T 

189 return fig_bottoms, fig_tops, fig_lefts, fig_rights 

190 

191 @staticmethod 

192 def _check_gridspec_exists(figure, nrows, ncols): 

193 """ 

194 Check if the figure already has a gridspec with these dimensions, 

195 or create a new one 

196 """ 

197 for ax in figure.get_axes(): 

198 gs = ax.get_gridspec() 

199 if gs is not None: 

200 if hasattr(gs, 'get_topmost_subplotspec'): 

201 # This is needed for colorbar gridspec layouts. 

202 # This is probably OK because this whole logic tree 

203 # is for when the user is doing simple things with the 

204 # add_subplot command. For complicated layouts 

205 # like subgridspecs the proper gridspec is passed in... 

206 gs = gs.get_topmost_subplotspec().get_gridspec() 

207 if gs.get_geometry() == (nrows, ncols): 

208 return gs 

209 # else gridspec not found: 

210 return GridSpec(nrows, ncols, figure=figure) 

211 

212 def __getitem__(self, key): 

213 """Create and return a `.SubplotSpec` instance.""" 

214 nrows, ncols = self.get_geometry() 

215 

216 def _normalize(key, size, axis): # Includes last index. 

217 orig_key = key 

218 if isinstance(key, slice): 

219 start, stop, _ = key.indices(size) 

220 if stop > start: 

221 return start, stop - 1 

222 raise IndexError("GridSpec slice would result in no space " 

223 "allocated for subplot") 

224 else: 

225 if key < 0: 

226 key = key + size 

227 if 0 <= key < size: 

228 return key, key 

229 elif axis is not None: 

230 raise IndexError(f"index {orig_key} is out of bounds for " 

231 f"axis {axis} with size {size}") 

232 else: # flat index 

233 raise IndexError(f"index {orig_key} is out of bounds for " 

234 f"GridSpec with size {size}") 

235 

236 if isinstance(key, tuple): 

237 try: 

238 k1, k2 = key 

239 except ValueError as err: 

240 raise ValueError("Unrecognized subplot spec") from err 

241 num1, num2 = np.ravel_multi_index( 

242 [_normalize(k1, nrows, 0), _normalize(k2, ncols, 1)], 

243 (nrows, ncols)) 

244 else: # Single key 

245 num1, num2 = _normalize(key, nrows * ncols, None) 

246 

247 return SubplotSpec(self, num1, num2) 

248 

249 def subplots(self, *, sharex=False, sharey=False, squeeze=True, 

250 subplot_kw=None): 

251 """ 

252 Add all subplots specified by this `GridSpec` to its parent figure. 

253 

254 See `.Figure.subplots` for detailed documentation. 

255 """ 

256 

257 figure = self.figure 

258 

259 if figure is None: 

260 raise ValueError("GridSpec.subplots() only works for GridSpecs " 

261 "created with a parent figure") 

262 

263 if not isinstance(sharex, str): 

264 sharex = "all" if sharex else "none" 

265 if not isinstance(sharey, str): 

266 sharey = "all" if sharey else "none" 

267 

268 _api.check_in_list(["all", "row", "col", "none", False, True], 

269 sharex=sharex, sharey=sharey) 

270 if subplot_kw is None: 

271 subplot_kw = {} 

272 # don't mutate kwargs passed by user... 

273 subplot_kw = subplot_kw.copy() 

274 

275 # Create array to hold all Axes. 

276 axarr = np.empty((self._nrows, self._ncols), dtype=object) 

277 for row in range(self._nrows): 

278 for col in range(self._ncols): 

279 shared_with = {"none": None, "all": axarr[0, 0], 

280 "row": axarr[row, 0], "col": axarr[0, col]} 

281 subplot_kw["sharex"] = shared_with[sharex] 

282 subplot_kw["sharey"] = shared_with[sharey] 

283 axarr[row, col] = figure.add_subplot( 

284 self[row, col], **subplot_kw) 

285 

286 # turn off redundant tick labeling 

287 if sharex in ["col", "all"]: 

288 for ax in axarr.flat: 

289 ax._label_outer_xaxis(skip_non_rectangular_axes=True) 

290 if sharey in ["row", "all"]: 

291 for ax in axarr.flat: 

292 ax._label_outer_yaxis(skip_non_rectangular_axes=True) 

293 

294 if squeeze: 

295 # Discarding unneeded dimensions that equal 1. If we only have one 

296 # subplot, just return it instead of a 1-element array. 

297 return axarr.item() if axarr.size == 1 else axarr.squeeze() 

298 else: 

299 # Returned axis array will be always 2-d, even if nrows=ncols=1. 

300 return axarr 

301 

302 

303class GridSpec(GridSpecBase): 

304 """ 

305 A grid layout to place subplots within a figure. 

306 

307 The location of the grid cells is determined in a similar way to 

308 `.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace* 

309 and *hspace*. 

310 

311 Indexing a GridSpec instance returns a `.SubplotSpec`. 

312 """ 

313 def __init__(self, nrows, ncols, figure=None, 

314 left=None, bottom=None, right=None, top=None, 

315 wspace=None, hspace=None, 

316 width_ratios=None, height_ratios=None): 

317 """ 

318 Parameters 

319 ---------- 

320 nrows, ncols : int 

321 The number of rows and columns of the grid. 

322 

323 figure : `.Figure`, optional 

324 Only used for constrained layout to create a proper layoutgrid. 

325 

326 left, right, top, bottom : float, optional 

327 Extent of the subplots as a fraction of figure width or height. 

328 Left cannot be larger than right, and bottom cannot be larger than 

329 top. If not given, the values will be inferred from a figure or 

330 rcParams at draw time. See also `GridSpec.get_subplot_params`. 

331 

332 wspace : float, optional 

333 The amount of width reserved for space between subplots, 

334 expressed as a fraction of the average axis width. 

335 If not given, the values will be inferred from a figure or 

336 rcParams when necessary. See also `GridSpec.get_subplot_params`. 

337 

338 hspace : float, optional 

339 The amount of height reserved for space between subplots, 

340 expressed as a fraction of the average axis height. 

341 If not given, the values will be inferred from a figure or 

342 rcParams when necessary. See also `GridSpec.get_subplot_params`. 

343 

344 width_ratios : array-like of length *ncols*, optional 

345 Defines the relative widths of the columns. Each column gets a 

346 relative width of ``width_ratios[i] / sum(width_ratios)``. 

347 If not given, all columns will have the same width. 

348 

349 height_ratios : array-like of length *nrows*, optional 

350 Defines the relative heights of the rows. Each row gets a 

351 relative height of ``height_ratios[i] / sum(height_ratios)``. 

352 If not given, all rows will have the same height. 

353 

354 """ 

355 self.left = left 

356 self.bottom = bottom 

357 self.right = right 

358 self.top = top 

359 self.wspace = wspace 

360 self.hspace = hspace 

361 self.figure = figure 

362 

363 super().__init__(nrows, ncols, 

364 width_ratios=width_ratios, 

365 height_ratios=height_ratios) 

366 

367 _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"] 

368 

369 def update(self, **kwargs): 

370 """ 

371 Update the subplot parameters of the grid. 

372 

373 Parameters that are not explicitly given are not changed. Setting a 

374 parameter to *None* resets it to :rc:`figure.subplot.*`. 

375 

376 Parameters 

377 ---------- 

378 left, right, top, bottom : float or None, optional 

379 Extent of the subplots as a fraction of figure width or height. 

380 wspace, hspace : float, optional 

381 Spacing between the subplots as a fraction of the average subplot 

382 width / height. 

383 """ 

384 for k, v in kwargs.items(): 

385 if k in self._AllowedKeys: 

386 setattr(self, k, v) 

387 else: 

388 raise AttributeError(f"{k} is an unknown keyword") 

389 for figmanager in _pylab_helpers.Gcf.figs.values(): 

390 for ax in figmanager.canvas.figure.axes: 

391 if ax.get_subplotspec() is not None: 

392 ss = ax.get_subplotspec().get_topmost_subplotspec() 

393 if ss.get_gridspec() == self: 

394 ax._set_position( 

395 ax.get_subplotspec().get_position(ax.figure)) 

396 

397 def get_subplot_params(self, figure=None): 

398 """ 

399 Return the `.SubplotParams` for the GridSpec. 

400 

401 In order of precedence the values are taken from 

402 

403 - non-*None* attributes of the GridSpec 

404 - the provided *figure* 

405 - :rc:`figure.subplot.*` 

406 

407 Note that the ``figure`` attribute of the GridSpec is always ignored. 

408 """ 

409 if figure is None: 

410 kw = {k: mpl.rcParams["figure.subplot."+k] 

411 for k in self._AllowedKeys} 

412 subplotpars = SubplotParams(**kw) 

413 else: 

414 subplotpars = copy.copy(figure.subplotpars) 

415 

416 subplotpars.update(**{k: getattr(self, k) for k in self._AllowedKeys}) 

417 

418 return subplotpars 

419 

420 def locally_modified_subplot_params(self): 

421 """ 

422 Return a list of the names of the subplot parameters explicitly set 

423 in the GridSpec. 

424 

425 This is a subset of the attributes of `.SubplotParams`. 

426 """ 

427 return [k for k in self._AllowedKeys if getattr(self, k)] 

428 

429 def tight_layout(self, figure, renderer=None, 

430 pad=1.08, h_pad=None, w_pad=None, rect=None): 

431 """ 

432 Adjust subplot parameters to give specified padding. 

433 

434 Parameters 

435 ---------- 

436 figure : `.Figure` 

437 The figure. 

438 renderer : `.RendererBase` subclass, optional 

439 The renderer to be used. 

440 pad : float 

441 Padding between the figure edge and the edges of subplots, as a 

442 fraction of the font-size. 

443 h_pad, w_pad : float, optional 

444 Padding (height/width) between edges of adjacent subplots. 

445 Defaults to *pad*. 

446 rect : tuple (left, bottom, right, top), default: None 

447 (left, bottom, right, top) rectangle in normalized figure 

448 coordinates that the whole subplots area (including labels) will 

449 fit into. Default (None) is the whole figure. 

450 """ 

451 if renderer is None: 

452 renderer = figure._get_renderer() 

453 kwargs = _tight_layout.get_tight_layout_figure( 

454 figure, figure.axes, 

455 _tight_layout.get_subplotspec_list(figure.axes, grid_spec=self), 

456 renderer, pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) 

457 if kwargs: 

458 self.update(**kwargs) 

459 

460 

461class GridSpecFromSubplotSpec(GridSpecBase): 

462 """ 

463 GridSpec whose subplot layout parameters are inherited from the 

464 location specified by a given SubplotSpec. 

465 """ 

466 def __init__(self, nrows, ncols, 

467 subplot_spec, 

468 wspace=None, hspace=None, 

469 height_ratios=None, width_ratios=None): 

470 """ 

471 Parameters 

472 ---------- 

473 nrows, ncols : int 

474 Number of rows and number of columns of the grid. 

475 subplot_spec : SubplotSpec 

476 Spec from which the layout parameters are inherited. 

477 wspace, hspace : float, optional 

478 See `GridSpec` for more details. If not specified default values 

479 (from the figure or rcParams) are used. 

480 height_ratios : array-like of length *nrows*, optional 

481 See `GridSpecBase` for details. 

482 width_ratios : array-like of length *ncols*, optional 

483 See `GridSpecBase` for details. 

484 """ 

485 self._wspace = wspace 

486 self._hspace = hspace 

487 if isinstance(subplot_spec, SubplotSpec): 

488 self._subplot_spec = subplot_spec 

489 else: 

490 raise TypeError( 

491 "subplot_spec must be type SubplotSpec, " 

492 "usually from GridSpec, or axes.get_subplotspec.") 

493 self.figure = self._subplot_spec.get_gridspec().figure 

494 super().__init__(nrows, ncols, 

495 width_ratios=width_ratios, 

496 height_ratios=height_ratios) 

497 

498 def get_subplot_params(self, figure=None): 

499 """Return a dictionary of subplot layout parameters.""" 

500 hspace = (self._hspace if self._hspace is not None 

501 else figure.subplotpars.hspace if figure is not None 

502 else mpl.rcParams["figure.subplot.hspace"]) 

503 wspace = (self._wspace if self._wspace is not None 

504 else figure.subplotpars.wspace if figure is not None 

505 else mpl.rcParams["figure.subplot.wspace"]) 

506 

507 figbox = self._subplot_spec.get_position(figure) 

508 left, bottom, right, top = figbox.extents 

509 

510 return SubplotParams(left=left, right=right, 

511 bottom=bottom, top=top, 

512 wspace=wspace, hspace=hspace) 

513 

514 def get_topmost_subplotspec(self): 

515 """ 

516 Return the topmost `.SubplotSpec` instance associated with the subplot. 

517 """ 

518 return self._subplot_spec.get_topmost_subplotspec() 

519 

520 

521class SubplotSpec: 

522 """ 

523 The location of a subplot in a `GridSpec`. 

524 

525 .. note:: 

526 

527 Likely, you will never instantiate a `SubplotSpec` yourself. Instead, 

528 you will typically obtain one from a `GridSpec` using item-access. 

529 

530 Parameters 

531 ---------- 

532 gridspec : `~matplotlib.gridspec.GridSpec` 

533 The GridSpec, which the subplot is referencing. 

534 num1, num2 : int 

535 The subplot will occupy the *num1*-th cell of the given 

536 *gridspec*. If *num2* is provided, the subplot will span between 

537 *num1*-th cell and *num2*-th cell **inclusive**. 

538 

539 The index starts from 0. 

540 """ 

541 def __init__(self, gridspec, num1, num2=None): 

542 self._gridspec = gridspec 

543 self.num1 = num1 

544 self.num2 = num2 

545 

546 def __repr__(self): 

547 return (f"{self.get_gridspec()}[" 

548 f"{self.rowspan.start}:{self.rowspan.stop}, " 

549 f"{self.colspan.start}:{self.colspan.stop}]") 

550 

551 @staticmethod 

552 def _from_subplot_args(figure, args): 

553 """ 

554 Construct a `.SubplotSpec` from a parent `.Figure` and either 

555 

556 - a `.SubplotSpec` -- returned as is; 

557 - one or three numbers -- a MATLAB-style subplot specifier. 

558 """ 

559 if len(args) == 1: 

560 arg, = args 

561 if isinstance(arg, SubplotSpec): 

562 return arg 

563 elif not isinstance(arg, Integral): 

564 raise ValueError( 

565 f"Single argument to subplot must be a three-digit " 

566 f"integer, not {arg!r}") 

567 try: 

568 rows, cols, num = map(int, str(arg)) 

569 except ValueError: 

570 raise ValueError( 

571 f"Single argument to subplot must be a three-digit " 

572 f"integer, not {arg!r}") from None 

573 elif len(args) == 3: 

574 rows, cols, num = args 

575 else: 

576 raise _api.nargs_error("subplot", takes="1 or 3", given=len(args)) 

577 

578 gs = GridSpec._check_gridspec_exists(figure, rows, cols) 

579 if gs is None: 

580 gs = GridSpec(rows, cols, figure=figure) 

581 if isinstance(num, tuple) and len(num) == 2: 

582 if not all(isinstance(n, Integral) for n in num): 

583 raise ValueError( 

584 f"Subplot specifier tuple must contain integers, not {num}" 

585 ) 

586 i, j = num 

587 else: 

588 if not isinstance(num, Integral) or num < 1 or num > rows*cols: 

589 raise ValueError( 

590 f"num must be an integer with 1 <= num <= {rows*cols}, " 

591 f"not {num!r}" 

592 ) 

593 i = j = num 

594 return gs[i-1:j] 

595 

596 # num2 is a property only to handle the case where it is None and someone 

597 # mutates num1. 

598 

599 @property 

600 def num2(self): 

601 return self.num1 if self._num2 is None else self._num2 

602 

603 @num2.setter 

604 def num2(self, value): 

605 self._num2 = value 

606 

607 def get_gridspec(self): 

608 return self._gridspec 

609 

610 def get_geometry(self): 

611 """ 

612 Return the subplot geometry as tuple ``(n_rows, n_cols, start, stop)``. 

613 

614 The indices *start* and *stop* define the range of the subplot within 

615 the `GridSpec`. *stop* is inclusive (i.e. for a single cell 

616 ``start == stop``). 

617 """ 

618 rows, cols = self.get_gridspec().get_geometry() 

619 return rows, cols, self.num1, self.num2 

620 

621 @property 

622 def rowspan(self): 

623 """The rows spanned by this subplot, as a `range` object.""" 

624 ncols = self.get_gridspec().ncols 

625 return range(self.num1 // ncols, self.num2 // ncols + 1) 

626 

627 @property 

628 def colspan(self): 

629 """The columns spanned by this subplot, as a `range` object.""" 

630 ncols = self.get_gridspec().ncols 

631 # We explicitly support num2 referring to a column on num1's *left*, so 

632 # we must sort the column indices here so that the range makes sense. 

633 c1, c2 = sorted([self.num1 % ncols, self.num2 % ncols]) 

634 return range(c1, c2 + 1) 

635 

636 def is_first_row(self): 

637 return self.rowspan.start == 0 

638 

639 def is_last_row(self): 

640 return self.rowspan.stop == self.get_gridspec().nrows 

641 

642 def is_first_col(self): 

643 return self.colspan.start == 0 

644 

645 def is_last_col(self): 

646 return self.colspan.stop == self.get_gridspec().ncols 

647 

648 def get_position(self, figure): 

649 """ 

650 Update the subplot position from ``figure.subplotpars``. 

651 """ 

652 gridspec = self.get_gridspec() 

653 nrows, ncols = gridspec.get_geometry() 

654 rows, cols = np.unravel_index([self.num1, self.num2], (nrows, ncols)) 

655 fig_bottoms, fig_tops, fig_lefts, fig_rights = \ 

656 gridspec.get_grid_positions(figure) 

657 

658 fig_bottom = fig_bottoms[rows].min() 

659 fig_top = fig_tops[rows].max() 

660 fig_left = fig_lefts[cols].min() 

661 fig_right = fig_rights[cols].max() 

662 return Bbox.from_extents(fig_left, fig_bottom, fig_right, fig_top) 

663 

664 def get_topmost_subplotspec(self): 

665 """ 

666 Return the topmost `SubplotSpec` instance associated with the subplot. 

667 """ 

668 gridspec = self.get_gridspec() 

669 if hasattr(gridspec, "get_topmost_subplotspec"): 

670 return gridspec.get_topmost_subplotspec() 

671 else: 

672 return self 

673 

674 def __eq__(self, other): 

675 """ 

676 Two SubplotSpecs are considered equal if they refer to the same 

677 position(s) in the same `GridSpec`. 

678 """ 

679 # other may not even have the attributes we are checking. 

680 return ((self._gridspec, self.num1, self.num2) 

681 == (getattr(other, "_gridspec", object()), 

682 getattr(other, "num1", object()), 

683 getattr(other, "num2", object()))) 

684 

685 def __hash__(self): 

686 return hash((self._gridspec, self.num1, self.num2)) 

687 

688 def subgridspec(self, nrows, ncols, **kwargs): 

689 """ 

690 Create a GridSpec within this subplot. 

691 

692 The created `.GridSpecFromSubplotSpec` will have this `SubplotSpec` as 

693 a parent. 

694 

695 Parameters 

696 ---------- 

697 nrows : int 

698 Number of rows in grid. 

699 

700 ncols : int 

701 Number of columns in grid. 

702 

703 Returns 

704 ------- 

705 `.GridSpecFromSubplotSpec` 

706 

707 Other Parameters 

708 ---------------- 

709 **kwargs 

710 All other parameters are passed to `.GridSpecFromSubplotSpec`. 

711 

712 See Also 

713 -------- 

714 matplotlib.pyplot.subplots 

715 

716 Examples 

717 -------- 

718 Adding three subplots in the space occupied by a single subplot:: 

719 

720 fig = plt.figure() 

721 gs0 = fig.add_gridspec(3, 1) 

722 ax1 = fig.add_subplot(gs0[0]) 

723 ax2 = fig.add_subplot(gs0[1]) 

724 gssub = gs0[2].subgridspec(1, 3) 

725 for i in range(3): 

726 fig.add_subplot(gssub[0, i]) 

727 """ 

728 return GridSpecFromSubplotSpec(nrows, ncols, self, **kwargs) 

729 

730 

731class SubplotParams: 

732 """ 

733 Parameters defining the positioning of a subplots grid in a figure. 

734 """ 

735 

736 def __init__(self, left=None, bottom=None, right=None, top=None, 

737 wspace=None, hspace=None): 

738 """ 

739 Defaults are given by :rc:`figure.subplot.[name]`. 

740 

741 Parameters 

742 ---------- 

743 left : float 

744 The position of the left edge of the subplots, 

745 as a fraction of the figure width. 

746 right : float 

747 The position of the right edge of the subplots, 

748 as a fraction of the figure width. 

749 bottom : float 

750 The position of the bottom edge of the subplots, 

751 as a fraction of the figure height. 

752 top : float 

753 The position of the top edge of the subplots, 

754 as a fraction of the figure height. 

755 wspace : float 

756 The width of the padding between subplots, 

757 as a fraction of the average Axes width. 

758 hspace : float 

759 The height of the padding between subplots, 

760 as a fraction of the average Axes height. 

761 """ 

762 for key in ["left", "bottom", "right", "top", "wspace", "hspace"]: 

763 setattr(self, key, mpl.rcParams[f"figure.subplot.{key}"]) 

764 self.update(left, bottom, right, top, wspace, hspace) 

765 

766 def update(self, left=None, bottom=None, right=None, top=None, 

767 wspace=None, hspace=None): 

768 """ 

769 Update the dimensions of the passed parameters. *None* means unchanged. 

770 """ 

771 if ((left if left is not None else self.left) 

772 >= (right if right is not None else self.right)): 

773 raise ValueError('left cannot be >= right') 

774 if ((bottom if bottom is not None else self.bottom) 

775 >= (top if top is not None else self.top)): 

776 raise ValueError('bottom cannot be >= top') 

777 if left is not None: 

778 self.left = left 

779 if right is not None: 

780 self.right = right 

781 if bottom is not None: 

782 self.bottom = bottom 

783 if top is not None: 

784 self.top = top 

785 if wspace is not None: 

786 self.wspace = wspace 

787 if hspace is not None: 

788 self.hspace = hspace