Skip to content

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

Imports a common ring width data file

Extended Summary

This function reads data from common ring width data files (.csv, .rwl) and stores them in pandas dataframes.

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. a file served 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 (the default) auto-detects the header the way dplR does, so the great majority of real ITRDB files "just work" without the caller having to know. Pass True or False to force the behaviour.

None
skip_lines int

indicates how many of the first few lines of the file to skip when reading it.

0
format (None, tucson, csv)

Force the file format regardless of suffix. None infers it: a .csv suffix is read as CSV; .rwl/.raw as Tucson; and any other suffix (e.g. .txt, or none at all) is decided by sniffing the content, so a valid Tucson file with a nonstandard extension still reads. Pass "tucson" or "csv" to override entirely. ("rwl"/"raw" are accepted as aliases for "tucson".)

None
strict bool

True (strict, the default) refuses a file with an unrecoverable problem, so an unaware caller gets safe, fail-loud behaviour. False (salvage) recovers as much as possible instead of raising: a series with a self-overlap or a measurement-precision shift is dropped, a duplicate series ID (two overlapping cores) has its later block(s) renamed and kept, and a file with nothing usable returns None. Every such action is warned about and recorded on df.attrs["dplpy_salvage"] (a list of {series, issue, action, detail}).

True
join bool

True (matching dplR) merges a series written as two or more disjoint same-ID blocks (e.g. 1651-1774 and 1800-1974) into one series. False keeps them as SEPARATE series, renaming the 2nd+ block to a unique ID -- the per-segment view a crossdating QA (COFECHA-style) needs.

True

Returns:

Name Type Description
data pandas dataframe

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("../tests/data/rwl/file.rwl", header=True)
>>> 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 (the default) refuses a file with no readable chronology; False returns None instead. (Individual malformed rows are skipped with a warning either way.)

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 samp_depth). Useful for multi-site bundles, where the default single wide frame is unwieldy. A single-site file yields a one-entry dict.

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 ' samp_depth' otherwise. With split_by_site=True, a dict {site_id: DataFrame}. df.attrs carries dplpy_crn (a summary) and dplpy_crn_stats (embedded statistics lines).

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).

Extended Summary

Tree-ring series are conventionally named with a site code, a tree number, and a core designator (the "STC" convention). This function splits each series name into a tree identifier (site + tree number, so that different trees -- and different sites -- never collide) and a core designator, and returns the mapping used by dpl.rwi_stats() and dpl.sss() to know which cores belong to the same tree.

Two parsing modes are available:

Pattern default (stc=None). Each name is split on its letter/digit boundaries: leading letters are the site, the first run of digits is the tree number, and any trailing characters are the core. This handles names with a LETTER core and a variable-length site automatically, e.g. both "ABC001A" (site ABC, tree 001, core A -> tree "ABC001") and "ABCD01" (site ABCD, tree 01, no core -> tree "ABCD01").

IMPORTANT: this pattern cannot see a DIGIT core. A name like "CAM031" (site CAM, tree 03, core 1) still matches -- the whole digit run "031" is read as the tree number and the core comes out empty -- so it parses WITHOUT any warning but leaves "CAM031" and "CAM032" as two separate trees instead of grouping them under "CAM03". For digit cores (and for site codes that contain digits) you MUST supply an explicit stc mask. The only names that trigger the "could not parse" warning are those that do not match the pattern at all (no leading letters, embedded separators, etc.).

STC mask (stc=(site_len, tree_len[, core_len])). Splits each name by fixed character positions: the tree identifier is the first site_len+tree_len characters, and the core is the remainder (or exactly core_len characters if a third element is given). Use this whenever the pattern default cannot resolve the structure -- e.g. digit cores like "CAM031" with stc=(3, 2, 1), or site codes that contain digits.

Parameters:

Name Type Description Default
data pandas dataframe or iterable of str

a dataframe whose column names are the series names (such as 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 ids argument of dpl.rwi_stats(), dpl.rwi_stats_running(), or dpl.sss().

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 y the second), or a list/tuple of datasets to combine in order.

required
y DataFrame

The second dataset, when x is a single DataFrame.

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.

Extended Summary

Given a pandas dataframe, this function writes its contents to a .csv, .rwl or .crn file as indicated by the format parameter. The file will be created in the same directory unless a different path is included in label.

For 'csv' and 'rwl', data is a ring-width dataframe (years x series). For 'crn', data is a chronology (the output of dpl.chron() -- a dataframe with an index column such as 'std'/'res' and a 'samp_depth' column), 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 written x1000, end-of-series marker -9999) or 0.01 (values x100, end marker 999). The precision->marker mapping follows dplR's write.tucson. Note two deliberate divergences from dplR: dplPy defaults to prec=0.001 (dplR defaults to 0.01), and interior gaps are encoded via the gaps option below rather than dplR's 0 / -9.99 missing string.

0.001
gaps (int, split)

for format='rwl', how to encode a true interior gap (a NaN inside a series -- missing measurement, as distinct from a real 0, which is a ring that was locally absent that year and is always written as 0): a negative integer (a dplPy convention, default -99; also e.g. -9) writes that sentinel in the gap within a continuous block -- it must be negative so it is not read as a ring width, and must not be a stop marker; dplPy's reader turns any such negative back into NaN on read. "split" instead closes the block with the end marker and reopens a new block at the next present year (no sentinel in the file; gap still reads back as NaN).

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', data may be a DataFrame, a single Series, or a list of year-aligned Series -- you choose the columns; dpl.samp_stats() and dpl.chron_ars() supply the usual sample-depth/seg/age and std/res/ars columns.

'\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', data may be a DataFrame, a single Series, or a list of year-aligned Series -- you choose the columns; dpl.samp_stats() and dpl.chron_ars() supply the usual sample-depth/seg/age and std/res/ars columns.

'\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', data may be a DataFrame, a single Series, or a list of year-aligned Series -- you choose the columns; dpl.samp_stats() and dpl.chron_ars() supply the usual sample-depth/seg/age and std/res/ars columns.

'\t'

Returns:

Type Description
None

summary

Summarizes a chronology

Extended Summary

This function summarizes a given dataframe of tree widths/rings.

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:

>>> import dplpy as dpl
>>> data = dpl.readers("../tests/data/csv/file.csv")
>>> dpl.summary(data)
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 absent rings listed by series

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:

>>> import dplpy as dpl
>>> data = dpl.readers("../tests/data/csv/file.csv")
>>> dpl.report(data) 
References

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

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

from_metadata(meta: dict) -> SiteMetadata

Build from a metadata dict (dpl.metadata() output or the same shape). Unknown keys (e.g. n_header_lines) are ignored.

from_rwl classmethod

from_rwl(data) -> SiteMetadata

Build from a frame read by dpl.readers() (uses df.attrs['dplpy_metadata']), or from a metadata dict directly.

coerce classmethod

coerce(obj) -> SiteMetadata

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

to_crn_header() -> dict

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'.