Coverage for /usr/lib/python3/dist-packages/matplotlib/figure.py: 45%

1019 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2`matplotlib.figure` implements the following classes: 

3 

4`Figure` 

5 Top level `~matplotlib.artist.Artist`, which holds all plot elements. 

6 Many methods are implemented in `FigureBase`. 

7 

8`SubFigure` 

9 A logical figure inside a figure, usually added to a figure (or parent 

10 `SubFigure`) with `Figure.add_subfigure` or `Figure.subfigures` methods 

11 (provisional API v3.4). 

12 

13`SubplotParams` 

14 Control the default spacing between subplots. 

15""" 

16 

17from contextlib import ExitStack 

18import inspect 

19import itertools 

20import logging 

21from numbers import Integral 

22 

23import numpy as np 

24 

25import matplotlib as mpl 

26from matplotlib import _blocking_input, backend_bases, _docstring, projections 

27from matplotlib.artist import ( 

28 Artist, allow_rasterization, _finalize_rasterization) 

29from matplotlib.backend_bases import ( 

30 DrawEvent, FigureCanvasBase, NonGuiException, MouseButton, _get_renderer) 

31import matplotlib._api as _api 

32import matplotlib.cbook as cbook 

33import matplotlib.colorbar as cbar 

34import matplotlib.image as mimage 

35 

36from matplotlib.axes import Axes, SubplotBase, subplot_class_factory 

37from matplotlib.gridspec import GridSpec 

38from matplotlib.layout_engine import ( 

39 ConstrainedLayoutEngine, TightLayoutEngine, LayoutEngine, 

40 PlaceHolderLayoutEngine 

41) 

42import matplotlib.legend as mlegend 

43from matplotlib.patches import Rectangle 

44from matplotlib.text import Text 

45from matplotlib.transforms import (Affine2D, Bbox, BboxTransformTo, 

46 TransformedBbox) 

47 

48_log = logging.getLogger(__name__) 

49 

50 

51def _stale_figure_callback(self, val): 

52 if self.figure: 

53 self.figure.stale = val 

54 

55 

56class _AxesStack: 

57 """ 

58 Helper class to track axes in a figure. 

59 

60 Axes are tracked both in the order in which they have been added 

61 (``self._axes`` insertion/iteration order) and in the separate "gca" stack 

62 (which is the index to which they map in the ``self._axes`` dict). 

63 """ 

64 

65 def __init__(self): 

66 self._axes = {} # Mapping of axes to "gca" order. 

67 self._counter = itertools.count() 

68 

69 def as_list(self): 

70 """List the axes that have been added to the figure.""" 

71 return [*self._axes] # This relies on dict preserving order. 

72 

73 def remove(self, a): 

74 """Remove the axes from the stack.""" 

75 self._axes.pop(a) 

76 

77 def bubble(self, a): 

78 """Move an axes, which must already exist in the stack, to the top.""" 

79 if a not in self._axes: 

80 raise ValueError("Axes has not been added yet") 

81 self._axes[a] = next(self._counter) 

82 

83 def add(self, a): 

84 """Add an axes to the stack, ignoring it if already present.""" 

85 if a not in self._axes: 

86 self._axes[a] = next(self._counter) 

87 

88 def current(self): 

89 """Return the active axes, or None if the stack is empty.""" 

90 return max(self._axes, key=self._axes.__getitem__, default=None) 

91 

92 

93class SubplotParams: 

94 """ 

95 A class to hold the parameters for a subplot. 

96 """ 

97 

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

99 wspace=None, hspace=None): 

100 """ 

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

102 

103 Parameters 

104 ---------- 

105 left : float 

106 The position of the left edge of the subplots, 

107 as a fraction of the figure width. 

108 right : float 

109 The position of the right edge of the subplots, 

110 as a fraction of the figure width. 

111 bottom : float 

112 The position of the bottom edge of the subplots, 

113 as a fraction of the figure height. 

114 top : float 

115 The position of the top edge of the subplots, 

116 as a fraction of the figure height. 

117 wspace : float 

118 The width of the padding between subplots, 

119 as a fraction of the average Axes width. 

120 hspace : float 

121 The height of the padding between subplots, 

122 as a fraction of the average Axes height. 

123 """ 

124 self._validate = True 

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

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

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

128 

129 # Also remove _validate after deprecation elapses. 

130 validate = _api.deprecate_privatize_attribute("3.5") 

131 

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

133 wspace=None, hspace=None): 

134 """ 

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

136 """ 

137 if self._validate: 

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

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

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

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

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

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

144 if left is not None: 

145 self.left = left 

146 if right is not None: 

147 self.right = right 

148 if bottom is not None: 

149 self.bottom = bottom 

150 if top is not None: 

151 self.top = top 

152 if wspace is not None: 

153 self.wspace = wspace 

154 if hspace is not None: 

155 self.hspace = hspace 

156 

157 

158class FigureBase(Artist): 

159 """ 

160 Base class for `.Figure` and `.SubFigure` containing the methods that add 

161 artists to the figure or subfigure, create Axes, etc. 

162 """ 

163 def __init__(self, **kwargs): 

164 super().__init__() 

165 # remove the non-figure artist _axes property 

166 # as it makes no sense for a figure to be _in_ an Axes 

167 # this is used by the property methods in the artist base class 

168 # which are over-ridden in this class 

169 del self._axes 

170 

171 self._suptitle = None 

172 self._supxlabel = None 

173 self._supylabel = None 

174 

175 # groupers to keep track of x and y labels we want to align. 

176 # see self.align_xlabels and self.align_ylabels and 

177 # axis._get_tick_boxes_siblings 

178 self._align_label_groups = {"x": cbook.Grouper(), "y": cbook.Grouper()} 

179 

180 self.figure = self 

181 self._localaxes = [] # track all axes 

182 self.artists = [] 

183 self.lines = [] 

184 self.patches = [] 

185 self.texts = [] 

186 self.images = [] 

187 self.legends = [] 

188 self.subfigs = [] 

189 self.stale = True 

190 self.suppressComposite = None 

191 self.set(**kwargs) 

192 

193 def _get_draw_artists(self, renderer): 

194 """Also runs apply_aspect""" 

195 artists = self.get_children() 

196 for sfig in self.subfigs: 

197 artists.remove(sfig) 

198 childa = sfig.get_children() 

199 for child in childa: 

200 if child in artists: 

201 artists.remove(child) 

202 

203 artists.remove(self.patch) 

204 artists = sorted( 

205 (artist for artist in artists if not artist.get_animated()), 

206 key=lambda artist: artist.get_zorder()) 

207 for ax in self._localaxes: 

208 locator = ax.get_axes_locator() 

209 ax.apply_aspect(locator(ax, renderer) if locator else None) 

210 

211 for child in ax.get_children(): 

212 if hasattr(child, 'apply_aspect'): 

213 locator = child.get_axes_locator() 

214 child.apply_aspect( 

215 locator(child, renderer) if locator else None) 

216 return artists 

217 

218 def autofmt_xdate( 

219 self, bottom=0.2, rotation=30, ha='right', which='major'): 

220 """ 

221 Date ticklabels often overlap, so it is useful to rotate them 

222 and right align them. Also, a common use case is a number of 

223 subplots with shared x-axis where the x-axis is date data. The 

224 ticklabels are often long, and it helps to rotate them on the 

225 bottom subplot and turn them off on other subplots, as well as 

226 turn off xlabels. 

227 

228 Parameters 

229 ---------- 

230 bottom : float, default: 0.2 

231 The bottom of the subplots for `subplots_adjust`. 

232 rotation : float, default: 30 degrees 

233 The rotation angle of the xtick labels in degrees. 

234 ha : {'left', 'center', 'right'}, default: 'right' 

235 The horizontal alignment of the xticklabels. 

236 which : {'major', 'minor', 'both'}, default: 'major' 

237 Selects which ticklabels to rotate. 

238 """ 

239 _api.check_in_list(['major', 'minor', 'both'], which=which) 

240 allsubplots = all(hasattr(ax, 'get_subplotspec') for ax in self.axes) 

241 if len(self.axes) == 1: 

242 for label in self.axes[0].get_xticklabels(which=which): 

243 label.set_ha(ha) 

244 label.set_rotation(rotation) 

245 else: 

246 if allsubplots: 

247 for ax in self.get_axes(): 

248 if ax.get_subplotspec().is_last_row(): 

249 for label in ax.get_xticklabels(which=which): 

250 label.set_ha(ha) 

251 label.set_rotation(rotation) 

252 else: 

253 for label in ax.get_xticklabels(which=which): 

254 label.set_visible(False) 

255 ax.set_xlabel('') 

256 

257 if allsubplots: 

258 self.subplots_adjust(bottom=bottom) 

259 self.stale = True 

260 

261 def get_children(self): 

262 """Get a list of artists contained in the figure.""" 

263 return [self.patch, 

264 *self.artists, 

265 *self._localaxes, 

266 *self.lines, 

267 *self.patches, 

268 *self.texts, 

269 *self.images, 

270 *self.legends, 

271 *self.subfigs] 

272 

273 def contains(self, mouseevent): 

274 """ 

275 Test whether the mouse event occurred on the figure. 

276 

277 Returns 

278 ------- 

279 bool, {} 

280 """ 

281 inside, info = self._default_contains(mouseevent, figure=self) 

282 if inside is not None: 

283 return inside, info 

284 inside = self.bbox.contains(mouseevent.x, mouseevent.y) 

285 return inside, {} 

286 

287 @_api.delete_parameter("3.6", "args") 

288 @_api.delete_parameter("3.6", "kwargs") 

289 def get_window_extent(self, renderer=None, *args, **kwargs): 

290 # docstring inherited 

291 return self.bbox 

292 

293 def _suplabels(self, t, info, **kwargs): 

294 """ 

295 Add a centered %(name)s to the figure. 

296 

297 Parameters 

298 ---------- 

299 t : str 

300 The %(name)s text. 

301 x : float, default: %(x0)s 

302 The x location of the text in figure coordinates. 

303 y : float, default: %(y0)s 

304 The y location of the text in figure coordinates. 

305 horizontalalignment, ha : {'center', 'left', 'right'}, default: %(ha)s 

306 The horizontal alignment of the text relative to (*x*, *y*). 

307 verticalalignment, va : {'top', 'center', 'bottom', 'baseline'}, \ 

308default: %(va)s 

309 The vertical alignment of the text relative to (*x*, *y*). 

310 fontsize, size : default: :rc:`figure.%(rc)ssize` 

311 The font size of the text. See `.Text.set_size` for possible 

312 values. 

313 fontweight, weight : default: :rc:`figure.%(rc)sweight` 

314 The font weight of the text. See `.Text.set_weight` for possible 

315 values. 

316 

317 Returns 

318 ------- 

319 text 

320 The `.Text` instance of the %(name)s. 

321 

322 Other Parameters 

323 ---------------- 

324 fontproperties : None or dict, optional 

325 A dict of font properties. If *fontproperties* is given the 

326 default values for font size and weight are taken from the 

327 `.FontProperties` defaults. :rc:`figure.%(rc)ssize` and 

328 :rc:`figure.%(rc)sweight` are ignored in this case. 

329 

330 **kwargs 

331 Additional kwargs are `matplotlib.text.Text` properties. 

332 """ 

333 

334 suplab = getattr(self, info['name']) 

335 

336 x = kwargs.pop('x', None) 

337 y = kwargs.pop('y', None) 

338 if info['name'] in ['_supxlabel', '_suptitle']: 

339 autopos = y is None 

340 elif info['name'] == '_supylabel': 

341 autopos = x is None 

342 if x is None: 

343 x = info['x0'] 

344 if y is None: 

345 y = info['y0'] 

346 

347 if 'horizontalalignment' not in kwargs and 'ha' not in kwargs: 

348 kwargs['horizontalalignment'] = info['ha'] 

349 if 'verticalalignment' not in kwargs and 'va' not in kwargs: 

350 kwargs['verticalalignment'] = info['va'] 

351 if 'rotation' not in kwargs: 

352 kwargs['rotation'] = info['rotation'] 

353 

354 if 'fontproperties' not in kwargs: 

355 if 'fontsize' not in kwargs and 'size' not in kwargs: 

356 kwargs['size'] = mpl.rcParams[info['size']] 

357 if 'fontweight' not in kwargs and 'weight' not in kwargs: 

358 kwargs['weight'] = mpl.rcParams[info['weight']] 

359 

360 sup = self.text(x, y, t, **kwargs) 

361 if suplab is not None: 

362 suplab.set_text(t) 

363 suplab.set_position((x, y)) 

364 suplab.update_from(sup) 

365 sup.remove() 

366 else: 

367 suplab = sup 

368 suplab._autopos = autopos 

369 setattr(self, info['name'], suplab) 

370 self.stale = True 

371 return suplab 

372 

373 @_docstring.Substitution(x0=0.5, y0=0.98, name='suptitle', ha='center', 

374 va='top', rc='title') 

375 @_docstring.copy(_suplabels) 

376 def suptitle(self, t, **kwargs): 

377 # docstring from _suplabels... 

378 info = {'name': '_suptitle', 'x0': 0.5, 'y0': 0.98, 

379 'ha': 'center', 'va': 'top', 'rotation': 0, 

380 'size': 'figure.titlesize', 'weight': 'figure.titleweight'} 

381 return self._suplabels(t, info, **kwargs) 

382 

383 @_docstring.Substitution(x0=0.5, y0=0.01, name='supxlabel', ha='center', 

384 va='bottom', rc='label') 

385 @_docstring.copy(_suplabels) 

386 def supxlabel(self, t, **kwargs): 

387 # docstring from _suplabels... 

388 info = {'name': '_supxlabel', 'x0': 0.5, 'y0': 0.01, 

389 'ha': 'center', 'va': 'bottom', 'rotation': 0, 

390 'size': 'figure.labelsize', 'weight': 'figure.labelweight'} 

391 return self._suplabels(t, info, **kwargs) 

392 

393 @_docstring.Substitution(x0=0.02, y0=0.5, name='supylabel', ha='left', 

394 va='center', rc='label') 

395 @_docstring.copy(_suplabels) 

396 def supylabel(self, t, **kwargs): 

397 # docstring from _suplabels... 

398 info = {'name': '_supylabel', 'x0': 0.02, 'y0': 0.5, 

399 'ha': 'left', 'va': 'center', 'rotation': 'vertical', 

400 'rotation_mode': 'anchor', 'size': 'figure.labelsize', 

401 'weight': 'figure.labelweight'} 

402 return self._suplabels(t, info, **kwargs) 

403 

404 def get_edgecolor(self): 

405 """Get the edge color of the Figure rectangle.""" 

406 return self.patch.get_edgecolor() 

407 

408 def get_facecolor(self): 

409 """Get the face color of the Figure rectangle.""" 

410 return self.patch.get_facecolor() 

411 

412 def get_frameon(self): 

413 """ 

414 Return the figure's background patch visibility, i.e. 

415 whether the figure background will be drawn. Equivalent to 

416 ``Figure.patch.get_visible()``. 

417 """ 

418 return self.patch.get_visible() 

419 

420 def set_linewidth(self, linewidth): 

421 """ 

422 Set the line width of the Figure rectangle. 

423 

424 Parameters 

425 ---------- 

426 linewidth : number 

427 """ 

428 self.patch.set_linewidth(linewidth) 

429 

430 def get_linewidth(self): 

431 """ 

432 Get the line width of the Figure rectangle. 

433 """ 

434 return self.patch.get_linewidth() 

435 

436 def set_edgecolor(self, color): 

437 """ 

438 Set the edge color of the Figure rectangle. 

439 

440 Parameters 

441 ---------- 

442 color : color 

443 """ 

444 self.patch.set_edgecolor(color) 

445 

446 def set_facecolor(self, color): 

447 """ 

448 Set the face color of the Figure rectangle. 

449 

450 Parameters 

451 ---------- 

452 color : color 

453 """ 

454 self.patch.set_facecolor(color) 

455 

456 def set_frameon(self, b): 

457 """ 

458 Set the figure's background patch visibility, i.e. 

459 whether the figure background will be drawn. Equivalent to 

460 ``Figure.patch.set_visible()``. 

461 

462 Parameters 

463 ---------- 

464 b : bool 

465 """ 

466 self.patch.set_visible(b) 

467 self.stale = True 

468 

469 frameon = property(get_frameon, set_frameon) 

470 

471 def add_artist(self, artist, clip=False): 

472 """ 

473 Add an `.Artist` to the figure. 

474 

475 Usually artists are added to `~.axes.Axes` objects using 

476 `.Axes.add_artist`; this method can be used in the rare cases where 

477 one needs to add artists directly to the figure instead. 

478 

479 Parameters 

480 ---------- 

