Input & output¶
Reading ring-width and chronology files, inspecting metadata, and writing data back out. See the Reading & writing data guide for worked examples.
readers¶
Read a common ring-width data file (.csv, .rwl) into a pandas DataFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
a data file (.CSV, .RWL or .RAW). May be a local path or an http(s) URL (e.g. from the NOAA/ITRDB archive) -- both are read the same way. |
required |
header
|
bool or None
|
whether a 3-line site-metadata header sits at the top of the file. |
None
|
skip_lines
|
int
|
how many of the first lines of the file to skip when reading it. |
0
|
format
|
(None, tucson, csv, tridas)
|
force the file format regardless of suffix. |
None
|
strict
|
bool
|
|
True
|
join
|
bool
|
|
True
|
encoding
|
str or None
|
character encoding. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
data |
pandas dataframe
|
Year-indexed ring widths. Non-fatal advisories about the file are attached to
|
Examples:
>>> import dplpy as dpl
>>> data = dpl.readers("../tests/data/csv/file.csv")
>>> data = dpl.readers("../tests/data/rwl/file.rwl") # header auto-detected
>>> data = dpl.readers("https://www.ncei.noaa.gov/pub/data/paleo/treering/"
... "measurements/northamerica/usa/ak132x.rwl") # read from a URL
References
.. [1] https:/opendendro.org/dplpy-man/#readers
readers_url¶
Read a Tucson (.rwl) file directly from a URL.
Deprecated: readers() now accepts an http(s) URL directly, so
dpl.readers(url) does the same thing. This thin wrapper is kept for
backward compatibility and simply forwards to readers.
metadata¶
Extract site/sample metadata from a Tucson (.rwl) file's header.
Returns a dict with best-effort fields (site_id, site_name, species_code, species_name, country_region, elevation_m, latitude, longitude, first_year, last_year, investigators) plus n_header_lines and the raw header lines. Unreadable fields are None. Reads only the header, so it is cheap and independent of loading the data; accepts a local path or an http(s) URL. This is a prototype -- see df.attrs['dplpy_metadata'] for the same result captured at read time.
read_crn¶
Read a Tucson (.crn) chronology file into a DataFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Path (or http/https URL) to a .crn chronology file. Standard single chronologies and combined multi-block files (stacked ARSTAN types, or many sites concatenated) are both handled. |
required |
strict
|
bool
|
|
True
|
split_by_site
|
bool
|
If True, return a dict mapping each site ID to its own DataFrame (each
framed as a single-site file: value columns named by chronology type
plus a shared |
False
|
Returns:
| Type | Description |
|---|---|
pandas.DataFrame or dict of pandas.DataFrame
|
By default one DataFrame indexed by year: one value column per
chronology (named by chronology type for a single-site file, e.g.
'std'/'res'/'ars'; by site, or 'site.type', for a multi-site file),
index values divided by 1000 and 9990 mapped to NaN, with sample depths
as 'samp_depth' (shared when several chronologies carry identical depth)
or ' |
Examples:
>>> dpl.read_crn("ga004.crn")
>>> dpl.read_crn("celaque_prelim_v01.rwl_crns.txt")
>>> by_site = dpl.read_crn("ALL.CRNS", split_by_site=True) # {site: DataFrame}
References
.. [1] https:/opendendro.org/dplpy-man/#read_crn
read_ids¶
Derive tree and core IDs from series names (site-tree-core convention).
Split each series name into a tree identifier (site + tree number, so trees and
sites never collide) and a core designator, and return the mapping
dpl.rwi_stats() and dpl.sss() use to know which cores belong to the same tree.
Two parsing modes: the pattern default (stc=None) splits on letter/digit
boundaries (leading letters = site, first digit run = tree, trailing characters
= core); an STC mask (stc=(site_len, tree_len[, core_len])) splits by fixed
character positions.
IMPORTANT: the pattern default cannot detect a DIGIT core. A name like "CAM031"
is read as tree "031" with an empty core (no warning), leaving "CAM031" and
"CAM032" as separate trees instead of grouping them under "CAM03". For digit
cores, or site codes that contain digits, supply an explicit stc mask (e.g.
stc=(3, 2, 1) for "CAM031").
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
pandas dataframe or iterable of str
|
a dataframe whose column names are the series names (e.g. from dpl.readers()), or any iterable of series-name strings. |
required |
stc
|
tuple of int, or None
|
None to use the pattern default; otherwise a (site_len, tree_len) or (site_len, tree_len, core_len) character mask. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
ids |
pandas dataframe indexed by series name, with columns 'tree' and
|
'core'. Pass this directly as the |
Examples:
>>> import dplpy as dpl
>>> data = dpl.readers("../tests/data/csv/file.csv")
>>> ids = dpl.read_ids(data) # letter-core names
>>> ids = dpl.read_ids(data, stc=(3, 2, 1)) # digit-core names (e.g. CAM031)
>>> dpl.rwi_stats(dpl.detrend(data, plot=False), ids=ids)
References
.. [1] https://rdrr.io/cran/dplR/man/read.ids.html
combine_rwl¶
Combine ring-width datasets on the union of their years (dplR combine.rwl).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
pandas.DataFrame or list/tuple of DataFrames
|
Either the first dataset (with |
required |
y
|
DataFrame
|
The second dataset, when |
None
|
warn_duplicates
|
bool
|
Emit a warning if the combined frame ends up with duplicate series names (the columns are still kept, matching dplR -- this only flags them). |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
All series side by side, indexed by a contiguous year range spanning the earliest to the latest year of the inputs (years with no data are NaN). |
Notes
Series columns are concatenated as-is: like dplR, duplicate series IDs are neither merged nor renamed. Deduplicate or rename beforehand if that matters for your workflow.
writers¶
Output dplpy datasets to .csv, .rwl and .crn files.
Write a dataframe to a .csv, .rwl, .crn or .txt file as set by format,
created in the current directory unless a path is included in label. For
'csv'/'rwl', data is a ring-width dataframe (years x series); for 'crn',
data is a chronology (from dpl.chron()) and a header of site metadata
is REQUIRED to populate the Tucson .crn header.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
pandas dataframe
|
ring widths (csv/rwl) or a chronology from dpl.chron() (crn). |
required |
label
|
str
|
name (can include file path) to give the file; no extension. |
required |
format
|
str
|
'csv', 'rwl', 'crn', or 'txt'. |
required |
header
|
dict, required for format='crn'
|
site metadata with the keys: 'site_id', 'site_name', 'species_code', 'state_country', 'species', 'elevation', 'latitude', 'longitude', 'investigators'; optionally 'completion_date'. First/last year are taken from the chronology. |
None
|
chronology_type
|
str
|
for format='crn', the ITRDB chronology type written in header record 2: 'standard' (blank code), 'arstan' ('A'), or 'residual' ('R'). |
'standard'
|
column
|
str
|
for format='crn', which chronology column to write (e.g. 'std', 'res'). |
'std'
|
prec
|
float
|
for format='rwl', the measurement precision in mm: 0.001 (values x1000,
end marker -9999) or 0.01 (values x100, end marker 999); the
precision->marker mapping follows dplR's write.tucson. Note dplPy defaults
to 0.001 (dplR defaults to 0.01) and encodes interior gaps via |
0.001
|
gaps
|
(int, split)
|
for format='rwl', how to encode a true interior gap (a NaN inside a series; a real 0 is a locally absent ring and is always written as 0): a negative integer (default -99) writes that sentinel in the gap (it must be negative so it is not read as a ring width, and not a stop marker; the reader turns it back into NaN), or "split" closes the block with the end marker and reopens a new block at the next present year. |
int
|
sep
|
for format='txt', the column delimiter (default tab), printf float format
(default '%.4f', None for full precision), and missing-value text (default
'NA'). For 'txt', |
'\t'
|
|
float_format
|
for format='txt', the column delimiter (default tab), printf float format
(default '%.4f', None for full precision), and missing-value text (default
'NA'). For 'txt', |
'\t'
|
|
na_rep
|
for format='txt', the column delimiter (default tab), printf float format
(default '%.4f', None for full precision), and missing-value text (default
'NA'). For 'txt', |
'\t'
|
Returns:
| Type | Description |
|---|---|
None
|
|
summary¶
Summarize a ring-width dataset.
Reports per-series summary information for a dataframe of tree-ring widths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inp
|
str or pandas dataframe
|
a data file (.CSV or .RWL) or a pandas dataframe imported from dpl.readers(). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
data |
pandas dataframe
|
|
Examples:
References
.. [1] https:/opendendro.org/dplpy-man/#summary
report¶
Generates a report
Extended Summary
Generates a text report about the input dataset that includes: Number of dated series Number of measurements Avg series length (years) Range (total years) Span (start-end year) Mean (Standard Deviation) series intercorrelation Mean (Standard Deviation) AR1 Years with locally absent rings (zero values), with per-series and total counts Years with internal NA (missing measurements), with per-series and total counts
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inp
|
str or pandas dataframe
|
a data file (.CSV or .RWL) or a pandas dataframe imported from dpl.readers(). |
required |
Returns:
| Type | Description |
|---|---|
None
|
|
Examples:
References
.. [1] https:/opendendro.org/dplpy-man/#report
check¶
Check a ring-width collection for defects, reported as a table of findings.
The data counterpart to :func:report: report prints what a file looks
like, check returns what is wrong with it, one row per finding. Every
finding carries a stable check id and a severity ("error", "warning",
"note"), and a check that fails becomes a RWL_CHECK_ERROR finding rather
than stopping the run. Analog of dplR 1.8.0's rwl.check.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
pandas.DataFrame, str, or list of str
|
a ring-width collection ( |
required |
file
|
str or None
|
label for the |
None
|
checks
|
list of str or None
|
which groups to run. Default all: structure, series, values, zeros, crossdating, file, provenance. |
None
|
summary
|
bool
|
if True, return one row per file (counts per check and per severity) instead
of the findings. |
False
|
min_depth
|
int
|
|
2
|
depth_run
|
int
|
|
2
|
min_length
|
int
|
|
2
|
run_min
|
int
|
|
2
|
lag_max
|
int
|
|
2
|
min_overlap
|
int
|
|
2
|
spline_nyrs
|
int
|
|
2
|
r_dating
|
float
|
|
0.35
|
r_margin
|
float
|
|
0.35
|
outlier_mad
|
float
|
|
0.35
|
outlier_gap
|
float
|
|
0.35
|
r_cohesion
|
float
|
|
0.35
|
plausible_mean
|
float
|
|
0.35
|
small_thresh
|
Optional[float]
|
tunables; defaults follow dplR's |
None
|
big_thresh
|
Optional[float]
|
tunables; defaults follow dplR's |
None
|
max_year
|
Optional[float]
|
tunables; defaults follow dplR's |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
the findings (columns |
References
.. [1] Bunn, A. G. (2026) dplR 1.8.0, rwl.check.
SiteMetadata¶
Site/sample metadata shared by dplPy's file exporters.
Field names mirror dpl.metadata() / df.attrs['dplpy_metadata']. Use
:meth:from_rwl to auto-fill from a frame read by dpl.readers(),
:meth:from_metadata from a metadata dict, or construct one directly and set
fields by hand. :meth:to_crn_header renders the dict the Tucson .crn
writer expects (which uses a few different key names).
from_metadata
classmethod
¶
Build from a metadata dict (dpl.metadata() output or the same
shape). Unknown keys (e.g. n_header_lines) are ignored.
from_rwl
classmethod
¶
Build from a frame read by dpl.readers() (uses
df.attrs['dplpy_metadata']), or from a metadata dict directly.
coerce
classmethod
¶
Return obj if it is already a SiteMetadata, or build one from a
metadata dict. Used by writers so they accept either form.
to_crn_header ¶
Render the header dict the Tucson .crn writer expects. The writer
uses a few different key names (state_country/species/
elevation); this maps them. Fields that are None are omitted, so the
writer's own "missing required key" check reports what still needs
filling rather than writing the literal 'None'.
read_tridas¶
Read a TRiDaS (Tree Ring Data Standard) XML file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
path to a |
required |
warn_units
|
bool
|
warn when a measurement series uses a variable that is not a width in a length unit (e.g. a density), which dplPy does not convert to mm. Such series are kept out of the ring-width tables. |
True
|
Returns:
| Type | Description |
|---|---|
TridasProject
|
A typed container: |
Notes
Missing values become NaN (not 0); units are converted to millimetres;
years use the dplPy continuous integer axis. See
dev/tridas_design_2026-10-14.md for the full design.
References
.. [1] Jansma, Brewer & Zandhuis (2010), Dendrochronologia 28, 99-130.
write_tridas¶
Write a TRiDaS 1.2.2 file from ring widths and/or a chronology.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fname
|
str
|
output path. |
required |
rwl
|
pandas DataFrame
|
ring widths (Year-indexed, series in columns), as from dpl.readers(). Written as measurementSeries under one object (site). |
None
|
crn
|
pandas DataFrame
|
a chronology from dpl.chron(); columns named |
None
|
metadata
|
TridasMetadata or dict
|
project/site metadata. Mandatory fields missing with |
None
|
prec
|
float
|
measurement precision in mm (0.001, 0.01, 0.02, 0.05, 0.1, 1, 10, 1000).
|
None
|
ids
|
pandas DataFrame
|
tree/core[/radius/measurement] grouping, as from dpl.read_ids(). Default: each series is its own element (tree). |
None
|
taxon
|
str
|
taxon for the elements. Mandatory per the standard when writing rwl. |
None
|
variable
|
str
|
the measured variable (controlled vocabulary). |
"ring width"
|
measuring_method
|
str
|
free-text measuring method (mandatory per the standard). |
"unknown"
|
validate
|
bool
|
enforce the mandatory-field set. |
True
|
Returns:
| Type | Description |
|---|---|
str
|
the path written. |
TridasProject¶
Parsed TRiDaS file.
Attributes:
| Name | Type | Description |
|---|---|---|
measurements |
dict of str -> DataFrame
|
Dated measurement series grouped into ring-width tables, keyed by
|
derived |
dict of str -> DataFrame
|
Chronologies (TRiDaS derivedSeries), keyed by series title. Each frame is
Year-indexed with the chronology column and, when the file records per
value counts, a |
undated |
dict of str -> Series
|
Measurement series with no calendar years (floating series), keyed by series id. Position-indexed; feed these to dpl.xdate_floater(). |
metadata |
TridasMetadata
|
The full metadata hierarchy. |
rwl ¶
Return the single ring-width table, or raise if the file holds more
than one measurement table (then use :attr:measurements).
TridasMetadata¶
The project/object/element/sample/radius/series metadata of a TRiDaS file.
Project-level fields are named (they are the mandatory ones in Brewer's list
and what a .crn-style export needs). The object hierarchy is kept as nested
dicts under :attr:objects so the whole tree stays navigable without a deep
class hierarchy. :attr:laboratories and :attr:extra capture the rest.