Line Configuration

unite’s line configuration system is designed to be flexible and feature rich, allowing user to set up complex multi-line models with shared and correlated parameters across a wide range of line profiles. This page walks though the core concepts and usage patterns for building line configurations.


Creating a Line Configuration

LineConfiguration is the core container that defines which emission lines to fit, their profile shapes, and how parameters are shared between lines. The best way to get started is to create an empty configurations. We’ll also need the prior module for defining priors on line parameters, and astropy.units for specifying line wavelengths.

from unite import line, prior
from astropy import units as u

lc = line.LineConfiguration()

Adding Lines

Basic Usage

lc.add_line('H_alpha', 6563.0 * u.AA)

Important

Line names must be unique within a LineConfiguration. Adding a second line with the same name raises a ValueError. Use distinct names for different kinematic components, e.g. 'Ha_narrow' and 'Ha_broad'.

At minimum each line requires:

  • A name (string) — used in results tables and YAML output

  • A rest-frame center wavelength

Centers must be astropy.units.Quantity with wavelength units:

lc.add_line('Ly_alpha', 1216.0 * u.AA, ...)
lc.add_line('CO_10', 2.6 * u.um, ...)

Adding a Single Line

Optionally each line can also include:

  • A relative redshift token (Redshift)

  • A flux token (Flux)

  • A profile shape (e.g. Gaussian, PseudoVoigt, etc.)

  • FWHM token(s) appropriate for the chosen profile

  • Additional shape parameters (e.g. h3, h4 for GaussHermite)

  • A strength parameter which multiplies the flux token, mostly used for line ratios (see below)

If not specified, default priors are used for redshift, flux, and FWHM tokens, and the profile defaults to Gaussian.

z = line.Redshift('z', prior=prior.Uniform(-0.01, 0.01))
fwhm = line.FWHM('fwhm', prior=prior.Uniform(50, 500))

lc.add_line(
    'H_alpha', 6563.0 * u.AA,
    redshift=z,
    fwhm_gauss=fwhm,
    flux=line.Flux('Ha_flux', prior=prior.Uniform(0, 1)),
)

You can preview your line configuration by printing it:

print(lc)
LineConfiguration: 1 lines, 1 flux / 1 z / 1 profile params

  Name     Wavelength        Profile   Redshift  Params  Flux     Strength
  -------  ----------------  --------  --------  ------  -------  --------
  H_alpha  6563.00 Angstrom  Gaussian  z         fwhm    Ha_flux  1.00

  Redshift:
    z  Uniform(low=-0.01, high=0.01)

  Params (fwhm_gauss):
    fwhm  Uniform(low=50.0, high=500.0)

  Flux:
    Ha_flux  Uniform(low=0.0, high=1.0)

Note

Redshift tokens/priors are relative to the systemic system redshift which is specified with the Instruments & Spectrum Loading. This allows configurations to be redshift-agnostic and reusable across different datasets.

Adding Multiple Lines

unite also supports adding multiple lines at once with add_lines. Each entry in centers becomes an independent line with a unique auto-generated name of the form '{name}_{center_value}' (e.g. 'OIII_4960', 'OIII_5008'). You can also supply an explicit names array of the same length as centers.

# Auto-generated names: 'OIII_4960' and 'OIII_5008'
lc.add_lines('OIII', [4960, 5008] * u.AA, redshift=z, fwhm_gauss=fwhm)

# Explicit names
lc.add_lines('OIII', [4960, 5008] * u.AA,
             names=['OIII_blue', 'OIII_red'], redshift=z)

Note how we fix the line ratio here.

flux = line.Flux('OIII')
lc.add_lines(
    'OIII', [4960, 5008] * u.AA,
    redshift = z, # Same redshift
    fwhm = [fwhm, fwhm], # Different FWHMs (just as an example)
    flux = [line.Flux(prior = prior.Fixed(flux / 3)), flux], # Fixed ratio
)

However, it is likely easier to specify multiples through the strength parameter, which multiplies the flux token when building the model. Both approaches yield the same result.

flux = line.Flux('OIII')
lc.add_lines(
    'OIII', [4960, 5008] * u.AA,
    flux = line.Flux(), # Default behaviour, this would mean all lines have the same flux
    strength = [1/3, 1] # But we pass a strength per line which is multiplied by the flux token when building the model
)

