Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 

8See the tutorial :ref:`sphx_glr_tutorials_intermediate_gridspec.py` for a 

9comprehensive usage guide. 

10""" 

11 

12import copy 

13import logging 

14 

15import numpy as np 

16 

17import matplotlib as mpl 

18from matplotlib import _pylab_helpers, cbook, tight_layout, rcParams 

19from matplotlib.transforms import Bbox 

20import matplotlib._layoutbox as layoutbox 

21 

22_log = logging.getLogger(__name__) 

23 

24 

25class GridSpecBase: 

26 """ 

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

28 that a subplot will be placed. 

29 """ 

30 

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

32 """ 

33 Parameters 

34 ---------- 

35 nrows, ncols : int 

36 The number of rows and columns of the grid. 

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

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

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

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

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

42 Defines the relative heights of the rows. Each column gets a 

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

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

45 """ 

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

47 self.set_height_ratios(height_ratios) 

48 self.set_width_ratios(width_ratios) 

49 

50 def __repr__(self): 

51 height_arg = (', height_ratios=%r' % (self._row_height_ratios,) 

52 if self._row_height_ratios is not None else '') 

53 width_arg = (', width_ratios=%r' % (self._col_width_ratios,) 

54 if self._col_width_ratios is not None else '') 

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

56 clsname=self.__class__.__name__, 

57 nrows=self._nrows, 

58 ncols=self._ncols, 

59 optionals=height_arg + width_arg, 

60 ) 

61 

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

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

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

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

66 

67 def get_geometry(self): 

68 """ 

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

70 """ 

71 return self._nrows, self._ncols 

72 

73 def get_subplot_params(self, figure=None): 

74 # Must be implemented in subclasses 

75 pass 

76 

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

78 """ 

79 Create and return a `.SubplotSpec` instance. 

80 

81 Parameters 

82 ---------- 

83 loc : (int, int) 

84 The position of the subplot in the grid as 

85 ``(row_index, column_index)``. 

86 rowspan, colspan : int, default: 1 

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

88 """ 

89 loc1, loc2 = loc 

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

91 return subplotspec 

92 

93 def set_width_ratios(self, width_ratios): 

94 """ 

95 Set the relative widths of the columns. 

96 

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

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

99 """ 

100 if width_ratios is not None and len(width_ratios) != self._ncols: 

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

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

103 self._col_width_ratios = width_ratios 

104 

105 def get_width_ratios(self): 

106 """ 

107 Return the width ratios. 

108 

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

110 """ 

111 return self._col_width_ratios 

112 

113 def set_height_ratios(self, height_ratios): 

114 """ 

115 Set the relative heights of the rows. 

116 

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

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

119 """ 

120 if height_ratios is not None and len(height_ratios) != self._nrows: 

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

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

123 self._row_height_ratios = height_ratios 

124 

125 def get_height_ratios(self): 

126 """ 

127 Return the height ratios. 

128 

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

130 """ 

131 return self._row_height_ratios 

132 

133 def get_grid_positions(self, fig, raw=False): 

134 """ 

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

136 

137 Parameters 

138 ---------- 

139 fig : `~matplotlib.figure.Figure` 

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

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

142 raw : bool, default: False 

143 If *True*, the subplot parameters of the figure are not taken 

144 into account. The grid spans the range [0, 1] in both directions 

145 without margins and there is no space between grid cells. This is 

146 used for constrained_layout. 

147 

148 Returns 

149 ------- 

150 bottoms, tops, lefts, rights : array 

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

152 figure coordinates. 

