Plotting#

biotuner.harmonic_geometry.plotting#

Visualisation for GeometryData objects.

This module is the single home for matplotlib-based rendering of every geom_type produced by the rest of biotuner.harmonic_geometry (curve/polygon/graph/tree/field/mesh/point-cloud, in 2-D and 3-D), plus the higher-level helpers used by the report generator scripts (galleries, sweep strips, rotation gifs, GA fitness curves, grid-relaxation animations).

Matplotlib is imported lazily inside each function so that simply importing biotuner.harmonic_geometry does not pull in the matplotlib stack.

Sections#

  1. Style helpers — palette, axis cleanup, figure save

  2. 2-D primitive renderers — curve/polygon/graph/field/cloud/tree/rectangles

  3. 3-D primitive renderers — mesh/cloud/tree, plus 3-D axis helpers

  4. Dispatcher — plot_geometry()

  5. Layout helpers — galleries and parameter sweeps

  6. Animation helpers — rotation, sequence, grid relax, evolution

  7. Resonance helpers — coupling matrices, GA curves, attractor graphs

Public API is exported through biotuner.harmonic_geometry.__init__ so external code can simply from biotuner.harmonic_geometry import plotting or import individual functions.

axis_clean(ax, equal: bool = True, grid: bool = False, spine_color: str = '#cccccc', spine_lw: float = 0.5) None[source]#

Strip ticks, harmonise spines, optionally enforce equal aspect / grid.

title_ax(ax, text: str, sub: str = '', fontsize: int = 8) None[source]#

Two-line axis title; the second line is rendered smaller and dimmer.

make_axis_3d(fig, pos, title: str = '', elev: int = 25, azim: int = 45)[source]#

Create a 3-D matplotlib axis with cleaned spines and equal aspect.

save_figure(fig, path: str | Path, dpi: int = 150, close: bool = True) Path[source]#

Save fig to path (creating parent dirs) and optionally close it.

draw_curve_2d(geom: GeometryData, ax, color: str = '#1f3b73', lw: float = 0.9, marker: str | None = None) None[source]#

Polyline in 2-D.

draw_polygon(geom: GeometryData, ax, color: str = '#a23e2c', lw: float = 1.4, fill: bool = False, alpha: float = 0.08, marker: str | None = 'o', ms: float = 4) None[source]#

Closed polygon (auto-closes by appending the first vertex).

draw_polygon_set(geom: GeometryData, ax, palette: Sequence[str] | None = None, lw: float = 1.4, ms: float = 3) None[source]#

List/sequence of polygons (geom.coordinates is iterable of (k, 2) arrays).

draw_graph_2d(geom: GeometryData, ax, edge_color: str = '#1f3b73', edge_lw: float = 0.4, edge_alpha: float = 0.55, node_color: str = '#a23e2c', node_size: float = 4, use_weights: bool = False) None[source]#

Edges as a LineCollection plus node scatter.

draw_hyperbolic_graph(geom: GeometryData, ax, color_by: str = 'harmonicity', cmap: str = 'plasma', highlight_mask: ndarray | None = None, highlight_color: str = '#a23e2c', show_disk: bool = True) Any[source]#

Stern-Brocot hyperbolic-disk layout. Returns the scatter (for colorbar).

draw_point_cloud_2d(geom: GeometryData, ax, color: str = '#a23e2c', edge_color: str = '#1f3b73', size: float = 30, use_weights: bool = True, ref_circle: bool = False) None[source]#

2-D scatter; sizes scaled by geom.weights when present.

draw_field_2d(geom: GeometryData, ax, cmap: str = 'RdBu_r', show_nodal: bool = True, signed: bool = True, vmin: float | None = None, vmax: float | None = None) Any[source]#

Pcolormesh of a 2-D scalar field stored in geom.coordinates.

For signed fields (e.g. Chladni) draws a zero-level contour. Returns the QuadMesh object (so callers can attach a colorbar).

draw_image(geom: GeometryData, ax, cmap: str = 'inferno', origin: str = 'lower', extent: Tuple[float, float, float, float] | None = None, vmin: float = 0.0, vmax: float = 1.0) Any[source]#

Imshow renderer for fields stored as a (H, W) array (Julia, Cantor, …).

draw_tree_2d(geom: GeometryData, ax, color: str = '#1f3b73', lw: float = 0.5, alpha: float = 0.75) None[source]#

L-system / fractal tree edges drawn as a LineCollection.

draw_rectangles(geom: GeometryData, ax, cmap: str = 'tab10', edge_color: str = 'white', edge_lw: float = 0.8) None[source]#

Continued-fraction rectangle tilings — a sequence of (4, 2) polygons.

draw_mesh_3d(ax, geom: GeometryData, color: str = '#1f3b73', alpha: float = 0.75, lw: float = 0.2, edge_color: str = 'white') None[source]#

3-D triangle mesh via Poly3DCollection.

draw_tree_3d(ax, geom: GeometryData, color: str = '#1f3b73', lw: float = 0.5, alpha: float = 0.7) None[source]#

3-D L-system tree edges via Line3DCollection.

draw_point_cloud_3d(ax, geom: GeometryData, color: str = '#a23e2c', size: float = 2, alpha: float = 0.6) None[source]#

