Metadata-Version: 2.4
Name: dplpy
Version: 0.9.0
Summary: Dendrochronology Program Library for Python
Author-email: Tyson Lee Swetnam <tswetnam@arizona.edu>, Ifeoluwa Ale <ifeoluwaale@arizona.edu>, Kevin Anchukaitis <kanchukaitis@arizona.edu>
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://opendendro.github.io/dplPy
Project-URL: Documentation, https://opendendro.github.io/dplPy
Project-URL: Repository, https://github.com/OpenDendro/dplPy
Project-URL: Changelog, https://github.com/OpenDendro/dplPy/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/OpenDendro/dplPy/issues
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering
Classifier: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23.2; python_version == "3.11"
Requires-Dist: numpy>=1.26.0; python_version >= "3.12"
Requires-Dist: pandas>=2.2.2
Requires-Dist: csaps>=1.1.0
Requires-Dist: matplotlib>=3.8.4
Requires-Dist: statsmodels>=0.14.2
Requires-Dist: scipy>=1.13.0
Provides-Extra: lipd
Requires-Dist: pylipd<2,>=1.5; extra == "lipd"
Dynamic: license-file

 <p align="center">
 <img src="https://github.com/OpenDendro/dplPy/blob/main/docs/assets/dplpy.png?raw=true" width="175"> 

