pycsamt.emtools.legacy#

pycsamt.emtools.legacy.check_em_kind(objs, /)#

Validate a collection of EM objects and return their common kind.

Ensures that all elements in objs are instances of either Edi or Z, but not a mix of both. Returns the common kind as "EDI" or "Z". Raises if the collection is empty, contains non-EM objects, or mixes kinds.

Parameters:

objs (iterable) – Iterable of objects expected to be all Edi or all Z. Strings and bytes are not valid inputs.

Returns:

"EDI" if all objects are EDI instances, else "Z" if all are Z instances.

Return type:

str

Raises:
  • TypeError – If objs is not an iterable, or is a string/bytes, or is empty.

  • EMError – If an element is neither Edi nor Z, or if the iterable mixes Edi and Z.

Notes

Uses is_instance_extended() to be robust to class reloads and alternate import paths.

Examples

>>> from pycsamt.utils.em import check_em_kind
>>> # assuming `eds` is a list of Edi instances
>>> check_em_kind(eds)
'EDI'
>>> # assuming `zs` is a list of Z instances
>>> check_em_kind(zs)
'Z'
pycsamt.emtools.legacy.extract_z_list(objs, /)#

Return a list of Z objects from EDI or Z inputs.

If objs is a collection of Edi, each element’s .Z attribute is extracted. If objs is already a collection of Z, it is returned as a plain list.

Parameters:

objs (iterable) – Iterable of EM objects. Must be all Edi or all Z. See check_em_kind().

Returns:

List of Z instances.

Return type:

list

Raises:
  • TypeError – If objs is not an iterable or is empty.

  • EMError – If objs mixes Edi and Z, contains non-EM objects, or an Edi is missing the .Z attribute.

Notes

Uses check_em_kind() to validate homogeneity.

Examples

>>> zs = extract_z_list(list_of_edi)   # from EDI inputs
>>> zs = extract_z_list(list_of_z)     # already Z
pycsamt.emtools.legacy.parse_tensor(out='resxy', *, tensor=None, component=None, kind='complex', **kws)#

Parse and validate a tensor request, returning name and component.

This helper normalizes shorthand like 'resxy' or explicit pairs like tensor='z', component='xy' and validates the desired numeric kind (e.g., complex, real, imag, modulus).

Parameters:
  • out (str, default='resxy') – Compact token specifying the tensor and component, e.g. 'resxy', 'zxy', 'phaseyx', or a frequency request such as 'freq'. When both tensor and component are given, they override out.

  • tensor (str, optional) – Tensor name or alias. Accepted values include: 'z', 'tensor', 'res', 'rho', 'rhoa', 'phase', 'phs', 'freq', 'frequency'.

  • component (str, optional) – EM component among 'xx', 'xy', 'yx', 'yy'. Required for 'z', 'resistivity' and 'phase'.

  • kind ({'complex','real','imag','modulus'}, default='complex') – Numeric form of the tensor to be later extracted. Aliases are accepted, e.g. 're'``→’real’, ``'im'``→’imag’, ``'abs'/'mod'``→’modulus’, ``'reel'``→’real’``.

  • **kws – Extra keywords ignored here. Kept for API symmetry with callers that also manage frequency expansion.

Returns:

(name, comp) – Normalized tensor name and its component. The name is one of 'z', 'resistivity', 'phase', '_freq', or includes the '_err' suffix for error arrays where applicable. comp is 'xx', 'xy', 'yx', 'yy' or None for frequency.

Return type:

tuple of (str, Optional[str])

Raises:
  • EMError – If only one of tensor or component is provided.

  • ValueError – If the parsed tokens are invalid, the component is missing for a tensor that requires it, or kind is unknown.

Examples

>>> parse_tensor('zxy')
('z', 'xy')
>>> parse_tensor(tensor='res', component='yx')
('resistivity', 'yx')
>>> parse_tensor('freq')
('_freq', None)
>>> parse_tensor('resx')
Traceback (most recent call last):
    ...
ValueError: 'Resistivity' component is missing...
pycsamt.emtools.legacy.compute_qc(z_or_edis_obj_list, /, tol=0.5, *, interpolate_freq=False, return_freq=False, tensor='res', return_data=False, to_log10=False, return_qco=False)#

Assess data quality across a collection of EDI/Z objects.