481 artist : `~matplotlib.artist.Artist` 

482 The artist to add to the figure. If the added artist has no 

483 transform previously set, its transform will be set to 

484 ``figure.transSubfigure``. 

485 clip : bool, default: False 

486 Whether the added artist should be clipped by the figure patch. 

487 

488 Returns 

489 ------- 

490 `~matplotlib.artist.Artist` 

491 The added artist. 

492 """ 

493 artist.set_figure(self) 

494 self.artists.append(artist) 

495 artist._remove_method = self.artists.remove 

496 

497 if not artist.is_transform_set(): 

498 artist.set_transform(self.transSubfigure) 

499 

500 if clip: 

501 artist.set_clip_path(self.patch) 

502 

503 self.stale = True 

504 return artist 

505 

506 @_docstring.dedent_interpd 

507 def add_axes(self, *args, **kwargs): 

508 """ 

509 Add an `~.axes.Axes` to the figure. 

510 

511 Call signatures:: 

512 

513 add_axes(rect, projection=None, polar=False, **kwargs) 

514 add_axes(ax) 

515 

516 Parameters 

517 ---------- 

518 rect : tuple (left, bottom, width, height) 

519 The dimensions (left, bottom, width, height) of the new 

520 `~.axes.Axes`. All quantities are in fractions of figure width and 

521 height. 

522 

523 projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ 

524'polar', 'rectilinear', str}, optional 

525 The projection type of the `~.axes.Axes`. *str* is the name of 

526 a custom projection, see `~matplotlib.projections`. The default 

527 None results in a 'rectilinear' projection. 

528 

529 polar : bool, default: False 

530 If True, equivalent to projection='polar'. 

531 

532 axes_class : subclass type of `~.axes.Axes`, optional 

533 The `.axes.Axes` subclass that is instantiated. This parameter 

534 is incompatible with *projection* and *polar*. See 

535 :ref:`axisartist_users-guide-index` for examples. 

536 

537 sharex, sharey : `~.axes.Axes`, optional 

538 Share the x or y `~matplotlib.axis` with sharex and/or sharey. 

539 The axis will have the same limits, ticks, and scale as the axis 

540 of the shared axes. 

541 

542 label : str 

543 A label for the returned Axes. 

544 

545 Returns 

546 ------- 

547 `~.axes.Axes`, or a subclass of `~.axes.Axes` 

548 The returned axes class depends on the projection used. It is 

549 `~.axes.Axes` if rectilinear projection is used and 

550 `.projections.polar.PolarAxes` if polar projection is used. 

551 

552 Other Parameters 

553 ---------------- 

554 **kwargs 

555 This method also takes the keyword arguments for 

556 the returned Axes class. The keyword arguments for the 

557 rectilinear Axes class `~.axes.Axes` can be found in 

558 the following table but there might also be other keyword 

559 arguments if another projection is used, see the actual Axes 

560 class. 

561 

562 %(Axes:kwdoc)s 

563 

564 Notes 

565 ----- 

566 In rare circumstances, `.add_axes` may be called with a single 

567 argument, an Axes instance already created in the present figure but 

568 not in the figure's list of Axes. 

569 

570 See Also 

571 -------- 

572 .Figure.add_subplot 

573 .pyplot.subplot 

574 .pyplot.axes 

575 .Figure.subplots 

576 .pyplot.subplots 

577 

578 Examples 

579 -------- 

580 Some simple examples:: 

581 

582 rect = l, b, w, h 

583 fig = plt.figure() 

584 fig.add_axes(rect) 

585 fig.add_axes(rect, frameon=False, facecolor='g') 

586 fig.add_axes(rect, polar=True) 

587 ax = fig.add_axes(rect, projection='polar') 

588 fig.delaxes(ax) 

589 fig.add_axes(ax) 

590 """ 

591 

592 if not len(args) and 'rect' not in kwargs: 

593 raise TypeError( 

594 "add_axes() missing 1 required positional argument: 'rect'") 

595 elif 'rect' in kwargs: 

596 if len(args): 

597 raise TypeError( 

598 "add_axes() got multiple values for argument 'rect'") 

599 args = (kwargs.pop('rect'), ) 

600 

601 if isinstance(args[0], Axes): 

602 a = args[0] 

603 key = a._projection_init 

604 if a.get_figure() is not self: 

605 raise ValueError( 

606 "The Axes must have been created in the present figure") 

607 else: 

608 rect = args[0] 

609 if not np.isfinite(rect).all(): 

610 raise ValueError('all entries in rect must be finite ' 

611 'not {}'.format(rect)) 

612 projection_class, pkw = self._process_projection_requirements( 

613 *args, **kwargs) 

614 

615 # create the new axes using the axes class given 

616 a = projection_class(self, rect, **pkw) 

617 key = (projection_class, pkw) 

618 return self._add_axes_internal(a, key) 

619 

620 @_docstring.dedent_interpd 

621 def add_subplot(self, *args, **kwargs): 

622 """ 

623 Add an `~.axes.Axes` to the figure as part of a subplot arrangement. 

624 

625 Call signatures:: 

626 

627 add_subplot(nrows, ncols, index, **kwargs) 

628 add_subplot(pos, **kwargs) 

629 add_subplot(ax) 

630 add_subplot() 

631 

632 Parameters 

633 ---------- 

634 *args : int, (int, int, *index*), or `.SubplotSpec`, default: (1, 1, 1) 

635 The position of the subplot described by one of 

636 

637 - Three integers (*nrows*, *ncols*, *index*). The subplot will 

638 take the *index* position on a grid with *nrows* rows and 

639 *ncols* columns. *index* starts at 1 in the upper left corner 

640 and increases to the right. *index* can also be a two-tuple 

641 specifying the (*first*, *last*) indices (1-based, and including 

642 *last*) of the subplot, e.g., ``fig.add_subplot(3, 1, (1, 2))`` 

643 makes a subplot that spans the upper 2/3 of the figure. 

644 - A 3-digit integer. The digits are interpreted as if given 

645 separately as three single-digit integers, i.e. 

646 ``fig.add_subplot(235)`` is the same as 

647 ``fig.add_subplot(2, 3, 5)``. Note that this can only be used 

648 if there are no more than 9 subplots. 

649 - A `.SubplotSpec`. 

650 

651 In rare circumstances, `.add_subplot` may be called with a single 

652 argument, a subplot Axes instance already created in the 

653 present figure but not in the figure's list of Axes. 

654 

655 projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ 

656'polar', 'rectilinear', str}, optional 

657 The projection type of the subplot (`~.axes.Axes`). *str* is the 

658 name of a custom projection, see `~matplotlib.projections`. The 

659 default None results in a 'rectilinear' projection. 

660 

661 polar : bool, default: False 

662 If True, equivalent to projection='polar'. 

663 

664 axes_class : subclass type of `~.axes.Axes`, optional 

665 The `.axes.Axes` subclass that is instantiated. This parameter 

666 is incompatible with *projection* and *polar*. See 

667 :ref:`axisartist_users-guide-index` for examples. 

668 

669 sharex, sharey : `~.axes.Axes`, optional 

670 Share the x or y `~matplotlib.axis` with sharex and/or sharey. 

671 The axis will have the same limits, ticks, and scale as the axis 

672 of the shared axes. 

673 

674 label : str 

675 A label for the returned Axes. 

676 

677 Returns 

678 ------- 

679 `.axes.SubplotBase`, or another subclass of `~.axes.Axes` 

680 

681 The Axes of the subplot. The returned Axes base class depends on 

682 the projection used. It is `~.axes.Axes` if rectilinear projection 

683 is used and `.projections.polar.PolarAxes` if polar projection 

684 is used. The returned Axes is then a subplot subclass of the 

685 base class. 

686 

687 Other Parameters 

688 ---------------- 

689 **kwargs 

690 This method also takes the keyword arguments for the returned Axes 

691 base class; except for the *figure* argument. The keyword arguments 

692 for the rectilinear base class `~.axes.Axes` can be found in 

693 the following table but there might also be other keyword 

694 arguments if another projection is used. 

695 

696 %(Axes:kwdoc)s 

697 

698 See Also 

699 -------- 

700 .Figure.add_axes 

701 .pyplot.subplot 

702 .pyplot.axes 

703 .Figure.subplots 

704 .pyplot.subplots 

705 

706 Examples 

707 -------- 

708 :: 

709 

710 fig = plt.figure() 

711 

712 fig.add_subplot(231) 

713 ax1 = fig.add_subplot(2, 3, 1) # equivalent but more general 

714 

715 fig.add_subplot(232, frameon=False) # subplot with no frame 

716 fig.add_subplot(233, projection='polar') # polar subplot 

717 fig.add_subplot(234, sharex=ax1) # subplot sharing x-axis with ax1 

718 fig.add_subplot(235, facecolor="red") # red subplot 

719 

720 ax1.remove() # delete ax1 from the figure 

721 fig.add_subplot(ax1) # add ax1 back to the figure 

722 """ 

723 if 'figure' in kwargs: 

724 # Axes itself allows for a 'figure' kwarg, but since we want to 

725 # bind the created Axes to self, it is not allowed here. 

726 raise TypeError( 

727 "add_subplot() got an unexpected keyword argument 'figure'") 

728 

729 if len(args) == 1 and isinstance(args[0], SubplotBase): 

730 ax = args[0] 

731 key = ax._projection_init 

732 if ax.get_figure() is not self: 

733 raise ValueError("The Subplot must have been created in " 

734 "the present figure") 

735 else: 

736 if not args: 

737 args = (1, 1, 1) 

738 # Normalize correct ijk values to (i, j, k) here so that 

739 # add_subplot(211) == add_subplot(2, 1, 1). Invalid values will 

740 # trigger errors later (via SubplotSpec._from_subplot_args). 

741 if (len(args) == 1 and isinstance(args[0], Integral) 

742 and 100 <= args[0] <= 999): 

743 args = tuple(map(int, str(args[0]))) 

744 projection_class, pkw = self._process_projection_requirements( 

745 *args, **kwargs) 

746 ax = subplot_class_factory(projection_class)(self, *args, **pkw) 

747 key = (projection_class, pkw) 

748 return self._add_axes_internal(ax, key) 

749 

750 def _add_axes_internal(self, ax, key): 

751 """Private helper for `add_axes` and `add_subplot`.""" 

752 self._axstack.add(ax) 

753 if ax not in self._localaxes: 

754 self._localaxes.append(ax) 

755 self.sca(ax) 

756 ax._remove_method = self.delaxes 

757 # this is to support plt.subplot's re-selection logic 

758 ax._projection_init = key 

759 self.stale = True 

760 ax.stale_callback = _stale_figure_callback 

761 return ax 

762 

763 def subplots(self, nrows=1, ncols=1, *, sharex=False, sharey=False, 

764 squeeze=True, width_ratios=None, height_ratios=None, 

765 subplot_kw=None, gridspec_kw=None): 

766 """ 

767 Add a set of subplots to this figure. 

768 

769 This utility wrapper makes it convenient to create common layouts of 

770 subplots in a single call. 

771 

772 Parameters 

773 ---------- 

774 nrows, ncols : int, default: 1 

775 Number of rows/columns of the subplot grid. 

776 

777 sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False 

778 Controls sharing of x-axis (*sharex*) or y-axis (*sharey*): 

779 

780 - True or 'all': x- or y-axis will be shared among all subplots. 

781 - False or 'none': each subplot x- or y-axis will be independent. 

782 - 'row': each subplot row will share an x- or y-axis. 

783 - 'col': each subplot column will share an x- or y-axis. 

784 

785 When subplots have a shared x-axis along a column, only the x tick 

786 labels of the bottom subplot are created. Similarly, when subplots 

787 have a shared y-axis along a row, only the y tick labels of the 

788 first column subplot are created. To later turn other subplots' 

789 ticklabels on, use `~matplotlib.axes.Axes.tick_params`. 

790 

791 When subplots have a shared axis that has units, calling 

792 `.Axis.set_units` will update each axis with the new units. 

793 

794 squeeze : bool, default: True 

795 - If True, extra dimensions are squeezed out from the returned 

796 array of Axes: 

797 

798 - if only one subplot is constructed (nrows=ncols=1), the 

799 resulting single Axes object is returned as a scalar. 

800 - for Nx1 or 1xM subplots, the returned object is a 1D numpy 

801 object array of Axes objects. 

802 - for NxM, subplots with N>1 and M>1 are returned as a 2D array. 

803 

804 - If False, no squeezing at all is done: the returned Axes object 

805 is always a 2D array containing Axes instances, even if it ends 

806 up being 1x1. 

807 

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

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

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

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

812 to ``gridspec_kw={'width_ratios': [...]}``. 

813 

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

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

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

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

818 to ``gridspec_kw={'height_ratios': [...]}``. 

819 

820 subplot_kw : dict, optional 

821 Dict with keywords passed to the `.Figure.add_subplot` call used to 

822 create each subplot. 

823 

824 gridspec_kw : dict, optional 

825 Dict with keywords passed to the 

826 `~matplotlib.gridspec.GridSpec` constructor used to create 

827 the grid the subplots are placed on. 

828 

829 Returns 

830 ------- 

831 `~.axes.Axes` or array of Axes 

832 Either a single `~matplotlib.axes.Axes` object or an array of Axes 

833 objects if more than one subplot was created. The dimensions of the 

834 resulting array can be controlled with the *squeeze* keyword, see 

835 above. 

836 

837 See Also 

838 -------- 

839 .pyplot.subplots 

840 .Figure.add_subplot 

841 .pyplot.subplot 

842 

843 Examples 

844 -------- 

845 :: 

846 

847 # First create some toy data: 

848 x = np.linspace(0, 2*np.pi, 400) 

849 y = np.sin(x**2) 

850 

851 # Create a figure 

852 plt.figure() 

853 

854 # Create a subplot 

855 ax = fig.subplots() 

856 ax.plot(x, y) 

857 ax.set_title('Simple plot') 

858 

859 # Create two subplots and unpack the output array immediately 

860 ax1, ax2 = fig.subplots(1, 2, sharey=True) 

861 ax1.plot(x, y) 

862 ax1.set_title('Sharing Y axis') 

863 ax2.scatter(x, y) 

864 

865 # Create four polar Axes and access them through the returned array 

866 axes = fig.subplots(2, 2, subplot_kw=dict(projection='polar')) 

867 axes[0, 0].plot(x, y) 

868 axes[1, 1].scatter(x, y) 

869 

870 # Share an X-axis with each column of subplots 

871 fig.subplots(2, 2, sharex='col') 

872 

873 # Share a Y-axis with each row of subplots 

874 fig.subplots(2, 2, sharey='row') 

875 

876 # Share both X- and Y-axes with all subplots 

877 fig.subplots(2, 2, sharex='all', sharey='all') 

878 

879 # Note that this is the same as 

880 fig.subplots(2, 2, sharex=True, sharey=True) 

881 """ 

882 gridspec_kw = dict(gridspec_kw or {}) 

883 if height_ratios is not None: 

884 if 'height_ratios' in gridspec_kw: 

885 raise ValueError("'height_ratios' must not be defined both as " 

886 "parameter and as key in 'gridspec_kw'") 

887 gridspec_kw['height_ratios'] = height_ratios 

888 if width_ratios is not None: 

889 if 'width_ratios' in gridspec_kw: 

890 raise ValueError("'width_ratios' must not be defined both as " 

891 "parameter and as key in 'gridspec_kw'") 

892 gridspec_kw['width_ratios'] = width_ratios 

893 

894 gs = self.add_gridspec(nrows, ncols, figure=self, **gridspec_kw) 

895 axs = gs.subplots(sharex=sharex, sharey=sharey, squeeze=squeeze, 

896 subplot_kw=subplot_kw) 

897 return axs 

898 

899 def delaxes(self, ax): 

900 """ 

901 Remove the `~.axes.Axes` *ax* from the figure; update the current Axes. 

902 """ 

903 

904 def _reset_locators_and_formatters(axis): 

905 # Set the formatters and locators to be associated with axis 

906 # (where previously they may have been associated with another 

907 # Axis instance) 

908 axis.get_major_formatter().set_axis(axis) 

909 axis.get_major_locator().set_axis(axis) 

910 axis.get_minor_formatter().set_axis(axis) 

911 axis.get_minor_locator().set_axis(axis) 

912 

913 def _break_share_link(ax, grouper): 

914 siblings = grouper.get_siblings(ax) 

915 if len(siblings) > 1: 

916 grouper.remove(ax) 

917 for last_ax in siblings: 

918 if ax is not last_ax: 

919 return last_ax 

920 return None 

921 

922 self._axstack.remove(ax) 

923 self._axobservers.process("_axes_change_event", self) 

924 self.stale = True 

925 self._localaxes.remove(ax) 

926 

927 # Break link between any shared axes 

928 for name in ax._axis_names: 

929 last_ax = _break_share_link(ax, ax._shared_axes[name]) 

930 if last_ax is not None: 

931 _reset_locators_and_formatters(getattr(last_ax, f"{name}axis")) 

932 

933 # Break link between any twinned axes 

934 _break_share_link(ax, ax._twinned_axes) 

935 

936 def clear(self, keep_observers=False): 

937 """ 