# dplPy -the Dendrochronology Program Library in Python

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22695105.svg)](https://doi.org/10.5281/zenodo.22695105)

[![PyPI Version](https://img.shields.io/pypi/v/dplpy?cacheSeconds=3600)](https://pypi.org/project/dplpy/)

The Dendrochronology Program Library (DPL) in Python has its roots in both the [original FORTRAN program](https://www.ltrr.arizona.edu/software.html) created by the [legendary Richard Holmes](https://repository.arizona.edu/items/e7703eeb-adca-43c8-926e-daf18f86b654) and the subsequent R Project package by Andy Bunn, [dplR](https://github.com/OpenDendro/dplR).  Our aim is to provide researchers working with tree-ring data the necessary tools in open-source environments, promoting open science practices, enhancing rigor and transparency in dendrochronology, and eventually allowing reproducible research entirely in a single programming language.

 The development of dplPy is supported by a grant from the Paleoclimate program of the US National Science Foundation (AGS-2054516) to Andy Bunn, Kevin Anchukaitis, Ed Cook, and Tyson Swetnam.
<br>


---


## Index

- [dplPy - the Dendrochronology Program Library in Python](#dplpy---the-dendrochronology-program-library-in-python)
  - [Index](#index)
  - [Requirements](#requirements)
  - [Current Version](#current-version-and-changelog)
  - [Installation](#installation)
  - [Building directly from Github](#building-directly-from-github)
  - [Functionalities and Usage](#functionalities-and-usage)
    - [Loading data using  `readers`](#loading-data-using--readers)
    - [Loading data from online sources using `readers_url`](#loading-data-from-online-sources-using-readers_url)
    - [Data Summary from `summary`](#data-summary-from-summary)
    - [Data Stastics from `stats`](#data-stastics-from-stats)
    - [Data Report from `report`](#data-report-from-report)
    - [Plotting raw data with `plot`](#plotting-raw-data-with-plot)
    - [Detrending using `detrend`](#detrending-using-detrend)
    - [Autoregressive (AR) modeling](#autoregressive-ar-modeling)
    - [Build a chronology with `chron`](#build-a-chronology-with-chron)
    - [Build a variance stabilized chronology with `chron_stabilized`](#build-a-variance-stabilized-chronology-with-chron_stabilized)
    - [Build an AR-based chronology with `chron_ars`](#build-an-ar-based-chronology-with-chron_ars)
    - [Crossdate with `xdate`](#crossdate-with-xdate)
    - [Date a floating series with `xdate_floater`](#date-a-floating-series-with-xdate_floater)
    - [Date undated series against each other with `xdate_undated`](#date-undated-series-against-each-other-with-xdate_undated)
    - [Regional Curve Standardization with `rcs`](#regional-curve-standardization-with-rcs)
    - [Read chronology files with `read_crn`](#read-chronology-files-with-read_crn)
    - [Agreement statistics: `glk` and `sgc`](#agreement-statistics-glk-and-sgc)
    - [Mean sensitivity: `sens1` and `sens2`](#mean-sensitivity-sens1-and-sens2)
    - [Average cores to trees with `tree_mean`](#average-cores-to-trees-with-tree_mean)
    - [Basal area increment with `bai_out` and `bai_in`](#basal-area-increment-with-bai_out-and-bai_in)
    - [Combine datasets with `combine_rwl`](#combine-datasets-with-combine_rwl)
    - [Output data to files using `writers`](#output-data-to-files-using-writers)
    - [Export and import LiPD with `to_lipd` and `from_lipd`](#export-and-import-lipd-with-to_lipd-and-from_lipd)
    - [Other functions](#other-functions)

---

## Requirements

- Python (>=3.11)
- Conda ([Anaconda](https://docs.anaconda.com/anaconda/install/index.html) or [Miniconda](https://docs.conda.io/projects/continuumio-conda/en/latest/user-guide/install/index.html)), or [Pip](https://pip.pypa.io/en/stable/installation/)

Under the hood, dplPy uses `numpy`, `pandas`, `matplotlib`, `statsmodels`, `scipy`, and `csaps`. LiPD import/export (`to_lipd`/`from_lipd`) additionally requires the optional [`pylipd`](https://pypi.org/project/pylipd/) package, installed with the `lipd` extra (`pip install "dplpy[lipd]"`); it is not needed for any other functionality.

dplPy has been successfully tested thus far on Ubuntu 20, Ubuntu 22, macOS (Intel and M2). Other operating systems may experience unexpected errors or conflicts.  Please let the developers know. 

## Current Version

dplPy is currently at version `v0.9.0` - The project uses a unusual development structure where all development will be on `main` (and therefore main is unstable) and then pre/releases and updates to [Pypi](https://pypi.org/project/dplpy/) are first branched to a version number branch and then deployed (an action that is triggered by the creation of the branch). The full documentation, including the user guide and the API reference, is at **[opendendro.github.io/dplPy](https://opendendro.github.io/dplPy/)**; it is built from `main`, so it may describe functions not yet in the PyPI release (see [CHANGELOG.md](CHANGELOG.md)). In Python, `dpl.help()` lists every function and `dpl.help("readers")` shows one function's signature and documentation.

## Installation

dplPy is now available to [install via pip](https://pypi.org/project/dplpy/):

```
pip install dplpy
```

To ensure you have the latest version of dplPy installed, you can run:

```
pip install dplpy --upgrade
```


You can install a conda virtual environment using the [environment.yml for the project](https://github.com/OpenDendro/dplPy/blob/main/environment.yml):

```
$ conda env create -f environment.yml     
```

---


## Building directly from Github

You can still still install dplPy firectly from Github if you wish:

1\. Clone and change directory to this repository


```
$ git clone https://github.com/OpenDendro/dplPy.git
$ cd dplPy
```

2\. Create a conda environment through the `environment.yml` file. This will ensure all packages required are installed.

```
$ conda env create -f environment.yml     

# if you have mamba installed you could instead do

$ mamba env create -f environment.yml
```

When prompted for permission to install required packages (with `y/n`), select `y`.

3\. Activate your environment:

```
$ conda activate dplpy
```

Your environment should be successfully built.

4\. Your python environment should be able to import `numpy`, `pandas`, `matplotlib`, `statsmodels` and `csaps`.

---

## Functionalities and Usage

Import the dplPy tool with
```
import dplpy 
```
or to import with an alias (we will use `dpl`):

```
import dplpy as dpl
```
  
This will load the package and its functions, allowing them to be accessed with the package name or alias given.


### Loading data using  `readers`

- Description: reads data from supported file types (`csv` and `rwl`) and stores them in a year-indexed dataframe (one column per series).
- Options:
    - `header`: whether the `rwl` file has header lines. Default is `None`, which **auto-detects** the number of header lines; pass `header=True`/`False` to force it, or `skip_lines=N` to skip a known number of lines.
    - `strict`: `True` (default) stops on a malformed record; `False` salvages what it can and reports problems.  Users should be very careful using salvage mode. 
- Usage examples:
    ```
    >>> data = dpl.readers("/path/to/file.csv")
    # or (header lines auto-detected)
    >>> data = dpl.readers("/path/to/file.rwl")
    # force header handling, or salvage a messy file
    >>> data = dpl.readers("/path/to/file.rwl", header=True)
    >>> data = dpl.readers("/path/to/file.rwl", strict=False)
    ```

### Loading data from online sources using  `readers_url`

- Description: `readers()` accepts an `http(s)` URL in place of a file path, so a Tucson `rwl` file can be read directly from an online source such as the [NCEI/ITRDB archive](https://www.ncei.noaa.gov/pub/data/paleo/treering/measurements/). `readers_url` is a thin wrapper kept for backward compatibility that forwards to `readers`.
- Options: as for `readers` (`header`, `skip_lines`, `strict`).
- Usage examples:
    ```
    >>> data = dpl.readers("https://www.ncei.noaa.gov/pub/data/paleo/treering/measurements/northamerica/usa/ca533.rwl")
    >>> data = dpl.readers_url("http://link/to/file.rwl", header=True)   # same thing
    ```

### Data Summary from `summary`

- Description: generates a summary of each series recorded in `rwl`  and `csv` format files
- Usage examples:
    ```
    >>> dpl.summary("/path/to/file.rwl")
    # or
    >>> dpl.summary(data)
    ```

### Data Stastics from `stats`

- Description: generates summary statistics for `rwl`  and `csv` format files
- Usage Example:
    ```
    >>> dpl.stats("/path/to/file.rwl")
    # or
    >>> dpl.stats(data)
    ```

### Data Report from `report`

- Description: generates a report about ring measurements and absent rings in the data set
- Usage Example:
    ```
    >>> dpl.report("/path/to/file.rwl")
    # or
    >>> dpl.report(data)
    ```

### Plotting raw data with `plot`

- Description: generates plots of tree-ring data from dataframes. Capable of `seg` (segment, the default), `spag` (spaghetti) and `line` plots.
- Options:
    - `type="seg"`: segment/coverage plot, one bar per series (default)
    - `type="spag"`: spaghetti plot; `color=` takes a colormap name (e.g. `"viridis"`, `"turbo"`) to shade series by first year, or any single colour (default `"black"`)
    - `type="line"`: overplot every series against year
    - `ax=`: draw into an existing matplotlib Axes; `show=False`: return the figure without displaying it (so you can save it). `plot()` returns `(fig, ax)`.
- Usage Example:
    ```
    >>> dpl.plot(data)                     # segment plot (default)
    >>> dpl.plot(data, type="spag")        # spaghetti (black)
    >>> dpl.plot(data, type="spag", color="viridis")   # shade by first year

    # Select specific series of interest (SERIES_1, SERIES_2, SERIES_3):
    >>> dpl.plot(data[["SERIES_1", "SERIES_2", "SERIES_3"]], type="spag")

    # Keep the figure to save it:
    >>> fig, ax = dpl.plot(data, type="seg", show=False)
    >>> fig.savefig("segments.png", dpi=300)
    ```

### Detrending using `detrend`

- Description: Detrends a given series or dataframe, first by fitting a growth curve (`fit`), then by forming the ring-width index as a ratio or difference of the data to the curve (`method`).
- **`fit` chooses the CURVE, `method` chooses the ARITHMETIC** (this differs from dplR, where `method` selects the curve). Names are case-insensitive; the canonical spellings are dplR's.
- Options:
    - `fit=` (the growth curve), one of:
        - `"Spline"` — smoothing spline (default)
        - `"AgeDepSpline"` — age-dependent smoothing spline
        - `"ModNegExp"` — modified negative exponential (with a linear→mean fallback)
        - `"ModHugershoff"` — Hugershoff curve (nonlinear least squares, dplR-style)
        - `"Hugershoff"` — Hugershoff curve (Cook/ARSTAN log-linearised closed form)
        - `"Linear"` — best-fit straight line
        - `"Mean"` — horizontal line at the series mean
        - `fit` may also be a **list** of curves (e.g. `["Spline", "ModNegExp"]`) to compare them.
    - `method="ratio"`: ring-width index = data ÷ curve (default; `"division"` is a synonym)
    - `method="difference"`: ring-width index = data − curve
    - `spline_period=`: stiffness of the `"Spline"` fit (dplR's `nyrs`); default is a 67%-of-length spline, a negative value is an ARSTAN percent-of-length spline.
    - `plot=True|False`: whether to plot results, default `False` (`plot="sequential"` steps through the series one figure at a time).
- Usage Example:
    ```
    # detrend with default options (Spline fit, ratio index)
    >>> rwi = dpl.detrend(data)

    # fit a Hugershoff curve and form the index by difference
    >>> dpl.detrend(data, fit="ModHugershoff", method="difference")

    # detrend only SERIES_1, SERIES_2 and SERIES_3
    >>> dpl.detrend(data[["SERIES_1", "SERIES_2", "SERIES_3"]], fit="ModNegExp")
    ```


### Autoregressive (AR) modeling 

- Description: Contains methods that fit series to autoregressive models and perform functions related to AR modeling.
- Functions:
    - `autoreg(data['Name of series'], ar_max=10)`: returns the parameters of the best-fit AR model of order up to `ar_max`
    - `ar_func(data['Name of series'], ar_max=10)`: returns the residuals plus mean of the best-fit AR model (the prewhitened series); accepts a whole dataframe too
- Options:
    - `ar_max`: maximum AR order considered, default 10 (the ARSTAN/COFECHA cap).
    - `method`: the AR estimator, `"yw"` (Yule-Walker, default, as in R's `ar()`), `"burg"` or `"ols"`.
    - `first_aic_min`: default `True` selects the order at the first local AIC minimum (the ARSTAN/COFECHA rule); `False` takes the global minimum, as R's `ar()` does.
- Usage Example:
    ```
    >>> dpl.autoreg(data[SERIES_1])
    # or
    >>> dpl.ar_func(data[SERIES_2], ar_max=7)
    ```

### Build a chronology with `chron`

- Description: creates a mean value chronology for a dataset, typically the ring width indices of a detrended series. **Note: input data has to be detrended first.**
- Options:
    - `biweight`: find means using Tukey's biweight robust mean; default `True`.
    - `prewhiten`: also return a residual (prewhitened) chronology; default `False`. The AR fit is controlled by `ar_max` (default 10), `ar_method` (default `"yw"`) and `first_aic_min` (default `True`).
    - `plot`: plots results; default `True`.
    - `ci`: also return bootstrap confidence limits on the mean (`conf=0.95`, `R=100` resamples); default `False`.
- Usage Example:
    ```
    # Detrend data first!
    >>> rwi_data = dpl.detrend(data)

    # Perform chronology
    >>> dpl.chron(rwi_data, biweight=False, plot=False)
    ```

### Build a variance stabilized chronology with `chron_stabilized`

- Description: Builds a variance stabilized mean-value chronology for a dataset of **detrended** ring width indices, by multiplying the chronology with the square root of the effective independent sample size, $ Neff $.

    Note: where n(t) is the number of series at time t, and rbar is the running interseries correlation, 

    $$ Neff = { n(t) \over 1+(n(t)-1)rbar(t) } $$

- Options:
    - `window_length`: an integer for specifying the window lengths where interseries correlations will be calculated (default `50`). Should not be greater than the number of years in the dataset, recommended to be between 30% and 50% of the number of years.
    - `spline_period`: for `method="spline"`/`"both"`, the stiffness of the variance-stabilizing spline; default is a 67%-of-length spline (ARSTAN's choice).
    - `min_seg_ratio`: the minimum ratio of non-NA values to the window length for a series to be considered in an Neff calculation (default `0.33`).
    - `biweight`: boolean indicating whether or not to use Tukey's bi-weight robust mean when calculating the mean-value chronology; default `True`.
    - `running_rbar`: boolean indicating whether or not to return the running interseries correlations as part of chronology output; default `False`.
- Usage Example:
    ```
    # Detrend data first!
    >>> rwi_data = dpl.detrend(data)

    # Perform chronology with default args
    >>> dpl.chron_stabilized(rwi_data)

    # Specify window_length, min_seg_ratio and running_rbar
    >>> dpl.chron_stabilized(rwi_data, window_length=60, min_seg_ratio=0.5, running_rbar=True)
    ```

### Crossdate with `xdate`
- Description: This function calculates correlation serially between each tree-ring series and a master chronology built from all the other series in the dataset (leave-one-out principle).
- Options:
    - `prewhiten`: default `True`, determines whether or not to prewhiten series using AR modeling
    - `corr`: default `'Spearman'`, the type of correlation to use. Can be `'Pearson'` or `'Spearman'`.
    - `window_length`: default `50`, the number of years to compare to the master chronology at a time (dplR's `seg.length`).
    - `lag`: default `10`, the lag range searched for a better match (dplR's `lag.max`).
    - `bin_floor`: default `100`, determines the minimum bin year. The minimum bin year is calculated as $ \lceil (min\_yr/bin\_floor)\rceil*bin.floor $ where `min_yr` is the first year in the dataset.
    - `p_val`: default `0.05`, determines the critical value below which interseries correlations are flagged.
    - `show_flags`: default `True`, determines whether to show flags in the function output to the console.
    - `plot`: default `False`; when `True`, also draws the dplR-style crossdating overview (`corr.rwl.seg` / `plot.crs`). (The former name `make_plot` still works as a deprecated alias.)
- Usage examples:
    ```
    >>> ca533_rwi = dpl.detrend(ca533, plot=False)

    # Crossdating of detrended data with default args
    >>> dpl.xdate(ca533_rwi)

    # Crossdating with Pearson correlation, plus the overview plot
    # (other options set to defaults when not specified).
    >>> dpl.xdate(ca533_rwi, corr="Pearson", plot=True)
    ```
- Related: `dpl.xdate_plot(rwi)` draws the crossdating overview on its own; `dpl.series_corr(rwi, "SERIES_1")` gives the per-series moving-correlation and cross-correlation diagnostics (same `window_length`/`lag` vocabulary as `xdate`); `dpl.interseries_corr(rwi)` returns a dict with the mean interseries correlation (`"mean"`) and the per-series table (`"table"`).

### Build an AR-based chronology with `chron_ars`

- Description: builds ARSTAN-style chronologies from **detrended** ring-width indices — the standard mean chronology, the residual (AR-prewhitened) chronology, and the rescaled "ARSTAN" chronology that adds the pooled autoregression back onto the residual chronology.
- Usage Example:
    ```
    >>> rwi = dpl.detrend(data, plot=False)
    >>> dpl.chron_ars(rwi)                 # standard + residual + ARSTAN chronologies
    ```

### Date a floating series with `xdate_floater`

- Description: finds the best calendar placement for an **undated (floating)** ring-width series against a dated master collection, reporting a t-value, autocorrelation-adjusted degrees of freedom, Bonferroni-adjusted p-value and isolation factor for each candidate position (after Wilson 2026).
- Key arguments: `data` (the dated master collection), `series` (the undated series), `min_overlap` (default `50`), `plot=True` for the Wilson-style dating figure.
- Usage Example:
    ```
    # 'master' is a dated rwl/rwi collection; 'floater' is an undated series
    >>> result = dpl.xdate_floater(master, floater, series_name="UNK01", plot=True)
    >>> result["best"]["max_year"], result["best"]["t"]   # best end year and its t-value
    ```

### Date undated series against each other with `xdate_undated`

- Description: when there is **no dated reference** but a set of undated samples overlap one another in time (sub-fossil wood, timbers from one structure), `xdate_undated` crossdates the series against each other and assembles a single relatively-dated floating chronology, in the manner of COFECHA's UFLOAT routine. Each series joins the running mean only if its best t-value reaches `crit_t` (default `4.0`); every placement is then re-checked leave-one-out and flagged for review if ambiguous. The result can be dated absolutely afterwards with `xdate_floater`.
- Usage Example:
    ```
    >>> floating = dpl.xdate_undated(undated_rwl, plot=True)
    >>> floating["offsets"]       # relative start/end of each series
    >>> floating["chronology"]    # the mean floating chronology
    >>> floating["unplaced"]      # series that never reached crit_t
    ```

### Regional Curve Standardization with `rcs`

- Description: detrends by the Regional Curve method — aligning all series by cambial age, fitting one common growth curve, and dividing each series by it (preserves low-frequency/long-timescale variance that per-series detrending removes).
- Options: `po` (a pith-offset table aligning series to cambial age — the offset is the number of rings between the pith and the first measured ring, so `0` means the pith is present; omit `po` to assume `0` for all series), `fit` (the regional-curve type, from the same vocabulary as `detrend` — default `"AgeDepSpline"`, ARSTAN's recommended RCS curve), `method` (`"ratio"` or `"difference"`), `spline_period`/`nyrs0`/`f` (curve stiffness), `pos_slope` (default `False`: a non-increasing old-age end, as in ARSTAN/CRUST), and `plot` (default `True`).
- Usage Example:
    ```
    # po: DataFrame of series -> pith offset (0 = pith present)
    >>> rwi = dpl.rcs(data, po=pith_offsets)                           # default: age-dependent spline, ratios
    >>> rwi = dpl.rcs(data, po=pith_offsets, fit="Spline", spline_period=-10) # fixed 10%-of-length spline
    >>> rwi = dpl.rcs(data, po=pith_offsets, method="difference")      # subtractive index
    ```
- Related: `dpl.sfrcs(data, po=pith_offsets)` is **signal-free** RCS (a port of CRUST's single-curve algorithm), taking the same `method`/`plot` arguments; `dpl.mrcs(data, po=pith_offsets, n_curves=2)` is **multiple-curve** RCS (CRUST), which sorts trees into growth-rate classes and standardizes each by its own curve; `dpl.sfmrcs(...)` is its signal-free counterpart.

### Read chronology files with `read_crn`

- Description: reads Tucson `.crn` chronology files into a dataframe (the read side of `writers(..., format="crn")`).
- Usage Example:
    ```
    >>> crn = dpl.read_crn("/path/to/file.crn")
    ```

### Agreement statistics: `glk` and `sgc`

- Description: `glk` computes Gleichläufigkeit (the sign-agreement / parallel-run statistic) between series; `sgc` computes synchronous growth changes. Both return the pairwise matrix (and, by default, its significance).
- Usage Example:
    ```
    >>> dpl.glk(data)      # Gleichläufigkeit
    >>> dpl.sgc(data)      # synchronous growth changes
    ```

### Mean sensitivity: `sens1` and `sens2`

- Description: `sens1` is the classic mean sensitivity of each series; `sens2` is the alternative (Bunn/dplR) formulation.
- Usage Example:
    ```
    >>> dpl.sens1(data)
    >>> dpl.sens2(data)
    ```

### Average cores to trees with `tree_mean`

- Description: averages multiple cores from the same tree into per-tree series (dplR `treeMean`), given an ID mapping (see `read_ids`).
- Usage Example:
    ```
    >>> ids = dpl.read_ids(data)
    >>> trees = dpl.tree_mean(data, ids)
    ```

### Basal area increment with `bai_out` and `bai_in`

- Description: converts ring widths to basal area increment, the annual cross-sectional area of wood added. `bai_out` works from the outside (bark) in; `bai_in` works from the pith out.
- Options: `diam` (per-series stem diameters) for `bai_out`; `d2pith` (distance-to-pith offsets) for `bai_in`.
- Usage Example:
    ```
    >>> bai = dpl.bai_out(data)                    # radius = summed ring widths
    >>> bai = dpl.bai_out(data, diam=diam_table)   # measured stem diameters
    >>> bai = dpl.bai_in(data, d2pith=d2pith_table)
    ```

### Combine datasets with `combine_rwl`

- Description: merges several ring-width datasets onto the union of their years (a thin wrapper over `pandas`, matching dplR's `combine.rwl`).
- Usage Example:
    ```
    >>> both = dpl.combine_rwl([site_a, site_b])   # or dpl.combine_rwl(site_a, site_b)
    ```

### Output data to files using  `writers`

- Description: writes data from dataframe to supported file types (`csv`, `rwl`, `crn`, `txt`).
- Required parameters: 
    - `data`: dataframe with ring widths (presumably one read from `readers` or `readers_url`)
    - `label`: name (can include file path) to give to the created file. **should not include file extension**
    - `format`: extension for file to be created. Can be `'csv'`, `'rwl'`, `'crn'` or `'txt'`.

- Returns the path of the file written (and prints nothing).
- Usage examples:
    ```
    # Write data to file_name.csv in current working directory.
    >>> dpl.writers(data, "file_name", "csv")
    'file_name.csv'

    # Write data to file_name.csv in ./path/to/ directory.
    >>> dpl.writers(data, "./path/to/file_name", "csv")
    ```
    
### Export and import LiPD with `to_lipd` and `from_lipd`

- Description: writes a completed chronology (and, optionally, the underlying ring widths, running statistics, site metadata and publication info) to a LiPD file, and reads dplPy/ITRDB LiPD files back in. Requires the optional `pylipd` dependency (`pip install "dplpy[lipd]"`).
- Usage Example:
    ```
    >>> rwl = dpl.readers("co021.rwl")
    >>> rwi = dpl.detrend(rwl, plot=False)
    >>> crn = dpl.chron(rwi, plot=False)
    >>> dpl.to_lipd(crn, "co021", rwl=rwl)         # writes co021.lpd
    >>> back = dpl.from_lipd("co021.lpd")          # dict: chronology, rwl, metadata, ...
    ```

### Other functions

These are also available; see each function's docstring (`help(dpl.<name>)`) for details.

| Function | Purpose |
|---|---|
| `series_corr` | per-series crossdating diagnostics (moving correlation + cross-correlation) |
| `interseries_corr` | mean interseries correlation (rbar) for a dataset, as `{"mean", "table"}` |
| `rwi_stats` / `rwi_stats_running` | chronology signal statistics (rbar, EPS, SNR), overall or in a running window |
| `stabilize_chron` | variance-stabilize an already-built chronology (rbar, spline or both; `return_info=True` returns a dict) |
| `sss` | subsample signal strength |
| `samp_stats` | sample-depth statistics through time |
| `common_interval` | find (and optionally plot) the common overlap interval of a dataset |
| `ssf` | simple signal-free standardization |
| `powt` | power transformation of ring widths (Cook & Peters) |
| `ads` | standalone age-dependent smoothing spline |
| `fill_internal` | fill internal missing (NA) values within series |
| `edit_rwl` | insert, delete or change one ring in a series |
| `check` | screen a collection for defects (short series, gaps, outliers, dating) |
| `help` / `readme` | `dpl.help()` lists every function, `dpl.help("name")` documents one; `dpl.readme()` opens the online manual |
| `read_ids` | parse tree/core IDs from series names |
| `po_to_wc` / `wc_to_po` | convert between pith offsets and years-to-pith |
| `SiteMetadata` | container for site metadata (used by the LiPD and `.crn` writers) |

