pycsamt.interp.plot#

plot — visualization for pycsamt.interp results.

Three plot classes cover the main interpretation deliverables:

  • PlotStratigraphicLog — single-station pseudo-stratigraphic log in the style of Fig. 5d / Fig. 7 of Kouadio et al. (2022).

  • PlotFenceDiagram — multi-station panel with all logs arranged along the profile.

  • PlotCalibratedModel — side-by-side CRM vs NM with the misfit G (%) map overlaid.

All classes follow the same pattern:

fig = PlotStratigraphicLog(log).plot()
fig.savefig("S17_log.png", dpi=200)

Classes

PlotAquiferCharacterization(result, *[, ...])

Dar-Zarrouk profile — TR, S, water table, and transmissivity.

PlotCalibratedModel(crm, nm[, misfit_map, ...])

Compare CRM vs NM and display the G (%) misfit map.

PlotFenceDiagram(logs, *[, figsize, title, ...])

Multi-station fence diagram of pseudo-stratigraphic logs.

PlotHydroSection(result[, quantity, style, ...])

2-D hydrogeological section from an EMHydroResult.

PlotMultiTimeLapseGrid(timelapse[, ...])

Grid of EM sections at successive time steps — Fig.

PlotPetrophysicalCrossPlot(result, *[, ...])

ρ vs φ scatter colored by Sw with the fitted Archie/WS model curve.

PlotResistivityDepthProfile(source[, ...])

1-D resistivity depth profile with zone shading — Fig.

PlotStratigraphicLog(log, *[, figsize, ...])

Single-station pseudo-stratigraphic log.

PlotTimeLapseSection(timelapse[, quantity, ...])

Difference section for time-lapse EM monitoring.

PlotUncertaintyHistogram(unc[, quantity, ...])

Posterior histograms of key hydro quantities per station.

PlotUncertaintyProfile(unc, *[, style, ...])

Profile plot: water-table depth and transmissivity with P10–P90 envelopes.

PlotUncertaintySection(unc[, quantity, ...])

Two-panel section showing the P50 estimate and the uncertainty spread.

PlotWaterTableProfile(result, *[, style, ...])

Profile plot: water-table depth and transmissivity along the section.

class pycsamt.interp.plot.PlotStratigraphicLog(log, *, figsize=(8, 10), depth_unit='m', title=None, annotation_kws=None)[source]#

Bases: object

Single-station pseudo-stratigraphic log.

Reproduces the two-panel layout of Fig. 5d / Fig. 7 in Kouadio et al. (2022):

  • Left panel — colour / hatch blocks for each geological layer with lithology annotations and thickness values.

  • Right panel — log₁₀(ρ) depth curve overlaid on the same depth axis.

Parameters:
  • log (StratigraphicLog)

  • figsize (tuple)

  • depth_unit (str) – Label for the depth axis (default 'm').

  • title (str, optional)

  • annotation_kws (dict, optional) – Extra keyword arguments passed to ax.annotate.

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotFenceDiagram(logs, *, figsize=None, title='Fence Diagram', max_depth=None)[source]#

Bases: object

Multi-station fence diagram of pseudo-stratigraphic logs.

Plots every log as a vertical panel side by side, sharing the depth axis, so the lateral geological evolution along the profile is immediately visible.

Parameters:
  • logs (list of StratigraphicLog) – Ordered list of station logs (West → East, or South → North).

  • figsize (tuple, optional) – Defaults to (2 * n_logs, 10).

  • title (str, optional)

  • max_depth (float, optional) – Truncate display at this depth (metres).

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotCalibratedModel(crm, nm, misfit_map=None, *, figsize=(12, 10), cmap_rho='jet', vmin_rho=1.0, vmax_rho=5.0, title=None)[source]#

Bases: object

Compare CRM vs NM and display the G (%) misfit map.

Three sub-plots stacked vertically:

  1. CRM — original inversion result (log₁₀ρ colour image)

  2. NM — calibrated New Model (same colour scale)

  3. Misfit G (%) — diverging colour scale highlighting where the model was corrected the most

Parameters:
  • crm (ResistivityModel) – Original CRM.

  • nm (ResistivityModel) – Calibrated NM from calibrated_model().

  • misfit_map (ndarray (n_z, n_x), optional) – G (%) array from misfit_map(). If None, computed from the difference between nm and crm.

  • figsize (tuple)

  • cmap_rho (str) – Matplotlib colourmap for the resistivity panels.

  • vmin_rho (float) – Colour-scale limits for log₁₀(ρ).

  • vmax_rho (float) – Colour-scale limits for log₁₀(ρ).

  • title (str, optional)

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotHydroSection(result, quantity='K', *, style=None, cmap=None, vmin=None, vmax=None, show_water_table=True, figsize=None, title=None, depth_min=None, depth_max=None)[source]#