153 """ 

154 nrows, ncols = self.get_geometry() 

155 

156 if raw: 

157 left = 0. 

158 right = 1. 

159 bottom = 0. 

160 top = 1. 

161 wspace = 0. 

162 hspace = 0. 

163 else: 

164 subplot_params = self.get_subplot_params(fig) 

165 left = subplot_params.left 

166 right = subplot_params.right 

167 bottom = subplot_params.bottom 

168 top = subplot_params.top 

169 wspace = subplot_params.wspace 

170 hspace = subplot_params.hspace 

171 tot_width = right - left 

172 tot_height = top - bottom 

173 

174 # calculate accumulated heights of columns 

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

176 sep_h = hspace * cell_h 

177 if self._row_height_ratios is not None: 

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

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

180 else: 

181 cell_heights = [cell_h] * nrows 

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

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

184 

185 # calculate accumulated widths of rows 

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

187 sep_w = wspace * cell_w 

188 if self._col_width_ratios is not None: 

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

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

191 else: 

192 cell_widths = [cell_w] * ncols 

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

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

195 

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

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

198 return fig_bottoms, fig_tops, fig_lefts, fig_rights 

199 

200 def __getitem__(self, key): 

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

202 nrows, ncols = self.get_geometry() 

203 

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

205 orig_key = key 

206 if isinstance(key, slice): 

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

208 if stop > start: 

209 return start, stop - 1 

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

211 "allocated for subplot") 

212 else: 

213 if key < 0: 

214 key = key + size 

215 if 0 <= key < size: 

216 return key, key 

217 elif axis is not None: 

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

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

220 else: # flat index 

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

222 f"GridSpec with size {size}") 

223 

224 if isinstance(key, tuple): 

225 try: 

226 k1, k2 = key 

227 except ValueError: 

228 raise ValueError("unrecognized subplot spec") 

229 num1, num2 = np.ravel_multi_index( 

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

231 (nrows, ncols)) 

232 else: # Single key 

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

234 

235 return SubplotSpec(self, num1, num2) 

236 

237 

238class GridSpec(GridSpecBase): 

239 """ 

240 A grid layout to place subplots within a figure. 

241 

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

