tephpy.plotting.barbs ===================== .. py:module:: tephpy.plotting.barbs .. autoapi-nested-parse:: The wind-barb gutter staff (spec §3.2). Free geometry builders — bare numpy in diagram-native units, headlessly testable (the ``isopleths.py``/``shading.py`` pattern) — plus :class:`BarbStaff`, the zoom-aware artist ``plot_barbs`` installs in the gutter axes. Each draw places every barb at the y where its level's isobar meets the diagram's right edge (the printed-form staff convention), thins the visible levels to the densest subset at least ``BARB_MIN_SEPARATION`` apart, and renders them through matplotlib's barbs machinery with the Met Office increments (flag 50 kt, full 10 kt, half 5 kt, 5 kt binning). .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: tephpy.plotting.barbs.BarbStaff Functions --------- .. autoapisummary:: tephpy.plotting.barbs.staff_y tephpy.plotting.barbs.select_barbs Module Contents --------------- .. py:function:: staff_y(pressure: numpy.typing.ArrayLike, x_edge: float) -> numpy.typing.NDArray[numpy.float64] Find the y where each pressure's isobar crosses a staff x. The tephigram x decomposes along an isobar into a level-independent part and a pressure offset: ``x = g(T) + c(p)`` with ``g(T) = MA·ln(T + KELVIN_ZERO) + T`` (strictly increasing) and ``c(p) = MA·KAPPA·ln(P_REF / p)``, from ``x = MA·ln(theta_K) + T`` and Poisson's equation. Each level's crossing temperature solves ``g(T*) = x_edge - c(p)`` by inverse interpolation on one sampled ``g``, and the crossing y then comes from the real transforms at ``(T*, p)``. :Parameters: **pressure** : :obj:`ArrayLike ` Level pressures in hPa. **x_edge** : :class:`python:float` The staff's x in tephigram data space — the diagram's right edge. :Returns: :obj:`numpy.ndarray` The float64 crossing ys in tephigram data space; NaN where the crossing temperature falls outside ``_STAFF_TEMPERATURE_SPAN`` (or the pressure is not positive and finite). .. !! processed by numpydoc !! .. py:function:: select_barbs(y: numpy.typing.ArrayLike, *, minimum_separation: float) -> numpy.typing.NDArray[numpy.bool_] Thin barb positions to a minimum vertical separation. A greedy scan in input order — surface-first, so the surface barb always survives — keeps each position at least `minimum_separation` from the last kept one; non-finite positions are dropped. Positions and separation share one space (the staff uses display points), so zooming in spreads the ys and reveals more levels (spec §3.2). :Parameters: **y** : :obj:`ArrayLike ` Barb positions, ordered surface-first. **minimum_separation** : :class:`python:float` The minimum spacing between kept positions. :Returns: :obj:`numpy.ndarray` Boolean keep-mask over `y`. .. !! processed by numpydoc !! .. py:class:: BarbStaff(main_axes: matplotlib.axes.Axes, pressure: numpy.typing.NDArray[numpy.float64], u: numpy.typing.NDArray[numpy.float64], v: numpy.typing.NDArray[numpy.float64], *, x: float = BARB_STAFF_POSITION, minimum_separation: float, **kwargs: Any) Bases: :py:obj:`matplotlib.artist.Artist` One sounding's wind barbs on the gutter staff (spec §3.2). A zoom-aware artist (the ``IsoplethFamily`` refresh pattern) that manages a :class:`matplotlib.quiver.Barbs` child. Each draw reads the main axes' view, places every level at its isobar's staff crossing (:func:`staff_y`), masks the levels outside the view or closer than the minimum separation (:func:`select_barbs`), and hands the child the same-length masked arrays — matplotlib's barbs machinery skips masked points, so the member count never changes. :Parameters: **main_axes** : :obj:`matplotlib.axes.Axes` The tephigram axes the staff annotates. **pressure** : :obj:`numpy.ndarray` Level pressures in hPa, surface-first. **u, v** : :obj:`numpy.ndarray` Wind components in knots (the barb-increment units). **x** : :class:`python:float` The staff position as a fraction across the gutter. **minimum_separation** : :class:`python:float` Minimum vertical separation between drawn barbs, in points. **\*\*kwargs** : :obj:`Any` Passed through to :class:`matplotlib.quiver.Barbs`, over the ``_constants`` conventions (increments, rounding, length). .. !! processed by numpydoc !! .. py:property:: barbs :type: matplotlib.quiver.Barbs | None The managed matplotlib barbs collection. :Returns: :obj:`matplotlib.quiver.Barbs` or :data:`python:None` The child collection, or ``None`` before the first draw. .. !! processed by numpydoc !! .. py:method:: set_figure(fig: matplotlib.figure.Figure | matplotlib.figure.SubFigure) -> None Propagate the owning figure to the managed child. :Parameters: **fig** : :obj:`matplotlib.figure.Figure` or :obj:`matplotlib.figure.SubFigure` The figure the staff belongs to. .. !! processed by numpydoc !! .. py:method:: draw(renderer: matplotlib.backend_bases.RendererBase) -> None Draw the barbs visible in the current view. :Parameters: **renderer** : :obj:`matplotlib.backend_bases.RendererBase` The active renderer. .. !! processed by numpydoc !!