Bases: object

2-D hydrogeological section from an EMHydroResult.

Renders a colour-image cross-section of one quantitative hydro map (hydraulic conductivity K, water saturation Sw, or porosity φ) with optional overlays:

  • Water-table line — dashed blue line at the estimated WT depth.

  • Station markers — thin vertical tick-marks at each profile station.

Parameters:
  • result (EMHydroResult) – Quantitative hydro output from EMHydroModel.

  • quantity (str) – Which map to display: 'K' — hydraulic conductivity (log₁₀ scale), 'saturation' — water saturation Sw, 'porosity' — effective porosity φ.

  • cmap (str) – Matplotlib colourmap. Defaults: K → 'viridis', Sw → 'RdYlBu', φ → 'YlOrRd'.

  • vmin (float, optional) – Colour-scale limits. Auto-derived from the data if None.

  • vmax (float, optional) – Colour-scale limits. Auto-derived from the data if None.

  • show_water_table (bool) – Overlay the water-table depth profile (default True).

  • figsize (tuple)

  • title (str, optional)

  • depth_min (float, optional) – Start display at this depth (m). Use to zoom past near-surface artefacts and push a shallow water-table line into view.

  • depth_max (float, optional) – Truncate display at this depth (m).

  • style (_StyleArg)

Examples

>>> fig = PlotHydroSection(result, quantity='K').plot()
>>> fig = PlotHydroSection(result, quantity='saturation',
...                        cmap='Blues', vmin=0, vmax=1).plot()
plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotWaterTableProfile(result, *, style=None, color_wt=None, color_T=None, reference_depth=None, figsize=None, title=None)[source]#

Bases: object

Profile plot: water-table depth and transmissivity along the section.

Two stacked panels share the same x-axis (profile distance):

  • Top — water-table depth (m) as a stem/bar plot. Shallower is better; the y-axis is inverted so deep values plot downward.

  • Bottom — transmissivity T (m²/s) on a log₁₀ scale.

Parameters:
  • result (EMHydroResult)

  • figsize (tuple)

  • color_wt (str) – Colour for the water-table bars (default 'steelblue').

  • color_T (str) – Colour for the transmissivity bars (default 'seagreen').

  • reference_depth (float, optional) – Draw a horizontal dashed line at this depth on the WT panel (e.g. a known piezometric level).

  • title (str, optional)

  • style (_StyleArg)

Examples

>>> fig = PlotWaterTableProfile(result, reference_depth=20.0).plot()
plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotTimeLapseSection(timelapse, quantity='rho', *, style=None, survey_idx=0, baseline_idx=0, petro=None, rho_w=20.0, phi=0.25, cmap=None, vmax=None, show_water_table=True, figsize=None, title=None, depth_max=None)[source]#

Bases: object

Difference section for time-lapse EM monitoring.

Shows Δlog₁₀(ρ) or Δ*Sw* between a selected survey and the baseline as a diverging colour image, allowing rapid visual identification of zones that became more conductive (wetting) or more resistive (drying).

Parameters:
  • timelapse (TimeLapseEM) – Time-lapse container holding all surveys.

  • quantity (str) – 'rho' — raw resistivity change Δlog₁₀ρ (default). 'saturation' — saturation change ΔSw (requires petro and rho_w).

  • survey_idx (int) – Index of the comparison survey in timelapse.surveys relative to the baseline (default 0 → first non-baseline survey).

  • baseline_idx (int) – Index of the baseline survey (default 0).

  • petro (ArchieModel, optional) – Required when quantity='saturation'.

  • rho_w (float) – Pore-water resistivity for saturation inversion (default 20 Ω·m).

  • phi (float or ndarray) – Porosity for Archie inversion (default 0.25).

  • cmap (str) – Diverging colourmap (default 'RdBu_r'). Positive (blue) → resistivity increase / drying. Negative (red) → resistivity decrease / wetting.

  • vmax (float, optional) – Symmetric colour-scale limit. Auto-derived from the 98th percentile of |data| if None.

  • show_water_table (bool) – Overlay the water-table profile from the comparison survey.

  • figsize (tuple)

  • title (str, optional)

  • depth_max (float, optional)

  • style (_StyleArg)

Examples