938 Clear the figure. 

939 

940 Parameters 

941 ---------- 

942 keep_observers: bool, default: False 

943 Set *keep_observers* to True if, for example, 

944 a gui widget is tracking the Axes in the figure. 

945 """ 

946 self.suppressComposite = None 

947 

948 # first clear the axes in any subfigures 

949 for subfig in self.subfigs: 

950 subfig.clear(keep_observers=keep_observers) 

951 self.subfigs = [] 

952 

953 for ax in tuple(self.axes): # Iterate over the copy. 

954 ax.clear() 

955 self.delaxes(ax) # Remove ax from self._axstack. 

956 

957 self.artists = [] 

958 self.lines = [] 

959 self.patches = [] 

960 self.texts = [] 

961 self.images = [] 

962 self.legends = [] 

963 if not keep_observers: 

964 self._axobservers = cbook.CallbackRegistry() 

965 self._suptitle = None 

966 self._supxlabel = None 

967 self._supylabel = None 

968 

969 self.stale = True 

970 

971 # synonym for `clear`. 

972 def clf(self, keep_observers=False): 

973 """ 

974 [*Discouraged*] Alias for the `clear()` method. 

975 

976 .. admonition:: Discouraged 

977 

978 The use of ``clf()`` is discouraged. Use ``clear()`` instead. 

979 

980 Parameters 

981 ---------- 

982 keep_observers: bool, default: False 

983 Set *keep_observers* to True if, for example, 

984 a gui widget is tracking the Axes in the figure. 

985 """ 

986 return self.clear(keep_observers=keep_observers) 

987 

988 # Note: the docstring below is modified with replace for the pyplot 

989 # version of this function because the method name differs (plt.figlegend) 

990 # the replacements are: 

991 # " legend(" -> " figlegend(" for the signatures 

992 # "fig.legend(" -> "plt.figlegend" for the code examples 

993 # "ax.plot" -> "plt.plot" for consistency in using pyplot when able 

994 @_docstring.dedent_interpd 

995 def legend(self, *args, **kwargs): 

996 """ 

997 Place a legend on the figure. 

998 

999 Call signatures:: 

1000 

1001 legend() 

1002 legend(handles, labels) 

1003 legend(handles=handles) 

1004 legend(labels) 

1005 

1006 The call signatures correspond to the following different ways to use 

1007 this method: 

1008 

1009 **1. Automatic detection of elements to be shown in the legend** 

1010 

1011 The elements to be added to the legend are automatically determined, 

1012 when you do not pass in any extra arguments. 

1013 

1014 In this case, the labels are taken from the artist. You can specify 

1015 them either at artist creation or by calling the 

1016 :meth:`~.Artist.set_label` method on the artist:: 

1017 

1018 ax.plot([1, 2, 3], label='Inline label') 

1019 fig.legend() 

1020 

1021 or:: 

1022 

1023 line, = ax.plot([1, 2, 3]) 

1024 line.set_label('Label via method') 

1025 fig.legend() 

1026 

1027 Specific lines can be excluded from the automatic legend element 

1028 selection by defining a label starting with an underscore. 

1029 This is default for all artists, so calling `.Figure.legend` without 

1030 any arguments and without setting the labels manually will result in 

1031 no legend being drawn. 

1032 

1033 

1034 **2. Explicitly listing the artists and labels in the legend** 

1035 

1036 For full control of which artists have a legend entry, it is possible 

1037 to pass an iterable of legend artists followed by an iterable of 

1038 legend labels respectively:: 

1039 

1040 fig.legend([line1, line2, line3], ['label1', 'label2', 'label3']) 

1041 

1042 

1043 **3. Explicitly listing the artists in the legend** 

1044 

1045 This is similar to 2, but the labels are taken from the artists' 

1046 label properties. Example:: 

1047 

1048 line1, = ax1.plot([1, 2, 3], label='label1') 

1049 line2, = ax2.plot([1, 2, 3], label='label2') 

1050 fig.legend(handles=[line1, line2]) 

1051 

1052 

1053 **4. Labeling existing plot elements** 

1054 

1055 .. admonition:: Discouraged 

1056 

1057 This call signature is discouraged, because the relation between 

1058 plot elements and labels is only implicit by their order and can 

1059 easily be mixed up. 

1060 

1061 To make a legend for all artists on all Axes, call this function with 

1062 an iterable of strings, one for each legend item. For example:: 

1063 

1064 fig, (ax1, ax2) = plt.subplots(1, 2) 

1065 ax1.plot([1, 3, 5], color='blue') 

1066 ax2.plot([2, 4, 6], color='red') 

1067 fig.legend(['the blues', 'the reds']) 

1068 

1069 

1070 Parameters 

1071 ---------- 

1072 handles : list of `.Artist`, optional 

1073 A list of Artists (lines, patches) to be added to the legend. 

1074 Use this together with *labels*, if you need full control on what 

1075 is shown in the legend and the automatic mechanism described above 

1076 is not sufficient. 

1077 

1078 The length of handles and labels should be the same in this 

1079 case. If they are not, they are truncated to the smaller length. 

1080 

1081 labels : list of str, optional 

1082 A list of labels to show next to the artists. 

1083 Use this together with *handles*, if you need full control on what 

1084 is shown in the legend and the automatic mechanism described above 

1085 is not sufficient. 

1086 

1087 Returns 

1088 ------- 

1089 `~matplotlib.legend.Legend` 

1090 

1091 Other Parameters 

1092 ---------------- 

1093 %(_legend_kw_doc)s 

1094 

1095 See Also 

1096 -------- 

1097 .Axes.legend 

1098 

1099 Notes 

1100 ----- 

1101 Some artists are not supported by this function. See 

1102 :doc:`/tutorials/intermediate/legend_guide` for details. 

1103 """ 

1104 

1105 handles, labels, extra_args, kwargs = mlegend._parse_legend_args( 

1106 self.axes, 

1107 *args, 

1108 **kwargs) 

1109 # check for third arg 

1110 if len(extra_args): 

1111 # _api.warn_deprecated( 

1112 # "2.1", 

1113 # message="Figure.legend will accept no more than two " 

1114 # "positional arguments in the future. Use " 

1115 # "'fig.legend(handles, labels, loc=location)' " 

1116 # "instead.") 

1117 # kwargs['loc'] = extra_args[0] 

1118 # extra_args = extra_args[1:] 

1119 pass 

1120 transform = kwargs.pop('bbox_transform', self.transSubfigure) 

1121 # explicitly set the bbox transform if the user hasn't. 

1122 l = mlegend.Legend(self, handles, labels, *extra_args, 

1123 bbox_transform=transform, **kwargs) 

1124 self.legends.append(l) 

1125 l._remove_method = self.legends.remove 

1126 self.stale = True 

1127 return l 

1128 

1129 @_docstring.dedent_interpd 

1130 def text(self, x, y, s, fontdict=None, **kwargs): 

1131 """ 

1132 Add text to figure. 

1133 

1134 Parameters 

1135 ---------- 

1136 x, y : float 

1137 The position to place the text. By default, this is in figure 

1138 coordinates, floats in [0, 1]. The coordinate system can be changed 

1139 using the *transform* keyword. 

1140 

1141 s : str 

1142 The text string. 

1143 

1144 fontdict : dict, optional 

1145 A dictionary to override the default text properties. If not given, 

1146 the defaults are determined by :rc:`font.*`. Properties passed as 

1147 *kwargs* override the corresponding ones given in *fontdict*. 

1148 

1149 Returns 

1150 ------- 

1151 `~.text.Text` 

1152 

1153 Other Parameters 

1154 ---------------- 

1155 **kwargs : `~matplotlib.text.Text` properties 

1156 Other miscellaneous text parameters. 

1157 

1158 %(Text:kwdoc)s 

1159 

1160 See Also 

1161 -------- 

1162 .Axes.text 

1163 .pyplot.text 

1164 """ 

1165 effective_kwargs = { 

1166 'transform': self.transSubfigure, 

1167 **(fontdict if fontdict is not None else {}), 

1168 **kwargs, 

1169 } 

1170 text = Text(x=x, y=y, text=s, **effective_kwargs) 

1171 text.set_figure(self) 

1172 text.stale_callback = _stale_figure_callback 

1173 

1174 self.texts.append(text) 

1175 text._remove_method = self.texts.remove 

1176 self.stale = True 

1177 return text 

1178 

1179 @_docstring.dedent_interpd 

1180 def colorbar( 

1181 self, mappable, cax=None, ax=None, use_gridspec=True, **kwargs): 

1182 """ 

1183 Add a colorbar to a plot. 

1184 

1185 Parameters 

1186 ---------- 

1187 mappable 

1188 The `matplotlib.cm.ScalarMappable` (i.e., `.AxesImage`, 

1189 `.ContourSet`, etc.) described by this colorbar. This argument is 

1190 mandatory for the `.Figure.colorbar` method but optional for the 

1191 `.pyplot.colorbar` function, which sets the default to the current 

1192 image. 

1193 

1194 Note that one can create a `.ScalarMappable` "on-the-fly" to 

1195 generate colorbars not attached to a previously drawn artist, e.g. 

1196 :: 

1197 

1198 fig.colorbar(cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax) 

1199 

1200 cax : `~matplotlib.axes.Axes`, optional 

1201 Axes into which the colorbar will be drawn. 

1202 

1203 ax : `~.axes.Axes` or list or `numpy.ndarray` of Axes, optional 

1204 One or more parent axes from which space for a new colorbar axes 

1205 will be stolen, if *cax* is None. This has no effect if *cax* is 

1206 set. 

1207 

1208 use_gridspec : bool, optional 

1209 If *cax* is ``None``, a new *cax* is created as an instance of 

1210 Axes. If *ax* is an instance of Subplot and *use_gridspec* is 

1211 ``True``, *cax* is created as an instance of Subplot using the 

1212 :mod:`.gridspec` module. 

1213 

1214 Returns 

1215 ------- 

1216 colorbar : `~matplotlib.colorbar.Colorbar` 

1217 

1218 Other Parameters 

1219 ---------------- 

1220 %(_make_axes_kw_doc)s 

1221 %(_colormap_kw_doc)s 

1222 

1223 Notes 

1224 ----- 

1225 If *mappable* is a `~.contour.ContourSet`, its *extend* kwarg is 

1226 included automatically. 

1227 

1228 The *shrink* kwarg provides a simple way to scale the colorbar with 

1229 respect to the axes. Note that if *cax* is specified, it determines the 

1230 size of the colorbar and *shrink* and *aspect* kwargs are ignored. 

1231 

1232 For more precise control, you can manually specify the positions of the 

1233 axes objects in which the mappable and the colorbar are drawn. In this 

1234 case, do not use any of the axes properties kwargs. 

1235 

1236 It is known that some vector graphics viewers (svg and pdf) renders 

1237 white gaps between segments of the colorbar. This is due to bugs in 

1238 the viewers, not Matplotlib. As a workaround, the colorbar can be 

1239 rendered with overlapping segments:: 

1240 

1241 cbar = colorbar() 

1242 cbar.solids.set_edgecolor("face") 

1243 draw() 

1244 

1245 However, this has negative consequences in other circumstances, e.g. 

1246 with semi-transparent images (alpha < 1) and colorbar extensions; 

