Transfer Functions And Tipper Diagnostics#

The transfer-function tools in pycsamt.emtools focus on the vertical-field response, usually called the tipper. The tipper relates the vertical magnetic field to the horizontal magnetic field:

Hz = Tx Hx + Ty Hy

where Tx and Ty are complex, frequency-dependent transfer functions. When the subsurface is laterally uniform, the vertical field is weak. When current is channelled by lateral conductors or sharp resistivity contrasts, the tipper grows and induction arrows become one of the fastest qualitative diagnostics for conductor position, strike, and period-dependent structure.

This page covers two related workflows:

Workflow

Main tools

Purpose

EDI or Sites tipper diagnostics

plot_tipper_hodograms, plot_tipper_polar, plot_induction_map, plot_induction_section, plot_induction_rose

Work from assembled transfer functions, usually EDI files.

Spectra-direct tipper diagnostics

plot_induction_map_from_spectra, plot_tipper_polar_from_spectra, plot_induction_rose_from_spectra

Work from spectral estimates before a final EDI has been written.

All public functions used below are exported from pycsamt.emtools, so the examples use the two-level import style.

Use A Dataset With Tipper#

Many AMT/CSAMT data sets contain only horizontal electric and magnetic channels. Those files can have valid impedance but no vertical magnetic transfer function. The tipper functions will then return graceful "no tipper" messages.

For induction-vector work, first verify that the selected survey really has tipper data. The bundled KAP03 long-period MT profile is useful for examples because it includes vertical-field measurements.

 1from pathlib import Path
 2
 3from pycsamt.emtools import ensure_sites
 4
 5edi_dir = Path("data/MT/kap03lmt_edis")
 6sites = ensure_sites(
 7    edi_dir,
 8    recursive=True,
 9    on_dup="replace",
10    strict=False,
11    verbose=0,
12)

If a plot says "no tipper", check the data before changing plotting options. Missing tipper is a data-content issue, not necessarily a failed plot.

What The Tipper Stores#

For each station and frequency, pyCSAMT expects a two-component complex tipper:

Quantity

Meaning

Tx

Complex coefficient relating Hx to Hz.

Ty

Complex coefficient relating Hy to Hz.

real(T)

In-phase part. Commonly used for Parkinson induction arrows.

imag(T)

Quadrature part. Useful for checking frequency-dependent or inductive behavior that is out of phase with the horizontal field.

abs(T)

Magnitude, often summarized as sqrt(abs(Tx)**2 + abs(Ty)**2).

You usually do not need to extract these arrays manually. The plotting functions read them from the site objects. Still, understanding the components helps interpret the figures.

Choose Periods And Bands#

Tipper diagnostics are strongly period-dependent. A station may be weak at short period, strong at mid-period, and weak again at long period. Choose periods and period bands deliberately.

 1import numpy as np
 2
 3# Example period choices for a broad-band MT profile.
 4periods = [25.0, 650.0, 2000.0, 17000.0]
 5short_band = (25.0, 200.0)
 6long_band = (2000.0, 17000.0)
 7
 8print("periods:", periods)
 9print("short band:", short_band)
10print("long band:", long_band)
periods: [25.0, 650.0, 2000.0, 17000.0]
short band: (25.0, 200.0)
long band: (2000.0, 17000.0)

Use the same period choices across maps, roses, and sections when you want the figures to support one interpretation.

Single-Station Hodograms#

Start with plot_tipper_hodograms when inspecting one station. It plots Tx and Ty in the complex plane, with colors split by period band.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_tipper_hodograms
 4
 5fig = plot_tipper_hodograms(
 6    sites,
 7    station="kap151",
 8    bands=[
 9        (25.0, 200.0),
10        (200.0, 2000.0),
11        (2000.0, 17000.0),
12    ],
13    unit_circle=True,
14    normalize=False,
15)
16fig.savefig("tf_tipper_hodograms.png", dpi=200, bbox_inches="tight")
17plt.close(fig)
../../_images/user-guide-emtools-tf-03.png

Read a hodogram before reading arrows. It shows whether a station has a smooth, coherent complex response or a scattered cloud. A large loop outside the unit circle can be real for strong 3-D/lateral induction; it is not automatically an error.

Set normalize=True only when comparing shape rather than amplitude. For conductor-strength interpretation, keep the raw amplitude.

Single-Station Polar View#

plot_tipper_polar converts one station’s tipper into azimuth and magnitude versus period. The polar angle is the tipper direction, radius is magnitude, and color is log-period.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_tipper_polar
 4
 5ax = plot_tipper_polar(
 6    sites,
 7    station="kap151",
 8    component="real",
 9)
10ax.figure.savefig("tf_tipper_polar.png", dpi=200, bbox_inches="tight")
11plt.close(ax.figure)
../../_images/user-guide-emtools-tf-04.png

Valid components are "real", "imag", and "abs". Use "real" for a Parkinson-style conductor-direction reading, use "imag" to inspect the quadrature response, and use "abs" when you mainly care about magnitude.

