faceted 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
faceted/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .faceted import __version__, faceted, faceted_ax # noqa: F401
Binary file
Binary file
faceted/faceted.py ADDED
@@ -0,0 +1,639 @@
1
+ from itertools import product
2
+
3
+ import matplotlib
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ from packaging.version import Version
7
+
8
+ from mpl_toolkits.axes_grid1 import AxesGrid
9
+
10
+
11
+ __version__ = "0.2.2"
12
+
13
+
14
+ def faceted(
15
+ rows,
16
+ cols,
17
+ width=None,
18
+ height=None,
19
+ aspect=None,
20
+ top_pad=0.25,
21
+ bottom_pad=0.25,
22
+ left_pad=0.25,
23
+ right_pad=0.25,
24
+ internal_pad=0.33,
25
+ cbar_mode=None,
26
+ cbar_short_side_pad=0.0,
27
+ cbar_pad=0.5,
28
+ cbar_size=0.125,
29
+ cbar_location="right",
30
+ sharex="all",
31
+ sharey="all",
32
+ axes_kwargs=None,
33
+ ):
34
+ """Create figure and tiled axes objects with precise attributes.
35
+
36
+ In general exactly two of width, height, and aspect should be defined.
37
+ However, if none or one of them are defined then reasonable defaults are
38
+ selected:
39
+
40
+ - If none are provided the width is assumed to be ``8.0`` inches and the
41
+ aspect is assumed to be ``0.618``.
42
+ - If only a ``width`` is provided, the ``aspect`` is assumed to be
43
+ ``0.618``.
44
+ - If only a ``height`` is provided, the ``aspect`` is assumed to be
45
+ ``0.618``.
46
+ - If only an ``aspect`` is provided, the ``width`` is assumed to be ``8.0``
47
+ inches.
48
+
49
+ Parameters
50
+ ----------
51
+ rows : int
52
+ Number of rows of tiles in figure
53
+ cols : int
54
+ Number of columns of tiles in figure
55
+ width : float
56
+ Width of figure
57
+ height : float
58
+ Height of figure
59
+ aspect : float
60
+ Aspect ratio of plots in each tile
61
+ top_pad : float
62
+ Spacing (in inches) between top of figure and axes
63
+ bottom_pad : float
64
+ Spacing (in inches) between bottom of figure and axes
65
+ left_pad : float
66
+ Spacing (in inches) between left of figure and axes
67
+ right_pad : float
68
+ Spacing (in inches) between right of figure and axes
69
+ internal_pad : float or tuple
70
+ Spacing in between panels in both the horizontal and vertical
71
+ directions (in inches); if an individual number, the spacing is the
72
+ same in the horizontal and vertical; if a tuple is specified, the left
73
+ value is the horizontal pad, and the right value is the vertical pad.
74
+ cbar_mode : {None, 'single', 'edge', 'each'}
75
+ Mode for adding colorbar(s) to figure
76
+ cbar_short_side_pad : float
77
+ Spacing between the ends of the colorbar and the edges
78
+ of the axes (in inches); controls the length of the
79
+ colorbar
80
+ cbar_pad : float
81
+ Spacing between plot axes and the colorbar axes (in inches)
82
+ cbar_size : float
83
+ Width of the colorbar in inches
84
+ cbar_location : {'top', 'bottom', 'left', 'right'}
85
+ Side of the plot axes (or figure) for the colorbar
86
+ sharex : bool or {'all', 'col', 'row', 'none'}
87
+ Share x-axis limits, ticks, and tick labels
88
+ sharey : bool or {'all', 'col', 'row', 'none'}
89
+ Share y-axis limits, ticks, and tick labels
90
+ axes_kwargs : dict
91
+ Keyword arguments to pass to Axes constructor
92
+
93
+ Returns
94
+ -------
95
+ fig, axes, caxes (if caxes requested)
96
+ """
97
+ if isinstance(internal_pad, (float, int)):
98
+ internal_pad = (internal_pad, internal_pad)
99
+ if len(internal_pad) != 2:
100
+ raise ValueError(
101
+ "Invalid internal pad provided; it must either be a "
102
+ "float or a sequence of two values. Got "
103
+ "{}".format(internal_pad)
104
+ )
105
+ if cbar_mode not in [None, "single", "edge", "each"]:
106
+ raise ValueError(f"Invalid cbar mode provided. Got {cbar_mode}.")
107
+
108
+ width, height, aspect = _infer_constraints(width, height, aspect)
109
+ grid_class = _infer_grid_class(width, height, aspect)
110
+ grid = grid_class(
111
+ rows,
112
+ cols,
113
+ width=width,
114
+ height=height,
115
+ aspect=aspect,
116
+ top_pad=top_pad,
117
+ bottom_pad=bottom_pad,
118
+ left_pad=left_pad,
119
+ right_pad=right_pad,
120
+ cbar_mode=cbar_mode,
121
+ cbar_location=cbar_location,
122
+ cbar_pad=cbar_pad,
123
+ cbar_size=cbar_size,
124
+ cbar_short_side_pad=cbar_short_side_pad,
125
+ axes_pad=internal_pad,
126
+ sharex=sharex,
127
+ sharey=sharey,
128
+ axes_kwargs=axes_kwargs,
129
+ )
130
+ if cbar_mode is None:
131
+ return grid.fig, grid.axes
132
+ elif cbar_mode in ["each", "edge", "single"]:
133
+ return grid.fig, grid.axes, grid.caxes
134
+
135
+
136
+ def faceted_ax(cbar_mode=None, **kwargs):
137
+ """A convenience version of faceted for creating single-axis figures.
138
+
139
+ In general exactly two of width, height, and aspect should be defined.
140
+ However, if none or one of them are defined then reasonable defaults are
141
+ selected:
142
+
143
+ - If none are provided the width is assumed to be ``8.0`` inches and the
144
+ aspect is assumed to be ``0.618``.
145
+ - If only a ``width`` is provided, the ``aspect`` is assumed to be
146
+ ``0.618``.
147
+ - If only a ``height`` is provided, the ``aspect`` is assumed to be
148
+ ``0.618``.
149
+ - If only an ``aspect`` is provided, the ``width`` is assumed to be ``8.0``
150
+ inches.
151
+
152
+ Parameters
153
+ ----------
154
+ width : float
155
+ Width of figure
156
+ height : float
157
+ Height of figure
158
+ aspect : float
159
+ Aspect ratio of plots in each tile
160
+ top_pad : float
161
+ Spacing (in inches) between top of figure and axes
162
+ bottom_pad : float
163
+ Spacing (in inches) between bottom of figure and axes
164
+ left_pad : float
165
+ Spacing (in inches) between left of figure and axes
166
+ right_pad : float
167
+ Spacing (in inches) between right of figure and axes
168
+ internal_pad : float or tuple
169
+ Spacing in between panels in both the horizontal and vertical
170
+ directions (in inches); if an individual number, the spacing is the
171
+ same in the horizontal and vertical; if a tuple is specified, the left
172
+ value is the horizontal pad, and the right value is the vertical pad.
173
+ cbar_mode : {None, 'single', 'edge', 'each'}
174
+ Mode for adding colorbar(s) to figure
175
+ cbar_short_side_pad : float
176
+ Spacing between the ends of the colorbar and the edges
177
+ of the axes (in inches); controls the length of the
178
+ colorbar
179
+ cbar_pad : float
180
+ Spacing between plot axes and the colorbar axes (in inches)
181
+ cbar_size : float
182
+ Width of the colorbar in inches
183
+ cbar_location : {'top', 'bottom', 'left', 'right'}
184
+ Side of the plot axes (or figure) for the colorbar
185
+ sharex : bool or {'all', 'col', 'row', 'none'}
186
+ Share x-axis limits, ticks, and tick labels
187
+ sharey : bool or {'all', 'col', 'row', 'none'}
188
+ Share y-axis limits, ticks, and tick labels
189
+ axes_kwargs : dict
190
+ Keyword arguments to pass to Axes constructor
191
+
192
+ Returns
193
+ -------
194
+ fig, ax, cax (if cax requested)
195
+ """
196
+ if cbar_mode is None:
197
+ fig, (ax,) = faceted(1, 1, **kwargs)
198
+ return fig, ax
199
+ elif cbar_mode == "single":
200
+ fig, (ax,), cax = faceted(1, 1, cbar_mode=cbar_mode, **kwargs)
201
+ return fig, ax, cax
202
+ elif cbar_mode in ("edge", "each"):
203
+ fig, (ax,), (cax,) = faceted(1, 1, cbar_mode=cbar_mode, **kwargs)
204
+ return fig, ax, cax
205
+
206
+
207
+ _DEFAULT_WIDTH = 8.0
208
+ _DEFAULT_ASPECT = 0.618
209
+ _LR = ["left", "right"]
210
+ _BT = ["bottom", "top"]
211
+
212
+
213
+ def _infer_constraints(width, height, aspect):
214
+ if all(constraint is not None for constraint in (width, height, aspect)):
215
+ raise ValueError(
216
+ "At most two of 'width', 'height', and 'aspect' must be provided."
217
+ )
218
+ elif all(constraint is None for constraint in (width, height, aspect)):
219
+ return _DEFAULT_WIDTH, None, _DEFAULT_ASPECT
220
+ elif width is not None and height is None and aspect is None:
221
+ return width, None, _DEFAULT_ASPECT
222
+ elif height is not None and width is None and aspect is None:
223
+ return None, height, _DEFAULT_ASPECT
224
+ elif aspect is not None and width is None and height is None:
225
+ return _DEFAULT_WIDTH, None, aspect
226
+ else:
227
+ return width, height, aspect
228
+
229
+
230
+ def _infer_grid_class(width, height, aspect):
231
+ if width is not None and aspect is not None:
232
+ return WidthConstrainedAxesGrid
233
+ elif height is not None and aspect is not None:
234
+ return HeightConstrainedAxesGrid
235
+ else:
236
+ return HeightAndWidthConstrainedAxesGrid
237
+
238
+
239
+ class CbarShortSidePadMixin(object):
240
+ """Methods to redraw colorbar Axes created in AxesGrid, allowing for
241
+ customization of their length."""
242
+
243
+ def resize_colorbar(self, cax):
244
+ """Add a short-side pad to a given AxesGrid colorbar"""
245
+ locator = cax.get_axes_locator()
246
+ position = locator(cax, None)
247
+ cax.set_visible(False) # Maybe we should delete it completely?
248
+ new_position = self.cax_position(position)
249
+ return self.fig.add_axes(new_position)
250
+
251
+ def resize_colorbars(self):
252
+ """Depending on the cbar_mode resize colorbar(s) to accomodate
253
+ short-side pad option"""
254
+ if self.cbar_mode == "each":
255
+ return [self.resize_colorbar(cax) for cax in self.grid.cbar_axes]
256
+ elif self.cbar_mode == "edge":
257
+ return [
258
+ self.resize_colorbar(cax)
259
+ for cax in self.grid.cbar_axes
260
+ if cax.get_axes_locator() is not None
261
+ ]
262
+ elif self.cbar_mode == "single":
263
+ return self.resize_colorbar(self.grid.cbar_axes[0])
264
+ else:
265
+ return None
266
+
267
+ def cax_position(self, position):
268
+ """Compute a new colorbar position from an old one"""
269
+ if self.cbar_location in _BT:
270
+ x0 = position.x0 + self.cbar_short_side_pad / self.width
271
+ y0 = position.y0
272
+ width = position.width - 2.0 * self.cbar_short_side_pad / self.width
273
+ height = position.height
274
+ return [x0, y0, width, height]
275
+ elif self.cbar_location in _LR:
276
+ x0 = position.x0
277
+ y0 = position.y0 + self.cbar_short_side_pad / self.height
278
+ width = position.width
279
+ height = position.height - 2.0 * self.cbar_short_side_pad / self.height
280
+ return [x0, y0, width, height]
281
+
282
+
283
+ class ShareAxesMixin(object):
284
+ """Methods for redrawing axes created by an AxesGrid object
285
+
286
+ Enables axes sharing in the style of plt.subplots and for the passing of
287
+ custom keyword arguments to the Axes constructor (e.g. this allows one to
288
+ pass a cartopy projection).
289
+ """
290
+
291
+ @property
292
+ def sharex(self):
293
+ """The sharex mode of the object."""
294
+ if isinstance(self._sharex, bool):
295
+ result = "all" if self._sharex else "none"
296
+ else:
297
+ result = self._sharex
298
+ return result
299
+
300
+ @property
301
+ def sharey(self):
302
+ """The sharey mode of the object"""
303
+ if isinstance(self._sharey, bool):
304
+ result = "all" if self._sharey else "none"
305
+ else:
306
+ result = self._sharey
307
+ return result
308
+
309
+ def redraw_ax(self, ax, sharex=None, sharey=None, axes_kwargs={}):
310
+ """Redraw an Axes object created in AxesGrid with additional sharing
311
+ and keyword arguments."""
312
+ locator = ax.get_axes_locator()
313
+ position = locator(ax, None)
314
+ ax.set_visible(False)
315
+ return self.fig.add_axes(position, sharex=sharex, sharey=sharey, **axes_kwargs)
316
+
317
+ def redraw_axes(self):
318
+ """Redraw all Axes objects created in AxesGrid with appropriate shared
319
+ axes depending on the sharing modes."""
320
+ col_ref_axes = [None] * self.cols
321
+ row_ref_axes = [None] * self.rows
322
+ all_ref = None
323
+
324
+ axes = []
325
+ rows_cols = product(range(self.rows), range(self.cols))
326
+ for ax, (row, col) in zip(self.grid.axes_all, rows_cols):
327
+ if self.sharex == "all":
328
+ sharex = all_ref
329
+ elif self.sharex == "col":
330
+ sharex = col_ref_axes[col]
331
+ elif self.sharex == "row":
332
+ sharex = row_ref_axes[row]
333
+ else:
334
+ sharex = None
335
+
336
+ if self.sharey == "all":
337
+ sharey = all_ref
338
+ elif self.sharey == "col":
339
+ sharey = col_ref_axes[col]
340
+ elif self.sharey == "row":
341
+ sharey = row_ref_axes[row]
342
+ else:
343
+ sharey = None
344
+
345
+ new = self.redraw_ax(
346
+ ax, sharex=sharex, sharey=sharey, axes_kwargs=self.axes_kwargs
347
+ )
348
+ axes.append(new)
349
+ all_ref = new
350
+ col_ref_axes[col] = new
351
+ row_ref_axes[row] = new
352
+
353
+ return axes
354
+
355
+ def make_shared_ticklabels_invisible(self):
356
+ """Make inner Axes tick labels of shared Axes invisible."""
357
+ axes = np.reshape(self.axes, (self.rows, self.cols))
358
+ if self.sharex in ["col", "all"]:
359
+ for ax in axes[:-1, :].flatten():
360
+ ax.xaxis.set_tick_params(
361
+ which="both", labelbottom=False, labeltop=False
362
+ )
363
+
364
+ if self.sharey in ["row", "all"]:
365
+ for ax in axes[:, 1:].flatten():
366
+ ax.yaxis.set_tick_params(
367
+ which="both", labelbottom=False, labeltop=False
368
+ )
369
+
370
+
371
+ class ConstrainedAxesGrid(CbarShortSidePadMixin, ShareAxesMixin):
372
+ def __init__(
373
+ self,
374
+ rows,
375
+ cols,
376
+ width=None,
377
+ height=None,
378
+ aspect=None,
379
+ top_pad=0.0,
380
+ bottom_pad=0.0,
381
+ left_pad=0.0,
382
+ right_pad=0.0,
383
+ cbar_size=0.125,
384
+ cbar_pad=0.125,
385
+ axes_pad=(0.2, 0.2),
386
+ cbar_mode=None,
387
+ cbar_location="bottom",
388
+ cbar_short_side_pad=0.0,
389
+ sharex=False,
390
+ sharey=False,
391
+ axes_kwargs=None,
392
+ ):
393
+ self.rows = rows
394
+ self.cols = cols
395
+ self._width = width
396
+ self._height = height
397
+ self._aspect = aspect
398
+
399
+ self.axes_pad = axes_pad
400
+
401
+ self.top_pad = top_pad
402
+ self.bottom_pad = bottom_pad
403
+ self.left_pad = left_pad
404
+ self.right_pad = right_pad
405
+
406
+ self.cbar_mode = cbar_mode
407
+ self.cbar_size = cbar_size
408
+ self.cbar_pad = cbar_pad
409
+ self.cbar_location = cbar_location
410
+ self.cbar_short_side_pad = cbar_short_side_pad
411
+
412
+ self._sharex = sharex
413
+ self._sharey = sharey
414
+
415
+ if axes_kwargs is None:
416
+ self.axes_kwargs = {}
417
+ else:
418
+ self.axes_kwargs = axes_kwargs
419
+
420
+ self.construct_axes()
421
+
422
+ def construct_axes(self):
423
+ self.fig = plt.figure()
424
+ self.grid = AxesGrid(
425
+ self.fig,
426
+ self.rect,
427
+ nrows_ncols=(self.rows, self.cols),
428
+ cbar_size=self.cbar_size,
429
+ cbar_pad=self.axes_grid_cbar_pad,
430
+ axes_pad=self.axes_pad,
431
+ cbar_mode=self.cbar_mode,
432
+ cbar_location=self.cbar_location,
433
+ aspect=False,
434
+ )
435
+ self.fig.set_size_inches(self.width, self.height)
436
+ self.axes = self.redraw_axes()
437
+ self.make_shared_ticklabels_invisible()
438
+ self.caxes = self.resize_colorbars()
439
+
440
+ @property
441
+ def axes_grid_cbar_pad(self):
442
+ # Prior to matplotlib version 3.10.0, when the colorbar is placed at
443
+ # the bottom or left and the colorbar mode is "single", AxesGrid adds
444
+ # an extra axes pad to the colorbar padding; we correct this manually
445
+ # if needed here.
446
+ horizontal_pad, vertical_pad = self.axes_pad
447
+ cbar_pad = self.cbar_pad
448
+ if Version(matplotlib.__version__) < Version("3.10.0"):
449
+ if self.cbar_location == "bottom" and self.cbar_mode == "single":
450
+ cbar_pad = self.cbar_pad - vertical_pad
451
+ elif self.cbar_location == "left" and self.cbar_mode == "single":
452
+ cbar_pad = self.cbar_pad - horizontal_pad
453
+ return cbar_pad
454
+
455
+ @property
456
+ def rect(self):
457
+ """Compute the rect defining the area within the outer padding"""
458
+ x0 = self.left_pad / self.width
459
+ y0 = self.bottom_pad / self.height
460
+ width = (self.width - self.left_pad - self.right_pad) / self.width
461
+ height = (self.height - self.top_pad - self.bottom_pad) / self.height
462
+ return [x0, y0, width, height]
463
+
464
+
465
+ class WidthConstrainedAxesGrid(
466
+ ConstrainedAxesGrid, CbarShortSidePadMixin, ShareAxesMixin
467
+ ):
468
+ """An AxesGrid object with a figure constrained to a precise width
469
+ with panels with a prescribed aspect ratio.
470
+ """
471
+
472
+ @property
473
+ def plot_width(self):
474
+ """Width of plot area in each panel (in inches)"""
475
+ hpad, _ = self.axes_pad
476
+ inner_width = self.width - self.left_pad - self.right_pad
477
+ inner_pad = (self.cols - 1) * hpad
478
+ cbar_width = self.cbar_pad + self.cbar_size
479
+
480
+ if self.cbar_mode is None or self.cbar_location in _BT:
481
+ return (inner_width - inner_pad) / self.cols
482
+ elif self.cbar_mode == "each" and self.cbar_location in _LR:
483
+ return (inner_width - inner_pad - self.cols * cbar_width) / self.cols
484
+ elif (
485
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
486
+ ) and self.cbar_location in _LR:
487
+ return (inner_width - inner_pad - cbar_width) / self.cols
488
+
489
+ @property
490
+ def plot_height(self):
491
+ """Height of plot area in panel (in inches)"""
492
+ return self.plot_width * self.aspect
493
+
494
+ @property
495
+ def width(self):
496
+ """Width of the complete figure in inches"""
497
+ return self._width
498
+
499
+ @property
500
+ def aspect(self):
501
+ """Aspect ratio of each panel in the figure (height / width)"""
502
+ return self._aspect
503
+
504
+ @property
505
+ def height(self):
506
+ """Height of the complete figure in inches"""
507
+ _, vpad = self.axes_pad
508
+ total_plot_height = self.rows * self.plot_height
509
+ total_axes_pad = (self.rows - 1) * vpad
510
+ outer_pad = self.top_pad + self.bottom_pad
511
+ cbar_width = self.cbar_size + self.cbar_pad
512
+
513
+ if self.cbar_mode is None or self.cbar_location in _LR:
514
+ return total_plot_height + total_axes_pad + outer_pad
515
+ elif self.cbar_mode == "each" and self.cbar_location in _BT:
516
+ return (
517
+ total_plot_height + total_axes_pad + outer_pad + self.rows * cbar_width
518
+ )
519
+ elif (
520
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
521
+ ) and self.cbar_location in _BT:
522
+ return total_plot_height + total_axes_pad + outer_pad + cbar_width
523
+
524
+
525
+ class HeightConstrainedAxesGrid(
526
+ ConstrainedAxesGrid, CbarShortSidePadMixin, ShareAxesMixin
527
+ ):
528
+ """An AxesGrid object with a figure constrained to a precise height
529
+ with panels with a prescribed aspect ratio.
530
+ """
531
+
532
+ @property
533
+ def plot_height(self):
534
+ """Height of plot area in each panel (in inches)"""
535
+ _, vertical_pad = self.axes_pad
536
+ inner_height = self.height - self.bottom_pad - self.top_pad
537
+ inner_pad = (self.rows - 1) * vertical_pad
538
+ cbar_width = self.cbar_pad + self.cbar_size
539
+
540
+ if self.cbar_mode is None or self.cbar_location in _LR:
541
+ return (inner_height - inner_pad) / self.rows
542
+ elif self.cbar_mode == "each" and self.cbar_location in _BT:
543
+ return (inner_height - inner_pad - self.rows * cbar_width) / self.rows
544
+ elif (
545
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
546
+ ) and self.cbar_location in _BT:
547
+ return (inner_height - inner_pad - cbar_width) / self.rows
548
+
549
+ @property
550
+ def plot_width(self):
551
+ """Width of plot area in panel (in inches)"""
552
+ return self.plot_height / self.aspect
553
+
554
+ @property
555
+ def height(self):
556
+ """Height of the complete figure in inches"""
557
+ return self._height
558
+
559
+ @property
560
+ def aspect(self):
561
+ """Aspect ratio of each panel in the figure (height / width)"""
562
+ return self._aspect
563
+
564
+ @property
565
+ def width(self):
566
+ """Width of the complete figure in inches"""
567
+ horizontal_pad, _ = self.axes_pad
568
+ total_plot_width = self.cols * self.plot_width
569
+ total_axes_pad = (self.cols - 1) * horizontal_pad
570
+ outer_pad = self.left_pad + self.right_pad
571
+ cbar_width = self.cbar_size + self.cbar_pad
572
+
573
+ if self.cbar_mode is None or self.cbar_location in _BT:
574
+ return total_plot_width + total_axes_pad + outer_pad
575
+ elif self.cbar_mode == "each" and self.cbar_location in _LR:
576
+ return (
577
+ total_plot_width + total_axes_pad + outer_pad + self.cols * cbar_width
578
+ )
579
+ elif (
580
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
581
+ ) and self.cbar_location in _LR:
582
+ return total_plot_width + total_axes_pad + outer_pad + cbar_width
583
+
584
+
585
+ class HeightAndWidthConstrainedAxesGrid(
586
+ ConstrainedAxesGrid, CbarShortSidePadMixin, ShareAxesMixin
587
+ ):
588
+ """An AxesGrid object with a figure constrained to a precise height and width
589
+ with panels with a flexible aspect ratio.
590
+ """
591
+
592
+ @property
593
+ def plot_width(self):
594
+ """Width of plot area in each panel (in inches)"""
595
+ hpad, _ = self.axes_pad
596
+ inner_width = self.width - self.left_pad - self.right_pad
597
+ inner_pad = (self.cols - 1) * hpad
598
+ cbar_width = self.cbar_pad + self.cbar_size
599
+
600
+ if self.cbar_mode is None or self.cbar_location in _BT:
601
+ return (inner_width - inner_pad) / self.cols
602
+ elif self.cbar_mode == "each" and self.cbar_location in _LR:
603
+ return (inner_width - inner_pad - self.cols * cbar_width) / self.cols
604
+ elif (
605
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
606
+ ) and self.cbar_location in _LR:
607
+ return (inner_width - inner_pad - cbar_width) / self.cols
608
+
609
+ @property
610
+ def plot_height(self):
611
+ """Height of plot area in each panel (in inches)"""
612
+ _, vertical_pad = self.axes_pad
613
+ inner_height = self.height - self.bottom_pad - self.top_pad
614
+ inner_pad = (self.rows - 1) * vertical_pad
615
+ cbar_width = self.cbar_pad + self.cbar_size
616
+
617
+ if self.cbar_mode is None or self.cbar_location in _LR:
618
+ return (inner_height - inner_pad) / self.rows
619
+ elif self.cbar_mode == "each" and self.cbar_location in _BT:
620
+ return (inner_height - inner_pad - self.rows * cbar_width) / self.rows
621
+ elif (
622
+ self.cbar_mode == "single" or self.cbar_mode == "edge"
623
+ ) and self.cbar_location in _BT:
624
+ return (inner_height - inner_pad - cbar_width) / self.rows
625
+
626
+ @property
627
+ def height(self):
628
+ """Height of the complete figure in inches"""
629
+ return self._height
630
+
631
+ @property
632
+ def width(self):
633
+ """Width of the complete figure in inches"""
634
+ return self._width
635
+
636
+ @property
637
+ def aspect(self):
638
+ """Aspect ratio of each panel in the figure (height / width)"""
639
+ return self.plot_height / self.plot_width
File without changes