1.8. Section Plot Layout#

pycsamt.api.section is the shared layout system behind every 2-D station-by-depth or station-by-period plot pyCSAMT draws: Pseudosection QC panels, inversion sections, and compact dashboard tiles alike. It answers three questions the same way for all of them – how big should the figure be, how should the axes behave, and how should the colourbar look – through PYCSAMT_SECTION, one singleton following the same pattern as Plot Styles and Interpretation Plot Styles.

Every demonstration below uses the same real WILLY AMT line as Plot Styles:

>>> from pathlib import Path
>>> from pycsamt.emtools import ensure_sites
>>> from pycsamt.emtools.qc import plot_frequency_confidence_psection
>>> from pycsamt.api.section import PYCSAMT_SECTION

>>> edi_dir = Path("data/AMT/WILLY_DATA/L18PLT")
>>> sites = ensure_sites(
...     edi_dir,
...     recursive=True,
...     on_dup="replace",
...     strict=False,
...     verbose=0,
... )
>>> len(sites)
28

The full science behind the confidence metric itself – plot_frequency_confidence_psection()’s method/metric arguments and what “confidence” means – is covered in Quality-Control Confidence Scoring; this page only uses it as a real, data-driven anchor for the layout system.

Six presets ship with the package – "pseudosection" (the default), "inversion", "publication", "compact", "dashboard", and "dynamic" – each bundling three leaf dataclasses: SectionFigureStyle (size and margins), SectionAxisStyle (labels, y-axis direction, aspect, and what the y-axis physically represents), and SectionColorbarStyle (placement and tick density). Printing the singleton summarises all six at once:

>>> print(PYCSAMT_SECTION)
PyCSAMTSection
  compact: figsize=(7.0, 3.1), y='down', stations='pseudosection', cbar_ticks<=4
  dashboard: figsize=(6.0, 3.0), y='down', stations='pseudosection', cbar_ticks<=4
  dynamic: figsize='dynamic', y='down', stations='pseudosection', cbar_ticks<=6
  inversion: figsize=(10.5, 5.2), y='down', stations='inversion', cbar_ticks<=6
  pseudosection: figsize=(9.5, 4.4), y='down', stations='pseudosection', cbar_ticks<=6
  publication: figsize=(8.2, 3.6), y='down', stations='pseudosection', cbar_ticks<=5

1.8.1. Figure Sizing: Static Vs. Dynamic#

Every preset except "dynamic" uses a fixed figsize regardless of how much data is plotted – appropriate for a consistent grid of comparison figures, but a 200-station line and a 6-station line get the same width:

>>> pub = PYCSAMT_SECTION.style_for("publication")
>>> pub.figure.figsize
(8.2, 3.6)
>>> pub.figsize_for(n_stations=6, n_y=20)
(8.2, 3.6)
>>> pub.figsize_for(n_stations=120, n_y=20)
(8.2, 3.6)

"dynamic" instead computes a width and height from the actual station count, period/depth sample count, and longest station label, then clamps the result between min_width/max_width and min_height/max_height:

>>> dyn = PYCSAMT_SECTION.style_for("dynamic")
>>> tuple(round(v, 2) for v in dyn.figsize_for(n_stations=6, n_y=20))
(7.5, 3.4)
>>> tuple(round(v, 2) for v in dyn.figsize_for(n_stations=28, n_y=40))
(7.5, 3.48)
>>> tuple(round(v, 2) for v in dyn.figsize_for(n_stations=200, n_y=40))
(15.0, 3.48)

The 200-station call hits max_width=15.0 and stops growing – a deliberate ceiling so a very long line still produces a figure that fits on a page or slide rather than growing without bound. figsize_for() is what every section-plotting function calls internally when figsize=None (the default); passing an explicit figsize= to any of them always wins over both the fixed and the dynamic calculation.

1.8.2. Named Presets In Practice#

>>> for preset in ["dynamic", "publication", "compact"]:
...     ax = plot_frequency_confidence_psection(sites, section=preset, verbose=0)

"dynamic" widens slightly for 28 real stations and keeps its own figure title; "publication" and "compact" both suppress the title (SectionAxisStyle(title=False)) and shrink progressively, trading station-label legibility for a smaller footprint – exactly the tradeoff to make deliberately rather than by trimming a figure after the fact.

1.8.3. Axis Direction And Topography Awareness#

SectionAxisStyle carries a y_type tag – "period"/"frequency" for pseudosections, "depth"/"elevation" for inversion sections – that topo_active() checks against the package-wide PYCSAMT_TOPO setting. A period pseudosection carries no real elevation information, so Topography rendering is silently skipped there even when it is globally enabled – only depth-like sections pick it up:

>>> from pycsamt.topo.config import PYCSAMT_TOPO

>>> pseudo = PYCSAMT_SECTION.style_for("pseudosection")
>>> inv = PYCSAMT_SECTION.style_for("inversion")
>>> pseudo.axis.y_type, inv.axis.y_type
('period', 'depth')
>>> pseudo.topo_active(), inv.topo_active()
(False, False)

>>> _ = PYCSAMT_TOPO.configure(enabled=True)
>>> pseudo.topo_active(), inv.topo_active()
(False, True)

>>> PYCSAMT_TOPO.reset()

y_direction="down" (the default on every preset) inverts the y-axis so shallow/high-frequency values plot at the top, matching how a geologist reads a cross-section; set it to "up" or "normal" only for non-depth y-axes where that convention would be misleading.

1.8.4. Colorbar Controls#

SectionColorbarStyle controls placement, width, and – most often tuned – tick density via max_ticks. Fewer ticks read better on a small multi-panel figure than the default:

>>> from pycsamt.api.section import configure_section, reset_section

>>> pub.colorbar.max_ticks
5
>>> configure_section(publication__colorbar__max_ticks=3)
>>> PYCSAMT_SECTION.publication.colorbar.max_ticks
3

>>> ax = plot_frequency_confidence_psection(sites, section="publication", verbose=0)
The same publication-preset pseudosection with only 3 colourbar ticks instead of 5.

Same data and preset as the publication panel above, after lowering max_ticks to 3 – fewer labels, same underlying colour scale.#

>>> reset_section()
>>> PYCSAMT_SECTION.publication.colorbar.max_ticks
5

1.8.5. Configuring And Sharing Styles#

The same dotted-path configure_section() and PYCSAMT_SECTION.context() entry points used above apply to every field on every preset – figure, axis, or colorbar – and the context manager restores all six presets exactly as they were, even if the block raises:

>>> PYCSAMT_SECTION.pseudosection.figure.figsize
(9.5, 4.4)

>>> with PYCSAMT_SECTION.context("compact", pseudosection__axis__grid=True):
...     PYCSAMT_SECTION.pseudosection.figure.figsize, PYCSAMT_SECTION.pseudosection.axis.grid
((7.0, 3.1), True)

>>> PYCSAMT_SECTION.pseudosection.figure.figsize, PYCSAMT_SECTION.pseudosection.axis.grid
((9.5, 4.4), False)

PYCSAMT_SECTION.context(preset, ...) copies preset into the pseudosection slot for the duration of the block (mirroring use_preset()), applies any dotted-path overrides on top, then restores every preset – not only pseudosection – to its prior state on exit.

Each SectionStyle also carries a station_preset field ("pseudosection" or "inversion" by default) that apply_stations() uses to pull the matching station-marker style from pycsamt.api.station – station ticks, markers, and label rotation are configured separately from everything on this page, but every section preset already points at a sensible default for its own use case.

1.8.6. Next Steps#