Parameter Sharing

This is unite’s central design pattern. A token is a named Python object representing a model parameter. Same Python object = same parameter in the model.

These are the following token types:

Token

Role

Unit

Redshift

Redshift offset from systemic

dimensionless

FWHM

Line width

km/s

Flux

Line flux normalization

internal units

LineShape

Arbitrary profile parameter (h3, h4, etc.)

per-parameter basis

Note

Fluxes are relative to a scale computed based on the spectrum. See Flux and Error Scales in Building the Model for details.

Shared Kinematics

# One redshift, one FWHM → shared across all lines
z = line.Redshift('z', prior=prior.Uniform(-0.01, 0.01))
fwhm = line.FWHM('fwhm', prior=prior.Uniform(50, 500))

lc.add_line('H_alpha',  6563.0 * u.AA, redshift=z, fwhm_gauss=fwhm,
            flux=line.Flux('Ha_flux', prior=prior.Uniform(0, 10)))
lc.add_line('NII_6585', 6585.0 * u.AA, redshift=z, fwhm_gauss=fwhm,
            flux=line.Flux('NII6585_flux', prior=prior.Uniform(0, 10)))
lc.add_line('NII_6549', 6549.0 * u.AA, redshift=z, fwhm_gauss=fwhm,
            flux=line.Flux('NII6549_flux', prior=prior.Uniform(0, 10)))

Result: one z parameter and one fwhm parameter in the model, shared by all three lines.

Independent Parameters

z_narrow = line.Redshift('narrow', prior=prior.Uniform(-0.01, 0.01))
z_broad  = line.Redshift('broad',  prior=prior.Uniform(-0.01, 0.01))

lc.add_line('Ha_narrow', 6563.0 * u.AA, redshift=z_narrow, ...)
lc.add_line('Ha_broad',  6563.0 * u.AA, redshift=z_broad,  ...)

Parameter Names

All token classes accept an optional first positional argument that becomes a semantic label for the parameter. It is highly recommended to name your tokens — without a name, unite auto-generates one (e.g. fwhm_0, redshift_2) that becomes difficult to interpret in output.

A type-specific prefix is automatically prepended to your label to form the final site name:

  • Redshift('nlr') → site name 'z_nlr' (prefix: z_)

  • FWHM('broad') → site name 'fwhm_broad' (prefix: fwhm_)

  • Flux('Ha') → site name 'flux_Ha' (prefix: flux_)

So pass only the semantic label, not the full prefixed name:

# Auto-generated names → based on line name, less explicit
z = line.Redshift()

# Explicit semantic labels → clear, shareable across lines
z_nlr = line.Redshift('nlr')        # → site name 'z_nlr'
z_blr = line.Redshift('blr')        # → site name 'z_blr'
fwhm = line.FWHM('broad')           # → site name 'fwhm_broad'
flux = line.Flux('Ha')              # → site name 'flux_Ha'

The site names show up in:

  • The samples dict returned by mcmc.get_samples()

  • Column names in the parameter table from make_parameter_table()

Tip

Use short, semantic labels (without prefixes) that identify the physical component, e.g. 'nlr', 'blr', 'broad', 'Ha', 'NII'. The type-specific prefix is added automatically. This makes site names concise and easy to navigate in results.

Lines can share the same name but must have at least one different token, otherwise an error will be raised. This allows you to easily set up multi-component models with shared parameters.

z = line.Redshift('nlr', prior=prior.Uniform(-0.01, 0.01))

fwhm_n = line.FWHM('narrow', prior=prior.Uniform(50, 400))
fwhm_b = line.FWHM('broad',  prior=prior.Uniform(500, 3000))

lc.add_line('H_alpha', 6563.0 * u.AA, redshift=z, fwhm_gauss=fwhm_n,
            flux=line.Flux('Ha_n', prior=prior.Uniform(0, 10)))
lc.add_line('H_alpha', 6563.0 * u.AA, redshift=z, fwhm_gauss=fwhm_b,
            flux=line.Flux('Ha_b', prior=prior.Uniform(0, 10)))

Dependent Priors

Prior bounds on FWHM or Flux tokens can reference other tokens, creating dependency chains that are automatically resolved at model-build time. See Priors for the full reference.