243 `~.figure.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace* 

244 and *hspace*. 

245 """ 

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

247 left=None, bottom=None, right=None, top=None, 

248 wspace=None, hspace=None, 

249 width_ratios=None, height_ratios=None): 

250 """ 

251 Parameters 

252 ---------- 

253 nrows, ncols : int 

254 The number of rows and columns of the grid. 

255 

256 figure : `~.figure.Figure`, optional 

257 Only used for constrained layout to create a proper layoutbox. 

258 

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

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

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

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

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

264 

265 wspace : float, optional 

266 The amount of width reserved for space between subplots, 

267 expressed as a fraction of the average axis width. 

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

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

270 

271 hspace : float, optional 

272 The amount of height reserved for space between subplots, 

273 expressed as a fraction of the average axis height. 

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

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

276 

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

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

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

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

281 

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

283 Defines the relative heights of the rows. Each column gets a 

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

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

286 

287 """ 

288 self.left = left 

289 self.bottom = bottom 

290 self.right = right 

291 self.top = top 

292 self.wspace = wspace 

293 self.hspace = hspace 

294 self.figure = figure 

295 

296 GridSpecBase.__init__(self, nrows, ncols, 

297 width_ratios=width_ratios, 

298 height_ratios=height_ratios) 

299 

300 if self.figure is None or not self.figure.get_constrained_layout(): 

301 self._layoutbox = None 

302 else: 

303 self.figure.init_layoutbox() 

304 self._layoutbox = layoutbox.LayoutBox( 

305 parent=self.figure._layoutbox, 

306 name='gridspec' + layoutbox.seq_id(), 

307 artist=self) 

308 # by default the layoutbox for a gridspec will fill a figure. 

309 # but this can change below if the gridspec is created from a 

310 # subplotspec. (GridSpecFromSubplotSpec) 

311 

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

313 

314 def __getstate__(self): 

315 state = self.__dict__ 

316 try: 

317 state.pop('_layoutbox') 

318 except KeyError: 

319 pass 

320 return state 

321 

322 def __setstate__(self, state): 

323 self.__dict__ = state 

324 # layoutboxes don't survive pickling... 

325 self._layoutbox = None 

326 

327 def update(self, **kwargs): 

328 """ 

329 Update the subplot parameters of the grid. 

330 

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

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

333 

334 Parameters 

335 ---------- 

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

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

338 wspace, hspace : float, optional 

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

340 width / height. 

341 """ 

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

343 if k in self._AllowedKeys: 

344 setattr(self, k, v) 

345 else: 

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

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

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

349 # copied from Figure.subplots_adjust 

350 if not isinstance(ax, mpl.axes.SubplotBase): 

351 # Check if sharing a subplots axis 

352 if isinstance(ax._sharex, mpl.axes.SubplotBase): 

353 if ax._sharex.get_subplotspec().get_gridspec() == self: 

354 ax._sharex.update_params() 

355 ax._set_position(ax._sharex.figbox) 

356 elif isinstance(ax._sharey, mpl.axes.SubplotBase): 

357 if ax._sharey.get_subplotspec().get_gridspec() == self: 

358 ax._sharey.update_params() 

359 ax._set_position(ax._sharey.figbox) 

360 else: 

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

362 if ss.get_gridspec() == self: 

363 ax.update_params() 

364 ax._set_position(ax.figbox) 

365 

366 def get_subplot_params(self, figure=None): 

367 """ 

368 Return the `~.SubplotParams` for the GridSpec. 

369 

370 In order of precedence the values are taken from 

371 

372 - non-*None* attributes of the GridSpec 

373 - the provided *figure* 

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

375 """ 

376 if figure is None: 

377 kw = {k: rcParams["figure.subplot."+k] for k in self._AllowedKeys} 

378 subplotpars = mpl.figure.SubplotParams(**kw) 

379 else: 

380 subplotpars = copy.copy(figure.subplotpars) 

381 

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

383 

384 return subplotpars 

385 

386 def locally_modified_subplot_params(self): 

387 """ 

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

389 in the GridSpec. 

390 

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

392 """ 

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

394 

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

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

397 """ 

398 Adjust subplot parameters to give specified padding. 

399 

400 Parameters 

401 ---------- 

402 pad : float 

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

404 fraction of the font-size. 

405 h_pad, w_pad : float, optional 

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

407 Defaults to *pad*. 

408 rect : tuple of 4 floats, optional 

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

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

411 fit into. Default is (0, 0, 1, 1). 

412 """ 

413 

414 subplotspec_list = tight_layout.get_subplotspec_list( 

415 figure.axes, grid_spec=self) 

416 if None in subplotspec_list: 

417 cbook._warn_external("This figure includes Axes that are not " 

418 "compatible with tight_layout, so results " 

419 "might be incorrect.") 

420 

421 if renderer is None: 

422 renderer = tight_layout.get_renderer(figure) 

423 

424 kwargs = tight_layout.get_tight_layout_figure( 

425 figure, figure.axes, subplotspec_list, renderer, 

426 pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) 

427 if kwargs: 

428 self.update(**kwargs) 

429 

430 

431class GridSpecFromSubplotSpec(GridSpecBase): 

432 """ 

433 GridSpec whose subplot layout parameters are inherited from the 

434 location specified by a given SubplotSpec. 

435 """ 

436 def __init__(self, nrows, ncols, 

437 subplot_spec, 

438 wspace=None, hspace=None, 

439 height_ratios=None, width_ratios=None): 

440 """ 

441 The number of rows and number of columns of the grid need to 

442 be set. An instance of SubplotSpec is also needed to be set 

443 from which the layout parameters will be inherited. The wspace 

444 and hspace of the layout can be optionally specified or the 

445 default values (from the figure or rcParams) will be used. 

446 """ 

447 self._wspace = wspace 

448 self._hspace = hspace 

449 self._subplot_spec = subplot_spec 

450 GridSpecBase.__init__(self, nrows, ncols, 

451 width_ratios=width_ratios, 

452 height_ratios=height_ratios) 

453 # do the layoutboxes 

454 subspeclb = subplot_spec._layoutbox 

455 if subspeclb is None: 

456 self._layoutbox = None 

457 else: 

458 # OK, this is needed to divide the figure. 

459 self._layoutbox = subspeclb.layout_from_subplotspec( 

460 subplot_spec, 

461 name=subspeclb.name + '.gridspec' + layoutbox.seq_id(), 

462 artist=self) 

463 

464 def get_subplot_params(self, figure=None): 

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

466 """ 

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

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

469 else rcParams["figure.subplot.hspace"]) 

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

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

472 else rcParams["figure.subplot.wspace"]) 

473 

474 figbox = self._subplot_spec.get_position(figure) 

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

476 

477 return mpl.figure.SubplotParams(left=left, right=right, 

478 bottom=bottom, top=top, 

479 wspace=wspace, hspace=hspace) 

480 

481 def get_topmost_subplotspec(self): 

482 """ 

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

484 """ 

485 return self._subplot_spec.get_topmost_subplotspec() 

486 

487 

488class SubplotSpec: 

489 """ 

490 Specifies the location of a subplot in a `GridSpec`. 

491 

492 .. note:: 

493 

494 Likely, you'll never instantiate a `SubplotSpec` yourself. Instead you 

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

496 

497 Parameters 

498 ---------- 

499 gridspec : `~matplotlib.gridspec.GridSpec` 

500 The GridSpec, which the subplot is referencing. 

501 num1, num2 : int 

502 The subplot will occupy the num1-th cell of the given 

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

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

505 

506 The index starts from 0. 

507 """ 

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

509 self._gridspec = gridspec 

510 self.num1 = num1 

511 self.num2 = num2 

512 if gridspec._layoutbox is not None: 

513 glb = gridspec._layoutbox 

514 # So note that here we don't assign any layout yet, 

515 # just make the layoutbox that will contain all items 

516 # associated w/ this axis. This can include other axes like 

517 # a colorbar or a legend. 

518 self._layoutbox = layoutbox.LayoutBox( 

519 parent=glb, 

520 name=glb.name + '.ss' + layoutbox.seq_id(), 

521 artist=self) 

522 else: 

523 self._layoutbox = None 

524 

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

526 # mutates num1. 

527 

528 @property 

529 def num2(self): 

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

531 

532 @num2.setter 

533 def num2(self, value): 

534 self._num2 = value 

535 

536 def __getstate__(self): 

537 state = self.__dict__ 

538 try: 

539 state.pop('_layoutbox') 

540 except KeyError: 

541 pass 

542 return state 

543 

544 def __setstate__(self, state): 

545 self.__dict__ = state 

546 # layoutboxes don't survive pickling... 

547 self._layoutbox = None 

548 

549 def get_gridspec(self): 

550 return self._gridspec 

551 

552 def get_geometry(self): 

553 """ 

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

555 

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

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

558 ``start == stop``). 

559 """ 

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

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

562 

563 def get_rows_columns(self): 

564 """ 

565 Return the subplot row and column numbers as a tuple 

566 ``(n_rows, n_cols, row_start, row_stop, col_start, col_stop)``. 

567 """ 

568 gridspec = self.get_gridspec() 

569 nrows, ncols = gridspec.get_geometry() 

570 row_start, col_start = divmod(self.num1, ncols) 

571 row_stop, col_stop = divmod(self.num2, ncols) 

572 return nrows, ncols, row_start, row_stop, col_start, col_stop 

573 

574 @property 

575 def rowspan(self): 

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

577 ncols = self.get_gridspec().ncols 

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

579 

580 @property 

581 def colspan(self): 

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

583 ncols = self.get_gridspec().ncols 

584 return range(self.num1 % ncols, self.num2 % ncols + 1) 

585 

586 def get_position(self, figure, return_all=False): 

587 """ 

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

589 """ 

590 gridspec = self.get_gridspec() 

591 nrows, ncols = gridspec.get_geometry() 

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

593 fig_bottoms, fig_tops, fig_lefts, fig_rights = \ 

594 gridspec.get_grid_positions(figure) 

595 

596 fig_bottom = fig_bottoms[rows].min() 

597 fig_top = fig_tops[rows].max() 

598 fig_left = fig_lefts[cols].min() 

599 fig_right = fig_rights[cols].max() 

600 figbox = Bbox.from_extents(fig_left, fig_bottom, fig_right, fig_top) 

601 

602 if return_all: 

603 return figbox, rows[0], cols[0], nrows, ncols 

604 else: 

605 return figbox 

606 

607 def get_topmost_subplotspec(self): 

608 """ 

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

610 """ 

611 gridspec = self.get_gridspec() 

612 if hasattr(gridspec, "get_topmost_subplotspec"): 

613 return gridspec.get_topmost_subplotspec() 

614 else: 

615 return self 

616 

617 def __eq__(self, other): 

618 """ 

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

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

621 """ 

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

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

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

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

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

627 

628 def __hash__(self): 

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

630 

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

632 """ 

633 Create a GridSpec within this subplot. 

634 

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

636 a parent. 

637 

638 Parameters 

639 ---------- 

640 nrows : int 

641 Number of rows in grid. 

642 

643 ncols : int 

644 Number or columns in grid. 

645 

646 Returns 

647 ------- 

648 gridspec : `.GridSpecFromSubplotSpec` 

649 

650 Other Parameters 

651 ---------------- 

652 **kwargs 

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

654 

655 See Also 

656 -------- 

657 matplotlib.pyplot.subplots 

658 

659 Examples 

660 -------- 

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

662 

663 fig = plt.figure() 

664 gs0 = fig.add_gridspec(3, 1) 

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

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

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

668 for i in range(3): 

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

670 """ 

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