pycsamt.seg.survey#

Classes

EDIProfile(items, *[, verbose])

Profile helper for one or many EDIFile objects.

Stations(items, *[, verbose])

Lightweight table view for station metadata derived from EDIFile objects.

Topography(items, *[, use_profile_step, verbose])

Elevation profile helper.

class pycsamt.seg.survey.EDIProfile(items, *, verbose=0)[source]#

Bases: SurveyBase

Profile helper for one or many EDIFile objects. Computes small-area geometry (easting/northing), cumulative distance along line, profile azimuth, and exposes utilities to adjust coordinates and push them back into EDI headers.

The class accepts a single file, an iterable of files, or an EDICollection. Coordinates are read from >HEAD and converted to working planar coordinates. For short lines the equirectangular approximation is used, and distances/azimuth are computed in that local frame.

Parameters:
  • items (EDIFile or iterable of EDIFile or EDICollection) – The input sites to include in the profile.

  • verbose (int, default 0) – Verbosity level forwarded to internal helpers.

Variables:
  • stations (list of str) – Station identifiers resolved from DATAID or file name.

  • lon (lat,) – Geographic coordinates (degrees).

  • elev (ndarray of float) – Elevations when present, missing values become 0.

  • distance (ndarray of float) – Cumulative distance from the first site (meters).

  • azimuth (float) – Bearing of the profile in degrees, clockwise from North, in [0, 360).

  • xy (tuple of ndarray) – Working (easting, northing) arrays in meters.

  • table (list of dict) – Row-wise view exposing station, lat, lon, elev, easting, northing, and UTM zone (when available).

get_bearing(method='endpoints')[source]#

Compute bearing from either endpoints or a PCA-like fit of the track.

Parameters:

method (str)

Return type:

float | None

get_step()[source]#

Return cumulative distance and cache it for reuse.

Parameters:
Return type:

float | ndarray

adjust(origin=None, azimuth=None, spacing=None, use_mean=True)[source]#

Build an idealized straight profile and compute adjusted positions and lat/lon.

Parameters:
Return type:

EDIProfile

update(use_adjusted=True, update_elev=False)[source]#

Write back adjusted coordinates to each site’s header.

Parameters:
  • use_adjusted (bool)

  • update_elev (bool)

Return type:

EDIProfile

plot_profile(use_adjusted=False, annotate=True, title=None)[source]#

Plot elevation against along-profile distance.

Parameters:
Return type:

Axes

plot_track(use_adjusted=False, title=None)[source]#

Plot plan-view easting/northing track.

Parameters:
  • ax (Axes | None)

  • use_adjusted (bool)

  • title (str | None)

Return type:

Axes

Notes

The small-area equirectangular frame is adequate for short profiles. For long lines or large latitude spans prefer a full projection workflow. When the UTM zone can be determined, adjusted coordinates are converted back to geographic using that zone.

Examples

Load two sites and compute azimuth and distance:

prof = EDIProfile([ed1, ed2])
print(float(prof.azimuth))
d = prof.distance

Adjust to a regular spacing and push back to headers:

prof.adjust(spacing=50.0).update()

See also

Stations

Tabular view of station metadata and projected coordinates.

Topography

Elevation profile builder with smoothing and trend tools.

References

property stations: list[str][source]#
property lat: ndarray[source]#
property lon: ndarray[source]#
property elev: ndarray[source]#
property xy: tuple[ndarray, ndarray][source]#
property distance: ndarray[source]#
property azimuth: float[source]#
get_bearing(*, method='endpoints')[source]#

Estimate the survey bearing (azimuth) in degrees.

Parameters:

method ({‘endpoints’, ‘linear’}, default 'endpoints') – With 'endpoints' the azimuth is computed from the first to the last station. With 'linear' a best-fit axis is estimated by SVD of centered coordinates.

Returns:

Bearing in [0, 360) (clockwise from north), or None if fewer than two valid stations exist.

Return type:

float or None

Notes

Uses working projected coordinates (easting/northing), suitable for small-area profiles.

get_step(*, method='mean', as_array=False)[source]#

Derive the inter-station spacing from the track.

Parameters:
  • method ({‘mean’, ‘median’}, default 'mean') – Aggregation used when returning a scalar spacing.

  • as_array (bool, default False) – If True, return the pairwise segment lengths as a 1-D array of size n-1. If False, return a single spacing computed with method.

Returns:

Either a scalar spacing or the per-segment distances.

Return type:

float or ndarray

Notes

Distances are computed from consecutive projected coordinates; missing stations are ignored.