1247 therefore, this workaround is not used by default (see issue #1188). 

1248 """ 

1249 

1250 if ax is None: 

1251 ax = getattr(mappable, "axes", None) 

1252 

1253 if (self.get_layout_engine() is not None and 

1254 not self.get_layout_engine().colorbar_gridspec): 

1255 use_gridspec = False 

1256 # Store the value of gca so that we can set it back later on. 

1257 if cax is None: 

1258 if ax is None: 

1259 _api.warn_deprecated("3.6", message=( 

1260 'Unable to determine Axes to steal space for Colorbar. ' 

1261 'Using gca(), but will raise in the future. ' 

1262 'Either provide the *cax* argument to use as the Axes for ' 

1263 'the Colorbar, provide the *ax* argument to steal space ' 

1264 'from it, or add *mappable* to an Axes.')) 

1265 ax = self.gca() 

1266 current_ax = self.gca() 

1267 userax = False 

1268 if (use_gridspec and isinstance(ax, SubplotBase)): 

1269 cax, kwargs = cbar.make_axes_gridspec(ax, **kwargs) 

1270 else: 

1271 cax, kwargs = cbar.make_axes(ax, **kwargs) 

1272 cax.grid(visible=False, which='both', axis='both') 

1273 else: 

1274 userax = True 

1275 

1276 # need to remove kws that cannot be passed to Colorbar 

1277 NON_COLORBAR_KEYS = ['fraction', 'pad', 'shrink', 'aspect', 'anchor', 

1278 'panchor'] 

1279 cb_kw = {k: v for k, v in kwargs.items() if k not in NON_COLORBAR_KEYS} 

1280 

1281 cb = cbar.Colorbar(cax, mappable, **cb_kw) 

1282 

1283 if not userax: 

1284 self.sca(current_ax) 

1285 self.stale = True 

1286 return cb 

1287 

1288 def subplots_adjust(self, left=None, bottom=None, right=None, top=None, 

1289 wspace=None, hspace=None): 

1290 """ 

1291 Adjust the subplot layout parameters. 

1292 

1293 Unset parameters are left unmodified; initial values are given by 

1294 :rc:`figure.subplot.[name]`. 

1295 

1296 Parameters 

1297 ---------- 

1298 left : float, optional 

1299 The position of the left edge of the subplots, 

1300 as a fraction of the figure width. 

1301 right : float, optional 

1302 The position of the right edge of the subplots, 

1303 as a fraction of the figure width. 

1304 bottom : float, optional 

1305 The position of the bottom edge of the subplots, 

1306 as a fraction of the figure height. 

1307 top : float, optional 

1308 The position of the top edge of the subplots, 

1309 as a fraction of the figure height. 

1310 wspace : float, optional 

1311 The width of the padding between subplots, 

1312 as a fraction of the average Axes width. 

1313 hspace : float, optional 

1314 The height of the padding between subplots, 

1315 as a fraction of the average Axes height. 

1316 """ 

1317 if (self.get_layout_engine() is not None and 

1318 not self.get_layout_engine().adjust_compatible): 

1319 _api.warn_external( 

1320 "This figure was using a layout engine that is " 

1321 "incompatible with subplots_adjust and/or tight_layout; " 

1322 "not calling subplots_adjust.") 

1323 return 

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

1325 for ax in self.axes: 

1326 if hasattr(ax, 'get_subplotspec'): 

1327 ax._set_position(ax.get_subplotspec().get_position(self)) 

1328 self.stale = True 

1329 

1330 def align_xlabels(self, axs=None): 

1331 """ 

1332 Align the xlabels of subplots in the same subplot column if label 

1333 alignment is being done automatically (i.e. the label position is 

1334 not manually set). 

1335 

1336 Alignment persists for draw events after this is called. 

1337 

1338 If a label is on the bottom, it is aligned with labels on Axes that 

1339 also have their label on the bottom and that have the same 

1340 bottom-most subplot row. If the label is on the top, 

1341 it is aligned with labels on Axes with the same top-most row. 

1342 

1343 Parameters 

1344 ---------- 

1345 axs : list of `~matplotlib.axes.Axes` 

1346 Optional list of (or ndarray) `~matplotlib.axes.Axes` 

1347 to align the xlabels. 

1348 Default is to align all Axes on the figure. 

1349 

1350 See Also 

1351 -------- 

1352 matplotlib.figure.Figure.align_ylabels 

1353 matplotlib.figure.Figure.align_labels 

1354 

1355 Notes 

1356 ----- 

1357 This assumes that ``axs`` are from the same `.GridSpec`, so that 

1358 their `.SubplotSpec` positions correspond to figure positions. 

1359 

1360 Examples 

1361 -------- 

1362 Example with rotated xtick labels:: 

1363 

1364 fig, axs = plt.subplots(1, 2) 

1365 for tick in axs[0].get_xticklabels(): 

1366 tick.set_rotation(55) 

1367 axs[0].set_xlabel('XLabel 0') 

1368 axs[1].set_xlabel('XLabel 1') 

1369 fig.align_xlabels() 

1370 """ 

1371 if axs is None: 

1372 axs = self.axes 

1373 axs = np.ravel(axs) 

1374 axs = [ax for ax in axs if hasattr(ax, 'get_subplotspec')] 

1375 

1376 for ax in axs: 

1377 _log.debug(' Working on: %s', ax.get_xlabel()) 

1378 rowspan = ax.get_subplotspec().rowspan 

1379 pos = ax.xaxis.get_label_position() # top or bottom 

1380 # Search through other axes for label positions that are same as 

1381 # this one and that share the appropriate row number. 

1382 # Add to a grouper associated with each axes of siblings. 

1383 # This list is inspected in `axis.draw` by 

1384 # `axis._update_label_position`. 

1385 for axc in axs: 

1386 if axc.xaxis.get_label_position() == pos: 

1387 rowspanc = axc.get_subplotspec().rowspan 

1388 if (pos == 'top' and rowspan.start == rowspanc.start or 

1389 pos == 'bottom' and rowspan.stop == rowspanc.stop): 

1390 # grouper for groups of xlabels to align 

1391 self._align_label_groups['x'].join(ax, axc) 

1392 

1393 def align_ylabels(self, axs=None): 

1394 """ 

1395 Align the ylabels of subplots in the same subplot column if label 

1396 alignment is being done automatically (i.e. the label position is 

1397 not manually set). 

1398 

1399 Alignment persists for draw events after this is called. 

1400 

1401 If a label is on the left, it is aligned with labels on Axes that 

1402 also have their label on the left and that have the same 

1403 left-most subplot column. If the label is on the right, 

1404 it is aligned with labels on Axes with the same right-most column. 

1405 

1406 Parameters 

1407 ---------- 

1408 axs : list of `~matplotlib.axes.Axes` 

1409 Optional list (or ndarray) of `~matplotlib.axes.Axes` 

1410 to align the ylabels. 

1411 Default is to align all Axes on the figure. 

1412 

1413 See Also 

1414 -------- 

1415 matplotlib.figure.Figure.align_xlabels 

1416 matplotlib.figure.Figure.align_labels 

1417 

1418 Notes 

1419 ----- 

1420 This assumes that ``axs`` are from the same `.GridSpec`, so that 

1421 their `.SubplotSpec` positions correspond to figure positions. 

1422 

1423 Examples 

1424 -------- 

1425 Example with large yticks labels:: 

1426 

1427 fig, axs = plt.subplots(2, 1) 

1428 axs[0].plot(np.arange(0, 1000, 50)) 

1429 axs[0].set_ylabel('YLabel 0') 

1430 axs[1].set_ylabel('YLabel 1') 

1431 fig.align_ylabels() 

1432 """ 

1433 if axs is None: 

1434 axs = self.axes 

1435 axs = np.ravel(axs) 

1436 axs = [ax for ax in axs if hasattr(ax, 'get_subplotspec')] 

1437 

1438 for ax in axs: 

1439 _log.debug(' Working on: %s', ax.get_ylabel()) 

1440 colspan = ax.get_subplotspec().colspan 

1441 pos = ax.yaxis.get_label_position() # left or right 

1442 # Search through other axes for label positions that are same as 

1443 # this one and that share the appropriate column number. 

1444 # Add to a list associated with each axes of siblings. 

1445 # This list is inspected in `axis.draw` by 

1446 # `axis._update_label_position`. 

1447 for axc in axs: 

1448 if axc.yaxis.get_label_position() == pos: 

1449 colspanc = axc.get_subplotspec().colspan 

1450 if (pos == 'left' and colspan.start == colspanc.start or 

1451 pos == 'right' and colspan.stop == colspanc.stop): 

1452 # grouper for groups of ylabels to align 

1453 self._align_label_groups['y'].join(ax, axc) 

1454 

1455 def align_labels(self, axs=None): 

1456 """ 

1457 Align the xlabels and ylabels of subplots with the same subplots 

1458 row or column (respectively) if label alignment is being 

1459 done automatically (i.e. the label position is not manually set). 

1460 

1461 Alignment persists for draw events after this is called. 

1462 

1463 Parameters 

1464 ---------- 

1465 axs : list of `~matplotlib.axes.Axes` 

1466 Optional list (or ndarray) of `~matplotlib.axes.Axes` 

1467 to align the labels. 

1468 Default is to align all Axes on the figure. 

1469 

1470 See Also 

1471 -------- 

1472 matplotlib.figure.Figure.align_xlabels 

1473 

1474 matplotlib.figure.Figure.align_ylabels 

1475 """ 

1476 self.align_xlabels(axs=axs) 

1477 self.align_ylabels(axs=axs) 

1478 

1479 def add_gridspec(self, nrows=1, ncols=1, **kwargs): 

1480 """ 

1481 Return a `.GridSpec` that has this figure as a parent. This allows 

1482 complex layout of Axes in the figure. 

1483 

1484 Parameters 

1485 ---------- 

1486 nrows : int, default: 1 

1487 Number of rows in grid. 

1488 

1489 ncols : int, default: 1 

1490 Number of columns in grid. 

1491 

1492 Returns 

1493 ------- 

1494 `.GridSpec` 

1495 

1496 Other Parameters 

1497 ---------------- 

1498 **kwargs 

1499 Keyword arguments are passed to `.GridSpec`. 

1500 

1501 See Also 

1502 -------- 

1503 matplotlib.pyplot.subplots 

1504 

1505 Examples 

1506 -------- 

1507 Adding a subplot that spans two rows:: 

1508 

1509 fig = plt.figure() 

1510 gs = fig.add_gridspec(2, 2) 

1511 ax1 = fig.add_subplot(gs[0, 0]) 

1512 ax2 = fig.add_subplot(gs[1, 0]) 

1513 # spans two rows: 

1514 ax3 = fig.add_subplot(gs[:, 1]) 

1515 

1516 """ 

1517 

1518 _ = kwargs.pop('figure', None) # pop in case user has added this... 

1519 gs = GridSpec(nrows=nrows, ncols=ncols, figure=self, **kwargs) 

1520 return gs 

1521 

1522 def subfigures(self, nrows=1, ncols=1, squeeze=True, 

1523 wspace=None, hspace=None, 

1524 width_ratios=None, height_ratios=None, 

1525 **kwargs): 

1526 """ 

1527 Add a set of subfigures to this figure or subfigure. 

1528 

1529 A subfigure has the same artist methods as a figure, and is logically 

1530 the same as a figure, but cannot print itself. 

1531 See :doc:`/gallery/subplots_axes_and_figures/subfigures`. 

1532 

1533 Parameters 

1534 ---------- 

1535 nrows, ncols : int, default: 1 

1536 Number of rows/columns of the subfigure grid. 

1537 

1538 squeeze : bool, default: True 

1539 If True, extra dimensions are squeezed out from the returned 

1540 array of subfigures. 

1541 

1542 wspace, hspace : float, default: None 

1543 The amount of width/height reserved for space between subfigures, 

1544 expressed as a fraction of the average subfigure width/height. 

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

1546 rcParams when necessary. 

1547 

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

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

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

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

1552 

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

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

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

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

1557 """ 

1558 gs = GridSpec(nrows=nrows, ncols=ncols, figure=self, 

1559 wspace=wspace, hspace=hspace, 

1560 width_ratios=width_ratios, 

1561 height_ratios=height_ratios) 

1562 

1563 sfarr = np.empty((nrows, ncols), dtype=object) 

1564 for i in range(ncols): 

1565 for j in range(nrows): 

1566 sfarr[j, i] = self.add_subfigure(gs[j, i], **kwargs) 

1567 

1568 if squeeze: 

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

1570 # subfigure, just return it instead of a 1-element array. 

1571 return sfarr.item() if sfarr.size == 1 else sfarr.squeeze() 

1572 else: 

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

1574 return sfarr 

1575 

1576 def add_subfigure(self, subplotspec, **kwargs): 

1577 """ 

1578 Add a `.SubFigure` to the figure as part of a subplot arrangement. 

1579 

1580 Parameters 

1581 ---------- 

1582 subplotspec : `.gridspec.SubplotSpec` 

1583 Defines the region in a parent gridspec where the subfigure will 

1584 be placed. 

1585 

1586 Returns 

1587 ------- 

1588 `.SubFigure` 

1589 

1590 Other Parameters 

1591 ---------------- 

1592 **kwargs 

1593 Are passed to the `.SubFigure` object. 

1594 

1595 See Also 

1596 -------- 

1597 .Figure.subfigures 

1598 """ 

1599 sf = SubFigure(self, subplotspec, **kwargs) 

1600 self.subfigs += [sf] 

1601 return sf 

1602 

1603 def sca(self, a): 

1604 """Set the current Axes to be *a* and return *a*.""" 

1605 self._axstack.bubble(a) 

1606 self._axobservers.process("_axes_change_event", self) 

1607 return a 

1608 

1609 def gca(self): 

1610 """ 

1611 Get the current Axes. 

1612 

1613 If there is currently no Axes on this Figure, a new one is created 

1614 using `.Figure.add_subplot`. (To test whether there is currently an 

1615 Axes on a Figure, check whether ``figure.axes`` is empty. To test 

1616 whether there is currently a Figure on the pyplot figure stack, check 

1617 whether `.pyplot.get_fignums()` is empty.) 

1618 """ 

1619 ax = self._axstack.current() 

1620 return ax if ax is not None else self.add_subplot() 

1621 

1622 def _gci(self): 

1623 # Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere. 

1624 """ 

1625 Get the current colorable artist. 

1626 

1627 Specifically, returns the current `.ScalarMappable` instance (`.Image` 

1628 created by `imshow` or `figimage`, `.Collection` created by `pcolor` or 

1629 `scatter`, etc.), or *None* if no such instance has been defined. 

1630 

1631 The current image is an attribute of the current Axes, or the nearest 

1632 earlier Axes in the current figure that contains an image. 

1633 

1634 Notes 

1635 ----- 

1636 Historically, the only colorable artists were images; hence the name 

1637 ``gci`` (get current image). 

1638 """ 

1639 # Look first for an image in the current Axes. 

1640 ax = self._axstack.current() 

1641 if ax is None: 

1642 return None 

1643 im = ax._gci() 

1644 if im is not None: 

1645 return im 

1646 # If there is no image in the current Axes, search for 

1647 # one in a previously created Axes. Whether this makes 

1648 # sense is debatable, but it is the documented behavior. 

1649 for ax in reversed(self.axes): 

1650 im = ax._gci() 

1651 if im is not None: 

1652 return im 

1653 return None 

1654 

1655 def _process_projection_requirements( 

1656 self, *args, axes_class=None, polar=False, projection=None, 

1657 **kwargs): 

1658 """ 

1659 Handle the args/kwargs to add_axes/add_subplot/gca, returning:: 

1660 

1661 (axes_proj_class, proj_class_kwargs) 

1662 

1663 which can be used for new Axes initialization/identification. 

1664 """ 

1665 if axes_class is not None: 

1666 if polar or projection is not None: 

1667 raise ValueError( 

1668 "Cannot combine 'axes_class' and 'projection' or 'polar'") 

1669 projection_class = axes_class 

1670 else: 

1671 

1672 if polar: 

1673 if projection is not None and projection != 'polar': 

1674 raise ValueError( 

1675 f"polar={polar}, yet projection={projection!r}. " 

1676 "Only one of these arguments should be supplied." 

1677 ) 

1678 projection = 'polar' 

1679 

1680 if isinstance(projection, str) or projection is None: 

1681 projection_class = projections.get_projection_class(projection) 

1682 elif hasattr(projection, '_as_mpl_axes'): 

1683 projection_class, extra_kwargs = projection._as_mpl_axes() 

1684 kwargs.update(**extra_kwargs) 

1685 else: 

1686 raise TypeError( 

1687 f"projection must be a string, None or implement a " 

1688 f"_as_mpl_axes method, not {projection!r}") 

1689 if projection_class.__name__ == 'Axes3D': 

1690 kwargs.setdefault('auto_add_to_figure', False) 

1691 return projection_class, kwargs 

1692 

1693 def get_default_bbox_extra_artists(self): 

1694 bbox_artists = [artist for artist in self.get_children() 

1695 if (artist.get_visible() and artist.get_in_layout())] 

1696 for ax in self.axes: 

1697 if ax.get_visible(): 

1698 bbox_artists.extend(ax.get_default_bbox_extra_artists()) 

1699 return bbox_artists 

1700 

1701 def get_tightbbox(self, renderer=None, bbox_extra_artists=None): 

1702 """ 

1703 Return a (tight) bounding box of the figure *in inches*. 

1704 

1705 Note that `.FigureBase` differs from all other artists, which return 

1706 their `.Bbox` in pixels. 

1707 

1708 Artists that have ``artist.set_in_layout(False)`` are not included 

1709 in the bbox. 

1710 

1711 Parameters 

1712 ---------- 

1713 renderer : `.RendererBase` subclass 

1714 Renderer that will be used to draw the figures (i.e. 

1715 ``fig.canvas.get_renderer()``) 

1716 

1717 bbox_extra_artists : list of `.Artist` or ``None`` 

1718 List of artists to include in the tight bounding box. If 

1719 ``None`` (default), then all artist children of each Axes are 

1720 included in the tight bounding box. 

1721 

1722 Returns 

1723 ------- 

1724 `.BboxBase` 

1725 containing the bounding box (in figure inches). 

1726 """ 

1727 

1728 if renderer is None: 

1729 renderer = self.figure._get_renderer() 

1730 

1731 bb = [] 

1732 if bbox_extra_artists is None: 

1733 artists = self.get_default_bbox_extra_artists() 

1734 else: 

1735 artists = bbox_extra_artists 

1736 

1737 for a in artists: 

1738 bbox = a.get_tightbbox(renderer) 

1739 if bbox is not None: 

1740 bb.append(bbox) 

1741 

1742 for ax in self.axes: 

1743 if ax.get_visible(): 

1744 # some axes don't take the bbox_extra_artists kwarg so we 

1745 # need this conditional.... 

1746 try: 

1747 bbox = ax.get_tightbbox( 

1748 renderer, bbox_extra_artists=bbox_extra_artists) 

1749 except TypeError: 

1750 bbox = ax.get_tightbbox(renderer) 

1751 bb.append(bbox) 

1752 bb = [b for b in bb 

1753 if (np.isfinite(b.width) and np.isfinite(b.height) 

1754 and (b.width != 0 or b.height != 0))] 

1755 

1756 isfigure = hasattr(self, 'bbox_inches') 

1757 if len(bb) == 0: 

1758 if isfigure: 

1759 return self.bbox_inches 

1760 else: 

1761 # subfigures do not have bbox_inches, but do have a bbox 

1762 bb = [self.bbox] 

1763 

1764 _bbox = Bbox.union(bb) 

1765 

1766 if isfigure: 

1767 # transform from pixels to inches... 

1768 _bbox = TransformedBbox(_bbox, self.dpi_scale_trans.inverted()) 

1769 

1770 return _bbox 

1771 

1772 @staticmethod 

1773 def _normalize_grid_string(layout): 

1774 if '\n' not in layout: 

1775 # single-line string 

1776 return [list(ln) for ln in layout.split(';')] 

1777 else: 

1778 # multi-line string 

1779 layout = inspect.cleandoc(layout) 

1780 return [list(ln) for ln in layout.strip('\n').split('\n')] 

1781 

1782 def subplot_mosaic(self, mosaic, *, sharex=False, sharey=False, 

1783 width_ratios=None, height_ratios=None, 

1784 empty_sentinel='.', subplot_kw=None, gridspec_kw=None): 

1785 """ 

1786 Build a layout of Axes based on ASCII art or nested lists. 

1787 

1788 This is a helper function to build complex GridSpec layouts visually. 

1789 

1790 .. note:: 

1791 

1792 This API is provisional and may be revised in the future based on 

1793 early user feedback. 

1794 

1795 See :doc:`/tutorials/provisional/mosaic` 

1796 for an example and full API documentation 

1797 

1798 Parameters 

1799 ---------- 

1800 mosaic : list of list of {hashable or nested} or str 

1801 

1802 A visual layout of how you want your Axes to be arranged 

1803 labeled as strings. For example :: 

1804 

1805 x = [['A panel', 'A panel', 'edge'], 

1806 ['C panel', '.', 'edge']] 

1807 

1808 produces 4 Axes: 

1809 

1810 - 'A panel' which is 1 row high and spans the first two columns 

1811 - 'edge' which is 2 rows high and is on the right edge 

1812 - 'C panel' which in 1 row and 1 column wide in the bottom left 

1813 - a blank space 1 row and 1 column wide in the bottom center 

1814 

1815 Any of the entries in the layout can be a list of lists 

1816 of the same form to create nested layouts. 

1817 

1818 If input is a str, then it can either be a multi-line string of 

1819 the form :: 

1820 

1821 ''' 

1822 AAE 

1823 C.E 

1824 ''' 

1825 

1826 where each character is a column and each line is a row. Or it 

1827 can be a single-line string where rows are separated by ``;``:: 

1828 

1829 'AB;CC' 

1830 

1831 The string notation allows only single character Axes labels and 

1832 does not support nesting but is very terse. 

1833 

1834 sharex, sharey : bool, default: False 

1835 If True, the x-axis (*sharex*) or y-axis (*sharey*) will be shared 

1836 among all subplots. In that case, tick label visibility and axis 

1837 units behave as for `subplots`. If False, each subplot's x- or 

1838 y-axis will be independent. 

1839 

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

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

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

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

1844 to ``gridspec_kw={'width_ratios': [...]}``. 

1845 

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

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

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

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

1850 to ``gridspec_kw={'height_ratios': [...]}``. 

1851 

1852 subplot_kw : dict, optional 

1853 Dictionary with keywords passed to the `.Figure.add_subplot` call 

1854 used to create each subplot. 

1855 

1856 gridspec_kw : dict, optional 

1857 Dictionary with keywords passed to the `.GridSpec` constructor used 

1858 to create the grid the subplots are placed on. 

1859 

1860 empty_sentinel : object, optional 

1861 Entry in the layout to mean "leave this space empty". Defaults 

1862 to ``'.'``. Note, if *layout* is a string, it is processed via 

1863 `inspect.cleandoc` to remove leading white space, which may 

1864 interfere with using white-space as the empty sentinel. 

1865 

1866 Returns 

1867 ------- 

1868 dict[label, Axes] 

1869 A dictionary mapping the labels to the Axes objects. The order of 

1870 the axes is left-to-right and top-to-bottom of their position in the 

1871 total layout. 

1872 

1873 """ 

1874 subplot_kw = subplot_kw or {} 

1875 gridspec_kw = dict(gridspec_kw or {}) 

1876 if height_ratios is not None: 

1877 if 'height_ratios' in gridspec_kw: 

1878 raise ValueError("'height_ratios' must not be defined both as " 

1879 "parameter and as key in 'gridspec_kw'") 

1880 gridspec_kw['height_ratios'] = height_ratios 

1881 if width_ratios is not None: 

1882 if 'width_ratios' in gridspec_kw: 

1883 raise ValueError("'width_ratios' must not be defined both as " 

1884 "parameter and as key in 'gridspec_kw'") 

1885 gridspec_kw['width_ratios'] = width_ratios 

1886 

1887 # special-case string input 

1888 if isinstance(mosaic, str): 

1889 mosaic = self._normalize_grid_string(mosaic) 

1890 # Only accept strict bools to allow a possible future API expansion. 

1891 _api.check_isinstance(bool, sharex=sharex, sharey=sharey) 

1892 

1893 def _make_array(inp): 

1894 """ 

1895 Convert input into 2D array 

1896 

1897 We need to have this internal function rather than 

1898 ``np.asarray(..., dtype=object)`` so that a list of lists 

1899 of lists does not get converted to an array of dimension > 

1900 2 

1901 

1902 Returns 

1903 ------- 

1904 2D object array 

1905 

1906 """ 

1907 r0, *rest = inp 

1908 if isinstance(r0, str): 

1909 raise ValueError('List mosaic specification must be 2D') 

1910 for j, r in enumerate(rest, start=1): 

1911 if isinstance(r, str): 

1912 raise ValueError('List mosaic specification must be 2D') 

1913 if len(r0) != len(r): 

1914 raise ValueError( 

1915 "All of the rows must be the same length, however " 

1916 f"the first row ({r0!r}) has length {len(r0)} " 

1917 f"and row {j} ({r!r}) has length {len(r)}." 

1918 ) 

1919 out = np.zeros((len(inp), len(r0)), dtype=object) 

1920 for j, r in enumerate(inp): 

1921 for k, v in enumerate(r): 

1922 out[j, k] = v 

1923 return out 

1924 

1925 def _identify_keys_and_nested(mosaic): 

1926 """ 

1927 Given a 2D object array, identify unique IDs and nested mosaics 

1928 

1929 Parameters 

1930 ---------- 

1931 mosaic : 2D numpy object array 

1932 

1933 Returns 

1934 ------- 

1935 unique_ids : tuple 

1936 The unique non-sub mosaic entries in this mosaic 

1937 nested : dict[tuple[int, int]], 2D object array 

1938 """ 

1939 # make sure we preserve the user supplied order 

1940 unique_ids = cbook._OrderedSet() 

1941 nested = {} 

1942 for j, row in enumerate(mosaic): 

1943 for k, v in enumerate(row): 

1944 if v == empty_sentinel: 

1945 continue 

1946 elif not cbook.is_scalar_or_string(v): 

1947 nested[(j, k)] = _make_array(v) 

1948 else: 

1949 unique_ids.add(v) 

1950 

1951 return tuple(unique_ids), nested 

1952 

1953 def _do_layout(gs, mosaic, unique_ids, nested): 

1954 """ 

1955 Recursively do the mosaic. 

1956 

1957 Parameters 

1958 ---------- 

1959 gs : GridSpec 

1960 mosaic : 2D object array 

1961 The input converted to a 2D numpy array for this level. 

1962 unique_ids : tuple 

1963 The identified scalar labels at this level of nesting. 

1964 nested : dict[tuple[int, int]], 2D object array 

1965 The identified nested mosaics, if any. 

1966 

1967 Returns 

1968 ------- 

1969 dict[label, Axes] 

1970 A flat dict of all of the Axes created. 

1971 """ 

1972 output = dict() 

1973 

1974 # we need to merge together the Axes at this level and the axes 

1975 # in the (recursively) nested sub-mosaics so that we can add 

1976 # them to the figure in the "natural" order if you were to 

1977 # ravel in c-order all of the Axes that will be created 

1978 # 

1979 # This will stash the upper left index of each object (axes or 

1980 # nested mosaic) at this level 

1981 this_level = dict() 

1982 

1983 # go through the unique keys, 

1984 for name in unique_ids: 

1985 # sort out where each axes starts/ends 

1986 indx = np.argwhere(mosaic == name) 

1987 start_row, start_col = np.min(indx, axis=0) 

1988 end_row, end_col = np.max(indx, axis=0) + 1 

1989 # and construct the slice object 

1990 slc = (slice(start_row, end_row), slice(start_col, end_col)) 

1991 # some light error checking 

1992 if (mosaic[slc] != name).any(): 

1993 raise ValueError( 

1994 f"While trying to layout\n{mosaic!r}\n" 

1995 f"we found that the label {name!r} specifies a " 

1996 "non-rectangular or non-contiguous area.") 

1997 # and stash this slice for later 

1998 this_level[(start_row, start_col)] = (name, slc, 'axes') 

1999 

2000 # do the same thing for the nested mosaics (simpler because these 

2001 # can not be spans yet!) 

2002 for (j, k), nested_mosaic in nested.items(): 

2003 this_level[(j, k)] = (None, nested_mosaic, 'nested') 

2004 

2005 # now go through the things in this level and add them 

2006 # in order left-to-right top-to-bottom 

2007 for key in sorted(this_level): 

2008 name, arg, method = this_level[key] 

2009 # we are doing some hokey function dispatch here based 

2010 # on the 'method' string stashed above to sort out if this 

2011 # element is an Axes or a nested mosaic. 

2012 if method == 'axes': 

2013 slc = arg 

2014 # add a single axes 

2015 if name in output: 

2016 raise ValueError(f"There are duplicate keys {name} " 

2017 f"in the layout\n{mosaic!r}") 

2018 ax = self.add_subplot( 

2019 gs[slc], **{'label': str(name), **subplot_kw} 

2020 ) 

2021 output[name] = ax 

2022 elif method == 'nested': 

2023 nested_mosaic = arg 

2024 j, k = key 

2025 # recursively add the nested mosaic 

2026 rows, cols = nested_mosaic.shape 

2027 nested_output = _do_layout( 

2028 gs[j, k].subgridspec(rows, cols, **gridspec_kw), 

2029 nested_mosaic, 

2030 *_identify_keys_and_nested(nested_mosaic) 

2031 ) 

2032 overlap = set(output) & set(nested_output) 

2033 if overlap: 

2034 raise ValueError( 

2035 f"There are duplicate keys {overlap} " 

2036 f"between the outer layout\n{mosaic!r}\n" 

2037 f"and the nested layout\n{nested_mosaic}" 

2038 ) 

2039 output.update(nested_output) 

2040 else: 

2041 raise RuntimeError("This should never happen") 

2042 return output 

2043 

2044 mosaic = _make_array(mosaic) 

2045 rows, cols = mosaic.shape 

2046 gs = self.add_gridspec(rows, cols, **gridspec_kw) 

2047 ret = _do_layout(gs, mosaic, *_identify_keys_and_nested(mosaic)) 

2048 ax0 = next(iter(ret.values())) 

2049 for ax in ret.values(): 

2050 if sharex: 

2051 ax.sharex(ax0) 

2052 ax._label_outer_xaxis(check_patch=True) 

2053 if sharey: 

2054 ax.sharey(ax0) 

2055 ax._label_outer_yaxis(check_patch=True) 

2056 for k, ax in ret.items(): 

2057 if isinstance(k, str): 

2058 ax.set_label(k) 

2059 return ret 

2060 

2061 def _set_artist_props(self, a): 

2062 if a != self: 

2063 a.set_figure(self) 

2064 a.stale_callback = _stale_figure_callback 

2065 a.set_transform(self.transSubfigure) 

2066 

2067 

2068@_docstring.interpd 

2069class SubFigure(FigureBase): 

2070 """ 

2071 Logical figure that can be placed inside a figure. 

2072 

2073 Typically instantiated using `.Figure.add_subfigure` or 

2074 `.SubFigure.add_subfigure`, or `.SubFigure.subfigures`. A subfigure has 

2075 the same methods as a figure except for those particularly tied to the size 

2076 or dpi of the figure, and is confined to a prescribed region of the figure. 

2077 For example the following puts two subfigures side-by-side:: 

2078 

2079 fig = plt.figure() 

2080 sfigs = fig.subfigures(1, 2) 

2081 axsL = sfigs[0].subplots(1, 2) 

2082 axsR = sfigs[1].subplots(2, 1) 

2083 

2084 See :doc:`/gallery/subplots_axes_and_figures/subfigures` 

2085 """ 

2086 callbacks = _api.deprecated( 

2087 "3.6", alternative=("the 'resize_event' signal in " 

2088 "Figure.canvas.callbacks") 

2089 )(property(lambda self: self._fig_callbacks)) 

2090 

2091 def __init__(self, parent, subplotspec, *, 

2092 facecolor=None, 

2093 edgecolor=None, 

2094 linewidth=0.0, 

2095 frameon=None, 

2096 **kwargs): 

2097 """ 

2098 Parameters 

2099 ---------- 

2100 parent : `.Figure` or `.SubFigure` 

2101 Figure or subfigure that contains the SubFigure. SubFigures 

2102 can be nested. 

2103 

2104 subplotspec : `.gridspec.SubplotSpec` 

2105 Defines the region in a parent gridspec where the subfigure will 

2106 be placed. 

2107 

2108 facecolor : default: :rc:`figure.facecolor` 

2109 The figure patch face color. 

2110 

2111 edgecolor : default: :rc:`figure.edgecolor` 

2112 The figure patch edge color. 

2113 

2114 linewidth : float 

2115 The linewidth of the frame (i.e. the edge linewidth of the figure 

2116 patch). 

2117 

2118 frameon : bool, default: :rc:`figure.frameon` 

2119 If ``False``, suppress drawing the figure background patch. 

2120 

2121 Other Parameters 

2122 ---------------- 

2123 **kwargs : `.SubFigure` properties, optional 

2124 

2125 %(SubFigure:kwdoc)s 

2126 """ 

2127 super().__init__(**kwargs) 

2128 if facecolor is None: 

2129 facecolor = mpl.rcParams['figure.facecolor'] 

2130 if edgecolor is None: 

2131 edgecolor = mpl.rcParams['figure.edgecolor'] 

2132 if frameon is None: 

2133 frameon = mpl.rcParams['figure.frameon'] 

2134 

2135 self._subplotspec = subplotspec 

2136 self._parent = parent 

2137 self.figure = parent.figure 

2138 self._fig_callbacks = parent._fig_callbacks 

2139 

2140 # subfigures use the parent axstack 

2141 self._axstack = parent._axstack 

2142 self.subplotpars = parent.subplotpars 

2143 self.dpi_scale_trans = parent.dpi_scale_trans 

2144 self._axobservers = parent._axobservers 

2145 self.canvas = parent.canvas 

2146 self.transFigure = parent.transFigure 

2147 self.bbox_relative = None 

2148 self._redo_transform_rel_fig() 

2149 self.figbbox = self._parent.figbbox 

2150 self.bbox = TransformedBbox(self.bbox_relative, 

2151 self._parent.transSubfigure) 

2152 self.transSubfigure = BboxTransformTo(self.bbox) 

2153 

2154 self.patch = Rectangle( 

2155 xy=(0, 0), width=1, height=1, visible=frameon, 

2156 facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth, 

2157 # Don't let the figure patch influence bbox calculation. 

2158 in_layout=False, transform=self.transSubfigure) 

2159 self._set_artist_props(self.patch) 

2160 self.patch.set_antialiased(False) 

2161 

2162 @property 

2163 def dpi(self): 

2164 return self._parent.dpi 

2165 

2166 @dpi.setter 

2167 def dpi(self, value): 

2168 self._parent.dpi = value 

2169 

2170 def get_dpi(self): 

2171 """ 

2172 Return the resolution of the parent figure in dots-per-inch as a float. 

2173 """ 

2174 return self._parent.dpi 

2175 

2176 def set_dpi(self, val): 

2177 """ 

2178 Set the resolution of parent figure in dots-per-inch. 

2179 

2180 Parameters 

2181 ---------- 

2182 val : float 

2183 """ 

2184 self._parent.dpi = val 

2185 self.stale = True 

2186 

2187 def _get_renderer(self): 

2188 return self._parent._get_renderer() 

2189 

2190 def _redo_transform_rel_fig(self, bbox=None): 

2191 """ 

2192 Make the transSubfigure bbox relative to Figure transform. 

2193 

2194 Parameters 

2195 ---------- 

2196 bbox : bbox or None 

2197 If not None, then the bbox is used for relative bounding box. 

2198 Otherwise, it is calculated from the subplotspec. 

2199 """ 

2200 if bbox is not None: 

2201 self.bbox_relative.p0 = bbox.p0 

2202 self.bbox_relative.p1 = bbox.p1 

2203 return 

2204 # need to figure out *where* this subplotspec is. 

2205 gs = self._subplotspec.get_gridspec() 

2206 wr = np.asarray(gs.get_width_ratios()) 

2207 hr = np.asarray(gs.get_height_ratios()) 

2208 dx = wr[self._subplotspec.colspan].sum() / wr.sum() 

2209 dy = hr[self._subplotspec.rowspan].sum() / hr.sum() 

2210 x0 = wr[:self._subplotspec.colspan.start].sum() / wr.sum() 

2211 y0 = 1 - hr[:self._subplotspec.rowspan.stop].sum() / hr.sum() 

2212 if self.bbox_relative is None: 

2213 self.bbox_relative = Bbox.from_bounds(x0, y0, dx, dy) 

2214 else: 

2215 self.bbox_relative.p0 = (x0, y0) 

2216 self.bbox_relative.p1 = (x0 + dx, y0 + dy) 

2217 

2218 def get_constrained_layout(self): 

2219 """ 

2220 Return whether constrained layout is being used. 

2221 

2222 See :doc:`/tutorials/intermediate/constrainedlayout_guide`. 

2223 """ 

2224 return self._parent.get_constrained_layout() 

2225 

2226 def get_constrained_layout_pads(self, relative=False): 

2227 """ 

2228 Get padding for ``constrained_layout``. 

2229 

2230 Returns a list of ``w_pad, h_pad`` in inches and 

2231 ``wspace`` and ``hspace`` as fractions of the subplot. 

2232 

2233 See :doc:`/tutorials/intermediate/constrainedlayout_guide`. 

2234 

2235 Parameters 

2236 ---------- 

2237 relative : bool 

2238 If `True`, then convert from inches to figure relative. 

2239 """ 

2240 return self._parent.get_constrained_layout_pads(relative=relative) 

2241 

2242 def get_layout_engine(self): 

2243 return self._parent.get_layout_engine() 

2244 

2245 @property 

2246 def axes(self): 

2247 """ 

2248 List of Axes in the SubFigure. You can access and modify the Axes 

2249 in the SubFigure through this list. 

2250 

2251 Modifying this list has no effect. Instead, use `~.SubFigure.add_axes`, 

2252 `~.SubFigure.add_subplot` or `~.SubFigure.delaxes` to add or remove an 

2253 Axes. 

2254 

2255 Note: The `.SubFigure.axes` property and `~.SubFigure.get_axes` method 

2256 are equivalent. 

2257 """ 

2258 return self._localaxes[:] 

2259 

2260 get_axes = axes.fget 

2261 

2262 def draw(self, renderer): 

2263 # docstring inherited 

2264 

2265 # draw the figure bounding box, perhaps none for white figure 

2266 if not self.get_visible(): 

2267 return 

2268 

2269 artists = self._get_draw_artists(renderer) 

2270 

2271 try: 

2272 renderer.open_group('subfigure', gid=self.get_gid()) 

2273 self.patch.draw(renderer) 

2274 mimage._draw_list_compositing_images( 

2275 renderer, self, artists, self.figure.suppressComposite) 

2276 for sfig in self.subfigs: 

2277 sfig.draw(renderer) 

2278 renderer.close_group('subfigure') 

2279 

2280 finally: 

2281 self.stale = False 

2282 

2283 

2284@_docstring.interpd 

2285class Figure(FigureBase): 

2286 """ 

2287 The top level container for all the plot elements. 

2288 

2289 Attributes 

2290 ---------- 

2291 patch 

2292 The `.Rectangle` instance representing the figure background patch. 

2293 

2294 suppressComposite 

2295 For multiple images, the figure will make composite images 

2296 depending on the renderer option_image_nocomposite function. If 

2297 *suppressComposite* is a boolean, this will override the renderer. 

2298 """ 

2299 # Remove the self._fig_callbacks properties on figure and subfigure 

2300 # after the deprecation expires. 

2301 callbacks = _api.deprecated( 

2302 "3.6", alternative=("the 'resize_event' signal in " 

2303 "Figure.canvas.callbacks") 

2304 )(property(lambda self: self._fig_callbacks)) 

2305 

2306 def __str__(self): 

2307 return "Figure(%gx%g)" % tuple(self.bbox.size) 

2308 

2309 def __repr__(self): 

2310 return "<{clsname} size {h:g}x{w:g} with {naxes} Axes>".format( 

2311 clsname=self.__class__.__name__, 

2312 h=self.bbox.size[0], w=self.bbox.size[1], 

2313 naxes=len(self.axes), 

2314 ) 

2315 

2316 @_api.make_keyword_only("3.6", "facecolor") 

2317 def __init__(self, 

2318 figsize=None, 

2319 dpi=None, 

2320 facecolor=None, 

2321 edgecolor=None, 

2322 linewidth=0.0, 

2323 frameon=None, 

2324 subplotpars=None, # rc figure.subplot.* 

2325 tight_layout=None, # rc figure.autolayout 

2326 constrained_layout=None, # rc figure.constrained_layout.use 

2327 *, 

2328 layout=None, 

2329 **kwargs 

2330 ): 

2331 """ 

2332 Parameters 

2333 ---------- 

2334 figsize : 2-tuple of floats, default: :rc:`figure.figsize` 

2335 Figure dimension ``(width, height)`` in inches. 

2336 

2337 dpi : float, default: :rc:`figure.dpi` 

2338 Dots per inch. 

2339 

2340 facecolor : default: :rc:`figure.facecolor` 

2341 The figure patch facecolor. 

2342 

2343 edgecolor : default: :rc:`figure.edgecolor` 

2344 The figure patch edge color. 

2345 

2346 linewidth : float 

2347 The linewidth of the frame (i.e. the edge linewidth of the figure 

2348 patch). 

2349 

2350 frameon : bool, default: :rc:`figure.frameon` 

2351 If ``False``, suppress drawing the figure background patch. 

2352 

2353 subplotpars : `SubplotParams` 

2354 Subplot parameters. If not given, the default subplot 

2355 parameters :rc:`figure.subplot.*` are used. 

2356 

2357 tight_layout : bool or dict, default: :rc:`figure.autolayout` 

2358 Whether to use the tight layout mechanism. See `.set_tight_layout`. 

2359 

2360 .. admonition:: Discouraged 

2361 

2362 The use of this parameter is discouraged. Please use 

2363 ``layout='tight'`` instead for the common case of 

2364 ``tight_layout=True`` and use `.set_tight_layout` otherwise. 

2365 

2366 constrained_layout : bool, default: :rc:`figure.constrained_layout.use` 

2367 This is equal to ``layout='constrained'``. 

2368 

2369 .. admonition:: Discouraged 

2370 

2371 The use of this parameter is discouraged. Please use 

2372 ``layout='constrained'`` instead. 

2373 

2374 layout : {'constrained', 'compressed', 'tight', `.LayoutEngine`, None} 

2375 The layout mechanism for positioning of plot elements to avoid 

2376 overlapping Axes decorations (labels, ticks, etc). Note that 

2377 layout managers can have significant performance penalties. 

2378 Defaults to *None*. 

2379 

2380 - 'constrained': The constrained layout solver adjusts axes sizes 

2381 to avoid overlapping axes decorations. Can handle complex plot 

2382 layouts and colorbars, and is thus recommended. 

2383 

2384 See :doc:`/tutorials/intermediate/constrainedlayout_guide` 

2385 for examples. 

2386 

2387 - 'compressed': uses the same algorithm as 'constrained', but 

2388 removes extra space between fixed-aspect-ratio Axes. Best for 

2389 simple grids of axes. 

2390 

2391 - 'tight': Use the tight layout mechanism. This is a relatively 

2392 simple algorithm that adjusts the subplot parameters so that 

2393 decorations do not overlap. See `.Figure.set_tight_layout` for 

2394 further details. 

2395 

2396 - A `.LayoutEngine` instance. Builtin layout classes are 

2397 `.ConstrainedLayoutEngine` and `.TightLayoutEngine`, more easily 

2398 accessible by 'constrained' and 'tight'. Passing an instance 

2399 allows third parties to provide their own layout engine. 

2400 

2401 If not given, fall back to using the parameters *tight_layout* and 

2402 *constrained_layout*, including their config defaults 

2403 :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. 

2404 

2405 Other Parameters 

2406 ---------------- 

2407 **kwargs : `.Figure` properties, optional 

2408 

2409 %(Figure:kwdoc)s 

2410 """ 

2411 super().__init__(**kwargs) 

2412 self._layout_engine = None 

2413 

2414 if layout is not None: 

2415 if (tight_layout is not None): 

2416 _api.warn_external( 

2417 "The Figure parameters 'layout' and 'tight_layout' cannot " 

2418 "be used together. Please use 'layout' only.") 

2419 if (constrained_layout is not None): 

2420 _api.warn_external( 

2421 "The Figure parameters 'layout' and 'constrained_layout' " 

2422 "cannot be used together. Please use 'layout' only.") 

2423 self.set_layout_engine(layout=layout) 

2424 elif tight_layout is not None: 

2425 if constrained_layout is not None: 

2426 _api.warn_external( 

2427 "The Figure parameters 'tight_layout' and " 

2428 "'constrained_layout' cannot be used together. Please use " 

2429 "'layout' parameter") 

2430 self.set_layout_engine(layout='tight') 

2431 if isinstance(tight_layout, dict): 

2432 self.get_layout_engine().set(**tight_layout) 

2433 elif constrained_layout is not None: 

2434 if isinstance(constrained_layout, dict): 

2435 self.set_layout_engine(layout='constrained') 

2436 self.get_layout_engine().set(**constrained_layout) 

2437 elif constrained_layout: 

2438 self.set_layout_engine(layout='constrained') 

2439 

2440 else: 

2441 # everything is None, so use default: 

2442 self.set_layout_engine(layout=layout) 

2443 

2444 self._fig_callbacks = cbook.CallbackRegistry(signals=["dpi_changed"]) 

2445 # Callbacks traditionally associated with the canvas (and exposed with 

2446 # a proxy property), but that actually need to be on the figure for 

2447 # pickling. 

2448 self._canvas_callbacks = cbook.CallbackRegistry( 

2449 signals=FigureCanvasBase.events) 

2450 connect = self._canvas_callbacks._connect_picklable 

2451 self._mouse_key_ids = [ 

2452 connect('key_press_event', backend_bases._key_handler), 

2453 connect('key_release_event', backend_bases._key_handler), 

2454 connect('key_release_event', backend_bases._key_handler), 

2455 connect('button_press_event', backend_bases._mouse_handler), 

2456 connect('button_release_event', backend_bases._mouse_handler), 

2457 connect('scroll_event', backend_bases._mouse_handler), 

2458 connect('motion_notify_event', backend_bases._mouse_handler), 

2459 ] 

2460 self._button_pick_id = connect('button_press_event', self.pick) 

2461 self._scroll_pick_id = connect('scroll_event', self.pick) 

2462 

2463 if figsize is None: 

2464 figsize = mpl.rcParams['figure.figsize'] 

2465 if dpi is None: 

2466 dpi = mpl.rcParams['figure.dpi'] 

2467 if facecolor is None: 

2468 facecolor = mpl.rcParams['figure.facecolor'] 

2469 if edgecolor is None: 

2470 edgecolor = mpl.rcParams['figure.edgecolor'] 

2471 if frameon is None: 

2472 frameon = mpl.rcParams['figure.frameon'] 

2473 

2474 if not np.isfinite(figsize).all() or (np.array(figsize) < 0).any(): 

2475 raise ValueError('figure size must be positive finite not ' 

2476 f'{figsize}') 

2477 self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) 

2478 

2479 self.dpi_scale_trans = Affine2D().scale(dpi) 

2480 # do not use property as it will trigger 

2481 self._dpi = dpi 

2482 self.bbox = TransformedBbox(self.bbox_inches, self.dpi_scale_trans) 

2483 self.figbbox = self.bbox 

2484 self.transFigure = BboxTransformTo(self.bbox) 

2485 self.transSubfigure = self.transFigure 

2486 

2487 self.patch = Rectangle( 

2488 xy=(0, 0), width=1, height=1, visible=frameon, 

2489 facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth, 

2490 # Don't let the figure patch influence bbox calculation. 

2491 in_layout=False) 

2492 self._set_artist_props(self.patch) 

2493 self.patch.set_antialiased(False) 

2494 

2495 FigureCanvasBase(self) # Set self.canvas. 

2496 

2497 if subplotpars is None: 

2498 subplotpars = SubplotParams() 

2499 

2500 self.subplotpars = subplotpars 

2501 

2502 self._axstack = _AxesStack() # track all figure axes and current axes 

2503 self.clear() 

2504 

2505 def pick(self, mouseevent): 

2506 if not self.canvas.widgetlock.locked(): 

2507 super().pick(mouseevent) 

2508 

2509 def _check_layout_engines_compat(self, old, new): 

2510 """ 

2511 Helper for set_layout engine 

2512 

2513 If the figure has used the old engine and added a colorbar then the 

2514 value of colorbar_gridspec must be the same on the new engine. 

2515 """ 

2516 if old is None or new is None: 

2517 return True 

2518 if old.colorbar_gridspec == new.colorbar_gridspec: 

2519 return True 

2520 # colorbar layout different, so check if any colorbars are on the 

2521 # figure... 

2522 for ax in self.axes: 

2523 if hasattr(ax, '_colorbar'): 

2524 # colorbars list themselves as a colorbar. 

2525 return False 

2526 return True 

2527 

2528 def set_layout_engine(self, layout=None, **kwargs): 

2529 """ 

2530 Set the layout engine for this figure. 

2531 

2532 Parameters 

2533 ---------- 

2534 layout: {'constrained', 'compressed', 'tight', 'none'} or \ 

2535`LayoutEngine` or None 

2536 

2537 - 'constrained' will use `~.ConstrainedLayoutEngine` 

2538 - 'compressed' will also use `~.ConstrainedLayoutEngine`, but with 

2539 a correction that attempts to make a good layout for fixed-aspect 

2540 ratio Axes. 

2541 - 'tight' uses `~.TightLayoutEngine` 

2542 - 'none' removes layout engine. 

2543 

2544 If `None`, the behavior is controlled by :rc:`figure.autolayout` 

2545 (which if `True` behaves as if 'tight' was passed) and 

2546 :rc:`figure.constrained_layout.use` (which if `True` behaves as if 

2547 'constrained' was passed). If both are `True`, 

2548 :rc:`figure.autolayout` takes priority. 

2549 

2550 Users and libraries can define their own layout engines and pass 

2551 the instance directly as well. 

2552 

2553 kwargs: dict 

2554 The keyword arguments are passed to the layout engine to set things 

2555 like padding and margin sizes. Only used if *layout* is a string. 

2556 

2557 """ 

2558 if layout is None: 

2559 if mpl.rcParams['figure.autolayout']: 

2560 layout = 'tight' 

2561 elif mpl.rcParams['figure.constrained_layout.use']: 

2562 layout = 'constrained' 

2563 else: 

2564 self._layout_engine = None 

2565 return 

2566 if layout == 'tight': 

2567 new_layout_engine = TightLayoutEngine(**kwargs) 

2568 elif layout == 'constrained': 

2569 new_layout_engine = ConstrainedLayoutEngine(**kwargs) 

2570 elif layout == 'compressed': 

2571 new_layout_engine = ConstrainedLayoutEngine(compress=True, 

2572 **kwargs) 

2573 elif layout == 'none': 

2574 if self._layout_engine is not None: 

2575 new_layout_engine = PlaceHolderLayoutEngine( 

2576 self._layout_engine.adjust_compatible, 

2577 self._layout_engine.colorbar_gridspec 

2578 ) 

2579 else: 

2580 new_layout_engine = None 

2581 elif isinstance(layout, LayoutEngine): 

2582 new_layout_engine = layout 

2583 else: 

2584 raise ValueError(f"Invalid value for 'layout': {layout!r}") 

2585 

2586 if self._check_layout_engines_compat(self._layout_engine, 

2587 new_layout_engine): 

2588 self._layout_engine = new_layout_engine 

2589 else: 

2590 raise RuntimeError('Colorbar layout of new layout engine not ' 

2591 'compatible with old engine, and a colorbar ' 

2592 'has been created. Engine not changed.') 

2593 

2594 def get_layout_engine(self): 

2595 return self._layout_engine 

2596 

2597 # TODO: I'd like to dynamically add the _repr_html_ method 

2598 # to the figure in the right context, but then IPython doesn't 

2599 # use it, for some reason. 

2600 

2601 def _repr_html_(self): 

2602 # We can't use "isinstance" here, because then we'd end up importing 

2603 # webagg unconditionally. 

2604 if 'WebAgg' in type(self.canvas).__name__: 

2605 from matplotlib.backends import backend_webagg 

2606 return backend_webagg.ipython_inline_display(self) 

2607 

2608 def show(self, warn=True): 

2609 """ 

2610 If using a GUI backend with pyplot, display the figure window. 

2611 

2612 If the figure was not created using `~.pyplot.figure`, it will lack 

2613 a `~.backend_bases.FigureManagerBase`, and this method will raise an 

2614 AttributeError. 

2615 

2616 .. warning:: 

2617 

2618 This does not manage an GUI event loop. Consequently, the figure 

2619 may only be shown briefly or not shown at all if you or your 

2620 environment are not managing an event loop. 

2621 

2622 Use cases for `.Figure.show` include running this from a GUI 

2623 application (where there is persistently an event loop running) or 

2624 from a shell, like IPython, that install an input hook to allow the 

2625 interactive shell to accept input while the figure is also being 

2626 shown and interactive. Some, but not all, GUI toolkits will 

2627 register an input hook on import. See :ref:`cp_integration` for 

2628 more details. 

2629 

2630 If you're in a shell without input hook integration or executing a 

2631 python script, you should use `matplotlib.pyplot.show` with 

2632 ``block=True`` instead, which takes care of starting and running 

2633 the event loop for you. 

2634 

2635 Parameters 

2636 ---------- 

2637 warn : bool, default: True 

2638 If ``True`` and we are not running headless (i.e. on Linux with an 

2639 unset DISPLAY), issue warning when called on a non-GUI backend. 

2640 

2641 """ 

2642 if self.canvas.manager is None: 

2643 raise AttributeError( 

2644 "Figure.show works only for figures managed by pyplot, " 

2645 "normally created by pyplot.figure()") 

2646 try: 

2647 self.canvas.manager.show() 

2648 except NonGuiException as exc: 

2649 if warn: 

2650 _api.warn_external(str(exc)) 

2651 

2652 @property 

2653 def axes(self): 

2654 """ 

2655 List of Axes in the Figure. You can access and modify the Axes in the 

2656 Figure through this list. 

2657 

2658 Do not modify the list itself. Instead, use `~Figure.add_axes`, 

2659 `~.Figure.add_subplot` or `~.Figure.delaxes` to add or remove an Axes. 

2660 

2661 Note: The `.Figure.axes` property and `~.Figure.get_axes` method are 

2662 equivalent. 

2663 """ 

2664 return self._axstack.as_list() 

2665 

2666 get_axes = axes.fget 

2667 

2668 def _get_renderer(self): 

2669 if hasattr(self.canvas, 'get_renderer'): 

2670 return self.canvas.get_renderer() 

2671 else: 

2672 return _get_renderer(self) 

2673 

2674 def _get_dpi(self): 

2675 return self._dpi 

2676 

2677 def _set_dpi(self, dpi, forward=True): 

2678 """ 

2679 Parameters 

2680 ---------- 

2681 dpi : float 

2682 

2683 forward : bool 

2684 Passed on to `~.Figure.set_size_inches` 

2685 """ 

2686 if dpi == self._dpi: 

2687 # We don't want to cause undue events in backends. 

2688 return 

2689 self._dpi = dpi 

2690 self.dpi_scale_trans.clear().scale(dpi) 

2691 w, h = self.get_size_inches() 

2692 self.set_size_inches(w, h, forward=forward) 

2693 self._fig_callbacks.process('dpi_changed', self) 

2694 

2695 dpi = property(_get_dpi, _set_dpi, doc="The resolution in dots per inch.") 

2696 

2697 def get_tight_layout(self): 

2698 """Return whether `.tight_layout` is called when drawing.""" 

2699 return isinstance(self.get_layout_engine(), TightLayoutEngine) 

2700 

2701 @_api.deprecated("3.6", alternative="set_layout_engine", 

2702 pending=True) 

2703 def set_tight_layout(self, tight): 

2704 """ 

2705 [*Discouraged*] Set whether and how `.tight_layout` is called when 

2706 drawing. 

2707 

2708 .. admonition:: Discouraged 

2709 

2710 This method is discouraged in favor of `~.set_layout_engine`. 

2711 

2712 Parameters 

2713 ---------- 

2714 tight : bool or dict with keys "pad", "w_pad", "h_pad", "rect" or None 

2715 If a bool, sets whether to call `.tight_layout` upon drawing. 

2716 If ``None``, use :rc:`figure.autolayout` instead. 

2717 If a dict, pass it as kwargs to `.tight_layout`, overriding the 

2718 default paddings. 

2719 """ 

2720 if tight is None: 

2721 tight = mpl.rcParams['figure.autolayout'] 

2722 _tight_parameters = tight if isinstance(tight, dict) else {} 

2723 if bool(tight): 

2724 self.set_layout_engine(TightLayoutEngine(**_tight_parameters)) 

2725 self.stale = True 

2726 

2727 def get_constrained_layout(self): 

2728 """ 

2729 Return whether constrained layout is being used. 

2730 

2731 See :doc:`/tutorials/intermediate/constrainedlayout_guide`. 

2732 """ 

2733 return isinstance(self.get_layout_engine(), ConstrainedLayoutEngine) 

2734 

2735 @_api.deprecated("3.6", alternative="set_layout_engine('constrained')", 

2736 pending=True) 

2737 def set_constrained_layout(self, constrained): 

2738 """ 

2739 [*Discouraged*] Set whether ``constrained_layout`` is used upon 

2740 drawing. 

2741 

2742 If None, :rc:`figure.constrained_layout.use` value will be used. 

2743 

2744 When providing a dict containing the keys ``w_pad``, ``h_pad`` 

2745 the default ``constrained_layout`` paddings will be 

2746 overridden. These pads are in inches and default to 3.0/72.0. 

2747 ``w_pad`` is the width padding and ``h_pad`` is the height padding. 

2748 

2749 .. admonition:: Discouraged 

2750 

2751 This method is discouraged in favor of `~.set_layout_engine`. 

2752 

2753 Parameters 

2754 ---------- 

2755 constrained : bool or dict or None 

2756 """ 

2757 if constrained is None: 

2758 constrained = mpl.rcParams['figure.constrained_layout.use'] 

2759 _constrained = bool(constrained) 

2760 _parameters = constrained if isinstance(constrained, dict) else {} 

2761 if _constrained: 

2762 self.set_layout_engine(ConstrainedLayoutEngine(**_parameters)) 

2763 self.stale = True 

2764 

2765 @_api.deprecated( 

2766 "3.6", alternative="figure.get_layout_engine().set()", 

2767 pending=True) 

2768 def set_constrained_layout_pads(self, **kwargs): 

2769 """ 

2770 Set padding for ``constrained_layout``. 

2771 

2772 Tip: The parameters can be passed from a dictionary by using 

2773 ``fig.set_constrained_layout(**pad_dict)``. 

2774 

2775 See :doc:`/tutorials/intermediate/constrainedlayout_guide`. 

2776 

2777 Parameters 

2778 ---------- 

2779 w_pad : float, default: :rc:`figure.constrained_layout.w_pad` 

2780 Width padding in inches. This is the pad around Axes 

2781 and is meant to make sure there is enough room for fonts to 

2782 look good. Defaults to 3 pts = 0.04167 inches 

2783 

2784 h_pad : float, default: :rc:`figure.constrained_layout.h_pad` 

2785 Height padding in inches. Defaults to 3 pts. 

2786 

2787 wspace : float, default: :rc:`figure.constrained_layout.wspace` 

2788 Width padding between subplots, expressed as a fraction of the 

2789 subplot width. The total padding ends up being w_pad + wspace. 

2790 

2791 hspace : float, default: :rc:`figure.constrained_layout.hspace` 

2792 Height padding between subplots, expressed as a fraction of the 

2793 subplot width. The total padding ends up being h_pad + hspace. 

2794 

2795 """ 

2796 if isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): 

2797 self.get_layout_engine().set(**kwargs) 

2798 

2799 @_api.deprecated("3.6", alternative="fig.get_layout_engine().get()", 

2800 pending=True) 

2801 def get_constrained_layout_pads(self, relative=False): 

2802 """ 

2803 Get padding for ``constrained_layout``. 

2804 

2805 Returns a list of ``w_pad, h_pad`` in inches and 

2806 ``wspace`` and ``hspace`` as fractions of the subplot. 

2807 All values are None if ``constrained_layout`` is not used. 

2808 

2809 See :doc:`/tutorials/intermediate/constrainedlayout_guide`. 

2810 

2811 Parameters 

2812 ---------- 

2813 relative : bool 

2814 If `True`, then convert from inches to figure relative. 

2815 """ 

2816 if not isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): 

2817 return None, None, None, None 

2818 info = self.get_layout_engine().get_info() 

2819 w_pad = info['w_pad'] 

2820 h_pad = info['h_pad'] 

2821 wspace = info['wspace'] 

2822 hspace = info['hspace'] 

2823 

2824 if relative and (w_pad is not None or h_pad is not None): 

2825 renderer = self._get_renderer() 

2826 dpi = renderer.dpi 

2827 w_pad = w_pad * dpi / renderer.width 

2828 h_pad = h_pad * dpi / renderer.height 

2829 

2830 return w_pad, h_pad, wspace, hspace 

2831 

2832 def set_canvas(self, canvas): 

2833 """ 

2834 Set the canvas that contains the figure 

2835 

2836 Parameters 

2837 ---------- 

2838 canvas : FigureCanvas 

2839 """ 

2840 self.canvas = canvas 

2841 

2842 @_docstring.interpd 

2843 def figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, 

2844 vmin=None, vmax=None, origin=None, resize=False, **kwargs): 

2845 """ 

2846 Add a non-resampled image to the figure. 

2847 

2848 The image is attached to the lower or upper left corner depending on 

2849 *origin*. 

2850 

2851 Parameters 

2852 ---------- 

2853 X 

2854 The image data. This is an array of one of the following shapes: 

2855 

2856 - (M, N): an image with scalar data. Color-mapping is controlled 

2857 by *cmap*, *norm*, *vmin*, and *vmax*. 

2858 - (M, N, 3): an image with RGB values (0-1 float or 0-255 int). 

2859 - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), 

