Source code for bldfm.plotting.contours

"""Source area contour visualization functions.

These functions combine the output of ``bldfm.utils.get_source_area()``
with matplotlib contour overlays.  The ``get_source_area`` computation
itself lives in ``bldfm.utils`` -- this module handles only visualization.

Source area contours represent the spatial region that contributes a given
fraction of the measured flux.  Different "base functions" produce different
contour geometries:

- **Contribution contours** (g = f): standard isopleth contours
- **Circular contours** (g = -(r^2)): concentric circles from tower
- **Upwind contours** (g = dot(wind_hat, r)): upwind distance bands
- **Crosswind contours** (g = -(perp distance)^2): crosswind ridges
- **Sector contours** (g = -abs(theta)): angular sectors from upwind axis

See Also
--------
bldfm.utils.get_source_area : Rescale a field so contour levels represent
    cumulative contribution fractions.
"""

import numpy as np
import matplotlib.pyplot as plt

from ._common import ensure_ax, format_colorbar_scientific, _maybe_slice_level


[docs] def plot_source_area_contours( flx, grid, source_area_field, levels=None, ax=None, contour_colors=None, cmap="RdYlBu_r", title=None, level=0, colorbar=True, **pcolormesh_kw, ): """Plot footprint field with source area contour overlay. The ``source_area_field`` should be the output of ``get_source_area(flx, g)`` for some base function ``g``. Parameters ---------- flx : ndarray (ny, nx) or (nz, ny, nx) Original footprint field (plotted as pcolormesh background). If 3D, sliced at *level*. grid : tuple (X, Y, Z) or (X, Y) Coordinate arrays from the solver. source_area_field : ndarray (ny, nx) or (nz, ny, nx) Rescaled field from ``get_source_area()``, where contour levels represent cumulative contribution fractions. If 3D, sliced at *level*. levels : list of float, optional Contribution fraction levels (default [0.25, 0.5, 0.75]). ax : matplotlib Axes, optional contour_colors : list of str, optional Colors for contour lines (default ['white', 'magenta', 'cyan']). cmap : str Colourmap for background pcolormesh. title : str, optional level : int Z-index to use when fields are 3D. Default 0 (surface). colorbar : bool Whether to add a colorbar. Default True. **pcolormesh_kw Forwarded to ``ax.pcolormesh``. Returns ------- ax : matplotlib Axes """ flx, grid = _maybe_slice_level(flx, grid, level) if source_area_field.ndim == 3: source_area_field = source_area_field[level] X, Y = grid[:2] if levels is None: levels = [0.25, 0.5, 0.75] if contour_colors is None: contour_colors = ["white", "magenta", "cyan"] ax = ensure_ax(ax) pm = ax.pcolormesh(X, Y, flx, cmap=cmap, shading="auto", **pcolormesh_kw) if colorbar: cbar = ax.figure.colorbar(pm, ax=ax) format_colorbar_scientific(cbar, label="Footprint [m$^{-2}$]") cs = ax.contour(X, Y, source_area_field, levels=levels, colors=contour_colors) ax.clabel(cs, fmt=lambda x: f"{x:.0%}", fontsize=8, inline=True) ax.set_xlabel("x [m]") ax.set_ylabel("y [m]") ax.set_aspect("equal") if title: ax.set_title(title) return ax