>>> from pycsamt.interp.timelapse import TimeLapseEM
>>> tl  = TimeLapseEM([model_dry, model_wet], labels=['dry', 'wet'])
>>> fig = PlotTimeLapseSection(tl, quantity='rho').plot()
>>> fig = PlotTimeLapseSection(
...     tl, quantity='saturation',
...     petro=ArchieModel(), rho_w=20.0
... ).plot()
plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotUncertaintySection(unc, quantity='K', *, style=None, cmap_p50=None, cmap_spread=None, vmin_p50=None, vmax_p50=None, vmax_spread=None, show_water_table=True, figsize=None, title=None, depth_min=None, depth_max=None)[source]#

Bases: object

Two-panel section showing the P50 estimate and the uncertainty spread.

Panel layout:

  • Top — P50 (median) of the selected quantity as a colour image.

  • Bottom — Uncertainty spread: either the coefficient of variation (CV = std/mean, for K) or the P90–P10 range (for Sw, porosity).

Parameters:
  • unc (UncertaintyResult)

  • quantity (str) – 'K' (default) — hydraulic conductivity (log₁₀ scale for P50, CV for spread). 'saturation' — Sw (P50 and P90–P10 range). 'porosity' — φ (P50 and P90–P10 range).

  • cmap_p50 (str) – Colourmap for the P50 panel (defaults mirror PlotHydroSection).

  • cmap_spread (str) – Colourmap for the spread panel (default 'hot_r' — dark = high uncertainty).

  • vmin_p50 (float, optional) – Colour limits for P50 panel.

  • vmax_p50 (float, optional) – Colour limits for P50 panel.

  • vmax_spread (float, optional) – Upper colour limit for the spread panel. Auto if None.

  • show_water_table (bool) – Overlay median water-table on both panels (default True).

  • figsize (tuple)

  • title (str, optional)

  • depth_min (float, optional) – Start display at this depth (m) — mirrors PlotHydroSection.

  • depth_max (float, optional)

  • style (_StyleArg)

Examples

>>> fig = PlotUncertaintySection(unc_result, quantity='K').plot()
>>> fig = PlotUncertaintySection(unc_result, quantity='saturation',
...                              depth_max=200.0).plot()
plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotUncertaintyProfile(unc, *, style=None, color_wt=None, color_T=None, reference_depth=None, figsize=None, title=None)[source]#

Bases: object

Profile plot: water-table depth and transmissivity with P10–P90 envelopes.

Four data series are shown along the profile x-axis:

  • Top panel — water-table depth. Shaded band = P10–P90 range; solid line = P50 median. Optional reference depth.

  • Bottom panel — log₁₀(T). Shaded band = P10–P90; solid line = P50.

Parameters:
  • unc (UncertaintyResult)

  • figsize (tuple)

  • color_wt (str) – Colour for the water-table envelope (default 'steelblue').

  • color_T (str) – Colour for the transmissivity envelope (default 'seagreen').

  • reference_depth (float, optional) – Horizontal reference line on the WT panel.

  • title (str, optional)

  • style (_StyleArg)

Examples

>>> fig = PlotUncertaintyProfile(unc_result, reference_depth=20.0).plot()
plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotPetrophysicalCrossPlot(result, *, style=None, petro=None, color_by='saturation', show_hs_bounds=True, rho_matrix=5000.0, depth_range=None, Sw_for_curve=None, log_rho=True, figsize=None, title=None)[source]#

Bases: object

ρ vs φ scatter colored by Sw with the fitted Archie/WS model curve.

Reproduces the cross-plot of Fig. 3b/3c in Chen et al. (2026) for EM data. Each point is one model cell; the colour encodes water saturation (or depth). The petrophysical model curve is drawn at the mean observed saturation. Hashin-Shtrikman bounds are optionally shown as a shaded envelope — no existing tool combines all three in one panel.

Parameters:
  • result (EMHydroResult)

  • petro (ArchieModel or WaxmanSmitsModel, optional) – Defaults to result.config.petro.

  • color_by (str) – 'saturation' (default) or 'depth'.

  • show_hs_bounds (bool) – Overlay Hashin-Shtrikman bounds (default True).

  • rho_matrix (float) – Rock-matrix resistivity for HS bounds (Ω·m; default 5 000).

  • depth_range ((float, float), optional) – Restrict to this depth window (m).

  • Sw_for_curve (float, optional) – Sw value used to draw the model curve. Defaults to mean(Sw).

  • log_rho (bool) – Log₁₀ scale on the y-axis (default True).

  • style (_StyleArg)

  • figsize (tuple[float, float] | None)

  • title (str | None)

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotAquiferCharacterization(result, *, style=None, show_transmissivity=True, log_TR=True, reference_depth=None, figsize=None, title=None)[source]#

