pycsamt.site.edit#

Functions

fill_missing(site, *[, how, components, inplace])

Replace missing or non-finite values in Z and/or tipper arrays with zeros or NaNs.

recompute_res_phase(site, *[, inplace])

Recompute apparent resistivity and phase from the impedance tensor Z for a single site.

rename(site[, name, policy, inplace])

Rename a station using an explicit name or a policy function.

rename_all(sites, *[, policy, name_fn, inplace])

Batch rename a collection of sites.

rotate(site, angle_deg, *[, inplace])

Rotate impedance tensor Z (and tipper T, if present) by an azimuthal angle in degrees.

rotate_all(sites, angle_deg, *[, inplace])

Rotate every site in a collection by an azimuthal angle in degrees.

select_freq(site, *[, fmin, fmax, keep, inplace])

Subset the dataset along frequency by range or explicit indices, keeping all affected arrays aligned.

select_freq_all(sites, *[, fmin, fmax, ...])

Subset all sites in a collection along frequency, keeping arrays aligned.

set_coords(site, *[, lat, lon, elev, inplace])

Set geographic coordinates on the EDI header.

set_coords_all(sites, src, *[, inplace])

Batch set coordinates for a collection of sites.

set_coords_from_en(site, easting, northing, ...)

Project (easting, northing) to lon/lat and set a site's coords.

set_coords_from_table(sites, table, *[, ...])

Set site coordinates for many EDI files from a table.

pycsamt.site.edit.rotate(site, angle_deg, *, inplace=False)[source]#

Rotate impedance tensor Z (and tipper T, if present) by an azimuthal angle in degrees.