Computes a global completeness ratio \(1 - \#NaN / (N_{freq} N_{sta})\) from a 2-D tensor (freq × station). Frequencies whose per-row missing-data fraction exceeds tol are dropped. Optionally interpolate the retained frequencies and/or return a structured summary object.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Homogeneous collection of EM objects.

  • tol (float, default=0.5) – Tolerance threshold in [0, 1]. A frequency row is considered invalid and dropped when its fraction of missing values exceeds tol.

  • interpolate_freq (bool, default=False) – If True, interpolate the retained frequencies on a log-spaced grid spanning [min, max] with the same count.

  • return_freq (bool, default=False) – If True, return the retained (possibly interpolated) frequency vector.

  • tensor ({'z','res','rho','rhoa','phase','phs'}, default='res') – Tensor family used for QC. The function first attempts the TE component ('xy'); on failure, it falls back to TM ('yx').

  • return_data (bool, default=False) – If True, also return the subset of the tensor data corresponding to retained frequencies.

  • to_log10 (bool, default=False) – If True, return log10 of the retained frequencies. Applied after interpolation if interpolate_freq is set.

  • return_qco (bool, default=False) –

    If True, return a Bunch with the following attributes:

    • rate_: global completeness ratio

    • component_: selected component, 'xy' or 'yx'

    • mode_: EM mode, 'TE' or 'TM'

    • freqs_: retained (optionally interpolated) frequencies

    • invalid_freqs_: frequencies dropped by the QC

    • data_: tensor data at retained frequencies

    Setting this flag forces return_freq=True and return_data=True.

Returns:

Depending on the flags. rate is in [0, 1].

Return type:

(rate,) or (rate, freqs) or (rate, freqs, data) or Bunch

Notes

The 2-D tensor has shape (n_freq, n_stations). The per-row missing-data fraction is nan_count / n_stations.

Examples

>>> rate, = compute_qc(data)
>>> rate, freqs = compute_qc(data, return_freq=True)
>>> rep = compute_qc(data, return_qco=True)
>>> rep.rate_, rep.component_, rep.freqs_.shape
(0.75, 'xy', (56,))
pycsamt.emtools.legacy.full_freq(z_or_edis_obj_list, /, to_log10=False)#

Return the reference (clean) frequency grid for a collection.

The full frequency grid is taken from the site that contains the largest number of frequency samples (i.e., the most complete set). This is commonly used as the survey reference grid to which per-site tensors are aligned.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Homogeneous collection of Edi or Z objects.

  • to_log10 (bool, default=False) – If True, return log10(freqs). Frequencies must be strictly positive.

Returns:

The reference frequency vector.

Return type:

ndarray of shape (n_freq,)

Raises:
  • TypeError – If the input is empty or not iterable.

  • EMError – If the collection mixes Edi and Z, or any element is missing a frequency attribute.

  • ValueError – If to_log10=True and any frequency is non-positive.

Notes

For each object, the function looks for .Z._freq / .Z.freq (when Edi) or ._freq / .freq (when Z), using the first available attribute.

Examples

>>> f = full_freq(edi_data)
>>> f.shape
(56,)
>>> flog = full_freq(edi_data, to_log10=True)
pycsamt.emtools.legacy.tensor2d(z_or_edis_obj_list, /, tensor='z', component='xy', kind='modulus', return_freqs=False, freqs=None, **kws)#

Build a 2-D matrix (freq × station) from a tensor collection.

Converts a collection of Edi or Z objects into a 2-D array where rows are frequencies and columns are stations. Missing per-site frequencies are filled with NaN (no interpolation).

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Collection of EM objects. All items must be Edi or all Z.

  • tensor (str, default='z') – Tensor name or alias. Examples include 'z', 'res'/'rho'/'rhoa', 'phase'/'phs'. Error arrays are supported (e.g., 'resistivity_err').

  • component ({'xx','xy','yx','yy'}, default='xy') – Component to extract for non-frequency tensors.

  • kind ({'modulus','real','imag','complex'}, default='modulus') – Numeric form for complex Z tensors. Ignored for real arrays (e.g., resistivity/phase).

  • return_freqs (bool, default=False) – If True, also return the reference frequency vector.

  • freqs (array-like, optional) – Precomputed reference frequency grid. If given, it is used directly and get_full_frequency is not called. The grid should include (or supersede) each site’s frequencies; any missing values will be filled with NaN during alignment.

  • **kws – Extra keywords forwarded to the frequency extractor when freqs is not provided.

Returns:

  • mat2d (ndarray (n_freq, n_stations)) – 2-D matrix of the requested tensor component.

  • (mat2d, freqs) (tuple) – If return_freqs=True, also returns the frequency vector.

Raises:
  • EMError – If inputs are missing, mixed, or illegal (e.g., frequency requested as the primary tensor here).

  • ValueError – If an unknown kind is used for complex Z.

Notes

Each item in the input provides a 3-D tensor of shape (n_freq, 2, 2). Index positions map as:

xx -> (0, 0)   xy -> (0, 1)
yx -> (1, 0)   yy -> (1, 1)

Examples

>>> phase_yx = tensor2d(data, tensor='phase', component='yx')
>>> phase_yx.shape
(56, 7)
pycsamt.emtools.legacy.align_tensor(ref_freq, site_freq, z, fill_value=nan)#

Align a tensor component to a reference frequency grid.

The reference frequency grid (ref_freq) is assumed to be the complete set of clean frequencies for the survey. Site-level measurements (site_freq) may be missing some frequencies due to interferences. This function maps the provided tensor values (z) to the reference grid and fills gaps with fill_value.

Parameters:
  • ref_freq (ArrayLike) – Reference frequency grid collected in the field. It should contain all survey frequencies.

  • site_freq (ArrayLike) – Frequencies measured at a site. All values must be present in ref_freq (i.e., no out-of-grid frequencies).

  • z (ndarray of complex) – Tensor component values measured at site_freq. Typically the real or imaginary part for one of xx, xy, yx, or yy. Length must match site_freq.

  • fill_value (float, default=nan) – Value used to fill positions in the reference grid where the site tensor is missing.

Returns:

Array aligned to ref_freq with gaps filled by fill_value. The dtype matches z.dtype.

Return type:

ndarray of complex

Raises:
  • EMError – If the number of mappable positions inferred from site_freq does not match the length of z.

  • ValueError – If input shapes are inconsistent.

Notes

Internally uses ismissing() to identify positions in ref_freq that correspond to site_freq. The function does not interpolate values; it only aligns and fills gaps.

Examples

>>> ref_freq = np.linspace(7e7, 1.0, 20)
>>> site_freq = np.hstack([ref_freq[:7], ref_freq[12:]])
>>> z = np.random.randn(len(site_freq)) + 1j*np.random.randn(
...     len(site_freq)
... )
>>> z_aligned = align_tensor(ref_freq, site_freq, z)
>>> np.isnan(z_aligned).sum()  # gaps inserted
5
pycsamt.emtools.legacy.export_edis(edi_objs, new_z, savepath=None, **kws)#

Export new EDI files from a batch of EDI objects and Z tensors.

Applies updated impedance tensors to each input EDI object and writes new EDI files. This is typically used after applying corrections or replacements to the impedance tensor.

Parameters:
  • edi_objs (list of Edi) – Collection of EDI objects. All elements must be instances of Edi (no Z objects are allowed here).

  • new_z (list of ndarray (nfreq, 2, 2), complex) – Collection of impedance tensors matching edi_objs one-to- one. Each tensor is a 3-D complex array with shape (n_freq, 2, 2).

  • savepath (str, optional) – Directory to write the new EDI files. If None, the EDI writer decides (often the current directory).

  • **kws – Extra arguments forwarded to the EDI writer method Edi.write_new_edifile (e.g., naming options).

Returns:

Files are written as a side effect. The underlying writer may return paths, but this function does not collect them.

Return type:

None

Raises:
  • EdIDataError – If edi_objs does not contain exclusively EDI objects.

  • ValueError – If the lengths of edi_objs and new_z differ.

See also

exportedi

Helper for exporting a single EDI (if available in the API).

Examples

>>> # edi_objs: list[Edi], z_list: list[np.ndarray]
>>> export_edis(edi_objs, z_list, savepath="out/")
pycsamt.emtools.legacy.plot_confidence(z_or_edis_obj_list, /, tensor='res', view='1d', drop_outliers=True, distance=None, c_line=False, view_ci=True, figsize=(6.0, 2.0), fontsize=4.0, dpi=300, top_label='Stations', rotate_xlabel=90.0, fbtw=True, savefig=None, **plot_kws)#

Plot confidence diagnostics from tensor errors for EM data.

The default tensor for confidence evaluation is the resistivity error at TE mode ('xy'). This plot helps decide which frequencies (and stations) are reliable, recoverable, or should be discarded before further processing.

Three confidence levels are highlighted:

  • High: \(conf \ge 0.95\)

  • Soft: \(0.5 \le conf < 0.95\) (often recoverable)

  • Bad: \(conf < 0.5\) (usually discard)

Parameters:
  • z_or_edis_obj_list (list of EDI or Z) – Collection of Edi or Z objects.

  • tensor (str, default='res') – Tensor selector. Accepted aliases include resistivity ('res', 'rho', 'rhoa'), phase ('phase', 'phs'), or 'z'. Error arrays are used for resistivity/phase automatically.

  • view ({'1d', '2d'}, default='1d') – Plot as a 1-D profile (by station) or as a 2-D map (frequency vs. station).

  • drop_outliers (bool, default=True) – If True, suppress outliers in the error tensor before plotting (filled with nan).

  • distance (float, optional) – Inter-station distance. Used to scale the x-axis in 1-D view. If None, a unit spacing of 1 is used.

  • c_line (bool, default=False) – If True and view='2d', overlay the confidence line.

  • view_ci (bool, default=True) – If True, show markers indicating confidence classes.

  • figsize (tuple of float, default=(6.0, 2.0)) – Matplotlib figure size.

  • fontsize (float, default=4.0) – Base font size used for labels and ticks.

  • dpi (int, default=300) – Figure resolution in dots per inch.

  • top_label (str, default='Stations') – Title used for the top x-axis (station labels).

  • rotate_xlabel (float, default=90.0) – Rotation angle for station labels on the top x-axis.

  • fbtw (bool, default=True) – In 1-D view, fill between the curve and confidence bands.

  • savefig (str, optional) – Path to save the figure. If None, the figure is shown.

  • plot_kws (Any)

Returns:

The Matplotlib Axes with the plotted content.

Return type:

matplotlib.axes.Axes

Notes

Internally, the function computes an error tensor for the chosen tensor (resistivity/phase use error arrays). Confidence is aggregated across stations and displayed either as a 1-D line or a 2-D image with categorical markers.

Examples

>>> ax = plot_confidence(
...     emobj.ediObjs_, distance=20, view='2d',
...     figsize=(6, 2)
... )
>>> ax = plot_confidence(
...     emobj.ediObjs_, distance=20, view='1d',
...     figsize=(6, 3), fontsize=5
... )
pycsamt.emtools.legacy.plot_strike(list_of_edis, /, kind=2, period_tolerance=0.05, text_pad=1.65, rot_z=0.0, **kws)#

Plot strike angles from invariants and phase tensor as rose/polar diagrams.

Accepts a single .edi file path, a directory containing .edi files, or an iterable of .edi paths. Files are validated before plotting. Output is produced by mtpy.imaging.plotstrike. PlotStrike, with console output muted.

Parameters:
  • list_of_edis (str or iterable of str) – Path to an .edi file, a directory of .edi files, or a list/tuple of .edi file paths.

  • kind ({1, 2}, default=2) –

    Plot style for PlotStrike: - 1: plot individual decades in one plot. - 2: plot all period ranges in a polar diagram for each

    strike estimate.

  • period_tolerance (float, default=0.05) – Tolerance to match periods across different EDI files.

  • text_pad (float, default=1.65) – Padding of the angle label at the bottom of each polar diagram.

  • rot_z (float, default=0.0) – Clockwise rotation (degrees) applied to the tensor.

  • **kws – Extra keyword arguments forwarded to PlotStrike (e.g., plot_range, plot_tipper, fold, plot_orientation, color settings, etc.).

Returns:

Plots are created as a side effect.

Return type:

None

Notes

  • Files are validated with IsEdi._assert_edi.

  • Third-party output is muted via nullify_output().

Examples

>>> plot_strike("/path/to/edis_dir")
>>> plot_strike("/path/to/site.edi", kind=1)
>>> plot_strike(["a.edi", "b.edi"], rot_z=10.0)
pycsamt.emtools.legacy.plot_tensors(z_or_edis_obj_list, /, station='S00', zplot=False, show_error_bars=False, **kwargs)#

Plot tensors for one station (compat wrapper).

This is a compatibility wrapper around plot_station_tensors(). It preserves the legacy API—station, zplot (for impedance vs. app. resistivity/ phase), and show_error_bars—and forwards any additional styling options to the underlying plotter.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Collection of EM objects containing either Edi (from which the embedded Z is extracted) or Z directly.

  • station (int or str, default='S00') – Target station index or label. Strings such as 'S00' are parsed to 0-based indices.

  • zplot (bool, default=False) – If True, plot real/imag parts of the impedance tensor (Z). If False, plot apparent resistivity and phase.

  • show_error_bars (bool, default=False) – Whether to display error bars.

  • **kwargs – Additional plotting options passed to plot_station_tensors() (e.g., color_mode, markers, line widths, legend style, font sizes, etc.).

Returns:

The Z object for the selected station.

Return type:

Z

Notes

The heavy lifting (layout, filtering, styling) is handled by plot_station_tensors(). This wrapper exists to maintain source compatibility with v1.x code.

Examples

>>> z = plot_tensors(edi_list, station='S03', zplot=True)
>>> z = plot_tensors(edi_list, station=0, show_error_bars=True)
pycsamt.emtools.legacy.plot_station_tensors(z_or_edis_obj_list, /, station='S00', *, plot_z=False, show_error_bars=True, **kwargs)#

Plot tensors for one station: resistivity/phase or Z real/imag.

By default, the function plots apparent resistivity and phase panels for the four components (xx, xy, yx, yy). If plot_z is True, it plots the real and imaginary parts of the impedance tensor instead. Error bars can be displayed or hidden.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Collection containing either Edi or Z objects. When EDI objects are provided, the embedded Z is extracted.

  • station (int or str, default='S00') – Target station index or label. Strings like 'S00' are parsed to an integer index (0-based).

  • plot_z (bool, default=False) – If True, plot real/imag parts of Z. Otherwise, plot apparent resistivity and phase.

  • show_error_bars (bool, default=True) – Whether to include error bars on each panel.

  • **kwargs

    Plot customization such as: - fig_size (tuple, default=(6, 6)) - dpi (int, default=300) - subplot_wspace (float, default=0.3) - phase_limits (tuple[min,max] in deg) - freq_limits (tuple[min,max] in Hz) - period_limits (tuple[min,max] in s) - mod_base (int, default=360) - style: color_mode (‘color’|’bw’), markers, line widths,

    legend style, font sizes, etc.

Returns:

The Z object for the selected station.

Return type:

Z

Notes

The function expects the station’s Z object to provide (or compute on demand) the following arrays with shape (n_freq, 2, 2): - resistivity, resistivity_err - phase, phase_err - z (complex), z_err (complex) and a frequency vector _freq (Hz).

Examples

>>> z = plot_station_tensors(edi_list, station=3)
>>> z = plot_station_tensors(
...     edi_list, station="S00", plot_z=True,
...     show_error_bars=False, color_mode="bw"
... )
pycsamt.emtools.legacy.wrap_phase(phase, value_range=None, mod_base=360)#

Wrap phase values to a target range with a given periodic base.

By default, phases are wrapped into the interval [0, mod_base). When value_range is provided, the wrapped phases are linearly remapped from [0, mod_base) to the desired interval.

Parameters:
  • phase (array-like) – Phase values (any shape), possibly negative or outside the target range.

  • value_range ({None, scalar, (min, max)}, optional) – Target interval for the output. - None: return values in [0, mod_base). - scalar: treated as (0, scalar). - tuple/list (min, max): custom interval; min < max.

  • mod_base ({90, 180, 270, 360}, default=360) – Periodicity used for wrapping (degrees).

Returns:

Wrapped (and optionally remapped) phase values with the same shape as the input and dtype float.

Return type:

np.ndarray

Notes

  • For the common symmetric range (-180, 180], set value_range=(-180, 180) with mod_base=360.

  • The remapping is affine: values in [0, mod_base) are scaled to [min, max).

Examples

>>> x = np.array([-540, -180,   0, 180, 360, 540])
>>> # Default: [0, 360)
>>> wrap_phase(x, mod_base=360)
array([180., 180.,   0., 180.,   0., 180.])
>>> # Symmetric range (-180, 180)
>>> wrap_phase(x, value_range=(-180, 180), mod_base=360)
array([-180., -180.,    0.,  180.,    0.,  180.])
>>> # Custom half-range [0, 180)
>>> wrap_phase(x, value_range=180, mod_base=360)
array([90., 90.,  0., 90.,  0., 90.])
pycsamt.emtools.legacy.plot_lcurve(rms, roughness, tau=None, hansen_point=None, rms_target=None, view_tline=False, hpoint_kws=None, fig_size=(10.0, 4.0), ax=None, fig=None, style='classic', savefig=None, **plot_kws)#

Plot the Hansen L-curve (RMS vs. roughness) with annotations.

The L-curve criterion helps select a suitable model after running several inversions with different \(\tau\) values. This function plots RMS against model roughness, optionally highlights the Hansen knee point, displays the RMS target line, and labels each point with its \(\tau\).

Parameters:
  • rms (array-like) – Sequence of RMS values, one per inversion.

  • roughness (array-like) – Sequence of roughness values matching rms.

  • tau (array-like, optional) – Sequence of \(\tau\) values to annotate at each point. Length must match rms and roughness.

  • hansen_point ({'auto', (x, y)}, optional) – If 'auto', the knee point is detected automatically. Otherwise, pass a 2-tuple (roughness, rms) to highlight.

  • rms_target (float, optional) – Target RMS. If provided and view_tline=True, a horizontal line is drawn at this value. If provided and view_tline=False, the y-limits are expanded around it.

  • view_tline (bool, default=False) – Whether to draw the target RMS horizontal line.

  • hpoint_kws (dict, optional) – Matplotlib kwargs to style the Hansen point marker.

  • fig_size (tuple of float, default=(10.0, 4.0)) – Figure size used when creating a new figure.

  • ax (matplotlib.axes.Axes, optional) – Target axes. If None, a new figure/axes is created.

  • fig (matplotlib.figure.Figure, optional) – Figure handle used for saving when savefig is set. If omitted, the figure from ax is used or a new one created.

  • style (str, optional) – Matplotlib style to use within a context (not global).

  • savefig (str, optional) – Path to save the figure. If omitted, the plot is shown.

  • **plot_kws – Extra style passed to Axes.plot for the L-curve line.

Returns:

The axes with the plotted L-curve.

Return type:

matplotlib.axes.Axes

Notes

Knee detection uses a simple triangle-area curvature surrogate. See Hansen & O’Leary (1993) for background on the L-curve.

Examples

>>> rough = [0, 50, 100, 150, 200, 250, 300, 350]
>>> rmse = [3.16, 3.12, 3.10, 3.08, 3.06, 3.04, 3.02, 3.00]
>>> plot_lcurve(rmse, rough, hansen_point="auto")
pycsamt.emtools.legacy.get_full_frequency(z_or_edis_obj_list, /, to_log10=False)#

Return the reference (clean) frequency grid for a collection.

The full frequency grid is taken from the site that contains the largest number of frequency samples (i.e., the most complete set). This is commonly used as the survey reference grid to which per-site tensors are aligned.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Homogeneous collection of Edi or Z objects.

  • to_log10 (bool, default=False) – If True, return log10(freqs). Frequencies must be strictly positive.

Returns:

The reference frequency vector.

Return type:

ndarray of shape (n_freq,)

Raises:
  • TypeError – If the input is empty or not iterable.

  • EMError – If the collection mixes Edi and Z, or any element is missing a frequency attribute.

  • ValueError – If to_log10=True and any frequency is non-positive.

Notes

For each object, the function looks for .Z._freq / .Z.freq (when Edi) or ._freq / .freq (when Z), using the first available attribute.

Examples

>>> f = full_freq(edi_data)
>>> f.shape
(56,)
>>> flog = full_freq(edi_data, to_log10=True)
pycsamt.emtools.legacy.qc(z_or_edis_obj_list, /, tol=0.5, *, interpolate_freq=False, return_freq=False, tensor='res', return_data=False, to_log10=False, return_qco=False)#

Assess data quality across a collection of EDI/Z objects.

Computes a global completeness ratio \(1 - \#NaN / (N_{freq} N_{sta})\) from a 2-D tensor (freq × station). Frequencies whose per-row missing-data fraction exceeds tol are dropped. Optionally interpolate the retained frequencies and/or return a structured summary object.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Homogeneous collection of EM objects.

  • tol (float, default=0.5) – Tolerance threshold in [0, 1]. A frequency row is considered invalid and dropped when its fraction of missing values exceeds tol.

  • interpolate_freq (bool, default=False) – If True, interpolate the retained frequencies on a log-spaced grid spanning [min, max] with the same count.

  • return_freq (bool, default=False) – If True, return the retained (possibly interpolated) frequency vector.

  • tensor ({'z','res','rho','rhoa','phase','phs'}, default='res') – Tensor family used for QC. The function first attempts the TE component ('xy'); on failure, it falls back to TM ('yx').

  • return_data (bool, default=False) – If True, also return the subset of the tensor data corresponding to retained frequencies.

  • to_log10 (bool, default=False) – If True, return log10 of the retained frequencies. Applied after interpolation if interpolate_freq is set.

  • return_qco (bool, default=False) –

    If True, return a Bunch with the following attributes:

    • rate_: global completeness ratio

    • component_: selected component, 'xy' or 'yx'

    • mode_: EM mode, 'TE' or 'TM'

    • freqs_: retained (optionally interpolated) frequencies

    • invalid_freqs_: frequencies dropped by the QC

    • data_: tensor data at retained frequencies

    Setting this flag forces return_freq=True and return_data=True.

Returns:

Depending on the flags. rate is in [0, 1].

Return type:

(rate,) or (rate, freqs) or (rate, freqs, data) or Bunch

Notes

The 2-D tensor has shape (n_freq, n_stations). The per-row missing-data fraction is nan_count / n_stations.

Examples

>>> rate, = compute_qc(data)
>>> rate, freqs = compute_qc(data, return_freq=True)
>>> rep = compute_qc(data, return_qco=True)
>>> rep.rate_, rep.component_, rep.freqs_.shape
(0.75, 'xy', (56,))
pycsamt.emtools.legacy.plot_tensors2(z_or_edis_obj_list, /, station='S00', *, plot_z=False, show_error_bars=True, **kwargs)#

Plot tensors for one station: resistivity/phase or Z real/imag.

By default, the function plots apparent resistivity and phase panels for the four components (xx, xy, yx, yy). If plot_z is True, it plots the real and imaginary parts of the impedance tensor instead. Error bars can be displayed or hidden.

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Collection containing either Edi or Z objects. When EDI objects are provided, the embedded Z is extracted.

  • station (int or str, default='S00') – Target station index or label. Strings like 'S00' are parsed to an integer index (0-based).

  • plot_z (bool, default=False) – If True, plot real/imag parts of Z. Otherwise, plot apparent resistivity and phase.

  • show_error_bars (bool, default=True) – Whether to include error bars on each panel.

  • **kwargs

    Plot customization such as: - fig_size (tuple, default=(6, 6)) - dpi (int, default=300) - subplot_wspace (float, default=0.3) - phase_limits (tuple[min,max] in deg) - freq_limits (tuple[min,max] in Hz) - period_limits (tuple[min,max] in s) - mod_base (int, default=360) - style: color_mode (‘color’|’bw’), markers, line widths,

    legend style, font sizes, etc.

Returns:

The Z object for the selected station.

Return type:

Z

Notes

The function expects the station’s Z object to provide (or compute on demand) the following arrays with shape (n_freq, 2, 2): - resistivity, resistivity_err - phase, phase_err - z (complex), z_err (complex) and a frequency vector _freq (Hz).

Examples

>>> z = plot_station_tensors(edi_list, station=3)
>>> z = plot_station_tensors(
...     edi_list, station="S00", plot_z=True,
...     show_error_bars=False, color_mode="bw"
... )
pycsamt.emtools.legacy.plot_l_curve(rms, roughness, tau=None, hansen_point=None, rms_target=None, view_tline=False, hpoint_kws=None, fig_size=(10.0, 4.0), ax=None, fig=None, style='classic', savefig=None, **plot_kws)#

Plot the Hansen L-curve (RMS vs. roughness) with annotations.

The L-curve criterion helps select a suitable model after running several inversions with different \(\tau\) values. This function plots RMS against model roughness, optionally highlights the Hansen knee point, displays the RMS target line, and labels each point with its \(\tau\).

Parameters:
  • rms (array-like) – Sequence of RMS values, one per inversion.

  • roughness (array-like) – Sequence of roughness values matching rms.

  • tau (array-like, optional) – Sequence of \(\tau\) values to annotate at each point. Length must match rms and roughness.

  • hansen_point ({'auto', (x, y)}, optional) – If 'auto', the knee point is detected automatically. Otherwise, pass a 2-tuple (roughness, rms) to highlight.

  • rms_target (float, optional) – Target RMS. If provided and view_tline=True, a horizontal line is drawn at this value. If provided and view_tline=False, the y-limits are expanded around it.

  • view_tline (bool, default=False) – Whether to draw the target RMS horizontal line.

  • hpoint_kws (dict, optional) – Matplotlib kwargs to style the Hansen point marker.

  • fig_size (tuple of float, default=(10.0, 4.0)) – Figure size used when creating a new figure.

  • ax (matplotlib.axes.Axes, optional) – Target axes. If None, a new figure/axes is created.

  • fig (matplotlib.figure.Figure, optional) – Figure handle used for saving when savefig is set. If omitted, the figure from ax is used or a new one created.

  • style (str, optional) – Matplotlib style to use within a context (not global).

  • savefig (str, optional) – Path to save the figure. If omitted, the plot is shown.

  • **plot_kws – Extra style passed to Axes.plot for the L-curve line.

Returns:

The axes with the plotted L-curve.

Return type:

matplotlib.axes.Axes

Notes

Knee detection uses a simple triangle-area curvature surrogate. See Hansen & O’Leary (1993) for background on the L-curve.

Examples

>>> rough = [0, 50, 100, 150, 200, 250, 300, 350]
>>> rmse = [3.16, 3.12, 3.10, 3.08, 3.06, 3.04, 3.02, 3.00]
>>> plot_lcurve(rmse, rough, hansen_point="auto")
pycsamt.emtools.legacy.get2dtensor(z_or_edis_obj_list, /, tensor='z', component='xy', kind='modulus', return_freqs=False, freqs=None, **kws)#

Build a 2-D matrix (freq × station) from a tensor collection.

Converts a collection of Edi or Z objects into a 2-D array where rows are frequencies and columns are stations. Missing per-site frequencies are filled with NaN (no interpolation).

Parameters:
  • z_or_edis_obj_list (list of Edi or Z) – Collection of EM objects. All items must be Edi or all Z.

  • tensor (str, default='z') – Tensor name or alias. Examples include 'z', 'res'/'rho'/'rhoa', 'phase'/'phs'. Error arrays are supported (e.g., 'resistivity_err').

  • component ({'xx','xy','yx','yy'}, default='xy') – Component to extract for non-frequency tensors.

  • kind ({'modulus','real','imag','complex'}, default='modulus') – Numeric form for complex Z tensors. Ignored for real arrays (e.g., resistivity/phase).

  • return_freqs (bool, default=False) – If True, also return the reference frequency vector.

  • freqs (array-like, optional) – Precomputed reference frequency grid. If given, it is used directly and get_full_frequency is not called. The grid should include (or supersede) each site’s frequencies; any missing values will be filled with NaN during alignment.

  • **kws – Extra keywords forwarded to the frequency extractor when freqs is not provided.

Returns:

  • mat2d (ndarray (n_freq, n_stations)) – 2-D matrix of the requested tensor component.

  • (mat2d, freqs) (tuple) – If return_freqs=True, also returns the frequency vector.

Raises:
  • EMError – If inputs are missing, mixed, or illegal (e.g., frequency requested as the primary tensor here).

  • ValueError – If an unknown kind is used for complex Z.

Notes

Each item in the input provides a 3-D tensor of shape (n_freq, 2, 2). Index positions map as:

xx -> (0, 0)   xy -> (0, 1)
yx -> (1, 0)   yy -> (1, 1)

Examples

>>> phase_yx = tensor2d(data, tensor='phase', component='yx')
>>> phase_yx.shape
(56, 7)