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 +1 -0
- faceted/examples/basic-grid-example.png +0 -0
- faceted/examples/cartopy-example-sharex-row.png +0 -0
- faceted/examples/cartopy-example.png +0 -0
- faceted/examples/colorbar-grid-example.png +0 -0
- faceted/examples/multi-colorbar-grid-example.png +0 -0
- faceted/faceted.py +639 -0
- faceted/tests/__init__.py +0 -0
- faceted/tests/test_faceted.py +696 -0
- faceted-0.2.2.dist-info/METADATA +122 -0
- faceted-0.2.2.dist-info/RECORD +14 -0
- faceted-0.2.2.dist-info/WHEEL +5 -0
- faceted-0.2.2.dist-info/licenses/LICENSE +21 -0
- faceted-0.2.2.dist-info/top_level.txt +1 -0
faceted/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .faceted import __version__, faceted, faceted_ax # noqa: F401
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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
|