Dating a floating series¶
A floating series is undated wood — a beam from a historic building, a remnant
or sub-fossil log — whose rings are measured but not yet tied to calendar years.
xdate_floater estimates its calendar placement by sliding it across a dated
reference collection and scoring the fit at every offset.
The idea¶
You need two things:
- a dated reference, either a whole collection (a
DataFramefromreaders, indexed by calendar year, from which a master chronology is built by averaging the series) or a single, already-built chronology passed as apandas.Seriesor a one-columnDataFrame— for example a column fromread_crn; and - the floating series itself (a
pandas.Seriesof ring widths; its index does not need to be calendar years).
xdate_floater builds (or takes) a master from the reference, transforms the
floater the same way, and tests every alignment with at least min_overlap
overlapping rings, reporting the correlation and crossdating statistics at each.
The floating series may be longer than the reference.
Dating against an existing chronology. A .crn read with read_crn already
is a master, so pass the column you want (e.g. crn["std"]) directly as the
reference. For an already-prewhitened/residual chronology (an ARSTAN res/ars),
also pass transform="none" so it is not prewhitened a second time.
Example¶
import dplpy as dpl
reference = dpl.readers("reference_site.rwl", header=True)
placed = dpl.xdate_floater(reference, floating_series, series_name="beam1")
Best match for 'beam1': 1727 to 1983 (t = 17.83, r = 0.747, eff_df = 254,
p_bonf = 8.52e-44, 1/p = >1 million, IF = >1000, overlap n = 254)
If you don't pass series_name, it is taken from the series itself (a named
Series, or a one-column DataFrame's column header). To date against a published
chronology rather than a collection, hand it the column you want:
crn = dpl.read_crn("reference_site.crn")
placed = dpl.xdate_floater(crn["std"], floating_series, series_name="beam1")
The return value is a dictionary:
placed["best"]— the top-scoring placement:min_year,max_year,r,t,eff_df,p_bonf,one_over_p,isolation_factor, andn.placed["floater_cor_stats"]— every tested offset, highest-t first, so you can inspect the runners-up.- with
return_rwl=True, alsoplaced["placed"](the floater at its best-fit years) andplaced["combined"](floater merged with the reference).
Reading the statistics¶
| Statistic | What it tells you |
|---|---|
r |
The sliding correlation between floater and master at that offset. |
t |
The Baillie & Pilcher (1973) t statistic, r·√(df−2)/√(1−r²). Higher is stronger; values ≥ ~3.5 are the classic acceptance threshold. |
eff_df |
Effective degrees of freedom, reduced from the raw overlap for autocorrelation (Wigley et al. 1987). |
p_bonf |
One-tailed p-value of t, Bonferroni-corrected for the many offsets tested. |
isolation_factor (IF) |
How many times larger the runner-up's p-value is than the best offset's. A large IF means the date stands out cleanly from the alternatives. |
The best placement is chosen by the highest t, which accounts for the
degrees of freedom at each overlap. A confident date has a high t, a tiny
p_bonf, and a large isolation factor — as in the example above.
Useful arguments¶
min_overlap(default 50) — the minimum number of overlapping rings an alignment must have to be scored.transform(default"pw") andprewhiten— how the series are detrended and prewhitened before correlation.corr(default"spearman") — the correlation method.series_name— a label for the floater used in the outputs and plot title; when omitted it is taken from a named series or one-column frame, else"Unknown".plot=True— draw the dating figure: the sliding t and the Bonferroni-adjusted p-value against calendar year, the distribution of all t values with the best marked, and an overlay of the reference chronology against the best-placed floater over the dated overlap.
When the best date is impossible¶
dplPy also scores placements that run past the end of the reference into future
calendar years — this enriches the null distribution of t values and acts as a
sanity check. If the best placement lands after the present year, though, the
date is impossible and the match is almost certainly spurious, so xdate_floater
flags it loudly: best["date_warning"] is set to "future", a warning banner is
printed (even with verbose=False), and the returned plot carries a red
"best date is in the future" banner. Check the series orientation (oldest →
youngest) and the reference before trusting such a result.
Relationship to dplR¶
xdate_floater is based on dplR's xdate.floater and extends it with the t
statistic and additional crossdating statistics of Wilson (2026). It differs from
dplR in two documented ways: the best placement is selected by highest t (dplR
uses the highest correlation r), and dplPy does not apply dplR's future-year
trim — instead it tests those offsets and warns when the winning date is an
impossible future one (see When the best date is impossible). See the
xdate_floater reference and
Coming from dplR.