fwhm_narrow = line.FWHM('n', prior=prior.Uniform(50, 500))
fwhm_broad  = line.FWHM('b', prior=prior.Uniform(fwhm_narrow + 150, 5000))

This ensures the broad component is always at least 150 km/s wider than the narrow component.


Line Profiles

Here we list all currently supported profiles in unite. Most profiles are analytically integrated over pixels (exact CDF differences) and convolved with the instrumental LSF. The exception is SkewVoigt, which uses a midpoint-rule approximation (see below). See Core Concepts for the LSF convolution convention. Profiles are set via the profile argument (case-insensitive strings or class instances):

String

Profile

FWHM Parameter(s)

Shape Parameter(s)

Pixel integration

'gaussian', 'normal'

Gaussian

fwhm_gauss

analytic

'cauchy', 'lorentzian'

Cauchy

fwhm_lorentz

analytic

'pseudovoigt', 'voigt'

PseudoVoigt

fwhm_gauss, fwhm_lorentz

analytic

'laplace', 'exponential'

Laplace

fwhm_exp

analytic

'semg', 'exp-gaussian'

SEMG

fwhm_gauss, fwhm_exp

analytic

'hermite', 'gauss-hermite'

GaussHermite

fwhm_gauss

h3, h4

analytic

'split-normal', 'two-sided'

SplitNormal

fwhm_blue, fwhm_red

analytic

'skew-normal', 'skewnormal'

SkewNormal

fwhm_gauss

alpha

analytic

'skew-voigt', 'skewvoigt'

SkewVoigt

fwhm_gauss, fwhm_lorentz

alpha

midpoint rule

'boxgauss', 'box-gauss', 'boxcar'

BoxGauss

fwhm_box, fwhm_gauss

analytic

'gaussiansplitlaplace', 'gaussian-split-laplace', 'aemg'

GaussianSplitLaplace

fwhm_gauss, fwhm_l_blue, fwhm_l_red

analytic

Gaussian (default)

The simplest and most common profile. A Gaussian intrinsic shape convolved with the Gaussian LSF; the result is also Gaussian with \(\mathrm{FWHM} = \sqrt{\mathrm{fwhm\_gauss}^2 + \mathrm{lsf\_fwhm}^2}\).

Parameters: fwhm_gauss (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='Gaussian',
            redshift=z, fwhm_gauss=fwhm, flux=flux)

PseudoVoigt

The Voigt profile — the convolution of a Gaussian and a Lorentzian — computed via two different approximations depending on integration mode:

  • Analytic mode (CDF-based pixel integration): uses the extended pseudo-Voigt approximation of Ida, Ando & Toraya (2000), which decomposes the profile into four components (Gaussian, Lorentzian, intermediate, and Pearson-VII) with sixth-order polynomial mixing coefficients. Achieves < 0.12% peak-height deviation from the true Voigt profile. The Gaussian LSF is added in quadrature to fwhm_gauss before computing the approximation parameters.

  • Quadrature mode (PDF evaluation at nodes): uses the exact Voigt profile computed via the Faddeeva function \(w(z) = e^{-z^2}\operatorname{erfc}(-iz)\), approximated with the Humlicek (1982) W4 rational scheme (~\(10^{-4}\) relative error across the upper half-plane).

Parameters: fwhm_gauss (km/s), fwhm_lorentz (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='PseudoVoigt',
            redshift=z,
            fwhm_gauss=line.FWHM('g', prior=prior.Uniform(50, 500)),
            fwhm_lorentz=line.FWHM('l', prior=prior.Uniform(0, 500)),
            flux=flux)

Cauchy (Lorentzian)

A pure Lorentzian profile. Internally a PseudoVoigt with fwhm_gauss = 0.

Parameters: fwhm_lorentz (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='Cauchy',
            redshift=z,
            fwhm_lorentz=line.FWHM('fwhm', prior=prior.Uniform(0, 1000)),
            flux=flux)

Laplace (Exponential)

A double-exponential (Laplace) profile convolved with the Gaussian LSF.

Parameters: fwhm_exp (km/s)

SEMG — Symmetric Exponentially Modified Gaussian

A Gaussian convolved with a Laplace distribution. The Gaussian component (including LSF) contributes exponential wings that are symmetric about the centre. See SEMG for the closed-form CDF derivation.

Parameters: fwhm_gauss (km/s), fwhm_exp (km/s)

GaussHermite

A Gaussian modified by Hermite polynomial corrections using the probabilists’ convention. h3 controls skewness; h4 controls kurtosis. Convolution with the Gaussian LSF rescales the shape parameters as \(h_m' = h_m\,(\sigma_g/\sigma_\text{tot})^m\). See Gauss-Hermite for the full derivation.

Parameters: fwhm_gauss (km/s), h3 (dimensionless), h4 (dimensionless)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='GaussHermite',
            redshift=z,
            fwhm_gauss=line.FWHM('fwhm', prior=prior.Uniform(50, 1000)),
            h3=line.Param('h3', prior=prior.TruncatedNormal(0, 0.1, -0.3, 0.3)),
            h4=line.Param('h4', prior=prior.TruncatedNormal(0, 0.1, -0.3, 0.3)),
            flux=flux)

SplitNormal

A two-sided Gaussian with independent widths on the blue and red sides.

Parameters: fwhm_blue (km/s), fwhm_red (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='SplitNormal',
            redshift=z,
            fwhm_blue=line.FWHM('b', prior=prior.Uniform(50, 500)),
            fwhm_red=line.FWHM('r',  prior=prior.Uniform(50, 500)),
            flux=flux)

SkewNormal

A Gaussian (with LSF) multiplied by an erf skew factor \([1 + \text{erf}(\alpha_\text{eff}(x-c)/w_0')]\). For alpha = 0 the profile reduces exactly to a Gaussian.

Unlike SkewVoigt, the convolution with the Gaussian LSF is exact — the shape parameter rescales analytically as \(\alpha_\text{eff} = \alpha\sigma_g / \sqrt{\sigma_g^2 + (1+\alpha^2)\sigma_\text{lsf}^2}\), with no numerical correction. Pixel integration uses the closed-form skew-normal CDF \(\Phi(z) - 2T(z, \alpha_\text{eff})\) via Owen’s T function. See Skew Normal for the full derivation.

Parameters: fwhm_gauss (km/s), alpha (dimensionless)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='SkewNormal',
            redshift=z,
            fwhm_gauss=line.FWHM('fwhm', prior=prior.Uniform(50, 500)),
            alpha=line.LineShape('alpha', prior=prior.TruncatedNormal(0, 2, -10, 10)),
            flux=flux)

SkewVoigt

A pseudo-Voigt profile multiplied by a skew factor \([1 + \text{erf}(\alpha(x-c)/w_0)]\) where \(w_0 = \Gamma_V/(2\sqrt{\ln 2}) = \sigma_V\sqrt{2}\) is the erf scale derived from the Thompson et al. Voigt FWHM \(\Gamma_V\). For a pure Gaussian (\(\Gamma_l = 0\)) this reduces to the standard skew-normal with shape parameter \(\alpha\) and dispersion \(\sigma_g\). The profile integrates to 1 for any alpha because the skew factor is odd and the pseudo-Voigt is even. Convolution with the Gaussian LSF rescales the skewness to an effective \(\alpha_\text{eff}\) (see Skew Voigt).

Warning

SkewVoigt is not analytically integrated over pixels. The pixel integral of the skew correction requires Owen’s T function (Gaussian part) and a separate quadrature (Lorentzian part) — neither reduces to standard functions. Instead, unite evaluates the profile at each pixel midpoint and multiplies by the pixel width. This is accurate when the profile is well-resolved (intrinsic FWHM several times the pixel width), but introduces sub-pixel quadrature error for marginally resolved lines. Consider using integration_mode='quadrature' as an alternative integration mode.

Parameters: fwhm_gauss (km/s), fwhm_lorentz (km/s), alpha (dimensionless)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='SkewVoigt',
            redshift=z,
            fwhm_gauss=line.FWHM('g', prior=prior.Uniform(50, 500)),
            fwhm_lorentz=line.FWHM('l', prior=prior.Uniform(0, 500)),
            alpha=line.LineShape('alpha', prior=prior.TruncatedNormal(0, 2, -10, 10)),
            flux=flux)

BoxGauss

A uniform rectangular (boxcar) distribution convolved with a Gaussian. The intrinsic profile is constant across a velocity window of width fwhm_box and zero outside it (area = 1). Convolution with the combined Gaussian (LSF ⊕ fwhm_gauss in quadrature) smooths the sharp edges. The exact pixel integral is computed analytically using the antiderivative of the Gaussian CDF.

The profile reduces to a pure Gaussian as fwhm_box 0, and to a sharp rectangular window as fwhm_gauss 0 (with lsf_fwhm 0).

Parameters: fwhm_box (km/s), fwhm_gauss (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='BoxGauss',
            redshift=z,
            fwhm_box=line.FWHM('box', prior=prior.Uniform(100, 2000)),
            fwhm_gauss=line.FWHM('g', prior=prior.Uniform(0, 500)),
            flux=flux)

GaussianSplitLaplace (Asymmetric EMG)

A Gaussian (with LSF) convolved with a split-Laplace (asymmetric double-exponential) distribution, where the blue (short-wavelength) and red (long-wavelength) exponential tails are controlled independently. The exact pixel integral is computed analytically via the closed-form antiderivative of the Gaussian–split-Laplace CDF.

Parameters: fwhm_gauss (km/s), fwhm_l_blue (km/s), fwhm_l_red (km/s)

lc.add_line('H_alpha', 6563.0 * u.AA, profile='GaussianSplitLaplace',
            redshift=z,
            fwhm_gauss=line.FWHM('g', prior=prior.Uniform(50, 500)),
            fwhm_l_blue=line.FWHM('lb', prior=prior.Uniform(0, 500)),
            fwhm_l_red=line.FWHM('lr', prior=prior.Uniform(0, 500)),
            flux=flux)

Merging Configurations

LineConfiguration supports merging two configurations:

lc_narrow = line.LineConfiguration()
# ... add narrow lines ...

lc_broad = line.LineConfiguration()
# ... add broad lines ...

# strict=True (default, also __add__): raises on token name collisions
lc_combined = lc_narrow + lc_broad

# strict=False: shares same-named tokens of same type
lc_combined = lc_narrow.merge(lc_broad, strict=False)

The strict=False mode is useful when both configurations define tokens with the same name and you want them to be treated as the same model parameter. However, proceed with caution, it will not check that the priors for the same-named tokens are identical, it will choose the token from the first configuration.


Absorption Lines

unite supports absorption lines alongside emission lines. Absorption profiles produce a wavelength-dependent transmission T(λ) = exp(-τ₀ · φ_norm(λ)) that multiplies the emission and/or continuum flux, where τ₀ is the Tau parameter and φ_norm(λ) = φ(λ) / φ(λ_center) is the profile normalized to 1 at the nominal line center. The key difference from emission lines is that absorption lines use a Tau (optical depth) token instead of a Flux token.

Warning

Two distinct approximations apply to absorption lines — one mode-dependent, one universal.

Analytic mode only: each profile is integrated over pixels independently before the nonlinear transmission is applied, computing exp(-τ·∫φ) rather than ∫F·exp(-τ·φ). This is accurate when the absorber is well-resolved but introduces an approximation for unresolved or marginally resolved lines. Use integration_mode='quadrature' to avoid this.

Both modes: the absorption profile φ(λ) passed to exp(-τ·φ) is the LSF-convolved profile, not the intrinsic one. The correct observable requires convolving the nonlinear product F·exp(-τ·φ_intrinsic) with the LSF over its full multi-pixel support, which is not currently supported. This approximation is accurate when the absorber is resolved (intrinsic FWHM ≫ LSF FWHM) or optically thin (τ ≪ 1). For unresolved, optically thick absorbers the inferred τ will be biased high and the curve of growth misrepresented. See LSF Pre-Convolution of Absorption Profiles for a full discussion.

Adding Tau-Parametrized Lines

Tau-parametrized lines use the same profile shapes as flux-parametrized lines. The distinction is made by passing a Tau token instead of Flux. Any profile can be used — the profile controls the shape, tau vs flux controls how it enters the model:

# Gaussian absorption (single FWHM parameter)
lc.add_line('HI_abs', 6563.0 * u.AA, tau=line.Tau())

# Voigt absorption (Gaussian + Lorentzian FWHM)
lc.add_line('HI_voigt', 4861.0 * u.AA, profile='voigt', tau=line.Tau())

# Lorentzian absorption (single Lorentzian FWHM)
lc.add_line('HI_lor', 4341.0 * u.AA, profile='cauchy', tau=line.Tau())

Tau vs Flux

The Tau parameter is the optical depth at the nominal line center of the intrinsic (pre-LSF) profile — i.e. τ₀ = τ(λ_center) where λ_center is the rest-frame center wavelength shifted by the line’s redshift. Concretely:

  • τ₀ = 1 → transmission ≈ 37% at line center (optically thin to moderate)

  • τ₀ = 3 → transmission ≈ 5% (significantly optically thick)

  • τ₀ 1 → effectively black at line center

For symmetric profiles (Gaussian, PseudoVoigt, Cauchy, Laplace, SEMG, SplitNormal), τ₀ is also the maximum optical depth anywhere in the profile.

For asymmetric profiles (GaussHermite with h3 0, SkewVoigt with large alpha), the profile peak shifts away from the nominal center wavelength. τ₀ remains the optical depth at the nominal center, not the absolute maximum the profile reaches. If the physical peak depth matters for your science case, prefer a symmetric profile for absorption lines, or account for this distinction when interpreting posteriors.

# Explicit tau token with custom prior
tau = line.Tau('deep', prior=prior.Uniform(0, 50))
lc.add_line('HI_abs', 6563.0 * u.AA, tau=tau)

If neither flux nor tau is specified, the line defaults to emission (with an auto-created Flux token). Passing both flux and tau raises TypeError:

# This raises TypeError:
lc.add_line('bad', 6563.0 * u.AA, flux=line.Flux(), tau=line.Tau())  # Error!

Sharing Tau Parameters

Like Flux, Redshift, and FWHM tokens, Tau tokens can be shared across multiple absorption lines to produce a single model parameter:

tau = line.Tau('balmer_tau')
lc.add_line('HI_Ha', 6563.0 * u.AA, tau=tau)
lc.add_line('HI_Hb', 4861.0 * u.AA, tau=tau)

Mixing Emission and Absorption

Emission and absorption lines coexist naturally in the same configuration:

lc = line.LineConfiguration()
lc.add_line('Ha', 6563.0 * u.AA)  # emission (Gaussian by default)
lc.add_line('HI_abs', 6563.0 * u.AA, tau=line.Tau())  # absorption

Depth Ordering (zorder)

Each line carries an integer zorder that determines which tau absorbers attenuate it. A tau absorber at depth Z only absorbs components with zorder < Z — i.e. sources behind it.

Defaults (no arguments required for the common foreground-screen geometry):

Line type

Default zorder

Emission (Flux)

0

Absorption (Tau)

1

With these defaults every tau absorber sits in front of all emission lines.

Pass zorder explicitly to add_line() to break from the default geometry:

# Absorber at zorder=1 (default) — absorbs Ha (zorder=0) but not AGN (zorder=2)
lc = line.LineConfiguration()
lc.add_line('Ha',     6563.0 * u.AA)                    # emission, zorder=0
lc.add_line('AGN_Ha', 6563.0 * u.AA, zorder=2)          # emission, zorder=2 - not absorbed
lc.add_line('NaD',    5893.0 * u.AA, tau=line.Tau())    # absorber, zorder=1 (default)

The zorder column is visible when you print the configuration:

  Name     Wavelength  Profile   Redshift  Params  Flux/Tau  zorder  Strength
  -------  ----------  --------  --------  ------  --------  ------  --------
  Ha       6563.00     Gaussian  z         fwhm    ha        0       1.00
  AGN_Ha   6563.00     Gaussian  z         fwhm    ha_agn    2       1.00
  NaD      5893.00     Gaussian  z         fwhm    tau_nad   1       1.00

See Component Depth Ordering (zorder) in the model-building guide for the full mapping from zorder values to physical geometry, including how to reproduce the three classic absorber-position scenarios.


Serialization

LineConfiguration supports standalone YAML serialization:

lc.save('lines.yaml')
lc2 = line.LineConfiguration.load('lines.yaml')

Token sharing is preserved: if two lines shared a Redshift token before saving, they will share the same reconstructed token after loading. See Configuration Serialization for the full workflow and YAML format.