Skip to content

Canopy disturbance

Detecting and removing canopy-disturbance growth releases (radial-growth averaging; Druckenbrod, Cook, Pederson & Martin-Benito 2024). See the Canopy disturbance detrending guide for a worked example and for when to use each function.

releases

Detect canopy-disturbance release events by radial-growth averaging.

Finds releases in each series with the Lorimer & Frelich method as implemented in Druckenbrod et al. (2024): a trailing window_length-year running mean of ring width, the percent growth change between the preceding and subsequent windows, and -- for each run of years whose percent growth change meets threshold -- the single year of maximum change, taken as the release.

Detection runs on the RAW ring widths. The power transform in the Druckenbrod method is applied later, only for detrending (see the forthcoming disturbance_detrend), so do not pre-transform the series before calling this.

Parameters:

Name Type Description Default
data pandas DataFrame or Series, or str

ring widths from dpl.readers (years on the index, one column per series), a single series taken from one, or a path to an rwl/csv file (read with dpl.readers). Series shorter than 2 * window_length are skipped with a warning.

required
threshold int or float

percent-growth-change threshold for a release, in percent. Druckenbrod et al. recommend 50 over the more permissive 25.

50
window_length int

length in years of the running-mean window (Dan's ma). The recommended value is 15; the method needs at least 2 * window_length rings.

15
significance bool

whether to test each release for significance (Ed Cook's one-tailed two-sample t-test). Not implemented in this release and deferred pending confirmation of the test; True raises NotImplementedError.

False
method rga

the detection method. Only radial-growth averaging is available; the argument reserves room for other detectors.

"rga"
recode_zeros bool

recode literal zero (locally absent) rings to 0.001 before detection, the same convention as dpl.ssf (the input frame is never modified). When False, series containing zeros are detected as-is and a warning names them.

False
min_mean float

minimum preceding running-mean ring width, in mm, for a year to be eligible as a release. Guards the percent-growth-change denominator so a near-zero baseline (a window dominated by absent or recoded rings) cannot inflate into a spurious release. The default touches only such pathological windows; set 0 to disable the guard (exact v267_rga behaviour).

0.01
return_info bool

if True, also return a dict keyed by series name, each value a DataFrame indexed by year with the running_mean and pct_growth_change curves, for plotting or inspection.

False

Returns:

Type Description
DataFrame

one row per release with columns series, year (year of maximum percent growth change) and pct_growth_change, sorted by series then year. If return_info is True, returns (table, info).

References

Druckenbrod, D.L., Cook, E.R., Pederson, N. & Martin-Benito, D. (2024). Dendrochronologia 85, 126195. Lorimer, C.G. & Frelich, L.E. (1989). Canadian Journal of Forest Research 19, 651-663.

disturbance_detrend

Standardize ring widths by removing canopy-disturbance releases and the age trend.

The Druckenbrod et al. (2024) method. For each series: detect releases by radial growth averaging (see releases), power-transform the series, remove each release in turn (newest first) with a fixed-length age-dependent spline while it sustains elevated growth, age-detrend the disturbance-free series with a second spline, and re-express in ring-width units. The climate index is the ratio of the disturbance-standardized series to the age trend.

The returned index is per series and detrend-style, so it feeds dpl.chron exactly like dpl.detrend output.

Parameters:

Name Type Description Default
data pandas DataFrame or Series, or str

ring widths from dpl.readers, a single series, or a path to an rwl/csv file. Series shorter than 2 * window_length are returned all-NaN with a warning (parity with v267_rga, which cannot analyze them).

required
threshold int or float

percent-growth-change threshold for a release (see releases).

50
window_length int

running-mean window in years for detection, and the offset used by the transient-release test.

15
significance bool

significance testing of releases. Not implemented; True raises NotImplementedError.

False
release_flex int

stiffness (nyrs0) in years of the age-dependent spline fit to each release event.

10
age_flex int

stiffness (nyrs0) in years of the age-dependent spline fit to the disturbance-free series for the final age detrend.

30
transform (druckenbrod, powt, None)

the variance-stabilising power transform applied before detrending and inverted on re-expression, delegated to dpl.powt. "druckenbrod" is the method's own transform (powt(method="druckenbrod"): optimal power 1 - slope on the subsequent-ring level, natural-log branch at power <= 0.05) and is the validated default that reproduces the published method. "powt" uses dplPy's standard Cook & Peters transform (powt(method="cook")); it departs materially from the published method (on mo024 the per-series powers differ by ~0.3 on average) and is offered for workflows that prefer dplPy's house transform. None operates in raw ring-width units with no transform.

"druckenbrod"
recode_zeros bool

recode literal zero (locally absent) rings to 0.001 before processing, the dpl.ssf convention (the input frame is never modified). Absent rings otherwise flow through as zero growth and can yield NaN in the log-transform branch; when False and zeros are present, a warning names the series.

False
min_mean float

minimum preceding running-mean ring width (mm) for a release to be eligible (see releases). Guards against a near-zero baseline inflating the percent growth change; set 0 for exact v267_rga behaviour.

0.01
plot bool

if True, draw a single figure: the summary chronology (release histogram with sample depth, mean widths with the disturbance removed and the age trend, and the mean index) for a DataFrame, or the three-panel per-series figure for a single Series. A many-series call never draws one figure per series; use dpl.disturbance_plot to inspect named series.

False
return_info bool

if True, return a dict instead of just the index (see Returns).

False

Returns:

Type Description
DataFrame or Series

the age-and-disturbance-standardized climate index, same type as data (DataFrame of years x series, or a single Series), NaN outside each series' span. If return_info is True, returns a dict with: "index" (the climate index), "disturbance_standardized" (DSt), "age_trend" (At), "residual_index" (StTR, the transformed-space residual DStT - AtT), "releases" (the detection table from releases), and "averages" (a DataFrame of the straight across-series means: ring width, age trend, disturbance increment Dt, index, and running sample depth).

References

Druckenbrod, D.L., Cook, E.R., Pederson, N. & Martin-Benito, D. (2024). Dendrochronologia 85, 126195.

disturbance_plot

Plot the canopy-disturbance result for a chronology or named series.

With series=None and a DataFrame, draws the summary chronology figure; with series=None and a single Series, draws that series' three-panel figure. Pass series="DEM01A" or series=["DEM01A", "DEM07B"] to draw specific series' three-panel figures (detection, disturbance removal, index) -- the way to inspect individual cores without a figure per series. The detection and detrending parameters match disturbance_detrend.

Returns the matplotlib Figure (or a list of them when several series are drawn).