Skip to content

Commit 3a10b77

Browse files
committed
Add option for creating inset SkewTs [UNTESTED]
1 parent 3743106 commit 3a10b77

File tree

2 files changed

+155
-3
lines changed

2 files changed

+155
-3
lines changed

src/metpy/_vendor/matplotlib.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Copyright (c) 2019 MetPy Developers.
2+
# Distributed under the terms of the BSD 3-Clause License.
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
"""Vendor core functionality used from matplotlib.
5+
6+
This code has been reproduced from matplotlib 3.3.4 in accord with its license agreement
7+
(reproduced below).
8+
9+
1. This LICENSE AGREEMENT is between the Matplotlib Development Team ("MDT"), and the
10+
Individual or Organization ("Licensee") accessing and otherwise using matplotlib software
11+
in source or binary form and its associated documentation.
12+
13+
2. Subject to the terms and conditions of this License Agreement, MDT hereby grants
14+
Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test,
15+
perform and/or display publicly, prepare derivative works, distribute, and otherwise use
16+
matplotlib 3.3.4 alone or in any derivative version, provided, however, that MDT's License
17+
Agreement and MDT's notice of copyright, i.e., "Copyright (c) 2012-2013 Matplotlib
18+
Development Team; All Rights Reserved" are retained in matplotlib 3.3.4 alone or in any
19+
derivative version prepared by Licensee.
20+
21+
3. In the event Licensee prepares a derivative work that is based on or incorporates
22+
matplotlib 3.3.4 or any part thereof, and wants to make the derivative work available to
23+
others as provided herein, then Licensee hereby agrees to include in any such work a brief
24+
summary of the changes made to matplotlib 3.3.4.
25+
26+
4. MDT is making matplotlib 3.3.4 available to Licensee on an "AS IS" basis. MDT MAKES NO
27+
REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION,
28+
MDT MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
29+
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 3.3.4 WILL NOT INFRINGE ANY THIRD
30+
PARTY RIGHTS.
31+
32+
5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB 3.3.4 FOR ANY
33+
INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING,
34+
DISTRIBUTING, OR OTHERWISE USING MATPLOTLIB 3.3.4, OR ANY DERIVATIVE THEREOF, EVEN IF
35+
ADVISED OF THE POSSIBILITY THEREOF.
36+
37+
6. This License Agreement will automatically terminate upon a material breach of its terms
38+
and conditions.
39+
40+
7. Nothing in this License Agreement shall be deemed to create any relationship of agency,
41+
partnership, or joint venture between MDT and Licensee. This License Agreement does not
42+
grant permission to use MDT trademarks or trade name in a trademark sense to endorse or
43+
promote products or services of Licensee, or any third party.
44+
45+
8. By copying, installing or otherwise using matplotlib 3.3.4, Licensee agrees to be bound
46+
by the terms and conditions of this License Agreement.
47+
"""
48+
import matplotlib.transforms as mtransforms
49+
50+
51+
class _TransformedBoundsLocator:
52+
"""
53+
Copyright (c) 2012-2013 Matplotlib Development Team; All Rights Reserved
54+
55+
This class is reproduced exactly from matplotlib/axes/_base.py, excluding the
56+
modifications made to this comment.
57+
58+
Axes locator for `.Axes.inset_axes` and similarly positioned axes.
59+
The locator is a callable object used in `.Axes.set_aspect` to compute the
60+
axes location depending on the renderer.
61+
"""
62+
63+
def __init__(self, bounds, transform):
64+
"""
65+
*bounds* (a ``[l, b, w, h]`` rectangle) and *transform* together
66+
specify the position of the inset axes.
67+
"""
68+
self._bounds = bounds
69+
self._transform = transform
70+
71+
def __call__(self, ax, renderer):
72+
# Subtracting transSubfigure will typically rely on inverted(),
73+
# freezing the transform; thus, this needs to be delayed until draw
74+
# time as transSubfigure may otherwise change after this is evaluated.
75+
return mtransforms.TransformedBbox(
76+
mtransforms.Bbox.from_bounds(*self._bounds),
77+
self._transform - ax.figure.transSubfigure)

src/metpy/plots/skewt.py

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import numpy as np
2424

