Skip to content

Detrending & standardization

Removing the biological growth trend to produce ring-width index (RWI) series. See the Detrending & standardization guide for when to use each method.

detrend

Detrend a series or dataframe to ring-width indices.

Fit a growth curve to each series (a smoothing spline by default) and form the ring-width index as the ratio (method="ratio", division, the default) or the difference (method="difference", subtraction) of the data to the curve.

fit chooses the CURVE and method chooses the ARITHMETIC. This differs from dplR, where method selects the curve; passing a curve name to method raises a helpful error.

Parameters:

Name Type Description Default
data pandas dataframe or series

ring widths from dpl.readers, or a single series taken from one.

required
fit str or list

the growth curve to fit (case-insensitive; dplR's names are canonical): "Spline" (smoothing spline), "AgeDepSpline" (age-dependent spline), "ModNegExp" and "ModHugershoff" (negative-exponential and Hugershoff curves fit by nonlinear least squares, with a linear->mean fallback), "NegExp" and "Hugershoff" (the same curves by ARSTAN's deterministic fit), "GeneralExp", "LinearAny" (any-slope line), "LinearNegative" (non-positive-slope line, else the mean), and "Mean" (horizontal line at the series mean). A list of curves detrends by each and returns a comparison: a Series gives a DataFrame with one column per curve, a DataFrame gives a dict of them (not combinable with return_info).

"Spline"
method (ratio, difference)

how the index is formed: "ratio" divides the data by the curve, "difference" subtracts it.

"ratio"
plot boolean

draw the fitted curve and the detrended index.

True
period int or float

smoothing wavelength for fit="Spline" (get_period rule): a fraction of length in (0, 1], a percent-of-length spline if negative, or a fixed wavelength in years if > 1. None uses the dplR default (two thirds of length).

None
nyrs0 int

initial spline stiffness for fit="AgeDepSpline" (see dpl.ads).

50
pos_slope boolean

allow a positive slope at the old-age end (the ModNegExp linear fallback and AgeDepSpline). dplR uses pos.slope=FALSE.

False
f float

spline frequency-response amplitude at period (fit="Spline" only).

0.5
verbose boolean

print, per series, the curve fitted and the arithmetic used.

False
return_info boolean

if True, return a dict (like dplR's return.info) instead of just the data::

{"rwi":        the detrended series (same shape as the input),
 "curves":     the fitted detrending curves,
 "model_info": per-series description of the fit actually used,
 "data_info":  per-series {n_zeros, zero_years} of the input,
 "dirty_dog":  True if any curve went non-positive or fell back to the mean}
False

Returns:

Name Type Description
data pandas dataframe or series

the detrended data.

Examples:

>>> import dplpy as dpl
>>> data = dpl.readers("../tests/data/csv/file.csv")
>>> dpl.detrend(data)                     # all series in a dataframe
>>> dpl.detrend(data["SeriesA"], fit="ModNegExp", method="difference")
Notes

Interior NaN are dropped before fitting. The position-based fits (every curve except Spline and Mean) reconstruct cambial age by counting the surviving rings, so an interior gap compresses the age axis after it -- usually a minor distortion, but for large gaps prefer fit="Spline" or infill first with dpl.fill_internal. detrend warns when a position-based fit meets a series with interior gaps. Spline (fit over calendar years) and Mean (order-invariant) are unaffected.

References

.. [1] https:/opendendro.org/dplpy-man/#detrend

rcs

Regional Curve Standardization of a set of ring-width series.

Align every series on a common cambial-age axis using its pith offset, average to form the regional curve, smooth it, and divide (ratio) or subtract (difference) the curve value at each ring's cambial age. This preserves the low-frequency growth signal that per-series detrending removes. Shares the fit / method / period vocabulary of detrend. Analog of dplR's rcs.

Parameters:

Name Type Description Default
rwl DataFrame

ring-width series, years as the index and series as columns.

required
po DataFrame or None

pith offsets, columns series and pith_offset -- the number of rings between the pith and the first measured ring, so 0 means the pith is present. None assumes 0 for every series. (A dplR po table stores the cambial age of the first ring, where 1 = pith present, so subtract 1 first.)

None
fit str or None

curve fitted to the age-aligned mean, from the detrend vocabulary: "AgeDepSpline" (default; age-dependent spline, honours pos_slope), "Spline" (fixed-stiffness smoothing spline), "ModNegExp", "NegExp", "ModHugershoff", "Hugershoff", "GeneralExp", "LinearAny", "LinearNegative", "Mean", or None for no smoothing (the age-aligned mean itself is the regional curve). Case-insensitive.

"AgeDepSpline"
method (ratio, difference)

how each index is formed from the ring width and the regional-curve value at its cambial age: "ratio" divides, "difference" subtracts.

"ratio"
period int or float

smoothing wavelength for fit="Spline" (get_period rule): a fraction of length in (0, 1] (default 0.1 = 10%), a percent-of-length spline if negative (-10 = 10%), or a fixed wavelength in years if > 1.

0.1
nyrs0 int

initial stiffness for fit="AgeDepSpline" (see dpl.ads).

50
f float

frequency-response amplitude for fit="Spline".

0.5
pos_slope bool

whether the regional curve may rise at the old-age end. False keeps a non-increasing end, avoiding an artefactual old-age upturn. Applies to AgeDepSpline and the ModNegExp/NegExp/ModHugershoff linear fallbacks.

False
biweight bool

build the regional curve with a Tukey biweight robust mean (else arithmetic).

True
min_n int or None

truncate the regional-curve tail where by-age sample depth falls below this.

None
preset (None, crust)

None follows the parameters above. "crust" builds the regional curve the CRUST way (Melvin & Briffa 2014): an age-dependent spline smoothed only where sample depth >= 4 with the no-rise tail rule, gaps infilled, a 0.02 mm floor, and flat tail extension. When set, fit/period/nyrs0/f/pos_slope are ignored.

None
rescale_difference bool

used only when method="difference". If True, rescale each series' difference index onto the mean and standard deviation of its own ratio index, so differences sit on the ~1 ratio scale. Default False returns residuals centred on ~0.

False
rc_out bool

if True, return a dict with both the detrended rwi and the regional curve rc; otherwise return just rwi.

False
plot bool

draw the regional-curve figure (series and curve vs cambial age). The former name make_plot= is accepted for now with a DeprecationWarning.

True

Returns:

Type Description
DataFrame or dict

the detrended rwi (calendar-year indexed), or {"rwi", "rc"} when rc_out is True.

References

.. [1] https://rdrr.io/cran/dplR/man/rcs.html .. [2] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 1, Signal-Free RCS. Dendrochronologia, 32, 7-20. .. [3] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 2, Further RCS options and recommendations. Dendrochronologia, 32, 343-356.

sfrcs

Signal-Free Regional Curve Standardization of a set of ring-width series.

Ordinary RCS lets the single regional curve absorb some of the common climate signal when the sample's age structure varies over time, biasing the low frequencies. Signal-Free RCS breaks that feedback: it iterates, each pass rebuilding the regional curve from measurements with the current chronology divided out, while still forming the tree indices from the original measurements. Iteration stops when the chronology stops changing (tol). Port of CRUST's single-curve signal-free RCS (Melvin & Briffa 2014).

Parameters:

Name Type Description Default
rwl DataFrame

ring-width series, years as the index and series as columns.

required
po DataFrame or None

pith offsets, columns series and pith_offset -- rings between the pith and the first measured ring (0 = pith present). None assumes 0 for all. (A dplR po table stores the cambial age of the first ring, 1 = pith present, so subtract 1 first.)

None
method (ratio, difference)

how indices are formed: "ratio" divides, "difference" subtracts.

"ratio"
biweight_curve bool

build the regional curve with a biweight robust mean by cambial age. Default False (arithmetic mean by age) matches CRUST.

False
biweight_crn bool

build the yearly chronology mean with a biweight robust mean. Default False (arithmetic) matches CRUST's default.

False
ss int

age-dependent spline stiffness offset for the regional curve; per-point stiffness is ss + cambial age (ss=10 -> 11-year minimum), as in CRUST.

10
rise bool or None

allow the smoothed regional curve to rise in its final third. None uses CRUST's rule (allowed only for curves longer than 1500 years); otherwise the tail is flattened to prevent an artefactual old-age upturn.

None
max_iterations int

maximum signal-free iterations.

40
tol float

convergence threshold on the maximum chronology change between iterations.

1e-3
plot bool

draw the regional-curve figure (series and final curve vs cambial age). The former name make_plot= is accepted for now with a DeprecationWarning.

True
return_info bool

if True, return a dict of diagnostics (see Returns) instead of just rwi.

False
verbose bool

print a convergence line.

True

Returns:

Type Description
DataFrame or dict

the detrended rwi (calendar x series). With return_info=True, a dict::

{"rwi":        detrended series (calendar x series),
 "sfc":        the signal-free chronology (Series + samp.depth),
 "samp_depth": number of trees per calendar year,
 "conv":       max absolute chronology change at each iteration,
 "n_iter":     iterations run,
 "converged":  whether tol was reached within max_iterations,
 "rc":         the final regional curve (by cambial age)}
Notes

Single-curve case (CRUST trc=1, src=1); multiple-curve signal-free RCS is sfmrcs. There is no dplR reference for this method: the port follows CRUST's stand.f90 and its spline smoother is validated against CRUST's compiled kernel, but the full iteration is not checked against a gold standard, so treat results as CRUST-faithful rather than machine-verified.

References

.. [1] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 1, Signal-Free RCS. Dendrochronologia, 32, 7-20. .. [2] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 2, Further RCS options and recommendations. Dendrochronologia, 32, 343-356.

mrcs

Multiple-curve Regional Curve Standardisation.

Sort trees by relative growth rate, split them into n_curves equal-count classes, build a regional curve for each class, and standardise each tree by its own class curve. This removes the modern-sample-bias slope that a single regional curve injects when the sample's growth-rate (or age) mix changes over time. Each class curve is built by :func:rcs, so mrcs shares its fit/method/period/nyrs0/f/pos_slope/preset vocabulary, and mrcs(rwl, n_curves=1) is identical to rcs(rwl). Port of CRUST's multiple RCS.

Parameters:

Name Type Description Default
rwl DataFrame

ring-width series, years as the index and series as columns.

required
po DataFrame or None

pith offsets (columns series and pith_offset; a true offset, 0 = pith present), as in :func:rcs. None assumes 0 for every series.

None
n_curves int

number of regional curves. 1 reduces exactly to :func:rcs.

2
sort (growth, age, diameter, none)

how trees are ranked before the equal-count split: "growth" by relative growth rate, "age" by cambial age, "diameter" by total radius, "none" keeps input order.

"growth"
fit
'AgeDepSpline'
method
'AgeDepSpline'
period
'AgeDepSpline'
nyrs0
'AgeDepSpline'
f
'AgeDepSpline'
pos_slope
'AgeDepSpline'
biweight
'AgeDepSpline'
min_n
'AgeDepSpline'
preset
'AgeDepSpline'
rescale_difference

passed through to :func:rcs to build each class curve; see :func:rcs. Defaults match :func:rcs.

False
reset_means bool

if True (ratios only), rescale each tree's indices to the mean it would have had under one-curve RCS, recovering the low-frequency variance multiple RCS removes. Skipped with a warning for method="difference".

True
rc_out bool

if True, return a dict {"rwi", "rc", "alloc"} -- the indices, the list of per-class regional curves (by cambial age), and the series->class map.

False
plot bool

draw the per-class regional-curve figure. make_plot= is accepted as a deprecated alias.

True

Returns:

Type Description
DataFrame or dict

the detrended rwi (calendar-year indexed), or {"rwi", "rc", "alloc"} when rc_out is True.

References

.. [1] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 2, Further RCS options and recommendations. Dendrochronologia, 32, 343-356.

sfmrcs

Signal-Free multiple-curve Regional Curve Standardisation.

Combine :func:sfrcs (signal-free iteration) with :func:mrcs (multiple curves): sort trees by growth rate into n_curves equal-count classes, then iteratively rebuild each class's regional curve from measurements that have had the current chronology divided out, while forming the tree indices from the original measurements, until the chronology converges. reset_means (ratios only) restores each tree's one-curve mean to recover the low-frequency variance multiple RCS removes. sfmrcs(rwl, n_curves=1) is identical to sfrcs(rwl). Port of CRUST's signal-free multiple RCS.

Parameters:

Name Type Description Default
rwl DataFrame

ring-width series, years as the index and series as columns.

required
po DataFrame or None

pith offsets (true offset, 0 = pith present), as in :func:rcs.

None
n_curves int

number of regional curves. 1 reduces exactly to :func:sfrcs.

2
sort (growth, age, diameter, none)

how trees are ranked before the equal-count split (see :func:mrcs).

"growth"
method (ratio, difference)

ratio (division) or difference (subtraction) indices.

"ratio"
biweight_curve

the signal-free settings, identical to :func:sfrcs.

False
biweight_crn

the signal-free settings, identical to :func:sfrcs.

False
ss

the signal-free settings, identical to :func:sfrcs.

False
rise

the signal-free settings, identical to :func:sfrcs.

False
max_iterations

the signal-free settings, identical to :func:sfrcs.

False
tol

the signal-free settings, identical to :func:sfrcs.

False
verbose

the signal-free settings, identical to :func:sfrcs.

False
reset_means bool

restore each tree's one-curve mean (ratios only; skipped with a warning for method="difference").

True
plot bool

draw the per-class regional-curve figure (make_plot= is a deprecated alias).

True
return_info bool

if True, return a dict of diagnostics (see Returns) instead of rwi.

False

Returns:

Type Description
DataFrame or dict

the detrended rwi (calendar-year indexed), or, with return_info=True, a dict with rwi, sfc (the signal-free chronology + sample depth), samp_depth, conv (per-iteration max change), n_iter, converged, rc (list of per-class regional curves) and alloc (series -> class).

References

.. [1] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 2, Further RCS options and recommendations. Dendrochronologia, 32, 343-356.

ssf

Simple signal-free chronology (dplR's ssf()).

Build a signal-free chronology (Melvin & Briffa 2008): form an initial chronology, divide every series by it to strip the common signal, rescale and re-detrend the resulting signal-free measurements, and build a new chronology, repeating until the high-frequency chronology stops changing (the sample-depth- weighted median absolute difference falls below mad_threshold) or max_iterations is reached. Reproduces dplR's ssf().

Parameters:

Name Type Description Default
rwl DataFrame

ring-width series (raw), years as the index and series as columns.

required
method (Spline, AgeDepSpline)

detrending curve used at each iteration: a cubic smoothing spline (⅔-length stiffness) or an age-dependent spline (dpl.ads()).

"Spline"
nyrs int or None

spline stiffness. None uses ⅔ of each series' length for "Spline" or 50 for "AgeDepSpline"; a value in (0, 1) is a fraction of series length.

None
difference bool

detrend by subtraction (series - curve) rather than division.

False
max_iterations int

maximum signal-free iterations before giving up.

25
mad_threshold float

convergence threshold on the median absolute difference of the high-frequency chronology between successive iterations.

5e-4
recode_zeros bool

recode zero ring-widths to 0.001 before processing (avoids div-by-zero).

False
return_info bool

if True, return a dict of the full iteration history (chronologies, signal-free measurements and curves, MAD vector, ...) instead of just the final chronology.

False
verbose bool

print progress and the per-iteration convergence diagnostics.

True
preset (None, crust)

None reproduces the basic signal-free method (dplR's ssf; Melvin & Briffa 2008). "crust" adds CRUST's robustness guards (Melvin & Briffa 2014): multiplicative rescaling of the signal-free measurements, the raw measurement kept in any year where the chronology is near zero (< 0.01), and the fitted curves floored at 0.02 mm. These make ssf robust to sensitive sites with many absent rings (e.g. co021) that the basic method cannot standardise.

None

Returns:

Type Description
DataFrame

the signal-free chronology with columns sfc and samp_depth, indexed by year. If return_info is True, a dict of intermediates is returned instead (see above).

References

.. [1] https://rdrr.io/cran/dplR/man/ssf.html .. [2] Melvin, T. M. & Briffa, K. R. (2008) A "signal-free" approach to dendroclimatic standardisation. Dendrochronologia, 26(2), 71-86. .. [3] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 1, Signal-Free RCS. Dendrochronologia, 32, 7-20. .. [4] Melvin, T. M. & Briffa, K. R. (2014) CRUST: Software for the implementation of Regional Chronology Standardisation: Part 2, Further RCS options and recommendations. Dendrochronologia, 32, 343-356.

ads

Age-dependent smoothing spline of a single series (dplR's ads()).

Fit a smoothing spline whose stiffness increases with cambial age: the i-th ring is fit with an (nyrs0 + i - 1)-year spline, so young rings are smoothed least and the curve grows stiffer with age. Ports dplR's ads().

Parameters:

Name Type Description Default
y array - like

a single ring-width series (no missing values), oldest ring first.

required
nyrs0 int

initial spline stiffness (wavelength, in years) at the first ring.

50
pos_slope bool

if False, once the spline stops decreasing its tail is held flat and the spline is refit, preventing an artefactual upturn at the end of the series (dplR uses pos.slope=FALSE inside detrend()).

True

Returns:

Type Description
ndarray

the fitted spline curve, same length as y.

Examples:

>>> import dplpy as dpl
>>> rwl = dpl.readers("../tests/data/csv/ca533.csv")
>>> curve = dpl.ads(rwl["CAM011"].dropna().to_numpy(), nyrs0=50)
References

.. [1] https://rdrr.io/cran/dplR/man/ads.html .. [2] Melvin, T. M. (2004) Historical Growth Rates and Changing Climatic Sensitivity of Boreal Conifers. PhD Thesis, Climatic Research Unit, University of East Anglia. .. [3] Melvin, T. M., Briffa, K. R., Nicolussi, K. & Grabner, M. (2007) Time-varying-response smoothing. Dendrochronologia, 25(2), 65-69. .. [4] Cook, E. R. & Peters, K. (1981) The Smoothing Spline: A New Approach to Standardizing Forest Interior Tree-Ring Width Series for Dendroclimatic Studies. Tree-Ring Bulletin, 41, 45-53.

powt

Adaptive power transformation of ring-width series (variance stabilising).

Stabilise the variance of ring-width series by raising each value to a data-driven power p. For adjacent rings, level M = (x[t] + x[t-1]) / 2 and spread S = |x[t] - x[t-1]|; regressing log(S) on log(M) gives a slope b, and p = |1 - b| removes the level-spread dependence. Port of dplR's powt (Cook & Peters 1997).

Two methods are offered:

  • "cook" (default) estimates p independently for each series.
  • "universal" estimates a single p for the whole data set with a linear mixed-effects model (random intercept per year), matching dplR's default. Requires statsmodels; a log transform is used if the estimate is p <= 0.

Parameters:

Name Type Description Default
rwl DataFrame or Series

ring-width series (raw, non-negative), years as the index. A Series is allowed only with method='cook'.

required
method (cook, universal)

per-series ('cook') or single mixed-model power ('universal').

"cook"
rescale bool

if True, rescale each transformed series back to its original mean and standard deviation.

False
return_power bool

if True, return a (transformed, power) tuple; power is a Series over series for 'cook' or a single float for 'universal'.

False
plot bool

if True, draw the data-transform-statistics diagnostic: per-series skew and spread-vs-level correlation, before and after the transform. A successful transform drives the after values toward zero.

False
return_stats bool

if True, also return a per-series diagnostics DataFrame with columns skew_before, skew_after, r_before, r_after and power.

False

Returns:

Type Description
transformed data of the same type as ``rwl``. With ``return_power`` and/or
``return_stats`` the return becomes a tuple: ``(data, power)``,
``(data, stats)``, or ``(data, power, stats)`` (power first, stats last).
Notes

dplPy reproduces dplR's power exactly. A given series' power can differ slightly from ARSTAN's, which uses the trailing ring as the level and clamps p to [0, 1].

Examples:

>>> import dplpy as dpl
>>> rwl = dpl.readers("../tests/data/csv/ca533.csv")
>>> pt = dpl.powt(rwl)                          # per-series (cook)
>>> pt, p = dpl.powt(rwl, return_power=True)
>>> rwi = dpl.detrend(pt, plot=False)           # transform, then detrend
References

.. [1] https://rdrr.io/cran/dplR/man/powt.html .. [2] Cook & Peters (1997), The Holocene, 7, 361-370.