Induction Map At One Period#

plot_induction_map draws real and imaginary induction arrows at a single target period. The function picks the nearest available period for each station.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_map
 4
 5ax = plot_induction_map(
 6    sites,
 7    period=2000.0,
 8    convention="park",
 9    show_real=True,
10    show_imag=True,
11    scale=4.0,
12    station_labels=True,
13    reference_arrow=0.1,
14)
15ax.figure.savefig("tf_induction_map.png", dpi=200, bbox_inches="tight")
16plt.close(ax.figure)
../../_images/user-guide-emtools-tf-05.png

The station coordinates come from easting/northing, x/y, or lon/lat when available. If none are present, pyCSAMT falls back to an index along a line. That fallback is still useful for a profile, but do not interpret the x-axis as real distance unless the source data contain real coordinates.

scale controls arrow length in plot coordinates. If arrows are too small or overlap badly, adjust scale rather than changing the tipper data.

Compare Several Periods On One Axis#

plot_induction_arrows overlays arrows from several requested periods on one profile axis.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_arrows
 4
 5ax = plot_induction_arrows(
 6    sites,
 7    periods=[25.0, 650.0, 2000.0, 17000.0],
 8    convention="park",
 9    scale=1.0,
10    normalize=True,
11    strike_ticks=False,
12)
13ax.figure.savefig("tf_induction_arrows.png", dpi=200, bbox_inches="tight")
14plt.close(ax.figure)
../../_images/user-guide-emtools-tf-06.png

Use this for a fast period comparison, not as the final publication figure. Many periods on one axis can become visually crowded. If the period behavior matters, follow with a period section or a multi-period map.

Sign Conventions#

Induction-vector interpretation depends on convention. The two common views are Parkinson and Wiese. They are rotated relative to each other, so a figure can be misread if the convention is not stated.

plot_induction_convention puts Parkinson/Wiese and real/imaginary components in one 2-by-2 figure.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_convention
 4
 5plot_induction_convention(
 6    sites,
 7    period=650.0,
 8    station_labels=False,
 9)
10plt.gcf().savefig("tf_induction_convention.png", dpi=200, bbox_inches="tight")
11plt.close()
../../_images/user-guide-emtools-tf-07.png

Use this plot when communicating with collaborators or comparing to a paper. It makes sign and component choices visible instead of leaving them implicit.

Period Pseudosection#

plot_induction_section shows tipper magnitude or component strength over stations and period.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_section
 4
 5ax = plot_induction_section(
 6    sites,
 7    component="abs",
 8    n_periods=30,
 9    cmap="RdBu_r",
10    section="pseudosection",
11)
12ax.figure.savefig("tf_induction_section.png", dpi=200, bbox_inches="tight")
13plt.close(ax.figure)
../../_images/user-guide-emtools-tf-08.png

Use component="abs" for anomaly strength, "real" for in-phase strength, and "imag" for quadrature strength. A section is the best single view for answering: where along the line is the tipper strong, and at what periods?

Induction Rose#

plot_induction_rose summarizes arrow azimuths over all stations and selected periods.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_rose
 4
 5ax = plot_induction_rose(
 6    sites,
 7    component="real",
 8    pband=(25.0, 200.0),
 9    nbins=36,
10    title="Short-period induction azimuths",
11)
12ax.figure.savefig("tf_induction_rose_short.png", dpi=200, bbox_inches="tight")
13plt.close(ax.figure)
14
15ax = plot_induction_rose(
16    sites,
17    component="real",
18    pband=(2000.0, 17000.0),
19    nbins=36,
20    title="Long-period induction azimuths",
21)
22ax.figure.savefig("tf_induction_rose_long.png", dpi=200, bbox_inches="tight")
23plt.close(ax.figure)

Compare short and long period roses before claiming a regional conductor. A short-period rose may be scattered because shallow heterogeneity points in many directions. A long-period rose that tightens into one sector can support a deeper, more coherent conductive structure.

Multi-Period Map#

plot_induction_multiperiod_map stacks one map panel per period and is the most report-ready induction-vector figure. It can use real EDI tipper, or an explicit tipper_data override.

 1import matplotlib.pyplot as plt
 2
 3from pycsamt.emtools import plot_induction_multiperiod_map
 4
 5fig, axes = plot_induction_multiperiod_map(
 6    sites,
 7    periods=[25.0, 650.0, 2000.0, 17000.0],
 8    convention="park",
 9    arrow_scale=6.0,
10    reference_arrow=0.1,
11    show_background_cbar=False,
12    station_labels=False,
13    title="Induction vectors across period",
14)
15fig.savefig("tf_induction_multiperiod_map.png", dpi=200, bbox_inches="tight")
16plt.close(fig)
../../_images/user-guide-emtools-tf-10.png

When background is not supplied, the function draws a synthetic terrain-like background. That background is a visual placeholder, not a real DEM. For a report, pass your own background and background_extent.

