|
15 | 15 |
|
16 | 16 | import copy
|
17 | 17 | import logging
|
| 18 | +from numbers import Integral |
18 | 19 |
|
19 | 20 | import numpy as np
|
20 | 21 |
|
@@ -316,6 +317,125 @@ def get_subplot_params(self, figure=None):
|
316 | 317 | def locally_modified_subplot_params(self):
|
317 | 318 | return [k for k in self._AllowedKeys if getattr(self, k)]
|
318 | 319 |
|
| 320 | + def subplots(self, sharex=False, sharey=False, squeeze=True, |
| 321 | + subplot_kw=None): |
| 322 | + """ |
| 323 | + Add all subplots specified by this `GridSpec` to its parent figure. |
| 324 | +
|
| 325 | + This utility wrapper makes it convenient to create common layouts of |
| 326 | + subplots in a single call. |
| 327 | +
|
| 328 | + Parameters |
| 329 | + ---------- |
| 330 | + sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False |
| 331 | + Controls sharing of properties among x (`sharex`) or y (`sharey`) |
| 332 | + axes: |
| 333 | +
|
| 334 | + - True or 'all': x- or y-axis will be shared among all |
| 335 | + subplots. |
| 336 | + - False or 'none': each subplot x- or y-axis will be |
| 337 | + independent. |
| 338 | + - 'row': each subplot row will share an x- or y-axis. |
| 339 | + - 'col': each subplot column will share an x- or y-axis. |
| 340 | +
|
| 341 | + When subplots have a shared x-axis along a column, only the x tick |
| 342 | + labels of the bottom subplot are created. Similarly, when subplots |
| 343 | + have a shared y-axis along a row, only the y tick labels of the |
| 344 | + first column subplot are created. To later turn other subplots' |
| 345 | + ticklabels on, use `~matplotlib.axes.Axes.tick_params`. |
| 346 | +
|
| 347 | + squeeze : bool, optional, default: True |
| 348 | + - If True, extra dimensions are squeezed out from the returned |
| 349 | + array of Axes: |
| 350 | +
|
| 351 | + - if only one subplot is constructed (nrows=ncols=1), the |
| 352 | + resulting single Axes object is returned as a scalar. |
| 353 | + - for Nx1 or 1xM subplots, the returned object is a 1D numpy |
| 354 | + object array of Axes objects. |
| 355 | + - for NxM, subplots with N>1 and M>1 are returned |
| 356 | + as a 2D array. |
| 357 | +
|
| 358 | + - If False, no squeezing at all is done: the returned Axes object |
| 359 | + is always a 2D array containing Axes instances, even if it ends |
| 360 | + up being 1x1. |
| 361 | +
|
| 362 | + subplot_kw : dict, optional |
| 363 | + Dict with keywords passed to the |
| 364 | + :meth:`~matplotlib.figure.Figure.add_subplot` call used to create |
| 365 | + each subplot. |
| 366 | +
|
| 367 | + Returns |
| 368 | + ------- |
| 369 | + ax : `~.axes.Axes` object or array of Axes objects. |
| 370 | + *ax* can be either a single `~matplotlib.axes.Axes` object or |
| 371 | + an array of Axes objects if more than one subplot was created. The |
| 372 | + dimensions of the resulting array can be controlled with the |
| 373 | + squeeze keyword, see above. |
| 374 | +
|
| 375 | + See Also |
| 376 | + -------- |
| 377 | + .pyplot.subplots |
| 378 | + .Figure.add_subplot |
| 379 | + .pyplot.subplot |
| 380 | + """ |
| 381 | + |
| 382 | + if self.figure is None: |
| 383 | + raise ValueError("GridSpec.subplots() only works for GridSpecs " |
| 384 | + "created with a parent figure") |
| 385 | + |
| 386 | + if isinstance(sharex, bool): |
| 387 | + sharex = "all" if sharex else "none" |
| 388 | + if isinstance(sharey, bool): |
| 389 | + sharey = "all" if sharey else "none" |
| 390 | + # This check was added because it is very easy to type |
| 391 | + # `subplots(1, 2, 1)` when `subplot(1, 2, 1)` was intended. |
| 392 | + # In most cases, no error will ever occur, but mysterious behavior |
| 393 | + # will result because what was intended to be the subplot index is |
| 394 | + # instead treated as a bool for sharex. |
| 395 | + if isinstance(sharex, Integral): |
| 396 | + cbook._warn_external( |
| 397 | + "sharex argument to subplots() was an integer. Did you " |
| 398 | + "intend to use subplot() (without 's')?") |
| 399 | + cbook._check_in_list(["all", "row", "col", "none"], |
| 400 | + sharex=sharex, sharey=sharey) |
| 401 | + if subplot_kw is None: |
| 402 | + subplot_kw = {} |
| 403 | + # don't mutate kwargs passed by user... |
| 404 | + subplot_kw = subplot_kw.copy() |
| 405 | + |
| 406 | + # Create array to hold all axes. |
| 407 | + axarr = np.empty((self._nrows, self._ncols), dtype=object) |
| 408 | + for row in range(self._nrows): |
| 409 | + for col in range(self._ncols): |
| 410 | + shared_with = {"none": None, "all": axarr[0, 0], |
| 411 | + "row": axarr[row, 0], "col": axarr[0, col]} |
| 412 | + subplot_kw["sharex"] = shared_with[sharex] |
| 413 | + subplot_kw["sharey"] = shared_with[sharey] |
| 414 | + axarr[row, col] = self.figure.add_subplot( |
| 415 | + self[row, col], **subplot_kw) |
| 416 | + |
| 417 | + # turn off redundant tick labeling |
| 418 | + if sharex in ["col", "all"]: |
| 419 | + # turn off all but the bottom row |
| 420 | + for ax in axarr[:-1, :].flat: |
| 421 | + ax.xaxis.set_tick_params(which='both', |
| 422 | + labelbottom=False, labeltop=False) |
| 423 | + ax.xaxis.offsetText.set_visible(False) |
| 424 | + if sharey in ["row", "all"]: |
| 425 | + # turn off all but the first column |
| 426 | + for ax in axarr[:, 1:].flat: |
| 427 | + ax.yaxis.set_tick_params(which='both', |
| 428 | + labelleft=False, labelright=False) |
| 429 | + ax.yaxis.offsetText.set_visible(False) |
| 430 | + |
| 431 | + if squeeze: |
| 432 | + # Discarding unneeded dimensions that equal 1. If we only have one |
| 433 | + # subplot, just return it instead of a 1-element array. |
| 434 | + return axarr.item() if axarr.size == 1 else axarr.squeeze() |
| 435 | + else: |
| 436 | + # Returned axis array will be always 2-d, even if nrows=ncols=1. |
| 437 | + return axarr |
| 438 | + |
319 | 439 | def tight_layout(self, figure, renderer=None,
|
320 | 440 | pad=1.08, h_pad=None, w_pad=None, rect=None):
|
321 | 441 | """
|
|
0 commit comments