Source code for reasitic.plot
"""Plotting helpers (optional dependency on matplotlib).
If ``matplotlib`` isn't installed these functions raise a clear
``ImportError`` rather than the usual ModuleNotFoundError chain;
otherwise they return matplotlib ``Axes`` objects so callers can
further customise the plots.
The module itself imports lazily so just importing
``reasitic`` doesn't require matplotlib.
"""
from __future__ import annotations
from typing import Any
import numpy as np
from reasitic.geometry import Shape
def _require_matplotlib() -> Any:
try:
import matplotlib.pyplot as plt
except ImportError as e:
raise ImportError(
"matplotlib is required for reasitic.plot — "
"install with 'pip install matplotlib'"
) from e
return plt
[docs]
def plot_shape(shape: Shape, *, ax: Any = None, color: str | None = None) -> Any:
"""Plot a shape's polygons on the xy-plane.
Returns the matplotlib Axes for further customisation.
"""
plt = _require_matplotlib()
if ax is None:
_, ax = plt.subplots()
for poly in shape.polygons:
xs = [v.x for v in poly.vertices]
ys = [v.y for v in poly.vertices]
label = f"metal {poly.metal}" if color is None else None
ax.plot(xs, ys, "-", color=color, label=label)
ax.set_xlabel("x (μm)")
ax.set_ylabel("y (μm)")
ax.set_aspect("equal")
ax.set_title(f"Shape <{shape.name}>")
return ax
[docs]
def plot_sweep(
freqs_ghz: list[float],
L_nH: list[float] | np.ndarray,
R_ohm: list[float] | np.ndarray | None = None,
Q: list[float] | np.ndarray | None = None,
*,
ax: Any = None,
) -> Any:
"""Plot a frequency sweep of L, R, Q vs freq.
Pass any combination of L, R, Q; missing series are skipped.
Returns the matplotlib Axes (twin x-axes used for L vs R/Q).
"""
plt = _require_matplotlib()
if ax is None:
_, ax = plt.subplots()
ax.plot(freqs_ghz, L_nH, "b-", label="L (nH)")
ax.set_xlabel("Frequency (GHz)")
ax.set_ylabel("L (nH)", color="b")
if R_ohm is not None or Q is not None:
ax2 = ax.twinx()
if R_ohm is not None:
ax2.plot(freqs_ghz, R_ohm, "r-", label="R (Ω)")
ax2.set_ylabel("R (Ω)", color="r")
if Q is not None:
ax2.plot(freqs_ghz, Q, "g--", label="Q")
return ax
[docs]
def plot_lr_matrix(shape: Shape, *, ax: Any = None) -> Any:
"""Heat-map of the per-segment partial inductance matrix."""
plt = _require_matplotlib()
from reasitic.info import lr_matrix
M = lr_matrix(shape)
if ax is None:
_, ax = plt.subplots()
im = ax.imshow(M, cmap="RdBu_r", interpolation="nearest")
ax.set_xlabel("segment j")
ax.set_ylabel("segment i")
ax.set_title(f"Partial L (nH) — <{shape.name}>")
plt.colorbar(im, ax=ax)
return ax