The rotation is applied in the horizontal plane using the similarity transform \(Z' = R Z R^{-1}\), where \(R\) is the 2x2 rotation matrix built from angle_deg. When a tipper is available (either on the EDI object as T / TIP / Tip or attached to Z), the 2-component vector is rotated consistently.

Parameters:
  • site (Any) – An EDI-like object (e.g., pycsamt.seg.edi.EDIFile) or wrapper exposing a Z section compatible with a complex 2x2 impedance array and, optionally, a tipper.

  • angle_deg (float) – Rotation angle in degrees. Positive values rotate the measurement axes according to the internal convention of this package. If your acquisition system defines the sign oppositely, use the negative of your desired angle.

  • inplace (bool, optional) – If True, mutate site in place. Otherwise, work on a shallow copy and return that copy. Default is False.

Returns:

The rotated object. If inplace is True, this is the same object as site; otherwise a new object.

Return type:

Any

Notes

  • Error arrays (z_error or aliases) are rotated with a magnitude-only scheme (using absolute values of the rotation matrices) as a pragmatic best-effort. This is a common, but approximate, practice.

  • Only arrays with shapes consistent with MT tensors ((n, 2, 2) for Z, (n, 2) for T) are rotated. Other shapes are ignored silently.

  • The function is no-throw by design. If a section is not present or incompatible, it is skipped.

Examples

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import rotate
>>> ed = EDIFile("path/to/station.edi")
>>> ed_rot = rotate(ed, 30.0)       # copy by default
>>> ed_rot2 = rotate(ed, -45.0, inplace=True)

See also

select_freq

Subset rows by frequency range or indices.

rename

Rename the station using a policy or explicit name.

pycsamt.site.edit.rotate_all

Broadcast rotation over a collection.

References

pycsamt.site.edit.select_freq(site, *, fmin=None, fmax=None, keep=None, inplace=False)[source]#

Subset the dataset along frequency by range or explicit indices, keeping all affected arrays aligned.

This applies the selection to every frequency-indexed array found on the object, including Z, Z errors, derived resistivity/phase, and any tipper arrays resident on either the root EDI object or under its Z section.

Parameters:
  • site (Any) – An EDI-like object (e.g., pycsamt.seg.edi.EDIFile) with a discoverable frequency vector.

  • fmin (float, optional) – Keep rows with freq >= fmin. Ignored if None.

  • fmax (float, optional) – Keep rows with freq <= fmax. Ignored if None.

  • keep (Iterable[int] or numpy.ndarray, optional) – Explicit indices or a boolean mask to keep. If provided, fmin and fmax are ignored. Use integer indices for exact row picks, or a boolean mask of the same length as the frequency vector.

  • inplace (bool, optional) – If True, mutate site in place. Otherwise, operate on a shallow copy. Default is False.

Returns:

The object after selection. If inplace is True, this is the same object as site; otherwise a new object.

Return type:

Any

Notes

  • All known aliases are sliced consistently (e.g., frequency, Z, Z error, resistivity, phase, tipper, and related per-row arrays) to preserve alignment.

  • If the frequency vector is empty or missing, the call is a no-op.

  • The function is no-throw by design; incompatible shapes are skipped silently.

Examples

Keep only rows with frequency >= 10 Hz:

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import select_freq
>>> ed = EDIFile("path/to/station.edi")
>>> ed_hi = select_freq(ed, fmin=10.0)

Keep the first and last rows explicitly:

>>> sel = [0, -1]
>>> ed_edge = select_freq(ed, keep=sel)

Apply in place:

>>> _ = select_freq(ed, fmin=1.0, fmax=100.0, inplace=True)

See also

rotate

Rotate Z and tipper by an azimuth angle.

rename

Rename the station identifiers.

pycsamt.site.edit.select_freq_all

Broadcast selection over a collection.

References

pycsamt.site.edit.rename(site, name=None, policy=None, *, inplace=False)[source]#

Rename a station using an explicit name or a policy function.

This updates common station identifiers across the EDI header and attempts to keep them in sync so that downstream code resolves the new name consistently.

Parameters:
  • site (Any) – An EDI-like object (e.g., pycsamt.seg.edi.EDIFile) or wrapper with a modifiable HEAD section.

  • name (str, optional) – Explicit new station name to set. If provided, this takes precedence over policy.

  • policy (Callable[[str], str], optional) – A function mapping the current station name to a new one. Ignored when name is provided.

  • inplace (bool, optional) – If True, mutate site in place. Otherwise, operate on a shallow copy. Default is False.

Returns:

The object with updated identifiers. If inplace is True, this is the same object as site; otherwise a new object.

Return type:

Any

Notes

  • The function writes multiple header fields when present (e.g., dataid, station, and other common aliases) and also mirrors the name to edi.name. This increases the chance that name resolution remains stable across different readers.

  • The rename operation does not touch on-disk filenames. File paths remain unchanged unless you later write out using a template that depends on the station name.

  • If both name and policy are given, name wins.

Examples

Policy-based rename:

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import rename
>>> ed = EDIFile("path/to/station.edi")
>>> ed2 = rename(ed, policy=lambda n: f"X_{n}")

Explicit name, in place:

>>> _ = rename(ed, name="ST123A", inplace=True)

See also

rotate

Rotate Z and tipper by an azimuth angle.

select_freq

Subset rows by frequency range or indices.

pycsamt.site.edit.rename_all

Broadcast rename over a collection.

pycsamt.site.base.Site

Wrapper that resolves a stable site name for indexing.

References

pycsamt.site.edit.set_coords(site, *, lat=None, lon=None, elev=None, inplace=False)[source]#

Set geographic coordinates on the EDI header.

Only the values explicitly provided are updated. The call delegates to the same coordinate writer used by the Site API, so downstream tools see consistent lat, lon, and elev fields.

Parameters:
  • site (Any) – An EDI-like object (e.g., pycsamt.seg.edi.EDIFile) or wrapper exposing a mutable HEAD section.

  • lat (float, optional) – Latitude in degrees. If None, the field is left unchanged.

  • lon (float, optional) – Longitude in degrees. If None, the field is left unchanged.

  • elev (float, optional) – Elevation in meters. If None, the field is left unchanged.

  • inplace (bool, optional) – If True, mutate site in place. Otherwise, work on a shallow copy and return that copy. Default is False.

Returns:

The updated object. If inplace is True, this is the same object as site; otherwise a new object.

Return type:

Any

Notes

  • The function validates numeric types and writes to common HEAD attribute names (lat, lon, elev).

  • If a field is not present in the header, a best-effort attribute is created.

Examples

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import set_coords
>>> ed = EDIFile("path/to/station.edi")
>>> ed2 = set_coords(ed, lat=35.1, lon=12.8, elev=1234.0)
>>> _ = set_coords(ed, lat=36.0, inplace=True)

See also

pycsamt.site.base.Site.set_coords

Object-oriented wrapper.

pycsamt.site.edit.set_coords_all

Broadcast over a collection.

References

pycsamt.site.edit.fill_missing(site, *, how='zero', components=('Z', 'Tip'), inplace=False)[source]#

Replace missing or non-finite values in Z and/or tipper arrays with zeros or NaNs.

The operation preserves shapes and alignment across arrays. If an array is absent, a new one is allocated with the correct shape inferred from the frequency vector.

Parameters:
  • site (Any) – An EDI-like object with a discoverable frequency vector and optionally Z and tipper sections.

  • how ({"zero", "nan"}, optional) – Replacement policy. Use "zero" to fill with numeric zeros. Use "nan" to fill with NaN for all non-finite entries. Default is "zero".

  • components (Iterable[str], optional) – Which components to process. Accepts items like "Z" or "Tip" (case-insensitive). Default is ("Z", "Tip").

  • inplace (bool, optional) – If True, mutate in place. Otherwise, operate on a shallow copy and return that copy. Default is False.

Returns:

The object after filling. If inplace is True, this is the same object as site; otherwise a new object.

Return type:

Any

Notes

  • Z arrays are expected as shape (n, 2, 2) and tipper as (n, 2). Only arrays with the expected shapes are modified or allocated.

  • When Z exists, the function also fills common aliases for errors and derived quantities, such as z_error, rho (resistivity), and phase arrays, if present.

  • The frequency vector length n defines the number of rows used for any new arrays.

  • This function is no-throw by design. Incompatible or absent pieces are skipped silently.

Examples

Fill Z and tipper with zeros where values are non-finite:

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import fill_missing
>>> ed = EDIFile("path/to/station.edi")
>>> ed2 = fill_missing(ed, how="zero")

Fill only Z with NaNs, in place:

>>> _ = fill_missing(ed, how="nan", components=("Z",),
...                  inplace=True)

See also

select_freq

Subset rows by frequency while keeping arrays aligned.

rotate

Rotate Z and tipper by an azimuth angle.

References

pycsamt.site.edit.recompute_res_phase(site, *, inplace=False)[source]#

Recompute apparent resistivity and phase from the impedance tensor Z for a single site.

The function looks for a Z section and, if present, calls its compute_resistivity_phase() method. The operation is best-effort and suppresses exceptions.

Parameters:
  • site (Any) – An EDI-like object (EDIFile) or a wrapper exposing a Z section with the expected API.

  • inplace (bool, optional) – If True, mutate the given object in place. Otherwise work on a shallow copy and return it. Default is False.

Returns:

The mutated object (in place) or a new object (copy).

Return type:

Any

Notes

  • Derived quantities are typically written under common aliases (e.g., rho or resistivity for apparent resistivity in ohm-m, and phase in degrees).

  • The method assumes Z has shape (n, 2, 2) and that a frequency vector is present. If these are missing or incompatible, nothing is changed.

Examples

Single-site:

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import recompute_res_phase
>>> ed = EDIFile("path/to/station.edi")
>>> ed2 = recompute_res_phase(ed)

In place:

>>> _ = recompute_res_phase(ed, inplace=True)

See also

select_freq

Keep a subset of rows by frequency.

fill_missing

Ensure arrays are allocated and finite before recomputation.

pycsamt.site.base.Site.to_dataframe

Inspect derived arrays.

References

pycsamt.site.edit.rotate_all(sites, angle_deg, *, inplace=False)[source]#

Rotate every site in a collection by an azimuthal angle in degrees.

This is the broadcast variant of rotate(). It accepts either a Sites wrapper or any iterable of EDI-like objects and returns a new Sites unless inplace is requested.

Parameters:
  • sites (Any) – A pycsamt.site.base.Sites instance or any iterable of EDI-like objects.

  • angle_deg (float) – Rotation angle in degrees, passed through to rotate().

  • inplace (bool, optional) – If True, attempt to apply the rotation in place on the given container. Otherwise, return a new Sites. Default is False.

Returns:

A sites collection holding the rotated items, or the original container when mutated in place.

Return type:

pycsamt.site.base.Sites

Notes

  • The function preserves the input order of items.

  • If some items lack compatible arrays, they are skipped silently.

Examples

Using a list of EDI files:

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.edit import rotate_all
>>> eds = [EDIFile("A.edi"), EDIFile("B.edi")]
>>> ro = rotate_all(eds, 15.0)

Using a Sites wrapper:

>>> from pycsamt.site.base import Sites
>>> sites = Sites(eds)
>>> ro2 = rotate_all(sites, -30.0)

See also

rotate

Single-site rotation.

select_freq_all

Broadcast selection by frequency.

pycsamt.site.edit.select_freq_all(sites, *, fmin=None, fmax=None, keep=None, inplace=False)[source]#

Subset all sites in a collection along frequency, keeping arrays aligned.

This is the broadcast variant of select_freq(). It accepts a Sites wrapper or any iterable of EDI-like objects and returns a new Sites unless inplace is requested.

Parameters:
  • sites (Any) – A pycsamt.site.base.Sites instance or any iterable of EDI-like objects.

  • fmin (float, optional) – Keep rows with freq >= fmin. Ignored if None.

  • fmax (float, optional) – Keep rows with freq <= fmax. Ignored if None.

  • keep (Iterable[int] or numpy.ndarray, optional) – Explicit indices or a boolean mask to keep. If provided, fmin and fmax are ignored.

  • inplace (bool, optional) – If True, attempt to modify the given container in place. Otherwise, return a new Sites. Default is False.

Returns:

A sites collection with selection applied, or the original container when mutated in place.

Return type:

pycsamt.site.base.Sites

Notes

  • All known frequency-indexed arrays are sliced in sync for each site (Z, errors, derived quantities, and tipper).

  • Items missing a frequency vector are left unchanged.

Examples

>>> from pycsamt.seg.edi import EDIFile
>>> from pycsamt.site.base import Sites
>>> from pycsamt.site.edit import select_freq_all
>>> eds = [EDIFile("A.edi"), EDIFile("B.edi")]
>>> sites = Sites(eds)
>>> out = select_freq_all(sites, fmin=1.0, fmax=100.0)

Use explicit row indices for all sites:

>>> out2 = select_freq_all(eds, keep=[0, -1])

See also

select_freq

Single-site selection by frequency.

rotate_all

Broadcast rotation over a collection.

References

pycsamt.site.edit.rename_all(sites, *, policy=None, name_fn=None, inplace=False)[source]#

Batch rename a collection of sites.

This is the broadcast variant of rename(). It accepts a Sites wrapper or any iterable of EDI-like objects and produces a new Sites (unless inplace is True).

Parameters:
  • sites (Any) – A pycsamt.site.base.Sites instance or any iterable of EDI-like objects.

  • policy (Callable[[str], str], optional) – Function mapping the current station name to a new one, e.g. lambda n: f"X_{n}". Ignored if name_fn is provided.

  • name_fn (Callable[[Any], str], optional) – Function mapping each EDI object to a new name, e.g. from the file stem. This takes precedence over policy and is useful to guarantee uniqueness across sites.

  • inplace (bool, optional) – If True, attempt to modify the given container in place. Otherwise, return a new Sites. Default is False.

Returns:

A collection holding the renamed items, or the original container when mutated in place.

Return type:

pycsamt.site.base.Sites

Notes

  • The rename updates common header identifiers and mirrors the name to edi.name for robust downstream resolution.

  • If multiple sites share the same original name, a simple policy like lambda n: "X_" + n may produce duplicate outputs. Prefer name_fn that uses a unique attribute (e.g., the file stem) to avoid collisions.

  • The function preserves input order and is no-throw; items that cannot be renamed are skipped.

Examples

Policy-based rename for all items:

>>> from pycsamt.site.edit import rename_all
>>> out = rename_all(eds, policy=lambda n: f"X_{n}")

Unique names from file stems:

>>> from pathlib import Path
>>> out = rename_all(
...     eds,
...     name_fn=lambda e: f"X_{Path(getattr(e,'path','')).stem}",
... )

See also

rename

Single-site rename helper.

set_coords_all

Batch coordinate assignment.

pycsamt.site.base.Sites

Collection wrapper used here.

References

pycsamt.site.edit.set_coords_all(sites, src, *, inplace=False)[source]#

Batch set coordinates for a collection of sites.

Coordinates can be provided by a callable, a mapping keyed by station name, or an object exposing a .frame attribute with tabular data.

Parameters:
  • sites (Any) – A pycsamt.site.base.Sites instance or any iterable of EDI-like objects.

  • src (Any) –

    One of:
    • callable(edi) -> (lat, lon, elev)

    • mapping[name] -> (lat, lon, elev)

    • object with .frame DataFrame-like with columns: station plus either lat/lon or latitude/longitude, and optionally elev/elevation.

  • inplace (bool, optional) – If True, attempt to modify the given container in place. Otherwise, return a new Sites. Default is False.

Returns:

A collection with updated coordinates, or the original container when mutated in place.

Return type:

pycsamt.site.base.Sites

Notes

  • The lookup order is: callable then mapping by station name, then the optional .frame table. The first source that returns a non-None triple is used.

  • Latitude and longitude are expected in degrees; elevation in meters.

  • The function preserves input order and is no-throw; items without a matching entry are left unchanged.

Examples

From a mapping keyed by names:

>>> from pycsamt.site.edit import set_coords_all
>>> coords = {"S01": (35.1, 12.8, 1234.0)}
>>> out = set_coords_all(eds, coords)

From a callable using file stems:

>>> from pathlib import Path
>>> def pick(edi):
...     stem = Path(getattr(edi, "path", "")).stem
...     return (10.0, 20.0, 100.0) if stem == "S01" else \
...            (11.0, 21.0, 110.0)
>>> out = set_coords_all(eds, pick)

From a pandas DataFrame holder:

>>> class Holder:
...     def __init__(self, frame):
...         self.frame = frame
>>> out = set_coords_all(eds, Holder(df))

See also

set_coords

Single-site coordinate update.

rename_all

Batch rename helper.

pycsamt.site.base.Site.set_coords

OOP variant per site.

References

pycsamt.site.edit.set_coords_from_table(sites, table, *, columns=None, crs_from=None, to_crs='EPSG:4326', inplace=False)[source]#

Set site coordinates for many EDI files from a table.

This high-level helper accepts a wide range of table-like objects (CSV path, pandas DataFrame, numpy structured array, or list of dicts / tuples). It normalizes column names, optionally projects easting/northing to lon/lat, builds a mapping {station: (lat, lon, elev)}, and delegates to set_coords_all().

Parameters:
  • sites (Any) – A Sites instance, an iterable of EDIFile objects, or anything accepted by set_coords_all().

  • table (Any) –

    One of:
    • Path to a CSV or whitespace-delimited text file.

    • A pandas.DataFrame.

    • A numpy structured array.

    • A list of dicts or a list of tuples.

  • columns (dict, optional) – Explicit column mapping. Keys are canonical names and values are the actual column names present in table. Supported canonical keys are: 'station', 'lat', 'lon', 'elev', 'easting', 'northing'. Matching is case-insensitive.

  • crs_from (str, optional) – Source CRS used when the table provides easting and northing instead of lat and lon. Required in that case. Example: 'EPSG:32631' for UTM 31N.

  • to_crs (str, default "EPSG:4326") – Target CRS for output coordinates. The default is WGS84 lon/lat.

  • inplace (bool, default False) – If True, mutate the given collection and return it. Otherwise return a new Sites with updated EDI objects.

Returns:

The same semantics as set_coords_all(): either the mutated input (inplace=True) or a new Sites instance.

Return type:

Any

Raises:
  • ValueError – If the station column cannot be resolved, or if neither (lat, lon) nor (easting, northing) can be resolved, or if crs_from is required but missing.

  • ImportError – If projection is needed (easting/northing present) but pyproj is not installed.

Notes

Column detection is case-insensitive and understands common aliases:

  • station: station, name, site, id.

  • lat: lat, latitude.

  • lon: lon, long, longitude.

  • elev: elev, elevation, z.

  • easting: easting, x.

  • northing: northing, y.

When both geographic and projected fields are present, the geographic pair (lat, lon) is preferred. If only projected fields are present, a valid crs_from must be provided and pyproj will be used for projection.

Examples

Load from a CSV path with standard columns:

>>> from pycsamt.site.edit import set_coords_from_table
>>> from pycsamt.site.base import Sites
>>> edis = Sites([...])  # your EDI files
>>> out = set_coords_from_table(
...     edis, "coords.csv", inplace=False
... )
>>> isinstance(out, Sites)
True

Pass a DataFrame with aliases and an explicit mapping:

>>> import pandas as pd
>>> df = pd.DataFrame({
...     "name": ["S01", "S02"],
...     "latitude": [35.1, 35.2],
...     "long": [12.8, 12.9],
...     "elevation": [120.0, 130.0],
... })
>>> out = set_coords_from_table(
...     edis,
...     df,
...     columns={"station": "name",
...              "lat": "latitude",
...              "lon": "long",
...              "elev": "elevation"},
...     inplace=False,
... )

Use easting/northing with a source CRS:

>>> df = pd.DataFrame({
...     "station": ["S10"],
...     "easting": [400000.0],
...     "northing": [5750000.0],
... })
>>> out = set_coords_from_table(
...     edis,
...     df,
...     crs_from="EPSG:32631",  # UTM 31N
...     inplace=False,
... )

See also

set_coords_all

Broadcast setting of coordinates using a mapping.

set_coords

Single-site coordinate update helper.

References

pycsamt.site.edit.set_coords_from_en(site, easting, northing, *, crs_from, elev=None, to_crs='EPSG:4326', inplace=False)[source]#

Project (easting, northing) to lon/lat and set a site’s coords.

This convenience wraps projection and assignment for a single EDI site. It projects the provided easting/northing from crs_from to to_crs (default WGS84 lon/lat), then calls set_coords().

Parameters:
  • site (Any) – A single EDI-like object compatible with set_coords().

  • easting (float) – Easting value in meters for the source CRS.

  • northing (float) – Northing value in meters for the source CRS.

  • crs_from (str) – The EPSG or PROJ string that identifies the source CRS, for example 'EPSG:32631' for UTM 31N.

  • elev (float, optional) – Elevation in meters to store in the EDI header. If not provided, the previous elevation is kept (if any).

  • to_crs (str, default "EPSG:4326") – Target CRS for output coordinates. The default is WGS84 lon/lat.

  • inplace (bool, default False) – If True, mutate the given object and return it. Otherwise work on a copy and return the copy.

Returns:

The mutated site (inplace=True) or a new site object with updated coordinates.

Return type:

Any

Raises:

Notes

Projection uses pyproj with always_xy=True so that the axis order is interpreted as (lon, lat). Units are assumed to be meters for the easting and northing values.

The returned object follows the same semantics as set_coords(). If you need to update many sites, prefer set_coords_from_table() or set_coords_all().

Examples

Update a single site from UTM 31N (EPSG:32631) coordinates:

>>> from pycsamt.site.edit import set_coords_from_en
>>> site = ...  # an EDIFile
>>> site2 = set_coords_from_en(
...     site,
...     easting=400000.0,
...     northing=5750000.0,
...     crs_from="EPSG:32631",
...     elev=250.0,
...     inplace=False,
... )

Do the update in place and keep the existing elevation:

>>> _ = set_coords_from_en(
...     site,
...     easting=500000.0,
...     northing=4600000.0,
...     crs_from="EPSG:32630",
...     inplace=True,
... )

See also

set_coords

Assign lat, lon, elev on a single site.

set_coords_from_table

Batch update from tabular input.

set_coords_all

Broadcast update using a mapping.

References