3-D scatter.

draw_curve_3d(ax, geom: GeometryData, color: str = '#1f3b73', lw: float = 0.6) None[source]#

3-D polyline.

plot_geometry(geom: GeometryData, ax=None, **kwargs)[source]#

Auto-route a GeometryData to the matching renderer.

Parameters:
  • geom (GeometryData)

  • ax (matplotlib axis, optional) – If None, a new figure is created with the appropriate projection.

  • **kwargs – Forwarded to the underlying drawer.

Returns:

(fig, ax) (tuple)

gallery(geometries: Sequence[GeometryData], titles: Sequence[str] | None = None, n_cols: int = 3, fig_width: float = 6.5, row_height: float | None = None, color: str | Sequence[str] | None = None, suptitle: str | None = None, draw_kwargs: Dict[str, Any] | None = None, renderer: Callable | None = None)[source]#

Render an N × n_cols grid of geometries via plot_geometry().

Use renderer to force a specific drawer (otherwise dispatched per-geom). color may be a single string (applied to all) or a list. Returns (fig, axes).

sweep_strip(geometries: Sequence[GeometryData], labels: Sequence[str] | None = None, fig_width: float = 6.5, row_height: float | None = None, color: str = '#1f3b73', suptitle: str | None = None, draw_kwargs: Dict[str, Any] | None = None, renderer: Callable | None = None)[source]#

1×N strip — convenience wrapper over gallery() with n_cols=N.

rotation_strip(geom: GeometryData, n_strip: int = 6, fig_width: float = 6.5, elev: float = 20.0, color: str = '#1f3b73', draw_kwargs: Dict[str, Any] | None = None, renderer: Callable | None = None, suptitle: str | None = None)[source]#

1×N strip of the same 3-D geometry at evenly spaced azimuths.

Returns (fig, axes). Useful for showing a tube/knot/mesh from several viewing angles in a single static figure.

animate_rotation(geom: GeometryData, out_path: str | Path, n_frames: int = 36, fps: int = 12, elev: float = 20.0, fig_size: Tuple[float, float] = (3.5, 3.5), dpi: int = 100, color: str = '#1f3b73', draw_kwargs: Dict[str, Any] | None = None, renderer: Callable | None = None) Path[source]#

Save a rotating GIF of a 3-D GeometryData (mesh / tree / cloud).

Frames sweep azimuth from 0° to (n_frames−1) × (360 / n_frames). renderer defaults to plot_geometry()’s 3-D dispatch.

animate_geometry_sequence(geoms: Sequence[GeometryData], out_path: str | Path, fps: int = 8, fig_size: Tuple[float, float] = (4.5, 4.5), dpi: int = 100, color: str = '#1f3b73', draw_kwargs: Dict[str, Any] | None = None, elev: float = 25.0, azim: float = 35.0) Path[source]#

Save a GIF cycling through a list of geometries (2-D or 3-D).

plot_metric_radar(rows, labels: Sequence[str] | None = None, metrics: Sequence[str] | None = None, ax=None, colors: Sequence[str] | None = None, fill_alpha: float = 0.2, line_lw: float = 1.4, title: str | None = None)[source]#

Radar chart of normalised metrics for one or several rows.

Parameters:
  • rows (dict or list of dicts) – Either a single {metric: value} dict (one polygon) or a list of such dicts (multi-overlay). Values are auto-normalised to [0, 1] via biotuner.harmonic_geometry.metrics.normalize_metrics().

  • labels (sequence of str, optional) – One label per row. Defaults to row_0, row_1, .

  • metrics (sequence of str, optional) – Subset of metric keys to include. Defaults to the keys of the first row (with n_components excluded — it’s a count, not a metric).

  • ax (polar matplotlib axis, optional)

  • colors (sequence of str, optional)

  • fill_alpha, line_lw (floats)

  • title (str, optional)

Returns:

(fig, ax) (tuple)

plot_metric_trajectory(metrics_dict_or_seq, generator: Any | None = None, generator_kwargs: Dict[str, Any] | None = None, metrics: Sequence[str] | None = None, times: ndarray | None = None, ax=None, normalize: bool = False, colors: Sequence[str] | None = None, title: str | None = None)[source]#

Line plot of geometry-metric trajectories over time.

Two ways to pass data:

  • Pre-computed: metrics_dict_or_seq is a dict {name: 1-D ndarray of length T} — typically the output of sequence_metrics(). generator should be None.

  • From a HarmonicSequence: pass the sequence as the first argument and supply generator (e.g. harmonic_knot). The function computes sequence_metrics(seq, generator, **kwargs)() internally.

Parameters:
  • metrics_dict_or_seq (dict[str, ndarray] or HarmonicSequence)

  • generator (callable, optional) – Required when the first argument is a HarmonicSequence.

  • generator_kwargs (dict, optional) – Forwarded to generator for every frame.

  • metrics (sequence of str, optional) – Subset of metric trajectories to plot. Defaults to all keys.

  • times (ndarray, optional) – Explicit time axis. Inferred from the sequence if available.

  • ax (matplotlib axis, optional)

  • normalize (bool, default False) – Per-metric min-max scaling to [0, 1].

Returns:

(fig, ax) (tuple)