The fallback EDI read path in this function can only use a single tipper component in some situations. When you need full two-component vectors, pass tipper_data explicitly as a dictionary keyed by period:

 1import matplotlib.pyplot as plt
 2import numpy as np
 3
 4# Each value is an array with shape (n_stations, 2):
 5# column 0 is Tx, column 1 is Ty. Replace these synthetic
 6# rows with processed Tx/Ty values from your own workflow.
 7n_stations = 26
 8tipper_data = {}
 9for period, tx, ty in [
10    (25.0, 0.08 + 0.02j, 0.02 + 0.01j),
11    (650.0, 0.22 + 0.05j, 0.10 + 0.03j),
12    (2000.0, 0.16 + 0.03j, 0.18 + 0.04j),
13    (17000.0, 0.05 + 0.01j, 0.20 + 0.04j),
14]:
15    tipper_data[period] = np.tile(
16        np.array([[tx, ty]], dtype=complex),
17        (n_stations, 1),
18    )
19
20fig, axes = plot_induction_multiperiod_map(
21    sites,
22    periods=list(tipper_data),
23    tipper_data=tipper_data,
24    arrow_scale=6.0,
25    show_background_cbar=False,
26)
27fig.savefig(
28    "tf_induction_multiperiod_map_synthetic.png",
29    dpi=200,
30    bbox_inches="tight",
31)
32plt.close(fig)
../../_images/user-guide-emtools-tf-11.png

The station order in each tipper_data array must match the station order returned by ensure_sites for the input survey.

Spectra-Direct Workflows#

The spectra-direct helpers work before final EDI assembly. They expect Spectra objects or dictionaries of spectra objects and recover the tipper from spectral estimates.

Use these functions when your workflow is still at the spectra stage:

Function

Use

plot_induction_map_from_spectra

Draw real and imaginary induction arrows from one or more spectra objects.

plot_tipper_polar_from_spectra

Inspect one spectra object’s tipper azimuth and magnitude.

plot_induction_rose_from_spectra

Summarize spectra-derived induction azimuths over a period band.

 1import matplotlib.pyplot as plt
 2import numpy as np
 3
 4from pycsamt.emtools import (
 5    plot_induction_map_from_spectra,
 6    plot_induction_rose_from_spectra,
 7    plot_tipper_polar_from_spectra,
 8)
 9from pycsamt.z.tipper import Tipper
10
11class SpectraWithTipper:
12    def __init__(self, name, tx_scale, ty_scale):
13        self.name = name
14        self.freq = np.array([0.1, 0.01, 0.001])
15        periods = 1.0 / self.freq
16        tx = tx_scale * (0.08 + 0.02j) * np.sqrt(periods / periods[0])
17        ty = ty_scale * (0.04 + 0.01j) * np.sqrt(periods / periods[0])
18        self._tipper = np.column_stack([tx, ty])
19
20    def to_Z(self, estimate_error=False):
21        tipper = Tipper(tipper_array=self._tipper, freq=self.freq)
22        return None, tipper
23
24spectra_by_station = {
25    "S001": SpectraWithTipper("S001", 1.0, 0.6),
26    "S002": SpectraWithTipper("S002", 1.4, 0.9),
27    "S003": SpectraWithTipper("S003", 0.8, 1.3),
28}
29
30coords = {
31    "S001": (0.0, 0.0),
32    "S002": (500.0, 0.0),
33    "S003": (1000.0, 0.0),
34}
35
36plot_induction_map_from_spectra(
37    spectra_by_station,
38    coords=coords,
39    period=100.0,
40)
41plt.gcf().savefig("tf_spectra_induction_map.png", dpi=200, bbox_inches="tight")
42plt.close()
43
44plot_tipper_polar_from_spectra(
45    {"S001": spectra_by_station["S001"]},
46    component="real",
47)
48plt.gcf().savefig("tf_spectra_tipper_polar.png", dpi=200, bbox_inches="tight")
49plt.close()
50
51plot_induction_rose_from_spectra(
52    spectra_by_station,
53    component="real",
54    pband=(10.0, 1000.0),
55)
56plt.gcf().savefig("tf_spectra_induction_rose.png", dpi=200, bbox_inches="tight")
57plt.close()

For spectra maps, coords are plot coordinates (x, y). A bare Spectra object does not carry reliable map geometry.

Common Pitfalls#

Do not use tipper tools on surveys without vertical-field data and then interpret "no tipper" as a geological result.

Always state the sign convention. Parkinson and Wiese views are rotated relative to each other.

Do not interpret index-based map axes as geographic distance. If EDI coordinates are missing, the plots may fall back to station index.

Do not collapse all periods too early. A strong whole-band station may be strong only over a narrow period window.

Do not treat synthetic or placeholder backgrounds as real topography in multi-period maps. Pass a real background raster for publication.

Worked Example#

The gallery example uses the KAP03 MT profile with real tipper data. It moves from station-level hodograms and polar plots to maps, convention comparisons, roses, period sections, and a multi-period publication-style map.

Open the rendered gallery page here: Induction arrows and tipper diagnostics (pycsamt.emtools.tf).