Bases: object

Dar-Zarrouk profile — TR, S, water table, and transmissivity.

Three or four stacked panels with a shared profile-distance x-axis:

  1. TR = Σρᵢhᵢ (Ω·m²) — aquifer productivity indicator. Threshold line at sty.tr_threshold.

  2. S = Σhᵢ/ρᵢ (siemens) — clay-seal protective capacity. Narain-Mehrotra class lines at sty.s_threshold_moderate and sty.s_threshold_good.

  3. WT — water-table depth (m).

  4. T — log₁₀(T) (m²/s), optional.

Parameters:
  • result (EMHydroResult)

  • show_transmissivity (bool) – Add a fourth T panel (default True).

  • log_TR (bool) – Use a log₁₀ y-axis for the TR panel (default True). Recommended when a resistive basement dominates TR and compresses the productive-aquifer bars to near-zero on a linear scale.

  • reference_depth (float, optional) – Horizontal dashed line on the WT panel.

  • style (_StyleArg)

  • figsize (tuple[float, float] | None)

  • title (str | None)

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotMultiTimeLapseGrid(timelapse, quantity='rho', *, style=None, surveys=None, baseline_idx=0, petro=None, rho_w=20.0, phi=0.25, vmin=None, vmax=None, depth_max=None, figsize_panel=None, title=None)[source]#

Bases: object

Grid of EM sections at successive time steps — Fig. 5c/5d equivalent.

N mini-sections in one row, shared colourbar on the right.

Parameters:
  • timelapse (TimeLapseEM)

  • quantity (str) – 'rho' — absolute log₁₀ρ. 'delta_rho' — Δlog₁₀ρ from baseline (diverging). 'delta_saturation' — ΔSw from baseline (requires petro).

  • surveys (list of int, optional) – Survey indices to show (default: all).

  • baseline_idx (int) – Baseline for delta quantities (default 0).

  • petro – Petrophysics for saturation conversion.

  • rho_w (float) – Petrophysics for saturation conversion.

  • phi (float) – Petrophysics for saturation conversion.

  • vmin (float, optional)

  • vmax (float, optional)

  • depth_max (float, optional)

  • figsize_panel ((w, h), optional) – Size of each mini panel.

  • style (_StyleArg)

  • title (str | None)

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotResistivityDepthProfile(source, station=0, *, style=None, depth_max=None, show_zones=True, borehole=None, log_rho=True, figsize=None, title=None)[source]#

Bases: object

1-D resistivity depth profile with zone shading — Fig. 3a equivalent.

Plots the EM inversion ρ(z) curve at one station with a fill and optional hydraulic zone shading derived from an EMHydroResult.

Parameters:
  • source (ResistivityModel or EMHydroResult)

  • station (str or int) – Station name or column index.

  • depth_max (float, optional)

  • show_zones (bool) – Shade aquifer / vadose / basement zones from EMHydroResult (True).

  • borehole (Borehole, optional) – If given, a narrow borehole panel is added on the right.

  • log_rho (bool) – Log-scale x-axis (default True).

  • style (_StyleArg)

  • figsize (tuple[float, float] | None)

  • title (str | None)

plot()[source]#

Render and return the matplotlib Figure.

class pycsamt.interp.plot.PlotUncertaintyHistogram(unc, quantity='water_table', *, style=None, stations=None, wt_ensemble=None, T_ensemble=None, show_kde=True, show_percentiles=True, log_x=None, ncols=None, figsize=None, title=None)[source]#

Bases: object

Posterior histograms of key hydro quantities per station.

Shows the full MC posterior for water-table depth or transmissivity at up to 6 stations, with histogram bars, optional KDE, and P10/P50/P90 vertical lines. When raw ensemble arrays are not passed, a Gaussian approximation is drawn from the stored statistics.

Parameters:
  • unc (UncertaintyResult)

  • quantity (str) – 'water_table' (default) or 'transmissivity'.

  • stations (list of str or int, optional) – Stations to display (default: up to 6 evenly spaced).

  • wt_ensemble (ndarray (n_samples, n_x), optional)

  • T_ensemble (ndarray (n_samples, n_x), optional)

  • show_kde (bool)

  • show_percentiles (bool)

  • log_x (bool, optional) – Log scale (default True for T, False for WT).

  • ncols (int) – Subplot columns (default min(n_sta, 3)).

  • style (_StyleArg)

  • figsize (tuple[float, float] | None)

  • title (str | None)

plot()[source]#

Render and return the matplotlib Figure.