2525
from ._util import colored_line
26+
from .._vendor.matplotlib import _TransformedBoundsLocator
2627
from ..calc import dewpoint, dry_lapse, el, lcl, moist_lapse, vapor_pressure
2728
from ..calc.tools import _delete_masked_points
2829
from ..interpolate import interpolate_1d
@@ -264,7 +265,7 @@ class SkewT:
264265
265266
"""
266267

267-
def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5):
268+
def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5, **kwargs):
268269
r"""Create SkewT - logP plots.
269270
270271
Parameters
@@ -289,6 +290,8 @@ def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5):
289290
Aspect ratio (i.e. ratio of y-scale to x-scale) to maintain in the plot.
290291
Defaults to 80.5. Passing the string ``'auto'`` tells matplotlib to handle
291292
the aspect ratio automatically (this is not recommended for SkewT).
293+
kwargs
294+
Additional keyword arguments passed when creating the axes.
292295
293296
"""
294297
if fig is None:
@@ -301,7 +304,7 @@ def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5):
301304
raise ValueError("Specify only one of `rect' and `subplot', but not both")
302305

303306
elif rect:
304-
self.ax = fig.add_axes(rect, projection='skewx', rotation=rotation)
307+
self.ax = fig.add_axes(rect, projection='skewx', rotation=rotation, **kwargs)
305308

306309
else:
307310
if subplot is not None:
@@ -313,7 +316,12 @@ def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5):
313316
else:
314317
subplot = (1, 1, 1)
315318

316-
self.ax = fig.add_subplot(*subplot, projection='skewx', rotation=rotation)
319+
self.ax = fig.add_subplot(
320+
*subplot,
321+
projection='skewx',
322+
rotation=rotation,
323+
**kwargs
324+
)
317325

318326
# Set the yaxis as inverted with log scaling
319327
self.ax.set_yscale('log')
@@ -342,6 +350,73 @@ def __init__(self, fig=None, rotation=30, subplot=None, rect=None, aspect=80.5):
342350
if matplotlib.__version__[:3] > '3.1':
343351
self.ax.set_aspect(aspect, adjustable='box')
344352

353+
@classmethod
354+
def inset(cls, ax, bounds, transform=None, zorder=5, rotation=30, aspect=80.5, **kwargs):
355+
r"""Create SkewT - logP plot as an inset.
356+
357+
Parameters
358+
----------
359+
ax : matplotlib.axes.Axes
360+
Source axes on which to place the inset SkewT.
361+
bounds : tuple[float, float, float, float]
362+
Rectangle (left, bottom, width, height) in which to place the axes. This
363+
allows the user to place the axes at an arbitrary point on the figure. See the
364+
``transform`` argument for controlling the coordinate system used in these bounds.
365+
transform : matplotlib.transforms.Transform, optional
366+
Defaults to ``ax.transData``, the coordinate system for the data. Other options
367+
include ``ax.transAxes`` for axes-relative coordinates, ``fig.transFirgure`` for
368+
figure-relative coordinates, or
369+
``ax.get_x_axis_transform()``/``ax.get_y_axis_transform()`` for blended
370+
coordinates (data coordinates on one axis and axes coordinates on the other).
371+
zorder : number, optional
372+
Defaults to 5. Adjust higher or lower to change whether it is above or below data
373+
plotted on the parent axes.
374+
rotation : float or int, optional
375+
Controls the rotation of temperature relative to horizontal. Given
376+
in degrees counterclockwise from x-axis. Defaults to 30 degrees.
377+
aspect : float, int, or 'auto', optional
378+
Aspect ratio (i.e. ratio of y-scale to x-scale) to maintain in the plot.
379+
Defaults to 80.5. Passing the string ``'auto'`` tells matplotlib to handle
380+
the aspect ratio automatically (this is not recommended for SkewT).
381+
kwargs
382+
Additional keyword arguments passed when creating the axes.
383+
384+
Returns
385+
-------
386+
SkewT
387+
388+
"""
389+
if transform is None:
390+
transform = ax.transData
391+
392+
# This segement copied with modification from matplotlib: Copyright (c) 2012-2013
393+
# Matplotlib Development Team; All Rights Reserved. See license agreement in
394+
# _vendor/matplotlib.py. Modified from original to have parent Axes be an argument
395+
# rather than self, create a SkewT object rather than Axes directly, and use Axes from
396+
# that SkewT instance instead of directly created Axes.
397+
398+
# This puts the rectangle into figure-relative coordinates.
399+
inset_locator = _TransformedBoundsLocator(bounds, transform)
400+
bounds = inset_locator(ax, None).bounds
401+
402+
# Create the skewT using the transformed bounds
403+
skew_t = cls(
404+
ax.figure,
405+
rotation=rotation,
406+
rect=bounds,
407+
aspect=aspect,
408+
zorder=zorder,
409+
**kwargs
410+
)
411+
412+
# this locator lets the axes move if in data coordinates.
413+
# it gets called in `ax.apply_aspect() (of all places)
414+
skew_t.ax.set_axes_locator(inset_locator)
415+
416+
# End copy
417+
418+
return skew_t
419+
345420
def plot(self, pressure, t, *args, **kwargs):
346421
r"""Plot data.
347422

0 commit comments

Comments
 (0)