2860 i.e. including transparency. 

2861 

2862 xo, yo : int 

2863 The *x*/*y* image offset in pixels. 

2864 

2865 alpha : None or float 

2866 The alpha blending value. 

2867 

2868 %(cmap_doc)s 

2869 

2870 This parameter is ignored if *X* is RGB(A). 

2871 

2872 %(norm_doc)s 

2873 

2874 This parameter is ignored if *X* is RGB(A). 

2875 

2876 %(vmin_vmax_doc)s 

2877 

2878 This parameter is ignored if *X* is RGB(A). 

2879 

2880 origin : {'upper', 'lower'}, default: :rc:`image.origin` 

2881 Indicates where the [0, 0] index of the array is in the upper left 

2882 or lower left corner of the axes. 

2883 

2884 resize : bool 

2885 If *True*, resize the figure to match the given image size. 

2886 

2887 Returns 

2888 ------- 

2889 `matplotlib.image.FigureImage` 

2890 

2891 Other Parameters 

2892 ---------------- 

2893 **kwargs 

2894 Additional kwargs are `.Artist` kwargs passed on to `.FigureImage`. 

2895 

2896 Notes 

2897 ----- 

2898 figimage complements the Axes image (`~matplotlib.axes.Axes.imshow`) 

2899 which will be resampled to fit the current Axes. If you want 

2900 a resampled image to fill the entire figure, you can define an 

2901 `~matplotlib.axes.Axes` with extent [0, 0, 1, 1]. 

2902 

2903 Examples 

2904 -------- 

2905 :: 

2906 

2907 f = plt.figure() 

2908 nx = int(f.get_figwidth() * f.dpi) 

2909 ny = int(f.get_figheight() * f.dpi) 

2910 data = np.random.random((ny, nx)) 

2911 f.figimage(data) 

2912 plt.show() 

2913 """ 

2914 if resize: 

2915 dpi = self.get_dpi() 

2916 figsize = [x / dpi for x in (X.shape[1], X.shape[0])] 

2917 self.set_size_inches(figsize, forward=True) 

2918 

2919 im = mimage.FigureImage(self, cmap=cmap, norm=norm, 

2920 offsetx=xo, offsety=yo, 

2921 origin=origin, **kwargs) 

2922 im.stale_callback = _stale_figure_callback 

2923 

2924 im.set_array(X) 

2925 im.set_alpha(alpha) 

2926 if norm is None: 

2927 im.set_clim(vmin, vmax) 

2928 self.images.append(im) 

2929 im._remove_method = self.images.remove 

2930 self.stale = True 

2931 return im 

2932 

2933 def set_size_inches(self, w, h=None, forward=True): 

2934 """ 

2935 Set the figure size in inches. 

2936 

2937 Call signatures:: 

2938 

2939 fig.set_size_inches(w, h) # OR 

2940 fig.set_size_inches((w, h)) 

2941 

2942 Parameters 

2943 ---------- 

2944 w : (float, float) or float 

2945 Width and height in inches (if height not specified as a separate 

2946 argument) or width. 

2947 h : float 

2948 Height in inches. 

2949 forward : bool, default: True 

2950 If ``True``, the canvas size is automatically updated, e.g., 

2951 you can resize the figure window from the shell. 

2952 

2953 See Also 

2954 -------- 

2955 matplotlib.figure.Figure.get_size_inches 

2956 matplotlib.figure.Figure.set_figwidth 

2957 matplotlib.figure.Figure.set_figheight 

2958 

2959 Notes 

2960 ----- 

2961 To transform from pixels to inches divide by `Figure.dpi`. 

2962 """ 

2963 if h is None: # Got called with a single pair as argument. 

2964 w, h = w 

2965 size = np.array([w, h]) 

2966 if not np.isfinite(size).all() or (size < 0).any(): 

2967 raise ValueError(f'figure size must be positive finite not {size}') 

2968 self.bbox_inches.p1 = size 

2969 if forward: 

2970 manager = self.canvas.manager 

2971 if manager is not None: 

2972 manager.resize(*(size * self.dpi).astype(int)) 

2973 self.stale = True 

2974 

2975 def get_size_inches(self): 

2976 """ 

2977 Return the current size of the figure in inches. 

2978 

2979 Returns 

2980 ------- 

2981 ndarray 

2982 The size (width, height) of the figure in inches. 

2983 

2984 See Also 

2985 -------- 

2986 matplotlib.figure.Figure.set_size_inches 

2987 matplotlib.figure.Figure.get_figwidth 

2988 matplotlib.figure.Figure.get_figheight 

2989 

2990 Notes 

2991 ----- 

2992 The size in pixels can be obtained by multiplying with `Figure.dpi`. 

2993 """ 

2994 return np.array(self.bbox_inches.p1) 

2995 

2996 def get_figwidth(self): 

2997 """Return the figure width in inches.""" 

2998 return self.bbox_inches.width 

2999 

3000 def get_figheight(self): 

3001 """Return the figure height in inches.""" 

3002 return self.bbox_inches.height 

3003 

3004 def get_dpi(self): 

3005 """Return the resolution in dots per inch as a float.""" 

3006 return self.dpi 

3007 

3008 def set_dpi(self, val): 

3009 """ 

3010 Set the resolution of the figure in dots-per-inch. 

3011 

3012 Parameters 

3013 ---------- 

3014 val : float 

3015 """ 

3016 self.dpi = val 

3017 self.stale = True 

3018 

3019 def set_figwidth(self, val, forward=True): 

3020 """ 

3021 Set the width of the figure in inches. 

3022 

3023 Parameters 

3024 ---------- 

3025 val : float 

3026 forward : bool 

3027 See `set_size_inches`. 

3028 

3029 See Also 

3030 -------- 

3031 matplotlib.figure.Figure.set_figheight 

3032 matplotlib.figure.Figure.set_size_inches 

3033 """ 

3034 self.set_size_inches(val, self.get_figheight(), forward=forward) 

3035 

3036 def set_figheight(self, val, forward=True): 

3037 """ 

3038 Set the height of the figure in inches. 

3039 

3040 Parameters 

3041 ---------- 

3042 val : float 

3043 forward : bool 

3044 See `set_size_inches`. 

3045 

3046 See Also 

3047 -------- 

3048 matplotlib.figure.Figure.set_figwidth 

3049 matplotlib.figure.Figure.set_size_inches 

3050 """ 

3051 self.set_size_inches(self.get_figwidth(), val, forward=forward) 

3052 

3053 def clear(self, keep_observers=False): 

3054 # docstring inherited 

3055 super().clear(keep_observers=keep_observers) 

3056 # FigureBase.clear does not clear toolbars, as 

3057 # only Figure can have toolbars 

3058 toolbar = self.canvas.toolbar 

3059 if toolbar is not None: 

3060 toolbar.update() 

3061 

3062 @_finalize_rasterization 

3063 @allow_rasterization 

3064 def draw(self, renderer): 

3065 # docstring inherited 

3066 

3067 # draw the figure bounding box, perhaps none for white figure 

3068 if not self.get_visible(): 

3069 return 

3070 

3071 artists = self._get_draw_artists(renderer) 

3072 try: 

3073 renderer.open_group('figure', gid=self.get_gid()) 

3074 if self.axes and self.get_layout_engine() is not None: 

3075 try: 

3076 self.get_layout_engine().execute(self) 

3077 except ValueError: 

3078 pass 

3079 # ValueError can occur when resizing a window. 

3080 

3081 self.patch.draw(renderer) 

3082 mimage._draw_list_compositing_images( 

3083 renderer, self, artists, self.suppressComposite) 

3084 

3085 for sfig in self.subfigs: 

3086 sfig.draw(renderer) 

3087 

3088 renderer.close_group('figure') 

3089 finally: 

3090 self.stale = False 

3091 

3092 DrawEvent("draw_event", self.canvas, renderer)._process() 

3093 

3094 def draw_without_rendering(self): 

3095 """ 

3096 Draw the figure with no output. Useful to get the final size of 

3097 artists that require a draw before their size is known (e.g. text). 

3098 """ 

3099 renderer = _get_renderer(self) 

3100 with renderer._draw_disabled(): 

3101 self.draw(renderer) 

3102 

3103 def draw_artist(self, a): 

3104 """ 

3105 Draw `.Artist` *a* only. 

3106 """ 

3107 a.draw(self.canvas.get_renderer()) 

3108 

3109 def __getstate__(self): 

3110 state = super().__getstate__() 

3111 

3112 # The canvas cannot currently be pickled, but this has the benefit 

3113 # of meaning that a figure can be detached from one canvas, and 

3114 # re-attached to another. 

3115 state.pop("canvas") 

3116 

3117 # discard any changes to the dpi due to pixel ratio changes 

3118 state["_dpi"] = state.get('_original_dpi', state['_dpi']) 

3119 

3120 # add version information to the state 

3121 state['__mpl_version__'] = mpl.__version__ 

3122 

3123 # check whether the figure manager (if any) is registered with pyplot 

3124 from matplotlib import _pylab_helpers 

3125 if self.canvas.manager in _pylab_helpers.Gcf.figs.values(): 

3126 state['_restore_to_pylab'] = True 

3127 return state 

3128 

3129 def __setstate__(self, state): 

3130 version = state.pop('__mpl_version__') 

3131 restore_to_pylab = state.pop('_restore_to_pylab', False) 

3132 

3133 if version != mpl.__version__: 

3134 _api.warn_external( 

3135 f"This figure was saved with matplotlib version {version} and " 

3136 f"is unlikely to function correctly.") 

3137 

3138 self.__dict__ = state 

3139 

3140 # re-initialise some of the unstored state information 

3141 FigureCanvasBase(self) # Set self.canvas. 

3142 

3143 if restore_to_pylab: 

3144 # lazy import to avoid circularity 

3145 import matplotlib.pyplot as plt 

3146 import matplotlib._pylab_helpers as pylab_helpers 

3147 allnums = plt.get_fignums() 

3148 num = max(allnums) + 1 if allnums else 1 

3149 backend = plt._get_backend_mod() 

3150 mgr = backend.new_figure_manager_given_figure(num, self) 

3151 pylab_helpers.Gcf._set_new_active_manager(mgr) 

3152 plt.draw_if_interactive() 

3153 

3154 self.stale = True 

3155 

3156 def add_axobserver(self, func): 

3157 """Whenever the Axes state change, ``func(self)`` will be called.""" 

3158 # Connect a wrapper lambda and not func itself, to avoid it being 

3159 # weakref-collected. 

3160 self._axobservers.connect("_axes_change_event", lambda arg: func(arg)) 

3161 

3162 def savefig(self, fname, *, transparent=None, **kwargs): 

3163 """ 

3164 Save the current figure. 

3165 

3166 Call signature:: 

3167 

3168 savefig(fname, *, dpi='figure', format=None, metadata=None, 

3169 bbox_inches=None, pad_inches=0.1, 

3170 facecolor='auto', edgecolor='auto', 

3171 backend=None, **kwargs 

3172 ) 

3173 

3174 The available output formats depend on the backend being used. 

3175 

3176 Parameters 

3177 ---------- 

3178 fname : str or path-like or binary file-like 

3179 A path, or a Python file-like object, or 

3180 possibly some backend-dependent object such as 

3181 `matplotlib.backends.backend_pdf.PdfPages`. 

3182 

3183 If *format* is set, it determines the output format, and the file 

3184 is saved as *fname*. Note that *fname* is used verbatim, and there 

3185 is no attempt to make the extension, if any, of *fname* match 

3186 *format*, and no extension is appended. 

3187 

3188 If *format* is not set, then the format is inferred from the 

3189 extension of *fname*, if there is one. If *format* is not 

3190 set and *fname* has no extension, then the file is saved with 

3191 :rc:`savefig.format` and the appropriate extension is appended to 

3192 *fname*. 

3193 

3194 Other Parameters 

3195 ---------------- 

3196 dpi : float or 'figure', default: :rc:`savefig.dpi` 

3197 The resolution in dots per inch. If 'figure', use the figure's 

3198 dpi value. 

3199 

3200 format : str 

3201 The file format, e.g. 'png', 'pdf', 'svg', ... The behavior when 

3202 this is unset is documented under *fname*. 

3203 

3204 metadata : dict, optional 

3205 Key/value pairs to store in the image metadata. The supported keys 

3206 and defaults depend on the image format and backend: 

3207 

3208 - 'png' with Agg backend: See the parameter ``metadata`` of 

3209 `~.FigureCanvasAgg.print_png`. 

3210 - 'pdf' with pdf backend: See the parameter ``metadata`` of 

3211 `~.backend_pdf.PdfPages`. 

3212 - 'svg' with svg backend: See the parameter ``metadata`` of 

3213 `~.FigureCanvasSVG.print_svg`. 

3214 - 'eps' and 'ps' with PS backend: Only 'Creator' is supported. 

3215 

3216 bbox_inches : str or `.Bbox`, default: :rc:`savefig.bbox` 

3217 Bounding box in inches: only the given portion of the figure is 

3218 saved. If 'tight', try to figure out the tight bbox of the figure. 

3219 

3220 pad_inches : float, default: :rc:`savefig.pad_inches` 

3221 Amount of padding around the figure when bbox_inches is 'tight'. 

3222 

3223 facecolor : color or 'auto', default: :rc:`savefig.facecolor` 

3224 The facecolor of the figure. If 'auto', use the current figure 

3225 facecolor. 

3226 

3227 edgecolor : color or 'auto', default: :rc:`savefig.edgecolor` 

3228 The edgecolor of the figure. If 'auto', use the current figure 

3229 edgecolor. 

3230 

3231 backend : str, optional 

3232 Use a non-default backend to render the file, e.g. to render a 

3233 png file with the "cairo" backend rather than the default "agg", 

3234 or a pdf file with the "pgf" backend rather than the default 

3235 "pdf". Note that the default backend is normally sufficient. See 

3236 :ref:`the-builtin-backends` for a list of valid backends for each 

3237 file format. Custom backends can be referenced as "module://...". 

3238 

3239 orientation : {'landscape', 'portrait'} 

3240 Currently only supported by the postscript backend. 

3241 

3242 papertype : str 

3243 One of 'letter', 'legal', 'executive', 'ledger', 'a0' through 

3244 'a10', 'b0' through 'b10'. Only supported for postscript 

3245 output. 

3246 

3247 transparent : bool 

3248 If *True*, the Axes patches will all be transparent; the 

3249 Figure patch will also be transparent unless *facecolor* 

3250 and/or *edgecolor* are specified via kwargs. 

3251 

3252 If *False* has no effect and the color of the Axes and 

3253 Figure patches are unchanged (unless the Figure patch 

3254 is specified via the *facecolor* and/or *edgecolor* keyword 

3255 arguments in which case those colors are used). 

3256 

3257 The transparency of these patches will be restored to their 

3258 original values upon exit of this function. 

3259 

3260 This is useful, for example, for displaying 

3261 a plot on top of a colored background on a web page. 

3262 

3263 bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional 

3264 A list of extra artists that will be considered when the 

3265 tight bbox is calculated. 

3266 

3267 pil_kwargs : dict, optional 

3268 Additional keyword arguments that are passed to 

3269 `PIL.Image.Image.save` when saving the figure. 

3270 

3271 """ 

3272 

3273 kwargs.setdefault('dpi', mpl.rcParams['savefig.dpi']) 

3274 if transparent is None: 

3275 transparent = mpl.rcParams['savefig.transparent'] 

3276 

3277 with ExitStack() as stack: 

3278 if transparent: 

3279 kwargs.setdefault('facecolor', 'none') 

3280 kwargs.setdefault('edgecolor', 'none') 

3281 for ax in self.axes: 

3282 stack.enter_context( 

3283 ax.patch._cm_set(facecolor='none', edgecolor='none')) 

3284 

3285 self.canvas.print_figure(fname, **kwargs) 

3286 

3287 def ginput(self, n=1, timeout=30, show_clicks=True, 

3288 mouse_add=MouseButton.LEFT, 

3289 mouse_pop=MouseButton.RIGHT, 

3290 mouse_stop=MouseButton.MIDDLE): 

3291 """ 

3292 Blocking call to interact with a figure. 

3293 

3294 Wait until the user clicks *n* times on the figure, and return the 

3295 coordinates of each click in a list. 

3296 

3297 There are three possible interactions: 

3298 

3299 - Add a point. 

3300 - Remove the most recently added point. 

3301 - Stop the interaction and return the points added so far. 

3302 

3303 The actions are assigned to mouse buttons via the arguments 

3304 *mouse_add*, *mouse_pop* and *mouse_stop*. 

3305 

3306 Parameters 

3307 ---------- 

3308 n : int, default: 1 

3309 Number of mouse clicks to accumulate. If negative, accumulate 

3310 clicks until the input is terminated manually. 

3311 timeout : float, default: 30 seconds 

3312 Number of seconds to wait before timing out. If zero or negative 

3313 will never time out. 

3314 show_clicks : bool, default: True 

3315 If True, show a red cross at the location of each click. 

3316 mouse_add : `.MouseButton` or None, default: `.MouseButton.LEFT` 

3317 Mouse button used to add points. 

3318 mouse_pop : `.MouseButton` or None, default: `.MouseButton.RIGHT` 

3319 Mouse button used to remove the most recently added point. 

3320 mouse_stop : `.MouseButton` or None, default: `.MouseButton.MIDDLE` 

3321 Mouse button used to stop input. 

3322 

3323 Returns 

3324 ------- 

3325 list of tuples 

3326 A list of the clicked (x, y) coordinates. 

3327 

3328 Notes 

3329 ----- 

3330 The keyboard can also be used to select points in case your mouse 

3331 does not have one or more of the buttons. The delete and backspace 

3332 keys act like right-clicking (i.e., remove last point), the enter key 

3333 terminates input and any other key (not already used by the window 

3334 manager) selects a point. 

3335 """ 

3336 clicks = [] 

3337 marks = [] 

3338 

3339 def handler(event): 

3340 is_button = event.name == "button_press_event" 

3341 is_key = event.name == "key_press_event" 

3342 # Quit (even if not in infinite mode; this is consistent with 

3343 # MATLAB and sometimes quite useful, but will require the user to 

3344 # test how many points were actually returned before using data). 

3345 if (is_button and event.button == mouse_stop 

3346 or is_key and event.key in ["escape", "enter"]): 

3347 self.canvas.stop_event_loop() 

3348 # Pop last click. 

3349 elif (is_button and event.button == mouse_pop 

3350 or is_key and event.key in ["backspace", "delete"]): 

3351 if clicks: 

3352 clicks.pop() 

3353 if show_clicks: 

3354 marks.pop().remove() 

3355 self.canvas.draw() 

3356 # Add new click. 

3357 elif (is_button and event.button == mouse_add 

3358 # On macOS/gtk, some keys return None. 

3359 or is_key and event.key is not None): 

3360 if event.inaxes: 

3361 clicks.append((event.xdata, event.ydata)) 

3362 _log.info("input %i: %f, %f", 

3363 len(clicks), event.xdata, event.ydata) 

3364 if show_clicks: 

3365 line = mpl.lines.Line2D([event.xdata], [event.ydata], 

3366 marker="+", color="r") 

3367 event.inaxes.add_line(line) 

3368 marks.append(line) 

3369 self.canvas.draw() 

3370 if len(clicks) == n and n > 0: 

3371 self.canvas.stop_event_loop() 

3372 

3373 _blocking_input.blocking_input_loop( 

3374 self, ["button_press_event", "key_press_event"], timeout, handler) 

3375 

3376 # Cleanup. 

3377 for mark in marks: 

3378 mark.remove() 

3379 self.canvas.draw() 

3380 

3381 return clicks 

3382 

3383 def waitforbuttonpress(self, timeout=-1): 

3384 """ 

3385 Blocking call to interact with the figure. 

3386 

3387 Wait for user input and return True if a key was pressed, False if a 

3388 mouse button was pressed and None if no input was given within 

3389 *timeout* seconds. Negative values deactivate *timeout*. 

3390 """ 

3391 event = None 

3392 

3393 def handler(ev): 

3394 nonlocal event 

3395 event = ev 

3396 self.canvas.stop_event_loop() 

3397 

3398 _blocking_input.blocking_input_loop( 

3399 self, ["button_press_event", "key_press_event"], timeout, handler) 

3400 

3401 return None if event is None else event.name == "key_press_event" 

3402 

3403 @_api.deprecated("3.6", alternative="figure.get_layout_engine().execute()") 

3404 def execute_constrained_layout(self, renderer=None): 

3405 """ 

3406 Use ``layoutgrid`` to determine pos positions within Axes. 

3407 

3408 See also `.set_constrained_layout_pads`. 

3409 

3410 Returns 

3411 ------- 

3412 layoutgrid : private debugging object 

3413 """ 

3414 if not isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): 

3415 return None 

3416 return self.get_layout_engine().execute(self) 

3417 

3418 def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None): 

3419 """ 

3420 Adjust the padding between and around subplots. 

3421 

3422 To exclude an artist on the Axes from the bounding box calculation 

3423 that determines the subplot parameters (i.e. legend, or annotation), 

3424 set ``a.set_in_layout(False)`` for that artist. 

3425 

3426 Parameters 

3427 ---------- 

3428 pad : float, default: 1.08 

3429 Padding between the figure edge and the edges of subplots, 

3430 as a fraction of the font size. 

3431 h_pad, w_pad : float, default: *pad* 

3432 Padding (height/width) between edges of adjacent subplots, 

3433 as a fraction of the font size. 

3434 rect : tuple (left, bottom, right, top), default: (0, 0, 1, 1) 

3435 A rectangle in normalized figure coordinates into which the whole 

3436 subplots area (including labels) will fit. 

3437 

3438 See Also 

3439 -------- 

3440 .Figure.set_layout_engine 

3441 .pyplot.tight_layout 

3442 """ 

3443 # note that here we do not permanently set the figures engine to 

3444 # tight_layout but rather just perform the layout in place and remove 

3445 # any previous engines. 

3446 engine = TightLayoutEngine(pad=pad, h_pad=h_pad, w_pad=w_pad, 

3447 rect=rect) 

3448 try: 

3449 self.set_layout_engine(engine) 

3450 engine.execute(self) 

3451 finally: 

3452 self.set_layout_engine(None) 

3453 

3454 

3455def figaspect(arg): 

3456 """ 

3457 Calculate the width and height for a figure with a specified aspect ratio. 

3458 

3459 While the height is taken from :rc:`figure.figsize`, the width is 

3460 adjusted to match the desired aspect ratio. Additionally, it is ensured 

3461 that the width is in the range [4., 16.] and the height is in the range 

3462 [2., 16.]. If necessary, the default height is adjusted to ensure this. 

3463 

3464 Parameters 

3465 ---------- 

3466 arg : float or 2D array 

3467 If a float, this defines the aspect ratio (i.e. the ratio height / 

3468 width). 

3469 In case of an array the aspect ratio is number of rows / number of 

3470 columns, so that the array could be fitted in the figure undistorted. 

3471 

3472 Returns 

3473 ------- 

3474 width, height : float 

3475 The figure size in inches. 

3476 

3477 Notes 

3478 ----- 

3479 If you want to create an Axes within the figure, that still preserves the 

3480 aspect ratio, be sure to create it with equal width and height. See 

3481 examples below. 

3482 

3483 Thanks to Fernando Perez for this function. 

3484 

3485 Examples 

3486 -------- 

3487 Make a figure twice as tall as it is wide:: 

3488 

3489 w, h = figaspect(2.) 

3490 fig = Figure(figsize=(w, h)) 

3491 ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) 

3492 ax.imshow(A, **kwargs) 

3493 

3494 Make a figure with the proper aspect for an array:: 

3495 

3496 A = rand(5, 3) 

3497 w, h = figaspect(A) 

3498 fig = Figure(figsize=(w, h)) 

3499 ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) 

3500 ax.imshow(A, **kwargs) 

3501 """ 

3502 

3503 isarray = hasattr(arg, 'shape') and not np.isscalar(arg) 

3504 

3505 # min/max sizes to respect when autoscaling. If John likes the idea, they 

3506 # could become rc parameters, for now they're hardwired. 

3507 figsize_min = np.array((4.0, 2.0)) # min length for width/height 

3508 figsize_max = np.array((16.0, 16.0)) # max length for width/height 

3509 

3510 # Extract the aspect ratio of the array 

3511 if isarray: 

3512 nr, nc = arg.shape[:2] 

3513 arr_ratio = nr / nc 

3514 else: 

3515 arr_ratio = arg 

3516 

3517 # Height of user figure defaults 

3518 fig_height = mpl.rcParams['figure.figsize'][1] 

3519 

3520 # New size for the figure, keeping the aspect ratio of the caller 

3521 newsize = np.array((fig_height / arr_ratio, fig_height)) 

3522 

3523 # Sanity checks, don't drop either dimension below figsize_min 

3524 newsize /= min(1.0, *(newsize / figsize_min)) 

3525 

3526 # Avoid humongous windows as well 

3527 newsize /= max(1.0, *(newsize / figsize_max)) 

3528 

3529 # Finally, if we have a really funky aspect ratio, break it but respect 

3530 # the min/max dimensions (we don't want figures 10 feet tall!) 

3531 newsize = np.clip(newsize, figsize_min, figsize_max) 

3532 return newsize