adjust(*, origin=None, azimuth=None, spacing=None, step=None, use_mean=True)[source]#

Build an idealized, straightened profile and store the adjusted coordinates.

Parameters:
  • origin (tuple(float, float), optional) – Reference (easting, northing) for the first station. Defaults to the first raw station.

  • azimuth (float, optional) – Bearing of the adjusted line in degrees. Defaults to get_bearing().

  • spacing (float, optional) – Fixed spacing between consecutive stations (meters).

  • step (float, optional) – Alias for spacing for convenience.

  • use_mean (bool, default True) – When both spacing and step are None, compute spacing from observed distances using mean if True or median if False.

Returns:

The instance (allows chaining).

Return type:

EDIProfile

Notes

Adjusted easting/northing are projected back to latitude and longitude using the dominant UTM zone of the track. Results are stored in _adj_e/_adj_n/_adj_lat/_adj_lon.

update(*, use_adjusted=True, update_elev=False)[source]#

Push current coordinates back into the underlying EDI headers.

Parameters:
  • use_adjusted (bool, default True) – If True write adjusted lat/lon (from adjust()). If no adjusted coordinates exist, fall back to raw lat/lon.

  • update_elev (bool, default False) – Also write elevations when present in the profile table.

Returns:

The instance (allows chaining).

Return type:

EDIProfile

Notes

This mutates the in-memory EDIFile objects held by the profile; it does not write to disk.

plot_profile(*, ax=None, use_adjusted=False, annotate=True, title=None)[source]#

Plot elevation versus along-profile distance.

Parameters:
  • ax (matplotlib.axes.Axes, optional) – Target axes. If omitted, a new figure/axes is made.

  • use_adjusted (bool, default False) – If True recompute distances from adjusted coordinates for the overlay. Raw elevation values are used in both cases.

  • annotate (bool, default True) – Draw station labels next to points.

  • title (str, optional) – Axes title.

Returns:

The axes with the profile plot.

Return type:

matplotlib.axes.Axes

Notes

Uses the profile’s cached cumulative distances. Call adjust() first to visualize an adjusted line.

plot_track(*, ax=None, use_adjusted=False, title=None)[source]#

Plot plan-view station positions (easting vs. northing).

Parameters:
  • ax (matplotlib.axes.Axes, optional) – Target axes. If omitted, a new figure/axes is made.

  • use_adjusted (bool, default False) – Plot the straightened track if adjusted coordinates exist; otherwise plot raw positions.

  • title (str, optional) – Axes title.

Returns:

The axes with the track plot.

Return type:

matplotlib.axes.Axes

Notes

Axes aspect is set to equal for a faithful plan view.

as_table()[source]#
Return type:

list[dict[str, object]]

class pycsamt.seg.survey.Stations(items, *, verbose=0)[source]#

Bases: SurveyBase

Lightweight table view for station metadata derived from EDIFile objects. Provides quick access to names, geographic coordinates, optional elevations, and working projected coordinates to support survey tasks.

Parameters:
  • items (EDIFile or iterable of EDIFile or EDICollection) – The sites to summarize.

  • verbose (int, default 0) – Verbosity level for logging.

Variables:
  • count (int) – Number of valid stations (rows with lat/lon).

  • stations (list of str) – Station identifiers sourced from headers or filenames.

table()[source]#

Materialize the rows as a list of dicts with keys station, lat, lon, elev, e (east), n (north), zone and path.

Return type:

list[dict[str, object]]

to_dataframe()[source]#

Convert the table to a pandas DataFrame when pandas is available.

Parameters:
Return type:

DataFrame

bounds()#

Geographic bounding box as (min_lat, min_lon, max_lat, max_lon).

select(keys=None, pattern=None, regex=None, pred=None)[source]#

Return a filtered view. Multiple filters are combined with logical AND. See the method docstring for details.

Parameters:
Return type:

Stations

sort(by='station', reverse=False, inplace=True)[source]#

Sort rows by a column (e.g. 'station', 'lat', 'lon', 'elev', 'e', 'n'). Returns this instance or a new view depending on inplace.

Parameters:
Return type:

Stations

offsets(origin=None, azimuth=None)[source]#

Compute along-line and cross-line offsets in meters from projected coordinates. The profile axis is set by azimuth or inferred from endpoints.

Parameters:
Return type:

tuple[ndarray, ndarray]

set_coords(key, \*, lat=None, lon=None, elev=None)[source]#

Update coordinates for a single station. When the backing EDIFile is available its >HEAD values are kept in sync.

Parameters:
Return type:

None

Notes

The class performs minimal validation. Rows missing lat/lon are skipped. Projected coordinates are intended for short-range work; for mapping at scale prefer the GIS utilities provided elsewhere in the package.

Examples

Build a table and print a compact view:

sts = Stations(coll)
for r in sts.table():
    print(r["station"], r["lat"], r["lon"])

Filter, sort, and compute offsets:

sel = sts.select(pattern="K*",
                 pred=lambda r: r["elev"] > 800)
sel.sort(by="e")
along, across = sel.offsets()

See also

EDIProfile

Track-aware helper that computes distance and azimuth.

Topography

Produces elevation profiles from stations or profiles.

References

names()[source]#
Return type:

list[str]

table()[source]#
Return type:

list[dict[str, object]]

get(key)[source]#
Parameters:

key (str)

Return type:

EDIFile | None

row(key)[source]#
Parameters:

key (str)

Return type:

dict[str, object] | None

select(*, keys=None, pattern=None, regex=None, pred=None)[source]#

Return a filtered view of the stations table.

Multiple filters are combined with logical AND. When no filter is given the original view is returned.

Parameters:
  • keys (sequence of str, optional) – Station identifiers to keep. Unknown ids are ignored.

  • pattern (str, optional) – Glob-like pattern matched against station ids (e.g. 'AB*'). Case-sensitive.

  • regex (str, optional) – Regular expression matched against station ids using re.search().

  • pred (callable, optional) – A predicate pred(row) -> bool evaluated on each row dict. Keep rows for which the predicate returns True.

Returns:

A new Stations view with rows that match the filters.

Return type:

Stations

Notes

Filtering does not modify the original container. Rows lacking a station id are always dropped.

Examples

Keep stations starting with 'K' and above 800 m:

sel = sts.select(pattern="K*", pred=lambda r: r["elev"] > 800)
sort(*, by='station', reverse=False, inplace=True)[source]#

Sort the stations table by a column.

Parameters:
  • by (str, default 'station') – Column name to sort by (e.g. 'station', 'lat', 'lon', 'elev', 'e', 'n').

  • reverse (bool, default False) – If True sort in descending order.

  • inplace (bool, default True) – If True modify this instance and return it. Otherwise return a new sorted view.

Returns:

The sorted Stations object (self or a copy).

Return type:

Stations

Notes

Missing values are placed at the end. Unknown columns raise a KeyError.

offsets(*, origin=None, azimuth=None)[source]#

Compute along-line and cross-line offsets (meters).

Offsets are computed from projected coordinates. The along-line axis is defined by the given azimuth; the cross-line axis is perpendicular to it.

Parameters:
  • origin (tuple of float, optional) – Reference point (easting, northing) in meters. Defaults to the first valid station.

  • azimuth (float, optional) – Bearing in degrees, clockwise from North. When omitted it is inferred from the first and last stations.

Returns:

  • along (ndarray of float) – Distances projected on the profile axis.

  • across (ndarray of float) – Signed distances perpendicular to the profile axis.

Return type:

tuple[ndarray, ndarray]

Notes

Rows without valid projected coordinates are skipped in the computation and do not contribute to the result.

set_coords(key, *, lat=None, lon=None, elev=None)[source]#

Update coordinates for a single station.

Parameters:
  • key (str) – Station identifier to modify.

  • lat (float, optional) – New latitude in decimal degrees.

  • lon (float, optional) – New longitude in decimal degrees.

  • elev (float, optional) – New elevation in meters.

Return type:

None

Notes

The in-memory row is updated. If the backing EDIFile is attached for that station, its >HEAD values are also updated to keep them in sync. Unknown station ids raise a KeyError.

to_dataframe(*, columns=None, index='station', coerce_numeric=True)[source]#

Return a pandas DataFrame view of the station table.

Parameters:
  • columns (sequence of str, optional) – Subset and ordering of columns to include. When omitted, a sensible default is used: ('station','lat','lon','elev','e','n','zone', 'path'). Missing names are ignored.

  • index (str or None, default 'station') – Column to set as the DataFrame index. If the name is not present, no index is set. Use None to leave the default RangeIndex.

  • coerce_numeric (bool, default True) – Try converting known numeric columns (lat, lon, elev, e, n) to numeric dtypes. Non convertible values become NaN.

Returns:

A DataFrame with one row per station.

Return type:

pandas.DataFrame

Notes

pandas is imported lazily. If it is not available, an ImportError is raised. The method is read-only and does not mutate the underlying table.

Examples

Basic usage:

df = Stations(coll).to_dataframe()
print(df.head())

Custom subset and index:

df = Stations(coll).to_dataframe(
    columns=("station", "elev", "e", "n"),
    index="station",
)

See also

table

List-of-dicts representation of the rows.

bounds

Geographic bounding box.

select

Filter rows prior to conversion.

class pycsamt.seg.survey.Topography(items, *, use_profile_step=True, verbose=0)[source]#

Bases: SurveyBase

Elevation profile helper. Builds paired arrays of distance and elevation from an EDIProfile, Stations, a collection, or raw EDIFile inputs. Includes smoothing, detrending, resampling, and quick plotting.

Parameters:
  • items (EDIProfile or Stations or EDICollection or EDIFile ) – or iterable of EDIFile Source of station positions and elevations. When an EDIProfile is given, along-line distances are reused by default.

  • use_profile_step (bool, default True) – If True and items is an EDIProfile, copy its along-profile distances; otherwise recompute distances from planar coordinates.

  • verbose (int, default 0) – Verbosity level for diagnostics.

Variables:
  • distance (ndarray of float) – Along-track distances in meters.

  • elevation (ndarray of float) – Elevation values aligned with distance.

  • trend (ndarray of float or None) – Fitted linear trend after detrend(). Otherwise None.

smooth(window=5, method='median')[source]#

Apply moving median or mean smoothing to elevation.

Parameters:
Return type:

Topography

detrend()[source]#

Remove a best-fit linear trend and keep it for plotting.

Return type:

Topography

resample(step)[source]#

Resample to a fixed distance step using interpolation.

Parameters:

step (float)

Return type:

Topography

gradient(as_degrees=False)[source]#

First derivative of elevation vs distance; optionally in degrees.

Parameters:

as_degrees (bool)

Return type:

ndarray

plot(ax=None, title=None, show_trend=True)[source]#

Quick plot of elevation vs distance.

Parameters:
  • ax (Axes | None)

  • title (str | None)

  • show_trend (bool)

Return type:

Axes

as_arrays()[source]#

Return (distance, elevation) copies.

Return type:

tuple[ndarray, ndarray]

to_dict()[source]#

Return a dict with distance and elevation keys.

Return type:

dict[str, object]

Notes

If the input is an EDIProfile that has not yet computed distances, they are derived automatically. When distances or elevations are missing the result is empty.

Examples

From a profile and detrend before plotting:

topo = Topography(prof).detrend().smooth(window=7)
ax = topo.plot(title="Detrended topography")

From a list of files, resampled every 25 m:

topo = Topography(edis).resample(step=25.0)

See also

EDIProfile

Provides distances and azimuth and can adjust station positions.

Stations

Tabular access to station metadata.

References

property distance: ndarray[source]#
property elevation: ndarray[source]#
smooth(*, window=5, method='median')[source]#

Smooth the elevation series with a sliding window.

Parameters:
  • window (int, default 5) – Window length (samples). Values <=1 skip smoothing.

  • method ({‘median’, ‘mean’}, default 'median') – Smoothing kernel. 'median' is robust to spikes; 'mean' uses a simple moving average.

Returns:

The instance (in place), allowing chaining.

Return type:

Topography

Notes

Edge handling is performed by shrinking the window near the bounds. This modifies the internal elevation array.

detrend()[source]#
Return type:

Topography

resample(*, step)[source]#

Resample distance/elevation to a fixed along-line step.

Parameters:

step (float) – Target spacing in meters for the resampled profile.

Returns:

The instance (in place), allowing chaining.

Return type:

Topography

Notes

Distances are regridded on [dmin, dmax] with uniform spacing and elevations are linearly interpolated.

gradient(*, as_degrees=False)[source]#

Compute local slope between consecutive samples.

Parameters:

as_degrees (bool, default False) – If True, return the slope angle in degrees. If False, return the rise-over-run ratio.

Returns:

Array of length len(distance) - 1 with per-segment slopes (or angles when requested).

Return type:

ndarray

plot(*, ax=None, title=None, show_trend=True)[source]#

Plot elevation versus distance.

Parameters:
  • ax (matplotlib.axes.Axes, optional) – Target axes. A new figure/axes is created when omitted.

  • title (str, optional) – Title for the axes.

  • show_trend (bool, default True) – Overlay the last computed trend line (from detrend()) when available.

Returns:

The axes with the rendered profile.

Return type:

matplotlib.axes.Axes

as_arrays()[source]#
Return type:

tuple[ndarray, ndarray]

to_dict()[source]#
Return type:

dict[str, object]