tephpy.plotting.axes#
The tephigram matplotlib projection.
TephigramAxes (registered as the "tephigram" projection) uses the
native rotated x-y plane as its data space, with the temperature/theta
mapping exposed as an invertible matplotlib transform and the five
background isopleth families drawn by default as zoom-aware artists
(spec §3.2).
Side-of-axes layout contract (spec §10 item 7): panels beside the diagram
are appended with mpl_toolkits.axes_grid1’s axes divider, which tracks
the equal-aspect box height — right side, inside-out: the wind-barb
gutter, then the indices panel. One divider is created per axes, cached,
and shared by every side-panel method; _relayout_side_panels rebuilds
the divider’s horizontal stack and reassigns every locator whenever a
panel appears, so the inside-out order holds regardless of the order the
panel methods are called in (spec §3.2).
Classes#
Map |
|
Map tephigram |
|
Matplotlib axes for the |
Module Contents#
- class tephpy.plotting.axes.TephigramTransform(shorthand_name=None)[source]#
Bases:
matplotlib.transforms.TransformMap
(temperature, theta)pairs to tephigram(x, y)pairs.A thin, invertible matplotlib wrapper over
tephpy.transforms.xy_from_temperature_theta(); operates on(N, 2)arrays in diagram-native units (degrees Celsius).- input_dims = 2#
The number of input dimensions of this transform. Must be overridden (with integers) in the subclass.
- output_dims = 2#
The number of output dimensions of this transform. Must be overridden (with integers) in the subclass.
- is_separable = False#
True if this transform is separable in the x- and y- dimensions.
- has_inverse = True#
True if this transform has a corresponding inverse transform.
- transform_non_affine(values: numpy.typing.ArrayLike) numpy.typing.NDArray[numpy.float64][source]#
Transform (temperature, theta) pairs to (x, y).
- Parameters:
- values
ArrayLike Array-like of shape
(N, 2)or length2: temperature, theta in degrees Celsius.
- values
- Returns:
numpy.ndarrayThe tephigram x, y coordinates (the axes’ data space), with the input’s dimensionality preserved: shape
(N, 2)for(N, 2)input, shape(2,)for length-2 input.
- inverted() TephigramInvertedTransform[source]#
Return the inverse (x, y) -> (temperature, theta) transform.
- Returns:
TephigramInvertedTransformThe inverse transform.
- class tephpy.plotting.axes.TephigramInvertedTransform(shorthand_name=None)[source]#
Bases:
matplotlib.transforms.TransformMap tephigram
(x, y)pairs back to(temperature, theta).- input_dims = 2#
The number of input dimensions of this transform. Must be overridden (with integers) in the subclass.
- output_dims = 2#
The number of output dimensions of this transform. Must be overridden (with integers) in the subclass.
- is_separable = False#
True if this transform is separable in the x- and y- dimensions.
- has_inverse = True#
True if this transform has a corresponding inverse transform.
- transform_non_affine(values: numpy.typing.ArrayLike) numpy.typing.NDArray[numpy.float64][source]#
Transform (x, y) pairs to (temperature, theta).
- Parameters:
- values
ArrayLike Array-like of shape
(N, 2)or length2: tephigram x, y coordinates (the axes’ data space).
- values
- Returns:
numpy.ndarrayTemperature, theta in degrees Celsius, with the input’s dimensionality preserved: shape
(N, 2)for(N, 2)input, shape(2,)for length-2 input.
- inverted() TephigramTransform[source]#
Return the forward (temperature, theta) -> (x, y) transform.
- Returns:
TephigramTransformThe forward transform.
- class tephpy.plotting.axes.TephigramAxes(fig, *args, facecolor=None, frameon=True, sharex=None, sharey=None, label='', xscale=None, yscale=None, box_aspect=None, forward_navigation_events='auto', **kwargs)[source]#
Bases:
matplotlib.axes.AxesMatplotlib axes for the
"tephigram"projection.The data space is the native rotated x-y plane (dimensionless), with equal aspect so the isotherm/dry-adiabat grid stays exactly perpendicular on screen. The five background isopleth families are drawn by default as zoom-aware artists and reconfigured through the accessor methods (
isotherms(),isobars(),dry_adiabats(),moist_adiabats(),mixing_ratios()). The temperature/theta mapping is exposed astephigram_transform; artists plot in (temperature, theta) space viatransform=ax.tephigram_transform + ax.transData. Native x/y ticks carry no meteorological meaning and are hidden until a family claims an edge for its labels —labels=("bottom", "left")turns them into that family’s scale (spec §3.2).- name = 'tephigram'#
- tephigram_transform: TephigramTransform#
- clear() None[source]#
Reset the axes to the tephigram projection defaults.
Matplotlib calls this during
Axes.__init__and on userax.clear(); both paths recreate the projection-owned state: the tephigram transform, equal aspect, hidden native axes, the five background isopleth families, any edges they claim for their labels, and the default extent (tephpy.configdiagram extent, elseDEFAULT_EXTENT). Side panels — the barb gutter and the indices panel — are removed with the diagram they annotated, except when the figure is clearing itself: it removes every axes anyway, and it is iterating a snapshot this one must not delete from.- Raises:
TypeErrorIf
tephpy.configgives one diagram edge to two families, or names an unknown label placement, or carries a malformed familyemphasis— a non-mapping, a member value that will not convert to float, a style that is not a mapping, or an unknown style key (spec §3.2).ValueErrorIf a
tephpy.configfamilyemphasiskeys a member value that is not finite, or gives alinewidththat is not positive and finite, or analphaoutside[0, 1], or a familyintervalis not positive and finite.
- set_extent(extent: tuple[tuple[float, float], tuple[float, float]]) None[source]#
Fix the view from ((pressure, temperature), …) corners.
The cartopy-style idiom for directly comparable figures (spec §3.2): the two corners are mapped through the tephigram transforms to x/y limits, and autoscaling is disabled so later overlays never drift the window.
- Parameters:
- extent
tuple ((pressure, temperature), (pressure, temperature))bottom-left and top-right corners in hPa / degrees Celsius.
- extent
- Raises:
ValueErrorIf a corner is unphysical (non-positive pressure) or the corners are degenerate.
- format_coord(x: float, y: float) str[source]#
Report diagram-meaningful values for the cursor position (spec §3.2).
The navigation toolbar’s readout: the data-space cursor position inverts to (temperature, theta), pressure derives via Poisson’s equation, and the configured fields render in listed order, e.g.
850 hPa, -4.2 °C, θ 8.6 °C. Fields resolve as instance assignment >tephpy.config>_constants: assigningax.format_coord = fn(stock matplotlib) shadows this method entirely, andconfig.cursor.fieldsis read live on every call, so aconfig.context(cursor={"fields": ...})override applies to existing axes for its duration (spec §3.5). Fields whose value is undefined at the point are omitted from the readout.
- plot_profile(pressure: tephpy.calc.Profile, *, label: str | None = None, **kwargs: Any) matplotlib.lines.Line2D[source]#
- plot_profile(pressure: object, temperature: object, *, units: collections.abc.Mapping[str, str] | None = None, label: str | None = None, **kwargs: Any) matplotlib.lines.Line2D
Plot one profile of temperature against pressure (spec §3.2).
Both arrays are pint quantities — or bare arrays with the
units=mapping (spec §5) — converted to diagram-native units and plotted through the tephigram transform machinery. Matplotlib keywords pass through untouched, and out-of-domain values (pressure <= 0 hPa) propagate NaN, breaking the line (spec §3.1).The same signature also accepts a
calc.Profile(e.g. the return ofcalc.parcel_path) as its only positional argument; dispatch is duck-typed on theProfileshape — temperature omitted andpressure/temperature/lcl_pressureattributes present. Label precedence in that form: label argument >profile.label> no entry. In both forms no style defaults are set — this is the low-level primitive (spec §4 styles parcel paths explicitly at the call site).- Parameters:
- pressure
pint.Quantity,ArrayLike, orProfile Level pressures, or the profile to plot.
- temperature
pint.QuantityorArrayLike, optional Level temperatures; omitted in the
Profileform.- unitsmapping of
strtostr, optional Unit strings for bare arrays, keyed by argument name, e.g.
units={"pressure": "hPa", "temperature": "degC"}; not accepted in theProfileform.- label
str, optional Legend label for the line.
- **kwargs
Any Passed through to
matplotlib.axes.Axes.plot().
- pressure
- Returns:
matplotlib.lines.Line2DThe profile line.
- Raises:
TephpyUnitsErrorFor unit-less bare arrays, ambiguous or unparsable units, or the wrong dimensionality.
TypeErrorFor wrong argument combinations: a
Profiletogether with temperature orunits=, or temperature omitted when the sole argument is notProfile-shaped (a bare pressure array, or aSoundingpassed by mistake).
- plot_sounding(snd: tephpy.sounding.Sounding, *, label: str | None = None, **kwargs: Any) tuple[matplotlib.lines.Line2D, matplotlib.lines.Line2D | None][source]#
Plot a sounding’s temperature and dewpoint profiles (spec §3.2).
Temperature and dewpoint-when-present draw as two profile lines in the conventional colours (temperature red, dewpoint green), with one legend entry per sounding attached to the temperature line. Label precedence: label argument >
snd.label> no entry. Matplotlib keywords pass through to both lines, overriding the convention defaults; legends stay stock matplotlib — callax.legend().- Parameters:
- snd
Sounding The sounding to plot.
- label
str, optional Legend label override.
- **kwargs
Any Passed through to
matplotlib.axes.Axes.plot()for both lines.
- snd
- Returns:
tupleofmatplotlib.lines.Line2D(temperature_line, dewpoint_line); the dewpoint line isNonewhen the sounding has no dewpoint.
- shade_cape(snd: tephpy.sounding.Sounding, parcel: tephpy.calc.Profile, **kwargs: Any) matplotlib.patches.PathPatch | None[source]#
Shade the CAPE area between the sounding and a parcel path.
The positive-buoyancy region between the environment temperature and the parcel path, bounded as
metpy.calc.cape_cin()integrates — from the LFC to the EL, to the profile top when the parcel is still buoyant there — so the shading matches the annotated numbers (spec §3.2). Drawn as one compound-path patch; interrupted regions become multiple polygons in the same patch.- Parameters:
- snd
Sounding The environment sounding.
- parcel
Profile The parcel path, e.g. from
calc.parcel_path.- **kwargs
Any Passed through to
matplotlib.patches.PathPatch, overriding the_constantsconventions.
- snd
- Returns:
matplotlib.patches.PathPatchorNoneThe shaded patch, or
Nonefor zero area — 0 is an answer, not an error (spec §6).
- shade_cin(snd: tephpy.sounding.Sounding, parcel: tephpy.calc.Profile, **kwargs: Any) matplotlib.patches.PathPatch | None[source]#
Shade the CIN area between the sounding and a parcel path.
The negative-buoyancy region between the environment temperature and the parcel path, bounded as
metpy.calc.cape_cin()integrates — from the parcel start to the LFC — so the shading matches the annotated numbers (spec §3.2). Drawn as one compound-path patch; with no LFC there is no CIN region.- Parameters:
- snd
Sounding The environment sounding.
- parcel
Profile The parcel path, e.g. from
calc.parcel_path.- **kwargs
Any Passed through to
matplotlib.patches.PathPatch, overriding the_constantsconventions.
- snd
- Returns:
matplotlib.patches.PathPatchorNoneThe shaded patch, or
Nonefor zero area — 0 is an answer, not an error (spec §6).
- edge_axis(edge: str) matplotlib.axis.Axis[source]#
Return the matplotlib axis drawing one diagram edge’s ticks.
The uniform handle on all four edges (spec §3.2), keyed by the same names the
labelsoption takes. Bottom and left are the axes’ ownxaxis/yaxis; top and right belong to a secondary axes that has no other public handle. tephpy stamps its tick conventions on an edge axis once, when that axis is created, so everything stock matplotlib offers is the caller’s from the claim onwards — e.g.ax.edge_axis("top").set_tick_params(labelsize=12), orset_label_text("")to keep the ticks and drop the axis title. The only thing tephpy changes afterwards is the tick colour, and only when the owning family’s own colour or alpha changes, or another family takes the edge.- Parameters:
- edge
str The edge, one of
EDGES.
- edge
- Returns:
matplotlib.axis.AxisThe axis drawing that edge’s ticks.
- Raises:
TypeErrorIf edge is not one of
EDGES.ValueErrorIf no family labels that edge. An unclaimed edge renders nothing to style — bottom and left are hidden, and top and right have no axis yet — and probing one must not build a secondary axes nothing is using.
- plot_barbs(snd: tephpy.sounding.Sounding, *, x: float | None = None, minimum_separation: float | None = None, **kwargs: Any) tephpy.plotting.barbs.BarbStaff[source]#
Plot the sounding’s wind barbs on the gutter staff (spec §3.2).
The barbs draw on a right-hand gutter appended with the shared divider, each level at the y where its isobar meets the diagram’s right edge (the printed-form staff convention), thinned per draw to a minimum vertical separation — zooming in reveals more levels. Met Office symbology: flag 50 kt, full barb 10 kt, half barb 5 kt, speeds rounded to 5 kt bins; calm levels render as matplotlib’s small circle. Each call draws one staff: overlay soundings by calling again with another x, minimum_separation, and colour.
- Parameters:
- snd
Sounding The sounding to plot; must carry wind.
- x
float, optional The staff position as a fraction across the gutter (default
BARB_STAFF_POSITION).- minimum_separation
float, optional The minimum vertical separation between drawn barbs, in points (default
BARB_MIN_SEPARATION) — a longerlength=glyph wants a wider separation.- **kwargs
Any Passed through to
matplotlib.quiver.Barbs, over the_constantsconventions (increments, rounding, length).
- snd
- Returns:
BarbStaffThe zoom-aware staff artist; its
barbsproperty is the underlying matplotlib collection.
- Raises:
MissingDataErrorIf the sounding has no wind (spec §6).
- annotate_indices(indices: tephpy.calc.SoundingIndices) matplotlib.axes.Axes[source]#
Display derived parameters in a panel beside the diagram.
The first consumer of the side-of-axes contract (spec §3.2): the panel is appended with the
axes_grid1divider, one formatted line perSoundingIndicesfield, NaN rendered as an em dash. Calling it again updates the panel in place rather than stacking a second one, and the side-panel layout is rebuilt inside-out (barb gutter, then this panel) whichever order the panel methods are called in (spec §3.2).- Parameters:
- indices
SoundingIndices The derived parameters, e.g. from
calc.indices.
- indices
- Returns:
matplotlib.axes.AxesThe panel axes, for restyling.
- isotherms(*, values: collections.abc.Iterable[float] | None = None, interval: float | None = None, color: str | None = None, linewidth: float | None = None, alpha: float | None = None, labels: bool | str | tuple[str, Ellipsis] | None = None, emphasis: collections.abc.Mapping[float, collections.abc.Mapping[str, object]] | None = None, visible: bool | None = None) tephpy.plotting.isopleths.IsoplethFamily[source]#
Return (and optionally reconfigure) the isotherm family.
With no arguments this returns the family artist unchanged; any keyword given reconfigures it first (spec §3.2). Values are in degrees Celsius.
- Parameters:
- valuesiterable of
float, optional Explicit member temperatures; disables the zoom ladder.
- interval
float, optional Member interval; disables the zoom ladder.
- color
str, optional Line and label colour.
- linewidth
float, optional Line width in points.
- alpha
float, optional Line and label alpha.
- labelsbool or
strortupleofstr, optional Where member values are labelled:
True(every member inline — the default),False(none), or the diagram edge names"bottom","top","left"and"right", singly or as a tuple. Listed edges label the members that reach them; every member left over is labelled inline. One family per edge. An edge crowded by closely spaced members is thinned withinterval=; edge labelling never drops a member’s label itself.- emphasismapping of
floatto mapping, optional Members to distinguish, keyed by member value in degrees Celsius. Each value is a mapping of style overrides —
color,linewidth,linestyle,alpha— and an omitted key falls back to the family’s own style, so{0.0: {}}draws that member atEMPHASIS_LINEWIDTHin the family’s own colour. An emphasised member is always drawn, whatever the zoom ladder would select, so a value the interval never lands on still appears. An empty mapping emphasises nothing.- visiblebool, optional
Whether the family is drawn.
- valuesiterable of
- Returns:
IsoplethFamilyThe isotherm family artist.
- Raises:
TypeErrorIf
labelsnames an unknown placement,emphasisis malformed, or an edge another family already claims.ValueErrorIf an
emphasismember value is not finite, alinewidthis not positive and finite, analphafalls outside[0, 1], orintervalis not positive and finite.
- isobars(*, values: collections.abc.Iterable[float] | None = None, interval: float | None = None, color: str | None = None, linewidth: float | None = None, alpha: float | None = None, labels: bool | str | tuple[str, Ellipsis] | None = None, emphasis: collections.abc.Mapping[float, collections.abc.Mapping[str, object]] | None = None, visible: bool | None = None) tephpy.plotting.isopleths.IsoplethFamily[source]#
Return (and optionally reconfigure) the isobar family.
With no arguments this returns the family artist unchanged; any keyword given reconfigures it first (spec §3.2). Values are in hPa.
- Parameters:
- valuesiterable of
float, optional Explicit member pressures; disables the zoom ladder.
- interval
float, optional Member interval; disables the zoom ladder.
- color
str, optional Line and label colour.
- linewidth
float, optional Line width in points.
- alpha
float, optional Line and label alpha.
- labelsbool or
strortupleofstr, optional Where member values are labelled:
True(every member inline — the default),False(none), or the diagram edge names"bottom","top","left"and"right", singly or as a tuple. Listed edges label the members that reach them; every member left over is labelled inline. One family per edge. An edge crowded by closely spaced members is thinned withinterval=; edge labelling never drops a member’s label itself.- emphasismapping of
floatto mapping, optional Members to distinguish, keyed by member value in hPa. Each value is a mapping of style overrides —
color,linewidth,linestyle,alpha— and an omitted key falls back to the family’s own style, so{500.0: {}}draws that member atEMPHASIS_LINEWIDTHin the family’s own colour. An emphasised member is always drawn, whatever the zoom ladder would select, so a value the interval never lands on still appears. An empty mapping emphasises nothing.- visiblebool, optional
Whether the family is drawn.
- valuesiterable of
- Returns:
IsoplethFamilyThe isobar family artist.
- Raises:
TypeErrorIf
labelsnames an unknown placement,emphasisis malformed, or an edge another family already claims.ValueErrorIf an
emphasismember value is not finite, alinewidthis not positive and finite, analphafalls outside[0, 1], orintervalis not positive and finite.
- dry_adiabats(*, values: collections.abc.Iterable[float] | None = None, interval: float | None = None, color: str | None = None, linewidth: float | None = None, alpha: float | None = None, labels: bool | str | tuple[str, Ellipsis] | None = None, emphasis: collections.abc.Mapping[float, collections.abc.Mapping[str, object]] | None = None, visible: bool | None = None) tephpy.plotting.isopleths.IsoplethFamily[source]#
Return (and optionally reconfigure) the dry-adiabat family.
With no arguments this returns the family artist unchanged; any keyword given reconfigures it first (spec §3.2). Values are potential temperatures in degrees Celsius.
- Parameters:
- valuesiterable of
float, optional Explicit member potential temperatures; disables the zoom ladder.
- interval
float, optional Member interval; disables the zoom ladder.
- color
str, optional Line and label colour.
- linewidth
float, optional Line width in points.
- alpha
float, optional Line and label alpha.
- labelsbool or
strortupleofstr, optional Where member values are labelled:
True(every member inline — the default),False(none), or the diagram edge names"bottom","top","left"and"right", singly or as a tuple. Listed edges label the members that reach them; every member left over is labelled inline. One family per edge. An edge crowded by closely spaced members is thinned withinterval=; edge labelling never drops a member’s label itself.- emphasismapping of
floatto mapping, optional Members to distinguish, keyed by member value in degrees Celsius. Each value is a mapping of style overrides —
color,linewidth,linestyle,alpha— and an omitted key falls back to the family’s own style, so{0.0: {}}draws that member atEMPHASIS_LINEWIDTHin the family’s own colour. An emphasised member is always drawn, whatever the zoom ladder would select, so a value the interval never lands on still appears. An empty mapping emphasises nothing.- visiblebool, optional
Whether the family is drawn.
- valuesiterable of
- Returns:
IsoplethFamilyThe dry-adiabat family artist.
- Raises:
TypeErrorIf
labelsnames an unknown placement,emphasisis malformed, or an edge another family already claims.ValueErrorIf an
emphasismember value is not finite, alinewidthis not positive and finite, analphafalls outside[0, 1], orintervalis not positive and finite.
- moist_adiabats(*, values: collections.abc.Iterable[float] | None = None, interval: float | None = None, truncation: float | None = None, color: str | None = None, linewidth: float | None = None, alpha: float | None = None, labels: bool | str | tuple[str, Ellipsis] | None = None, emphasis: collections.abc.Mapping[float, collections.abc.Mapping[str, object]] | None = None, visible: bool | None = None) tephpy.plotting.isopleths.IsoplethFamily[source]#
Return (and optionally reconfigure) the moist-adiabat family.
With no arguments this returns the family artist unchanged; any keyword given reconfigures it first (spec §3.2). Values are wet-bulb potential temperatures in degrees Celsius.
- Parameters:
- valuesiterable of
float, optional Explicit member wet-bulb potential temperatures; disables the zoom ladder.
- interval
float, optional Member interval; disables the zoom ladder.
- truncation
float, optional Temperature (°C) below which the curves are truncated.
- color
str, optional Line and label colour.
- linewidth
float, optional Line width in points.
- alpha
float, optional Line and label alpha.
- labelsbool or
strortupleofstr, optional Where member values are labelled:
True(every member inline — the default),False(none), or the diagram edge names"bottom","top","left"and"right", singly or as a tuple. Listed edges label the members that reach them; every member left over is labelled inline. One family per edge. An edge crowded by closely spaced members is thinned withinterval=; edge labelling never drops a member’s label itself.- emphasismapping of
floatto mapping, optional Members to distinguish, keyed by member value in degrees Celsius. Each value is a mapping of style overrides —
color,linewidth,linestyle,alpha— and an omitted key falls back to the family’s own style, so{0.0: {}}draws that member atEMPHASIS_LINEWIDTHin the family’s own colour. An emphasised member is always drawn, whatever the zoom ladder would select, so a value the interval never lands on still appears. An empty mapping emphasises nothing.- visiblebool, optional
Whether the family is drawn.
- valuesiterable of
- Returns:
IsoplethFamilyThe moist-adiabat family artist.
- Raises:
TypeErrorIf
labelsnames an unknown placement,emphasisis malformed, or an edge another family already claims.ValueErrorIf an
emphasismember value is not finite, alinewidthis not positive and finite, analphafalls outside[0, 1], orintervalis not positive and finite.
- mixing_ratios(*, values: collections.abc.Iterable[float] | None = None, color: str | None = None, linewidth: float | None = None, alpha: float | None = None, labels: bool | str | tuple[str, Ellipsis] | None = None, emphasis: collections.abc.Mapping[float, collections.abc.Mapping[str, object]] | None = None, visible: bool | None = None) tephpy.plotting.isopleths.IsoplethFamily[source]#
Return (and optionally reconfigure) the mixing-ratio family.
With no arguments this returns the family artist unchanged; any keyword given reconfigures it first (spec §3.2). Values are humidity mixing ratios in g/kg; this family has no
interval(its members come from theMIXING_RATIO_VALUESladder).- Parameters:
- valuesiterable of
float, optional Explicit member mixing ratios; disables the zoom ladder.
- color
str, optional Line and label colour.
- linewidth
float, optional Line width in points.
- alpha
float, optional Line and label alpha.
- labelsbool or
strortupleofstr, optional Where member values are labelled:
True(every member inline — the default),False(none), or the diagram edge names"bottom","top","left"and"right", singly or as a tuple. Listed edges label the members that reach them; every member left over is labelled inline. One family per edge. An edge crowded by a large member set is thinned withvalues=; edge labelling never drops a member’s label itself.- emphasismapping of
floatto mapping, optional Members to distinguish, keyed by member value in g/kg. Each value is a mapping of style overrides —
color,linewidth,linestyle,alpha— and an omitted key falls back to the family’s own style, so{5.0: {}}draws that member atEMPHASIS_LINEWIDTHin the family’s own colour. An emphasised member is always drawn, whatever the zoom ladder would select, so a value the ladder never selects still appears. An empty mapping emphasises nothing.- visiblebool, optional
Whether the family is drawn.
- valuesiterable of
- Returns:
IsoplethFamilyThe mixing-ratio family artist.
- Raises:
TypeErrorIf
labelsnames an unknown placement,emphasisis malformed, or an edge another family already claims.ValueErrorIf an
emphasismember value is not finite, alinewidthis not positive and finite, or analphafalls outside[0, 1].