2.30. pycsamt.map#
Code-first station, profile, and 3-D mapping tools for pyCSAMT.
The pycsamt.map package is the reusable mapping layer for
scripts, notebooks, and applications. It accepts the same survey
inputs as pycsamt.emtools._core.ensure_sites(): an EDI
directory, one or more EDI files, EDI-like objects, or a
pycsamt.site.Sites container. For multi-line surveys, use
pycsamt.map.load_lines() or pycsamt.map.MapView.
2.30.1. Quick Use#
Function-style use is compact and works well in notebooks.
from pycsamt.map import (
ProfileMapOptions,
StationMapOptions,
VolumeMapOptions,
plot_pseudosection,
plot_station_map,
plot_volume_map,
)
line = "data/AMT/WILLY_DATA/L18PLT"
station_fig = plot_station_map(
line,
options=StationMapOptions(
overlay="rho",
frequency=10.0,
component="xy",
frequency_tolerance=2.0,
),
)
pseudo_fig = plot_pseudosection(
line,
options=ProfileMapOptions(
quantity="phase",
components=("xy", "yx"),
x_axis="distance",
),
)
volume_fig = plot_volume_map(
line,
options=VolumeMapOptions(
mode="fence",
component="xy",
depth_range=(0.0, 2000.0),
),
)
2.30.2. Builder API#
Builder classes keep one normalized survey in memory and let you create variants without reloading the EDI data.
from pycsamt.map import ProfileMap, StationMap, VolumeMap
station = (
StationMap("data/AMT/WILLY_DATA/L18PLT")
.with_overlay("skin_depth", frequency=10.0)
.with_options(show_labels=False)
.figure()
)
profile = (
ProfileMap("data/AMT/WILLY_DATA/L18PLT")
.with_quantity("rho")
.with_components("xy", "yx")
.pseudosection()
)
volume = (
VolumeMap("data/AMT/WILLY_DATA/L18PLT")
.with_mode("surface")
.with_quantity("phase")
.figure()
)
2.30.3. MapView#
pycsamt.map.MapView is a session facade for code users who
want the same survey to drive station, profile, and 3-D views.
from pycsamt.map import MapView
mv = MapView.from_folder(
"data/AMT/WILLY_DATA",
detect="folder",
)
station = mv.station(overlay="elevation")
pseudo = mv.pseudosection(component="xy")
fence = mv.map3d(mode="fence", depth_range=(0.0, 2000.0))
2.30.4. Export#
Use pycsamt.map.export_figure() for format-aware export, or
the direct helpers for explicit output types.
from pycsamt.map import ExportOptions, export_figure
export_figure(
station,
ExportOptions(path="station.html"),
)
export_figure(
fence,
ExportOptions(path="fence", format="html"),
)
2.30.5. Scientific Note#
The 3-D map modes in pycsamt.map are quick-look
visualizations. Fence, block, depth-slice, and isosurface views use
pseudo-depth grids derived from apparent resistivity and period. They
are useful for inspection and communication, but they are not a
replacement for a constrained 2-D or 3-D inversion model.
2.30.6. Public API#
Code-first mapping API for pyCSAMT surveys.
This package provides reusable station, profile, and 3-D map builders for scripts, notebooks, and applications.
Functions accept the same flexible inputs used by
pycsamt.emtools.ensure_sites: an EDI path, a directory,
an iterable of EDI-like objects, or a Sites instance.
- class pycsamt.map.BasemapConfig(style, center, zoom, bearing=0.0, layers=())#
Bases:
objectPlotly geographic map layout settings.
- class pycsamt.map.ComponentSpec(name, indices=None, mode='tensor')#
Bases:
objectParsed impedance component request.
- class pycsamt.map.CRSConfig(source, target=4326, always_xy=True)#
Bases:
objectCoordinate transform settings.
- pycsamt.map.basemap_style_and_layers(style, *, dark=False)#
Resolve a style name into a (base style, raster layers) pair.
ESRI styles are rendered as
white-bg+ a raster tile layer; native Plotly styles are returned as-is with no layers.
- pycsamt.map.build_geo_contour_image(lons, lats, values, *, cmap='jet', n_levels=12, opacity=0.6, mode='filled+lines', log_scale=False, grid_res=160, expand=0.06, interp='cubic', smooth_sigma=0.0, vmin=None, vmax=None)#
Render a Surfer-style filled-contour PNG for a basemap image layer.
Interpolates sparse station values onto a regular lon/lat grid and rasterises filled (and/or line) contours to a transparent PNG. The result is meant to be added to a Plotly map as an
imagelayer.- Returns:
{"image": "data:image/png;base64,...", "coordinates": [...], "vmin": float, "vmax": float}(coordinates are the TL, TR, BR, BL[lon, lat]corners), orNonewhen it cannot be built.- Return type:
dict | None
- Parameters:
- class pycsamt.map.ExportOptions(path, format=None, width=None, height=None, scale=2.0, include_plotlyjs='cdn')#
Bases:
objectOptions used by figure export helpers.
- Parameters:
- class pycsamt.map.FrequencySelection(requested, actual, index, delta, relative_delta, within_tolerance=True)#
Bases:
objectNearest-frequency selection metadata.
- Parameters:
- class pycsamt.map.FrequencyValue(station, value, selection)#
Bases:
objectStation value and selected-frequency metadata.
- Parameters:
station (str)
value (float)
selection (FrequencySelection)
- selection: FrequencySelection#
- class pycsamt.map.Map3D(data, *, options=None, **ensure_kwargs)#
Bases:
objectBuilder object for 3-D survey maps.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
ensure_kwargs (Any)
- with_options(**kwargs)#
Return a copy with updated options.
- with_quantity(quantity)#
Return a copy using another mapped quantity.
- with_component(component)#
Return a copy using another component.
- class pycsamt.map.MapData(sites, stations=(), profiles=(), metadata=<factory>)#
Bases:
objectNormalized survey data shared by map renderers.
- Parameters:
sites (Any)
stations (tuple[StationRecord, ...])
profiles (tuple[ProfileLine, ...])
- stations: tuple[StationRecord, ...] = ()#
- profiles: tuple[ProfileLine, ...] = ()#
- class pycsamt.map.MapView(data, *, theme='light', backend='plotly')#
Bases:
objectA code-first session bound to one (multi-line) survey.
- classmethod from_folder(path, *, detect='folder', recursive=True, theme='light', backend='plotly', **load_kwargs)#
Build a view from a directory of one or more lines.
- classmethod from_lines(lines, *, theme='light', backend='plotly', **load_kwargs)#
Build a view from an explicit
{line: source}mapping.
- classmethod from_inversion_results(folder, *, known_stations=None, fetch_elevation=True, theme='light', backend='plotly', verbose=0)#
Build a view from a ModEM 3-D inversion result folder.
See
pycsamt.map.inversion.load_modem_lines(). Passknown_stations=existing_view.data.stationsto geo-reference and group ModEM stations using a previously-loaded EDI survey. Passfetch_elevation=Falseto skip the best-effort online elevation lookup (e.g. offline use, or large surveys where the extra round-trip isn’t wanted).
- classmethod from_pcsf(path, *, known_stations=None, fetch_elevation=True, theme='light', backend='plotly', mesh_z_samples=60)#
Build a view from a backend-neutral
.pcsf/.pcsm/.pcsm.gzfile.See
pycsamt.map.inversion.load_pcsf_lines(). Works with a file in either PCSF encoding (binary.pcsfor its lossless ASCII sibling,.pcsm/gzip-compressed.pcsm.gz— seepycsamt/format/SPEC.mdS9) with any of the four geometry kinds —grid2d,multiline, nativegrid3d(e.g. ModEM 3-D), ormesh_unstructured(e.g. MARE2DEM, sampled by point-location on its real triangulation, seemesh_z_samples) — passknown_stations=existing_view.data.stationsto geo-reference it against a previously-loaded EDI survey, the same asfrom_inversion_results().
- table()#
Return survey stations as a
pandas.DataFrame.
- with_elevations(elev_map)#
Return a copy with station elevations overridden by elev_map.
- fetch_elevations(*, api_name='open_meteo')#
Fetch station elevations online (see
pycsamt.map.fetch_elevations()).
- export_topography(path, *, fmt=None)#
Export this survey’s station id/elevation/coordinates.
Useful for an EDI-sourced view: a ModEM (or Occam2D/MARE2DEM) inversion result carries no real elevation of its own, so exporting it here produces a small, portable file that can be re-applied later — even in a session that never reloads these EDIs — via the “Upload file” elevation source (see
pycsamt.map.topo.export_elevations()).
- station(*, options=None, **overrides)#
Build a 2-D station map figure.
- Parameters:
options (StationMapOptions | None)
overrides (Any)
- Return type:
- profile(*, options=None, **overrides)#
Build a profile-view figure.
- Parameters:
options (ProfileMapOptions | None)
overrides (Any)
- Return type:
- pseudosection(*, options=None, **overrides)#
Build a resistivity/phase pseudosection figure.
- Parameters:
options (ProfileMapOptions | None)
overrides (Any)
- Return type:
- map3d(*, mode='fence', options=None, **overrides)#
Build a 3-D fence/block/depth/surface figure.
- Parameters:
mode (str)
options (VolumeMapOptions | None)
overrides (Any)
- Return type:
- figure(view='station', **overrides)#
Build a figure for view by name.
- Parameters:
view ({"station", "profile", "pseudosection", "map3d"}) – Which renderer to call.
**overrides – Forwarded to the matching renderer.
- Return type:
- export(path, *, view='station', fmt=None, scale=2.0, width=None, height=None, **overrides)#
Render view and write it to path.
The format is inferred from the suffix unless fmt is given;
.html,.png,.jsonand Plotly static images are supported (seepycsamt.map.export_figure()).
- export_all(directory, *, fmt='html', views=('station', 'pseudosection', 'map3d'), **overrides)#
Export several views into directory, keyed by view name.
- class pycsamt.map.ProfileLine(name, stations=())#
Bases:
objectA named sequence of stations in one profile.
- Parameters:
name (str)
stations (tuple[StationRecord, ...])
- stations: tuple[StationRecord, ...] = ()#
- class pycsamt.map.ProfileMap(data, *, options=None, **ensure_kwargs)#
Bases:
objectBuilder object for profile maps.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
ensure_kwargs (Any)
- with_quantity(quantity)#
Return a copy using another mapped quantity.
- Parameters:
quantity (str)
- Return type:
- with_component(component)#
Return a copy using one impedance component.
- Parameters:
component (str)
- Return type:
- class pycsamt.map.ProfileMapOptions(quantity='rho', component='xy', components=('xy', 'yx'), theme='light', backend='plotly', period_range=None, phase_range=None, value_range=None, x_axis='station', log_rho=True, height_per_panel=260, show_errbar=False, cmap=None, by_line=False, line_cols=None)#
Bases:
objectOptions for pseudosection and profile-view maps.
- class pycsamt.map.StationMap(data, *, options=None, **ensure_kwargs)#
Bases:
objectBuilder object for station-map figures.
- Parameters:
data (Any)
options (StationMapOptions | None)
ensure_kwargs (Any)
- with_overlay(overlay, **kwargs)#
Return a copy with a different overlay.
- Parameters:
- Return type:
- class pycsamt.map.StationMapOptions(overlay='index', frequency=None, frequency_tolerance=None, depth=None, show_markers=True, component='xy', theme='light', backend='plotly', selected_id=None, line_filter=None, marker_size=10, basemap=None, cmap='plasma', value_range=None, log_color=False, opacity=0.92, show_labels=True, label_fontsize=8.0, label_rotation=0.0, show_profiles=True, elevation_mode='markers', show_contours=False, contour_image=False, contour_mode='filled+lines', contour_levels=12, contour_opacity=0.55, contour_interp='linear', contour_smooth=1.0, contour_grid_res=150, bearing=0.0, title='')#
Bases:
objectOptions for 2-D station maps.
- Parameters:
overlay (str)
frequency (float | None)
frequency_tolerance (float | None)
depth (float | None)
show_markers (bool)
component (str)
theme (Literal['light', 'dark', 'publication'])
backend (Literal['plotly', 'matplotlib'])
selected_id (str | None)
marker_size (int)
basemap (str | None)
cmap (str)
log_color (bool)
opacity (float)
show_labels (bool)
label_fontsize (float)
label_rotation (float)
show_profiles (bool)
elevation_mode (Literal['markers', 'contours'])
show_contours (bool)
contour_image (bool)
contour_mode (str)
contour_levels (int)
contour_opacity (float)
contour_interp (str)
contour_smooth (float)
contour_grid_res (int)
bearing (float)
title (str)
- class pycsamt.map.StationRecord(id, latitude=None, longitude=None, elevation=None, line=None, index=0, source=None)#
Bases:
objectA normalized station row used by map renderers.
- Parameters:
- class pycsamt.map.VolumeMapOptions(mode='fence', quantity='resistivity', component='xy', theme='light', cmap='RdYlBu_r', depth_range=None, period_range=None, rho_range=None, iso_range=None, value_range=None, crange_percentile=(2.0, 98.0), rho_display_max=None, log_color=True, opacity=0.85, show_contours=False, show_labels=True, n_slices=5, surface_count=12, line_spacing=1.0, azimuth=0.0, topography=True, show_terrain=True, terrain_opacity=0.7, show_stations=False, station_symbol='diamond', station_size=4, station_color='#1f2937', station_labels=False, station_label_angle=0.0, station_label_fraction=1.0, station_label_names=None, max_stations=None, aspectmode='data', vertical_exaggeration=None, x_unit='m', depth_unit='m', smooth_sections=True, section_res=100, volume_smoothing=0.0, title='', geology=None, geology_legend=True, geology_legend_style='swatch', geology_fill='solid', geology_patterns=None, pattern_tile_size_m=20.0)#
Bases:
objectOptions for 3-D fence, block, and depth-slice maps.
- Parameters:
mode (Literal['fence', 'block', 'depth', 'surface'])
quantity (str)
component (str)
theme (Literal['light', 'dark', 'publication'])
cmap (str)
rho_display_max (float | None)
log_color (bool)
opacity (float)
show_contours (bool)
show_labels (bool)
n_slices (int)
surface_count (int)
line_spacing (float)
azimuth (float)
topography (bool)
show_terrain (bool)
terrain_opacity (float)
show_stations (bool)
station_symbol (str)
station_size (int)
station_color (str)
station_labels (bool)
station_label_angle (float)
station_label_fraction (float)
max_stations (int | None)
aspectmode (str)
vertical_exaggeration (float | None)
x_unit (str)
depth_unit (str)
smooth_sections (bool)
section_res (int)
volume_smoothing (float)
title (str)
geology (tuple[tuple[float, float, str] | tuple[float, float, str, str], ...] | None)
geology_legend (bool)
geology_legend_style (str)
geology_fill (str)
geology_patterns (dict | None)
pattern_tile_size_m (float)
- pycsamt.map.apply_elevations(data, elev_map)#
Return a copy of data with station elevations overridden.
- pycsamt.map.build_3d_map(data, options)#
Build the concrete 3-D figure.
- Parameters:
data (MapData)
options (VolumeMapOptions)
- Return type:
- pycsamt.map.build_basemap_layout(lon, lat, *, dark=False, style=None, bearing=0.0)#
Return layout settings for geographic station maps.
- pycsamt.map.build_contour_overlay(x, y, values, *, levels=12, cmap='Viridis', opacity=0.65, grid_size=80, mode='lines')#
Build an interpolated map contour overlay.
Returns a Plotly
Contourtrace on a regular grid.
- pycsamt.map.build_profile_line_overlay(x, y, *, geo=False, name='Profile', color='#2563eb', width=2.0)#
Build a reusable profile-line overlay trace.
- pycsamt.map.build_profile_map(data, options)#
Build the concrete profile-view figure.
- Parameters:
data (MapData)
options (ProfileMapOptions)
- Return type:
- pycsamt.map.build_pseudosection(data, options)#
Build the concrete pseudosection figure.
- Parameters:
data (MapData)
options (ProfileMapOptions)
- Return type:
- pycsamt.map.build_station_map(data, options=None)#
Build a Plotly 2-D station map.
- Parameters:
data (MapData)
options (StationMapOptions | None)
- Return type:
- pycsamt.map.build_station_label_overlay(x, y, labels, *, geo=False, name='Station labels', color='#111827')#
Build a reusable station-label overlay trace.
- pycsamt.map.build_topography_overlay(x, y, elevation, *, opacity=0.7, colorscale='Earth')#
Build a Plotly 3-D terrain mesh or surface.
- pycsamt.map.component_spec(component)#
Return a parsed impedance component specification.
- Parameters:
component (str | None)
- Return type:
- pycsamt.map.ensure_map_data(data, *, recursive=True, line_map=None, verbose=0)#
Return normalized map data.
- Parameters:
data (Any) – EDI path, directory, iterable, or
Sites.recursive (bool) – Passed to
pycsamt.emtools._core.ensure_sites().line_map (dict[str, Iterable[str]] | None) – Optional
line -> station namesmapping used when line metadata is not embedded in EDI objects.verbose (int) – Verbosity passed to
ensure_sites().
- Return type:
- pycsamt.map.export_elevations(data, path, *, fmt=None)#
Export station id/elevation/coordinates to CSV or HDF5.
EDI files carry real, field-surveyed elevation; a ModEM (or Occam2D/MARE2DEM) inversion result does not. Exporting a survey’s EDI-derived topography here produces a small, portable lookup table —
station+elevation(pluslatitude/longitude/linefor provenance) — thatparse_elevation_file()already knows how to read back in. That means it can be applied to an inversion-sourced view later via the “Upload file” elevation source, in a different session that never reloads the original EDIs, matching stations by id (with the same normalized fallback used byapply_elevations()).- Parameters:
data (MapData) – Survey to export (typically EDI-sourced, where
elevationis already populated).path (path-like) – Destination file.
fmtdefaults to the file’s own suffix (.csv/.h5/.hdf5); pass it explicitly to override.fmt ({"csv", "h5", "hdf5"}, optional)
- Returns:
The path written to.
- Return type:
- Raises:
ValueError – If no station in data has a known elevation, or fmt is unsupported.
- pycsamt.map.export_figure(fig, options)#
Export fig according to options.
- Parameters:
fig (Any)
options (ExportOptions)
- Return type:
- pycsamt.map.fetch_elevations(data, *, api_name='open_meteo')#
Fetch station elevations online from their coordinates.
Uses
pycsamt.gis.utils.get_elevation_from_api()(needs an internet connection andrequests).
- pycsamt.map.figure_to_dict(fig)#
Return a serializable figure dictionary.
- pycsamt.map.group_modem_stations(station_names, *, known_stations=None)#
Group ModEM station names into survey lines.
Prefers matching each name against known_stations (e.g. previously loaded EDI stations) and using their
linetag. Falls back to parsing the line token out of the station-name convention{survey}-{line}-{station}{suffix}(e.g.23-18-001A-> line18) — a heuristic, used only when a station has no match in known_stations.
- pycsamt.map.interpolate_overlay_grid(x, y, values, *, grid_size=80, method='linear')#
Interpolate scattered values to a regular grid.
- pycsamt.map.load_lines(source, *, detect='folder', recursive=True, line_map=None, verbose=0)#
Build one combined
MapDatafrom multiple lines.- Parameters:
source (Any) – Mapping, sequence, directory, or file (see module docstring). A
MapDatais returned unchanged.detect ({"folder", "auto", "flat"}, default "folder") –
Line-grouping rule applied only when source is a single directory:
folderOne line per immediate sub-folder holding EDI files (a flat folder becomes one line named after it).
autoGroup by the station-ID prefix, e.g.
22-001->L22.flatTreat the whole directory as a single line.
recursive (bool) – Recurse into sub-directories when discovering EDI files and when calling
ensure_map_data().line_map (dict[str, Iterable[str]] | None) – Optional
line -> station namesmapping forwarded toensure_map_data()for sources without embedded line metadata.verbose (int) – Verbosity forwarded to
ensure_map_data().
- Returns:
Stations from every line, re-indexed and tagged with their resolved line name; profiles are rebuilt per line.
- Return type:
- pycsamt.map.load_modem_lines(folder, *, known_stations=None, fetch_elevation=True, verbose=0)#
Load a ModEM 3-D inversion result folder as a multi-line MapData.
- Parameters:
folder (path-like) – A ModEM output directory. The matching final-iteration
.rho/.datpair is auto-detected bypycsamt.models.modem.results.InversionResult.known_stations (iterable of StationRecord, optional) – Previously-loaded EDI stations (e.g.
existing_map_data.stations) used to geo-reference and group ModEM stations by real coordinates/line name — see the module docstring.fetch_elevation (bool, default True) – ModEM output carries no real elevation (unlike EDI, where it’s already in the file header, so “Drape topography” just works). When
True, any station still missing an elevation afterknown_stationsmatching gets a best-effort online lookup (Open-Meteo) so topography isn’t silently flat by default. Failures (offline, API error, …) are swallowed — elevation simply stays unset, same as passingFalse.verbose (int, default 0) – Verbosity forwarded to the ModEM readers.
- Returns:
sites=None(no EDI backing);stationscarries oneStationRecordper ModEM station with coordinates resolved where possible;metadata["sections"]carries the precomputed per-line(x, z, rho)curtains consumed directly bypycsamt.map.volume.- Return type:
- pycsamt.map.launch_app(source=None, *, host='127.0.0.1', port=8770, debug=False, open_browser=True, theme='light', backend='plotly', detect='folder', recursive=True, **load_kwargs)#
Launch the interactive map-view app.
- Parameters:
source (Any) – Optional survey source.
Nonestarts the welcome screen. Otherwise accepts data, paths, sites, or mappings.host (str) – Forwarded to
pycsamt.app.mapview.launch().port (int) – Forwarded to
pycsamt.app.mapview.launch().debug (bool) – Forwarded to
pycsamt.app.mapview.launch().open_browser (bool) – Forwarded to
pycsamt.app.mapview.launch().detect (str) – Used for path/folder inputs.
recursive (bool) – Used for path/folder inputs.
**load_kwargs (Any) – Extra options forwarded to
MapView.from_folderorload_lines().
- Return type:
None
- pycsamt.map.launch_mapview(source=None, **kwargs)#
Alias for
launch_app().
- pycsamt.map.normalize_component(component)#
Return the canonical map component name.
- pycsamt.map.normalize_epsg(epsg)#
Return an EPSG authority string.
- pycsamt.map.normalize_station_id(name)#
Loosely-normalized station id for fuzzy matching.
Lowercases and strips everything but letters/digits, so minor formatting differences between sources —
23-18-001Avs23_18_001avs23 18 001A— still match. Used as a fallback tier (never the only lookup) wherever a station from one source (EDI, ModEM, an uploaded elevation file, …) needs to be matched against another.
- pycsamt.map.open_app(source=None, **kwargs)#
Backward-compatible alias for
launch_app().
- pycsamt.map.parse_elevation_file(content, filename)#
Parse an uploaded elevation file into
{station_id: elev}.Supports CSV, HDF5 (
.h5/.hdf5) and NPZ. The file must hold a station-id column/array (one ofstation,id,name,sta) and an elevation column/array (elevation,elev,z,alt,altitude,height). Returns{}on any parse failure rather than raising.
- pycsamt.map.plot_3d_map(data, *, options=None, **kwargs)#
Build a 3-D map.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.plot_profile_map(data, *, options=None, **kwargs)#
Build a profile-view map.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.plot_pseudosection(data, *, options=None, **kwargs)#
Build a resistivity or phase pseudosection.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.plot_station_map(data, *, options=None, **kwargs)#
Build a 2-D station map.
- Parameters:
data (Any)
options (StationMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.plot_volume_map(data, *, options=None, **kwargs)#
Build a 3-D volume map.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.inversion_depth_range(data)#
(z_min, z_max)across every precomputed inversion section, orNonewhen the survey carries no inversion result.
- pycsamt.map.all_resistivity_values(data)#
Every finite, positive resistivity sample the 3-D volume renderers could draw data from – pre-computed inversion sections (
data.metadata["sections"]) when present, else each station’s raw EDI resistivity (Z.resistivity).Used by Map View’s Interpretation “auto-suggest” to propose a geology legend covering what a fence/block/depth/iso view is actually rendering, rather than a rock database’s full literature range. Returns an empty array (never raises) when neither source is usable.
- pycsamt.map.reproject_xy_to_lonlat(x, y, *, epsg)#
Reproject x, y from epsg to WGS84 lon/lat.
- pycsamt.map.resistivity_at_depth(data, depth)#
Per-station resistivity on a horizontal slice at
depth(m below the surface), read from the precomputed inversion sections indata.metadata["sections"].Each station column is linearly interpolated in depth; a query outside a column’s own sampled range returns no entry for that station (never a fabricated value). Returns
{}when the survey has no inversion result.
- pycsamt.map.resolve_crs_info(mode='geo', *, zone=50, hemisphere='N', epsg=4326)#
Return a human-readable CRS description.
- pycsamt.map.resolve_line_groups(source, *, detect='folder', recursive=True)#
Return a
{line_name: source}mapping for source.The values are passed straight to
ensure_map_data(), so they may be directories, lists of file paths, or EDI-like iterables. This mirrors thegroupsstore used by the GUI loader, making the two paths share one grouping contract.
- pycsamt.map.save_png(fig, path, **kwargs)#
Save a Matplotlib-like or Plotly-like figure as PNG.
- pycsamt.map.select_frequency(frequencies, requested=None, *, tolerance=None)#
Select the closest finite positive frequency.
- Parameters:
- Return type:
FrequencySelection | None
- pycsamt.map.transform_xy(x, y, *, crs)#
Transform coordinates between two CRS definitions.
- pycsamt.map.value_at_frequency_details(data, *, frequency, quantity='rho', component='xy', tolerance=None)#
Return values with selected-frequency metadata.
- pycsamt.map.write_html(fig, path, **kwargs)#
Write a Plotly-like figure to HTML.
- pycsamt.map.write_dict(fig, path)#
Write a figure dictionary as JSON text.
- pycsamt.map.write_image(fig, path, **kwargs)#
Write a Plotly-like image.
2.30.7. Modules#
Configuration dataclasses for |
|
Core data extraction helpers for |
|
Multi-line EDI ingestion for |
|
High-level |
|
2-D station-map API for pyCSAMT surveys. |
|
Profile-view and pseudosection API for pyCSAMT surveys. |
|
3-D map API for fence, block, and depth-slice views. |
|
Overlay helpers for station, profile, and 3-D maps. |
|
|
Style helpers for pyCSAMT map renderers. |
Figure export helpers for |
|
|
Import geophysical inversion results into |
|
Elevation / topography sources for |
Real-geometry line-layout helpers for 3-D survey maps. |
|
Place PCBH boreholes in the 3-D map's local scene coordinates. |
2.30.8. Detailed Module API#
Core data extraction helpers for pycsamt.map.
- pycsamt.map._core.normalize_station_id(name)[source]#
Loosely-normalized station id for fuzzy matching.
Lowercases and strips everything but letters/digits, so minor formatting differences between sources —
23-18-001Avs23_18_001avs23 18 001A— still match. Used as a fallback tier (never the only lookup) wherever a station from one source (EDI, ModEM, an uploaded elevation file, …) needs to be matched against another.
- class pycsamt.map._core.StationRecord(id, latitude=None, longitude=None, elevation=None, line=None, index=0, source=None)[source]#
Bases:
objectA normalized station row used by map renderers.
- Parameters:
- class pycsamt.map._core.ProfileLine(name, stations=())[source]#
Bases:
objectA named sequence of stations in one profile.
- Parameters:
name (str)
stations (tuple[StationRecord, ...])
- stations: tuple[StationRecord, ...] = ()#
- class pycsamt.map._core.MapData(sites, stations=(), profiles=(), metadata=<factory>)[source]#
Bases:
objectNormalized survey data shared by map renderers.
- Parameters:
sites (Any)
stations (tuple[StationRecord, ...])
profiles (tuple[ProfileLine, ...])
- stations: tuple[StationRecord, ...] = ()#
- profiles: tuple[ProfileLine, ...] = ()#
- class pycsamt.map._core.ComponentSpec(name, indices=None, mode='tensor')[source]#
Bases:
objectParsed impedance component request.
- class pycsamt.map._core.FrequencySelection(requested, actual, index, delta, relative_delta, within_tolerance=True)[source]#
Bases:
objectNearest-frequency selection metadata.
- Parameters:
- class pycsamt.map._core.FrequencyValue(station, value, selection)[source]#
Bases:
objectStation value and selected-frequency metadata.
- Parameters:
station (str)
value (float)
selection (FrequencySelection)
- selection: FrequencySelection#
- pycsamt.map._core.ensure_map_data(data, *, recursive=True, line_map=None, verbose=0)[source]#
Return normalized map data.
- Parameters:
data (Any) – EDI path, directory, iterable, or
Sites.recursive (bool) – Passed to
pycsamt.emtools._core.ensure_sites().line_map (dict[str, Iterable[str]] | None) – Optional
line -> station namesmapping used when line metadata is not embedded in EDI objects.verbose (int) – Verbosity passed to
ensure_sites().
- Return type:
- pycsamt.map._core.station_records(data, **kwargs)[source]#
Return normalized station records for data.
- Parameters:
- Return type:
tuple[StationRecord, …]
- pycsamt.map._core.profile_lines(data, **kwargs)[source]#
Return normalized profile lines for data.
- Parameters:
- Return type:
tuple[ProfileLine, …]
- pycsamt.map._core.component_spec(component)[source]#
Return a parsed impedance component specification.
- Parameters:
component (str | None)
- Return type:
- pycsamt.map._core.component_index(component)[source]#
Return tensor indices for an impedance component.
- pycsamt.map._core.component_values(arr, component, *, quantity='rho')[source]#
Extract a 1-D value series for one component.
- pycsamt.map._core.select_frequency(frequencies, requested=None, *, tolerance=None)[source]#
Select the closest finite positive frequency.
- Parameters:
- Return type:
FrequencySelection | None
- pycsamt.map._core.value_at_frequency(data, *, frequency, quantity='rho', component='xy', tolerance=None)[source]#
Return station values at the closest frequency.
- pycsamt.map._core.value_at_frequency_details(data, *, frequency, quantity='rho', component='xy', tolerance=None)[source]#
Return values with selected-frequency metadata.
- pycsamt.map._core.skin_depth_at_frequency(data, *, frequency, component='xy', tolerance=None)[source]#
Return skin depth at the closest frequency.
- pycsamt.map._core.inversion_depth_range(data)[source]#
(z_min, z_max)across every precomputed inversion section, orNonewhen the survey carries no inversion result.
- pycsamt.map._core.resistivity_at_depth(data, depth)[source]#
Per-station resistivity on a horizontal slice at
depth(m below the surface), read from the precomputed inversion sections indata.metadata["sections"].Each station column is linearly interpolated in depth; a query outside a column’s own sampled range returns no entry for that station (never a fabricated value). Returns
{}when the survey has no inversion result.
- pycsamt.map._core.all_resistivity_values(data)[source]#
Every finite, positive resistivity sample the 3-D volume renderers could draw data from – pre-computed inversion sections (
data.metadata["sections"]) when present, else each station’s raw EDI resistivity (Z.resistivity).Used by Map View’s Interpretation “auto-suggest” to propose a geology legend covering what a fence/block/depth/iso view is actually rendering, rather than a rock database’s full literature range. Returns an empty array (never raises) when neither source is usable.
- pycsamt.map._core.pseudosection_table(data, *, quantity='rho', component='xy')[source]#
Return long-form profile data for pseudosections.
Multi-line EDI ingestion for pycsamt.map.
A map-view survey is usually made of several profile lines, each
stored as its own EDI folder. The renderers in pycsamt.map
already understand the per-station line attribute, but the
normalizer pycsamt.map._core.ensure_map_data() only consumes a
single source. This module lifts the multi-line grouping logic out
of the GUI layer so scripts and notebooks can build one combined
MapData from many lines.
2.30.8.1. Accepted source forms#
- mapping
{line_name: dir | iterable_of_edis}— explicit line layout.- sequence of directories
[dir_a, dir_b, ...]— one line per directory (named after it).- sequence of EDI-like items / files
Treated as a single
"line".- single directory
Grouped according to detect (see
load_lines()).- single file
A one-station line named after the file stem.
- pycsamt.map.loader.load_lines(source, *, detect='folder', recursive=True, line_map=None, verbose=0)[source]#
Build one combined
MapDatafrom multiple lines.- Parameters:
source (Any) – Mapping, sequence, directory, or file (see module docstring). A
MapDatais returned unchanged.detect ({"folder", "auto", "flat"}, default "folder") –
Line-grouping rule applied only when source is a single directory:
folderOne line per immediate sub-folder holding EDI files (a flat folder becomes one line named after it).
autoGroup by the station-ID prefix, e.g.
22-001->L22.flatTreat the whole directory as a single line.
recursive (bool) – Recurse into sub-directories when discovering EDI files and when calling
ensure_map_data().line_map (dict[str, Iterable[str]] | None) – Optional
line -> station namesmapping forwarded toensure_map_data()for sources without embedded line metadata.verbose (int) – Verbosity forwarded to
ensure_map_data().
- Returns:
Stations from every line, re-indexed and tagged with their resolved line name; profiles are rebuilt per line.
- Return type:
- pycsamt.map.loader.resolve_line_groups(source, *, detect='folder', recursive=True)[source]#
Return a
{line_name: source}mapping for source.The values are passed straight to
ensure_map_data(), so they may be directories, lists of file paths, or EDI-like iterables. This mirrors thegroupsstore used by the GUI loader, making the two paths share one grouping contract.
High-level MapView session façade for pyCSAMT maps.
MapView is the single object scripts, notebooks, and the map-view
platform share. It holds one combined MapData
(possibly spanning many lines) and renders every view through the
existing builders, so the GUI carries no plotting logic of its own.
Examples
>>> from pycsamt.map import MapView
>>> mv = MapView.from_folder("data/survey", detect="folder")
>>> mv.lines
('L18PLT', 'L22PLT')
>>> fig = mv.station(overlay="rho", frequency=1024)
>>> mv.export("out/station.html")
- class pycsamt.map.view.MapView(data, *, theme='light', backend='plotly')[source]#
Bases:
objectA code-first session bound to one (multi-line) survey.
- classmethod from_folder(path, *, detect='folder', recursive=True, theme='light', backend='plotly', **load_kwargs)[source]#
Build a view from a directory of one or more lines.
- classmethod from_lines(lines, *, theme='light', backend='plotly', **load_kwargs)[source]#
Build a view from an explicit
{line: source}mapping.
- classmethod from_inversion_results(folder, *, known_stations=None, fetch_elevation=True, theme='light', backend='plotly', verbose=0)[source]#
Build a view from a ModEM 3-D inversion result folder.
See
pycsamt.map.inversion.load_modem_lines(). Passknown_stations=existing_view.data.stationsto geo-reference and group ModEM stations using a previously-loaded EDI survey. Passfetch_elevation=Falseto skip the best-effort online elevation lookup (e.g. offline use, or large surveys where the extra round-trip isn’t wanted).
- classmethod from_pcsf(path, *, known_stations=None, fetch_elevation=True, theme='light', backend='plotly', mesh_z_samples=60)[source]#
Build a view from a backend-neutral
.pcsf/.pcsm/.pcsm.gzfile.See
pycsamt.map.inversion.load_pcsf_lines(). Works with a file in either PCSF encoding (binary.pcsfor its lossless ASCII sibling,.pcsm/gzip-compressed.pcsm.gz— seepycsamt/format/SPEC.mdS9) with any of the four geometry kinds —grid2d,multiline, nativegrid3d(e.g. ModEM 3-D), ormesh_unstructured(e.g. MARE2DEM, sampled by point-location on its real triangulation, seemesh_z_samples) — passknown_stations=existing_view.data.stationsto geo-reference it against a previously-loaded EDI survey, the same asfrom_inversion_results().
- table()[source]#
Return survey stations as a
pandas.DataFrame.
- fetch_elevations(*, api_name='open_meteo')[source]#
Fetch station elevations online (see
pycsamt.map.fetch_elevations()).
- export_topography(path, *, fmt=None)[source]#
Export this survey’s station id/elevation/coordinates.
Useful for an EDI-sourced view: a ModEM (or Occam2D/MARE2DEM) inversion result carries no real elevation of its own, so exporting it here produces a small, portable file that can be re-applied later — even in a session that never reloads these EDIs — via the “Upload file” elevation source (see
pycsamt.map.topo.export_elevations()).
- station(*, options=None, **overrides)[source]#
Build a 2-D station map figure.
- Parameters:
options (StationMapOptions | None)
overrides (Any)
- Return type:
- profile(*, options=None, **overrides)[source]#
Build a profile-view figure.
- Parameters:
options (ProfileMapOptions | None)
overrides (Any)
- Return type:
- pseudosection(*, options=None, **overrides)[source]#
Build a resistivity/phase pseudosection figure.
- Parameters:
options (ProfileMapOptions | None)
overrides (Any)
- Return type:
- map3d(*, mode='fence', options=None, **overrides)[source]#
Build a 3-D fence/block/depth/surface figure.
- Parameters:
mode (str)
options (VolumeMapOptions | None)
overrides (Any)
- Return type:
- figure(view='station', **overrides)[source]#
Build a figure for view by name.
- Parameters:
view ({"station", "profile", "pseudosection", "map3d"}) – Which renderer to call.
**overrides – Forwarded to the matching renderer.
- Return type:
- export(path, *, view='station', fmt=None, scale=2.0, width=None, height=None, **overrides)[source]#
Render view and write it to path.
The format is inferred from the suffix unless fmt is given;
.html,.png,.jsonand Plotly static images are supported (seepycsamt.map.export_figure()).
- pycsamt.map.view.launch_app(source=None, *, host='127.0.0.1', port=8770, debug=False, open_browser=True, theme='light', backend='plotly', detect='folder', recursive=True, **load_kwargs)#
Launch the interactive map-view app.
- Parameters:
source (Any) – Optional survey source.
Nonestarts the welcome screen. Otherwise accepts data, paths, sites, or mappings.host (str) – Forwarded to
pycsamt.app.mapview.launch().port (int) – Forwarded to
pycsamt.app.mapview.launch().debug (bool) – Forwarded to
pycsamt.app.mapview.launch().open_browser (bool) – Forwarded to
pycsamt.app.mapview.launch().detect (str) – Used for path/folder inputs.
recursive (bool) – Used for path/folder inputs.
**load_kwargs (Any) – Extra options forwarded to
MapView.from_folderorload_lines().
- Return type:
None
- pycsamt.map.view.launch_mapview(source=None, **kwargs)#
Alias for
launch_app().
- pycsamt.map.view.open_app(source=None, **kwargs)#
Backward-compatible alias for
launch_app().
2-D station-map API for pyCSAMT surveys.
- class pycsamt.map.station.StationMap(data, *, options=None, **ensure_kwargs)[source]#
Bases:
objectBuilder object for station-map figures.
- Parameters:
data (Any)
options (StationMapOptions | None)
ensure_kwargs (Any)
- with_overlay(overlay, **kwargs)[source]#
Return a copy with a different overlay.
- Parameters:
- Return type:
- pycsamt.map.station.plot_station_map(data, *, options=None, **kwargs)[source]#
Build a 2-D station map.
- Parameters:
data (Any)
options (StationMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.station.build_station_map(data, options=None)[source]#
Build a Plotly 2-D station map.
- Parameters:
data (MapData)
options (StationMapOptions | None)
- Return type:
Profile-view and pseudosection API for pyCSAMT surveys.
- class pycsamt.map.profile.ProfileMap(data, *, options=None, **ensure_kwargs)[source]#
Bases:
objectBuilder object for profile maps.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
ensure_kwargs (Any)
- with_options(**kwargs)[source]#
Return a copy with updated options.
- Parameters:
kwargs (Any)
- Return type:
- with_quantity(quantity)[source]#
Return a copy using another mapped quantity.
- Parameters:
quantity (str)
- Return type:
- with_component(component)[source]#
Return a copy using one impedance component.
- Parameters:
component (str)
- Return type:
- pycsamt.map.profile.plot_profile_map(data, *, options=None, **kwargs)[source]#
Build a profile-view map.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.profile.plot_pseudosection(data, *, options=None, **kwargs)[source]#
Build a resistivity or phase pseudosection.
- Parameters:
data (Any)
options (ProfileMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.profile.build_profile_map(data, options)[source]#
Build the concrete profile-view figure.
- Parameters:
data (MapData)
options (ProfileMapOptions)
- Return type:
- pycsamt.map.profile.build_pseudosection(data, options)[source]#
Build the concrete pseudosection figure.
- Parameters:
data (MapData)
options (ProfileMapOptions)
- Return type:
3-D map API for fence, block, and depth-slice views.
- class pycsamt.map.volume.Map3D(data, *, options=None, **ensure_kwargs)[source]#
Bases:
objectBuilder object for 3-D survey maps.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
ensure_kwargs (Any)
- pycsamt.map.volume.plot_3d_map(data, *, options=None, **kwargs)[source]#
Build a 3-D map.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.volume.plot_volume_map(data, *, options=None, **kwargs)[source]#
Build a 3-D volume map.
- Parameters:
data (Any)
options (VolumeMapOptions | None)
kwargs (Any)
- Return type:
- pycsamt.map.volume.build_3d_map(data, options)[source]#
Build the concrete 3-D figure.
- Parameters:
data (MapData)
options (VolumeMapOptions)
- Return type:
- pycsamt.map.volume.apply_vertical_exaggeration(fig, ve=0.0, *, max_ratio=3.0)[source]#
Stretch the scene’s vertical axis by ve (
0= automatic).Sets
aspectmode="manual"with an aspect ratio from the data extents of every trace, so x and y stay true to each other and z is exaggerated (capped at max_ratio times the horizontal size). Automatic makes the depth about half the horizontal extent (1-50x). Returns the factor used (1.0 when the scene has no 3-D extent).
Configuration dataclasses for pycsamt.map.
- class pycsamt.map.config.StationMapOptions(overlay='index', frequency=None, frequency_tolerance=None, depth=None, show_markers=True, component='xy', theme='light', backend='plotly', selected_id=None, line_filter=None, marker_size=10, basemap=None, cmap='plasma', value_range=None, log_color=False, opacity=0.92, show_labels=True, label_fontsize=8.0, label_rotation=0.0, show_profiles=True, elevation_mode='markers', show_contours=False, contour_image=False, contour_mode='filled+lines', contour_levels=12, contour_opacity=0.55, contour_interp='linear', contour_smooth=1.0, contour_grid_res=150, bearing=0.0, title='')[source]#
Bases:
objectOptions for 2-D station maps.
- Parameters:
overlay (str)
frequency (float | None)
frequency_tolerance (float | None)
depth (float | None)
show_markers (bool)
component (str)
theme (Literal['light', 'dark', 'publication'])
backend (Literal['plotly', 'matplotlib'])
selected_id (str | None)
marker_size (int)
basemap (str | None)
cmap (str)
log_color (bool)
opacity (float)
show_labels (bool)
label_fontsize (float)
label_rotation (float)
show_profiles (bool)
elevation_mode (Literal['markers', 'contours'])
show_contours (bool)
contour_image (bool)
contour_mode (str)
contour_levels (int)
contour_opacity (float)
contour_interp (str)
contour_smooth (float)
contour_grid_res (int)
bearing (float)
title (str)
- class pycsamt.map.config.ProfileMapOptions(quantity='rho', component='xy', components=('xy', 'yx'), theme='light', backend='plotly', period_range=None, phase_range=None, value_range=None, x_axis='station', log_rho=True, height_per_panel=260, show_errbar=False, cmap=None, by_line=False, line_cols=None)[source]#
Bases:
objectOptions for pseudosection and profile-view maps.
- class pycsamt.map.config.VolumeMapOptions(mode='fence', quantity='resistivity', component='xy', theme='light', cmap='RdYlBu_r', depth_range=None, period_range=None, rho_range=None, iso_range=None, value_range=None, crange_percentile=(2.0, 98.0), rho_display_max=None, log_color=True, opacity=0.85, show_contours=False, show_labels=True, n_slices=5, surface_count=12, line_spacing=1.0, azimuth=0.0, topography=True, show_terrain=True, terrain_opacity=0.7, show_stations=False, station_symbol='diamond', station_size=4, station_color='#1f2937', station_labels=False, station_label_angle=0.0, station_label_fraction=1.0, station_label_names=None, max_stations=None, aspectmode='data', vertical_exaggeration=None, x_unit='m', depth_unit='m', smooth_sections=True, section_res=100, volume_smoothing=0.0, title='', geology=None, geology_legend=True, geology_legend_style='swatch', geology_fill='solid', geology_patterns=None, pattern_tile_size_m=20.0)[source]#
Bases:
objectOptions for 3-D fence, block, and depth-slice maps.
- Parameters:
mode (Literal['fence', 'block', 'depth', 'surface'])
quantity (str)
component (str)
theme (Literal['light', 'dark', 'publication'])
cmap (str)
rho_display_max (float | None)
log_color (bool)
opacity (float)
show_contours (bool)
show_labels (bool)
n_slices (int)
surface_count (int)
line_spacing (float)
azimuth (float)
topography (bool)
show_terrain (bool)
terrain_opacity (float)
show_stations (bool)
station_symbol (str)
station_size (int)
station_color (str)
station_labels (bool)
station_label_angle (float)
station_label_fraction (float)
max_stations (int | None)
aspectmode (str)
vertical_exaggeration (float | None)
x_unit (str)
depth_unit (str)
smooth_sections (bool)
section_res (int)
volume_smoothing (float)
title (str)
geology (tuple[tuple[float, float, str] | tuple[float, float, str, str], ...] | None)
geology_legend (bool)
geology_legend_style (str)
geology_fill (str)
geology_patterns (dict | None)
pattern_tile_size_m (float)
- class pycsamt.map.config.ExportOptions(path, format=None, width=None, height=None, scale=2.0, include_plotlyjs='cdn')[source]#
Bases:
objectOptions used by figure export helpers.
- Parameters:
Overlay helpers for station, profile, and 3-D maps.
- class pycsamt.map.overlays.ContourOverlay(values, x, y, levels=12, cmap='viridis', opacity=0.65)[source]#
Bases:
objectDescription of an interpolated contour overlay.
- class pycsamt.map.overlays.TopographyOverlay(elevation, source='stations', opacity=0.7)[source]#
Bases:
objectTopography aligned to map coordinates.
- class pycsamt.map.overlays.CRSConfig(source, target=4326, always_xy=True)[source]#
Bases:
objectCoordinate transform settings.
- class pycsamt.map.overlays.BasemapConfig(style, center, zoom, bearing=0.0, layers=())[source]#
Bases:
objectPlotly geographic map layout settings.
- pycsamt.map.overlays.basemap_style_and_layers(style, *, dark=False)[source]#
Resolve a style name into a (base style, raster layers) pair.
ESRI styles are rendered as
white-bg+ a raster tile layer; native Plotly styles are returned as-is with no layers.
- pycsamt.map.overlays.resolve_crs_info(mode='geo', *, zone=50, hemisphere='N', epsg=4326)[source]#
Return a human-readable CRS description.
- pycsamt.map.overlays.transform_xy(x, y, *, crs)[source]#
Transform coordinates between two CRS definitions.
- pycsamt.map.overlays.reproject_xy_to_lonlat(x, y, *, epsg)[source]#
Reproject x, y from epsg to WGS84 lon/lat.
- pycsamt.map.overlays.build_contour_overlay(x, y, values, *, levels=12, cmap='Viridis', opacity=0.65, grid_size=80, mode='lines')[source]#
Build an interpolated map contour overlay.
Returns a Plotly
Contourtrace on a regular grid.
- pycsamt.map.overlays.build_geo_contour_image(lons, lats, values, *, cmap='jet', n_levels=12, opacity=0.6, mode='filled+lines', log_scale=False, grid_res=160, expand=0.06, interp='cubic', smooth_sigma=0.0, vmin=None, vmax=None)[source]#
Render a Surfer-style filled-contour PNG for a basemap image layer.
Interpolates sparse station values onto a regular lon/lat grid and rasterises filled (and/or line) contours to a transparent PNG. The result is meant to be added to a Plotly map as an
imagelayer.- Returns:
{"image": "data:image/png;base64,...", "coordinates": [...], "vmin": float, "vmax": float}(coordinates are the TL, TR, BR, BL[lon, lat]corners), orNonewhen it cannot be built.- Return type:
dict | None
- Parameters:
- pycsamt.map.overlays.interpolate_overlay_grid(x, y, values, *, grid_size=80, method='linear')[source]#
Interpolate scattered values to a regular grid.
- pycsamt.map.overlays.build_topography_overlay(x, y, elevation, *, opacity=0.7, colorscale='Earth')[source]#
Build a Plotly 3-D terrain mesh or surface.
- pycsamt.map.overlays.build_station_label_overlay(x, y, labels, *, geo=False, name='Station labels', color='#111827')[source]#
Build a reusable station-label overlay trace.
- pycsamt.map.overlays.build_profile_line_overlay(x, y, *, geo=False, name='Profile', color='#2563eb', width=2.0)[source]#
Build a reusable profile-line overlay trace.
- pycsamt.map.overlays.build_basemap_layout(lon, lat, *, dark=False, style=None, bearing=0.0)[source]#
Return layout settings for geographic station maps.
Figure export helpers for pycsamt.map.
- pycsamt.map.export.save_png(fig, path, **kwargs)[source]#
Save a Matplotlib-like or Plotly-like figure as PNG.
- pycsamt.map.export.export_figure(fig, options)[source]#
Export fig according to options.
- Parameters:
fig (Any)
options (ExportOptions)
- Return type:
Real-geometry line-layout helpers for 3-D survey maps.
Multi-line 3-D views (fence, block, depth-slice) need two things per
survey line: an along-line (“profile distance”) axis and a
line-to-line (“offset”) position. Placing lines with a synthetic
index * spacing stack ignores where the lines actually sit on the
ground, which staggers panels that should be parallel and evenly
spaced.
This module derives both from real station coordinates instead:
every station is projected onto a shared local (u, v) frame — u
along the survey’s dominant strike, v across it — so parallel
lines stay parallel and the line-to-line spacing reflects their true
geographic separation.
Pure numpy, no Plotly/Dash/pycsamt-app dependencies, so it is safe to
import from both pycsamt.map (the code-first / mapview 3-D
builder) and pycsamt.app.web (the legacy 3-D map callbacks) —
whichever data structure each caller uses (MapData stations, or
plain per-line dicts) is adapted to plain id/lat/lon/line arrays
before calling in here.
- pycsamt.map.geometry.equirect_xy(lat, lon)[source]#
Local planar metres for lat/lon, equirectangular approx.
Centred implicitly at the mean latitude of lat.
- pycsamt.map.geometry.fit_strike(points, groups)[source]#
Return the shared along-line unit direction for points.
Fits each group’s (line’s) own best-fit axis — SVD on that group’s centred points — then averages them, sign-aligned and weighted by point count. This reflects “which way each line actually runs” rather than the aggregate shape of the whole point cloud, which can pick the wrong axis when a survey’s footprint is roughly as wide (line-to-line) as it is long (along-line), e.g. a short/dense grid.
Returns
Nonewhen no direction can be fit (fewer than two points overall, or a degenerate/singular point cloud).
- pycsamt.map.geometry.survey_uv(ids, lat, lon, line)[source]#
Project every station onto a shared local (u, v) frame, metres.
uis the along-strike distance,vthe cross-strike offset, both measured from the combined centroid of every station passed in. ids, lat, lon, line must be the same length and aligned (one entry per station).Returns
{}when there are fewer than two stations or no strike direction could be fit (e.g. all stations coincide).
- class pycsamt.map.geometry.SurveyFrame(mean_lat_deg, origin_xy, strike, perp)[source]#
Bases:
objectA survey’s local along/cross-strike frame, reusable for any point.
survey_uv()returns only the station projections; this exposes the frame itself so an arbitrary geographic point (a borehole collar, a target) can be placed in the same local metres the 3-D map builders use.projectmirrorssurvey_uv()exactly: equirectangular metres about the survey’s mean latitude, then a shift to the station centroid and a rotation onto the fitted strike.- Parameters:
- pycsamt.map.geometry.survey_frame(lat, lon, line)[source]#
Fit the shared local frame used by
survey_uv().Returns
Noneunder the same conditions assurvey_uv()(fewer than two stations, or no strike direction could be fit).
- pycsamt.map.geometry.normalize_offsets(offsets)[source]#
Shift offsets so the smallest value is zero.
Returns
None(signalling “no real geometry, fall back to a synthetic layout”) when offsets is empty or any value is missing/non-finite — mixing real and synthetic placement in the same plot would look inconsistent, so it is all-or-nothing.
- pycsamt.map.geometry.resolve_offset(name, idx, real_offsets, fallback_unit, spacing)[source]#
Cross-strike placement for one line, in metres.
Uses the survey’s true line-to-line spacing (scaled by spacing, e.g. a UI “line spacing” multiplier where
1.0means true spacing) when real_offsets is available, otherwise falls back to a syntheticidx * spacing * fallback_unitstack.
Place PCBH boreholes in the 3-D map’s local scene coordinates.
The fence / block / depth-slice / iso-surface builders in
pycsamt.map.volume do not work in real easting/northing. They
work in a synthetic profile space: x is along-strike distance,
y is cross-strike line offset, and z is elevation with depth
running downward from a z = 0 (or draped-topography) datum.
A PCBH document, by contrast, carries absolute collar coordinates in its
own CRS. Dropping those numbers straight into the scene puts the hole
kilometres away from the section. This module bridges the two: it
projects each collar into the survey’s
SurveyFrame, walks the desurveyed trajectory, and returns per-hole
polylines and coloured interval segments already in scene coordinates,
plus a note on how the hole sits relative to the imaged volume.
Pure numpy + the PCBH render model — no Plotly / Dash / Qt.
- class pycsamt.map.borehole_align.AlignedSegment(borehole_id, family, from_md, to_md, color, points, metadata=<factory>)[source]#
Bases:
objectOne logged interval as a scene-space polyline.
- Parameters:
- class pycsamt.map.borehole_align.AlignedHole(borehole_id, name, collar_scene, centerline, segments, display_radius, relation, warnings=(), placed=True)[source]#
Bases:
objectOne borehole placed in the 3-D map scene.
- Parameters:
- segments: tuple[AlignedSegment, ...]#
- class pycsamt.map.borehole_align.SceneAlignment(holes, family, warnings=())[source]#
Bases:
objectResult of aligning a whole document to one scene.
- Parameters:
holes (tuple[AlignedHole, ...])
family (str)
- holes: tuple[AlignedHole, ...]#
- property placed: tuple[AlignedHole, ...][source]#
- pycsamt.map.borehole_align.surface_from_sections(sections)[source]#
Build a
u -> elevationinterpolator from section terrain lines.sectionsis a list of(u_values, elevation_values)pairs, one per rendered line, in the same local metres asSurveyFrame. ReturnsNonewhen no finite terrain is available (the caller then falls back to a flatz = 0datum).
- pycsamt.map.borehole_align.align_boreholes_to_scene(document, frame, *, family='lithology', azimuth_deg=0.0, surface=None, datum='surface', scene_bounds=None, depth_range=None, radius_policy=None, offset_shift=0.0, offset_scale=1.0, lean_deg=0.0, lean_azimuth_deg=0.0, lean_only_vertical=True, sampling_step_md=10.0, selected_ids=None)[source]#
Align every borehole in document to a 3-D map scene.
- Parameters:
document (PCBHDocument)
frame (SurveyFrame) – The survey’s local frame (see
pycsamt.map.geometry. survey_frame()), fitted from the same stations the scene uses.family (str, default='lithology') – Interval-log family to colour the trajectory by.
azimuth_deg (float, default=0) – Scene azimuth, matching
VolumeMapOptions.azimuth— the hole’s cross-strike offset is rotated by it exactly as line panels are.surface (callable, optional) –
u -> elevationterrain function (seesurface_from_sections()). Required fordatum='surface'.datum ({'surface', 'collar_z', 'zero'}, default='surface') – Depth reference.
surfacedrapes the collar onto the terrain line,collar_ztrusts the PCBH collar elevation,zeroputs the collar atz = 0(matching a no-topography scene).scene_bounds (tuple, optional) –
(umin, umax, vmin, vmax, zmin, zmax)of the imaged volume, for the per-holerelationclassification.depth_range (tuple, optional) –
(lo, hi)metres-below-datum clip applied to the trajectory, matching the scene’s depth filter.radius_policy (DisplayRadiusPolicy, optional) – View-only tube radius policy (physical diameter is never changed).
offset_shift (float, default=0) – Cross-strike origin shift, in local metres, applied to every borehole
vbeforeoffset_scale. Thepycsamt.map.volumebuilders normalise the line panels so the front-most line sits atv = 0(seepycsamt.map.geometry.normalize_offsets()); pass that same shift here or the holes land in front of / behind their line.offset_scale (float, default=1) – Cross-strike exaggeration matching
VolumeMapOptions.line_spacing— the scene stretches the line-to-line axis by this factor, so the hole’s offset must stretch with it.lean_deg (float, default=0) – Apparent lean from vertical, in degrees, applied to holes that have no surveyed deviation (see
lean_only_vertical).0keeps every hole plumb.lean_azimuth_deg (float, default=0) – Compass bearing (0 = grid north, 90 = east) the leaned hole tips toward.
lean_only_vertical (bool, default=True) – When true, only holes whose desurveyed trajectory stays within ~1 m of the collar are leaned; real deviation surveys pass through untouched. Set false to force every hole to
lean_deg.sampling_step_md (float, default=10) – Trajectory sampling step in measured depth.
selected_ids (set of str, optional) – Highlighted borehole ids (passed through to the render model).
- Return type: