Skip to content

Crossdating

Statistical crossdating against a master chronology, COFECHA-style batch reporting, and floating-series dating. See the Crossdating & COFECHA guide.

xdate

Crossdate a set of ring-width series against a leave-one-out master.

Each series is normalized, optionally Yule-Walker prewhitened, and correlated against a biweight master built from all the other series, over segments of slide_period years overlapping by half. Mirrors dplR's corr.rwl.seg.

Flagged segments are labelled A or B (mutually exclusive):

  • B -- the segment correlates better at a non-dated lag (best lag != 0): a possible dating shift. (dplR flags on significance only; dplPy adds this COFECHA-style lag flag, also used by preset="COFECHA".)
  • A -- lag 0 is the best match but the correlation is not significant (one-tailed p >= p_val): weak but correctly placed.

Parameters:

Name Type Description Default
data DataFrame

detrended RWI (e.g. from dpl.detrend). With preset="COFECHA" pass the RAW ring-width frame instead; the preset detrends internally, so do not pre-detrend.

required
prewhiten bool

AR-prewhiten each series (Yule-Walker, matching dplR).

True
corr (spearman, pearson, kendall)

correlation method (case-insensitive).

"spearman"
slide_period int

segment length in years.

50
bin_floor int

the first segment is floored to a multiple of this.

100
p_val float

significance level for the A flag.

0.05
biweight bool

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

True
lag int

maximum ± lag examined for the B flag.

10
show_flags bool

print the flag summary and lag tables.

True
plot bool

draw the segment-correlation plot.

False
preset str or None

"COFECHA" emulates the COFECHA program instead of dplR. Pass the RAW frame (the preset detrends and variance-stabilizes it itself): it uses Pearson correlation, a z-scored arithmetic leave-one-out master, 50-year segments on a 25-year grid anchored to each series' span, a 99% one-tailed-t critical value, Burg AR prewhitening, and a lag search that slides the master past the dated segment. Adds the segments and n_problems keys; corr, biweight, bin_floor and p_val are ignored.

None
seg_lag int or None

segment step in years (overlap). None uses slide_period // 2. Preset only.

None
stabilize_period int

COFECHA preset only -- spline wavelength (years) for the internal detrend and variance stabilization.

32
absent DataFrame or None

COFECHA preset only -- marks locally absent rings to omit from a series' correlations. A boolean (years x series) frame, or a raw ring-width frame whose zeros mark them (e.g. absent=raw_rwl == 0). None disables the omission.

None
ar_max int or None

AR-order ceiling for prewhitening. None is dplR's floor(10*log10(n)); the COFECHA preset uses 10.

None

Returns:

Type Description
dict

with keys:

  • seg_corr -- DataFrame (series x bins) of segment correlations
  • p_val -- DataFrame (series x bins) of one-tailed p-values
  • overall -- DataFrame (series x ['rho', 'p_val']), the correlation with the leave-one-out master
  • avg_seg_corr -- Series (bins), mean correlation across series
  • flags -- dict {series: {'A': [...], 'B': [...]}}, each entry a dict {segment, best_lag, best_corr, lags}
  • bins -- list of "start-end" bin labels
  • rwi -- DataFrame of the normalized/prewhitened series used

With preset="COFECHA" also:

  • segments -- dict {series: [{lo, hi, r0, best_lag, best_corr, n, crit, flag, lags}]}
  • n_problems -- int, COFECHA's "possible problems" count

Examples:

>>> rwi = dpl.detrend(ca533, fit="spline", plot=False)
>>> res = dpl.xdate(rwi)
>>> res = dpl.xdate(rwl, preset="COFECHA")   # pass the RAW frame
>>> res["n_problems"]
References

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

xdate_report

Generate a COFECHA-style crossdating QA report for one or more .rwl files.

For each file: read (salvage mode), detrend, cross-date with dpl.xdate, collate per-series statistics, and print the report and/or save it as <name>.txt in out_dir (see output). Built for batch QA of ITRDB submissions. Pass preset="COFECHA" to emulate the COFECHA program instead (Burg prewhitening, spline variance stabilization, an arithmetic z-scored master, Pearson correlation, COFECHA segment anchoring and critical value, and "omit absent rings" fed from the raw frame); pass a RAW frame in that case.

Parameters:

Name Type Description Default
files str, pandas.DataFrame, or list

A .rwl path, an already-loaded ring-width DataFrame (e.g. from dpl.readers()), or a list mixing either. A DataFrame is reported directly (the read step is skipped). For the COFECHA preset, pass a RAW frame (zeros marking absent rings).

required
out_dir str

Directory for the .txt reports (created if needed).

"."
fit str

detrending curve passed to dpl.detrend (ignored when preset="COFECHA", which always uses a spline).

"Spline"
corr

passed through to dpl.xdate (corr, bin_floor and p_val are ignored when preset="COFECHA"; slide_period still applies).

'spearman'
slide_period

passed through to dpl.xdate (corr, bin_floor and p_val are ignored when preset="COFECHA"; slide_period still applies).

'spearman'
bin_floor

passed through to dpl.xdate (corr, bin_floor and p_val are ignored when preset="COFECHA"; slide_period still applies).

'spearman'
p_val

passed through to dpl.xdate (corr, bin_floor and p_val are ignored when preset="COFECHA"; slide_period still applies).

'spearman'
output (both, screen, file)

where the full report goes: "screen" prints it, "file" writes a <name>.txt in out_dir, "both" does both. The report text is always in the returned dict regardless.

"both"
verbose bool

print a one-line per-file progress note and a final tally.

True
preset str or None

set to "COFECHA" to emulate the COFECHA program (see above).

None
spline_period int or None

spline stiffness (years) for the preset="COFECHA" detrend; defaults to COFECHA's 32.

None
name str or None

Report label for a DataFrame input -- the report title, .txt filename, and key in the returned dict. Ignored for file paths. Defaults to "report".

None

Returns:

Type Description
dict

{path: {"text": str, "report": dict}} for files read successfully, or {path: {"error": str}} for files that failed.

xdate_plot

dplR-style crossdating overview for a set of series (see corr.rwl.seg).

A thin wrapper: crossdates data with :func:xdate (same parameters) and draws the green/blue/red segment plot -- green = series extent, blue = a segment that correlates significantly with the master, red = a flagged segment (p >= p_val). Returns the matplotlib Axes.

Note: this plot shows only the significance screen (dplR's corr.rwl.seg, i.e. the A flag) -- red marks a segment whose dated (lag-0) correlation is not significant. It does NOT show the B flag (a segment that correlates better at a non-dated lag -- a possible dating shift), which dplR's plot has no concept of. A B-flagged segment that still dates significantly is drawn blue here, so it looks fine on the plot even though :func:xdate reports it as a problem. Always read the text xdate() flag report alongside this plot to catch B (lag) flags.

xdate_floater

Estimate the calendar dating of a floating (undated) ring-width series.

Slide the floating series against a dated master and score each offset by correlation, reporting the best-fit placement with crossdating statistics (t-value, effective df, Bonferroni-corrected p, isolation factor).

Parameters:

Name Type Description Default
data DataFrame or Series

The dated reference (year-indexed). A DataFrame is a collection of ring-width series, averaged into the master; a Series (or one-column DataFrame) is used directly as the master -- e.g. crn["std"] from dpl.read_crn. For an already-residual/prewhitened chronology, pass transform="none" to avoid prewhitening twice.

required
series sequence or Series / DataFrame

The floating (undated) ring-width series -- ring values oldest to youngest; any calendar index is ignored.

required
series_name str or None

Label for the floating series. None takes it from the series itself (a named Series or one-column DataFrame header), falling back to "Unknown".

None
min_overlap int

Minimum overlapping rings required to score an offset.

50
transform (pw, fd, none)

High-pass transform applied (after mean-normalization) before correlating: "pw" Yule-Walker AR prewhitening, "fd" first differencing, or "none". First differencing sharpens the high-frequency signal but sharply reduces the effective degrees of freedom.

"pw"
prewhiten bool

Deprecated alias: True -> transform="pw", False -> transform="none". Overrides transform if given.

None
biweight bool

Build the master with a Tukey biweight robust mean (else arithmetic mean).

True
corr (spearman, pearson, kendall)

Correlation used to score each offset (one-sided).

"spearman"
ar_max int or None

AR order ceiling for transform="pw". The default follows COFECHA/ARSTAN (cap at 10); None uses dplR's floor(10*log10(n)).

10
first_aic_min bool

Select the AR order at the FIRST local AIC minimum (COFECHA/ARSTAN rule) rather than the global AIC minimum (dplR's ar(); set False).

True
plot bool

Plot the sliding t-value against the series' end year, marking the best fit.

False
return_rwl bool

Also return the floating series placed at its best-fit years (placed) and combined with the reference (combined).

False
segmented bool

Also date each overlapping segment of the floater independently against the master and check that they agree (COFECHA UDATE-style). Adds result["segments"], result["consensus"], result["segment_candidates"] and result["internal_error"] (a dict describing a detected missing/false ring, or None). A coherent one-year step between older and younger segments flags an internal dating error the whole-series fit cannot see; at least four segments are needed for that verdict. The single-best-t placement remains the primary result.

False
segment_topk int

With segmented, how many best placements to record per segment in result["segment_candidates"].

5
verbose bool

Print a short summary of the best-fit dating.

True

Returns:

Type Description
dict

series_name; floater_cor_stats (a DataFrame with one row per offset, highest t first, columns min_year, max_year, r, t, eff_df, p_bonf, n); best (the top-scoring placement, incl. isolation_factor and one_over_p); and, when return_rwl=True, placed and combined.

Notes

Ports dplR's xdate.floater and adds crossdating statistics (t-value, autocorrelation-adjusted effective degrees of freedom, a Bonferroni-corrected p-value, and an isolation factor; Baillie & Pilcher 1973, Wigley et al. 1987, Wilson 2026). The correlation scoring reuses dplPy's crossdating internals, so results are consistent with dpl.xdate.

series_corr

Crossdate one series against the master built from all the others.

Produces (and, by default, plots) a moving correlation of the series against the leave-one-out master, the per-segment correlations, and a per-segment lag table (COFECHA-style) showing how the correlation changes when the segment is shifted ± lag years -- large off-zero peaks suggest a dating error in that segment.

Parameters:

Name Type Description Default
data DataFrame

ring-width series (typically detrended RWI).

required
series_name str

the series to examine.

required
prewhiten

as in dpl.xdate() (seg_length is the segment length).

True
corr

as in dpl.xdate() (seg_length is the segment length).

True
seg_length

as in dpl.xdate() (seg_length is the segment length).

True
bin_floor

as in dpl.xdate() (seg_length is the segment length).

True
p_val

as in dpl.xdate() (seg_length is the segment length).

True
biweight

as in dpl.xdate() (seg_length is the segment length).

True
lag

as in dpl.xdate() (seg_length is the segment length).

True
plot bool

master switch for drawing any figure.

True
which (both, moving, ccf)

when plot is True, which figure(s) to draw: both, only the moving-correlation plot (corr.series.seg), or only the per-segment ccf panels (ccf.series.rwl).

'both'
series_x bool

lag convention for the dplR-style ccf. True calls ccf(x=series, y=master) so a positive lag marks a missing ring in the series (Bunn's intuitive convention); False matches dplR's stock series.x=FALSE (negative lag = missing ring).

True

Returns:

Type Description
dict with keys ``moving_corr`` (Series), ``seg_corr`` (Series over bins),
``overall`` ((rho, p_val)), ``lag_table`` (Spearman rank correlations at
shifted windows, lags x bins), ``ccf`` (dplR-style Pearson cross-correlation
per segment, lags x bins), ``ccf_bins`` and ``bins``.
References

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

interseries_corr

Mean interseries correlation (COFECHA's headline statistic).

For each series, correlate it against a master chronology built from every other series (leave-one-out), then average. This is dplR's interseries.cor(), and is distinct from rbar (rwi_stats), which averages the pairwise correlations between individual series.

Expects raw ring widths, not indices: each series is normalized by its own mean and, by default, prewhitened before the correlations are computed.

Parameters:

Name Type Description Default
data DataFrame

raw ring widths (as from dpl.readers), years as the index, series as columns.

required
prewhiten boolean

prewhiten each series with an autoregressive model before correlating.

True
biweight boolean

build each leave-one-out master with a Tukey biweight robust mean rather than the arithmetic mean.

True
corr (Spearman, Pearson)

correlation type.

"Spearman"

Returns:

Name Type Description
mean_corr float

collection-wide mean interseries correlation (3 decimals).

result DataFrame

per-series interseries correlation and one-sided p-value.

Examples:

>>> import dplpy as dpl
>>> mean_corr, per_series = dpl.interseries_corr(dpl.readers("series.rwl"))
References

.. [1] https://rdrr.io/cran/dplR/man/interseries.cor.html