Metadata-Version: 2.4
Name: acycle
Version: 0.5.0
Summary: AcyclePy: Advanced cyclostratigraphy and time series analysis toolkit for Python. Provides programmatic API (Series/detrend/spectral/wavelet/filtering/COCO) and full GUI tools for geological data analysis.
Author-email: Acycle Development Team <acycle@example.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/jnccClub/AcyclePy
Project-URL: Repository, https://github.com/jnccClub/AcyclePy.git
Project-URL: Issue Tracker, https://github.com/jnccClub/AcyclePy.git/issues
Project-URL: Documentation, https://github.com/jnccClub/AcyclePy/wiki
Keywords: cyclostratigraphy,time-series,spectral-analysis,wavelet,astronomy,geology,paleoclimate,paleoceanography,MTM,Lomb-Scargle,COCO,age-model,sedimentology
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.20.0
Requires-Dist: pandas>=1.3.0
Requires-Dist: PySide6>=6.0.0
Requires-Dist: matplotlib>=3.3.0
Requires-Dist: scipy>=1.6.0
Requires-Dist: scikit-image>=0.18.0
Requires-Dist: scikit-learn>=0.24.0
Requires-Dist: Pillow>=8.0.0
Requires-Dist: qt-material>=2.0.0
Requires-Dist: astropy>=5.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: flake8>=4.0.0; extra == "dev"
Provides-Extra: full
Requires-Dist: sounddevice>=0.4.0; extra == "full"
Requires-Dist: h5py>=3.0.0; extra == "full"
Requires-Dist: netCDF4>=1.5.0; extra == "full"

﻿# AcyclePy — Advanced Cyclostratigraphy and Time Series Analysis Toolkit

**Version 0.5.0** | [Repository](https://github.com/jnccClub/AcyclePy) | MIT License

AcyclePy is the Python library companion to the Acycle desktop application.
It provides a **programmatic API** for scientific time-series analysis,
cyclostratigraphy, spectral analysis, wavelet analysis, filtering, age
modeling, and astronomical calculations.

The library follows a Pyleoclim-style fluent design: load a time or depth
series, chain preprocessing and analysis calls, then plot or export
results — all in a few lines of code.

```python
import acycle as ac

s = ac.Series.from_file("Example-WayaoCarnianGR0.txt", x_unit="m", y_name="GR")
s2 = s.clean(sort=True).interpolate(step=0.33).detrend(window=80, method="lowess")
psd = s2.spectral(method="mtm", nw=2, noise="robust_ar1", fmax=1.0)
psd.plot(xaxis="period")
```

> **Note:** This package also bundles the full Acycle desktop GUI tools.
> Use `acycle-imageprocessor`, `acycle-plot`, etc. from the command line.

---

## Table of Contents

1. [Installation](#installation)
2. [Quick Start](#quick-start)
3. [Core API — The Series Object](#core-api--the-series-object)
4. [Data I/O](#data-io)
5. [Preprocessing](#preprocessing)
6. [Spectral Analysis](#spectral-analysis)
7. [Wavelet Analysis](#wavelet-analysis)
8. [Time Series Analysis](#time-series-analysis)
9. [Astronomical Calculations](#astronomical-calculations)
10. [Image Processing & Digitizing](#image-processing--digitizing)
11. [Plotting](#plotting)
12. [CLI Tools (GUI)](#cli-tools-gui)
13. [Result Objects](#result-objects)
14. [Example Datasets](#example-datasets)
15. [Contributing](#contributing)

---

## Installation

### From PyPI

```bash
pip install acycle
```

Optional extras:

```bash
pip install acycle[full]   # includes sounddevice, netCDF4, h5py
pip install acycle[dev]    # includes pytest, black, flake8
```

### From Source

```bash
git clone https://github.com/jnccClub/AcyclePy.git
cd AcyclePy
pip install -e .
```

### Requirements

- Python >= 3.8
- numpy, scipy, pandas, matplotlib, astropy
- PySide6 (for GUI tools), qt-material, Pillow

---

## Quick Start

### Load a dataset, clean, interpolate, and compute a power spectrum

```python
import acycle as ac

# Load built-in example data  
s = ac.load_example("la2004_etp")

# Chain preprocessing  
s2 = (
    s.clean(sort=True, dropna=True, duplicate="mean")
     .interpolate(step=2.0, method="linear")
     .detrend(window=800, method="lowess")
)

# Compute power spectrum  
psd = s2.spectral(method="mtm", nw=3, noise="robust_ar1")
psd.plot(xaxis="period")
```

### Generate a synthetic signal and visualize it

```python
import acycle as ac

sig = ac.signal_noise(start=0, stop=1000, step=1, model="sine",
                       amplitude=5, period=100, bias=0)
sig.plot()
```

---

## Core API — The Series Object

### `ac.Series(x, y, **kwargs)`

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `x` | array-like | — | Independent variable (time, depth, age) |
| `y` | array-like | — | Dependent variable (values) |
| `x_name` | str | `"x"` | Name of the x-axis quantity |
| `x_unit` | str | `""` | Unit label (e.g. `"m"`, `"ka"`) |
| `y_name` | str | `"y"` | Name of the y-axis quantity |
| `y_unit` | str | `""` | Unit label (e.g. `"permil"`, `"W/m^2"`) |
| `metadata` | dict | `{}` | Arbitrary metadata |

### Factory: `ac.Series.from_file(path, **kwargs)`

```python
s = ac.Series.from_file(
    "data.txt",
    columns=(0, 1),         # x and y column indices (0-based)
    delimiter=None,          # auto-detect: comma, tab, or whitespace
    x_unit="m", y_unit="permil",
    sort=True, dropna=True, duplicate="mean",
)
```

### Properties

| Property | Returns | Description |
|----------|---------|-------------|
| `s.x`, `s.y` | ndarray | Raw data arrays |
| `s.n` | int | Number of points |
| `s.dt` | float | Median sampling interval |
| `s.x_min`, `s.x_max` | float | X-axis extent |
| `s.history` | list[dict] | Chain of applied operations |

### Chainable Methods (all return a new Series)

| Method | Description |
|--------|-------------|
| `.clean(sort, duplicate, dropna)` | Sort, de-duplicate, drop NaN |
| `.interpolate(step, method)` | Uniform resampling |
| `.interpolate_to(reference)` | Resample onto another Series' grid |
| `.select(start, stop)` | Extract a sub-range |
| `.standardize()` | Z-score transformation |
| `.log10(handle_nonpositive)` | Base-10 logarithm |
| `.derivative(order)` | Numerical derivative |
| `.detrend(window, method)` | Remove long-term trend |
| `.prewhiten(method)` | AR(1) prewhitening |
| `.spectral(method, nw, noise)` | Power spectral density |
| `.wavelet(...)` | Continuous wavelet transform |
| `.filter(kind, method, ...)` | Bandpass/lowpass/highpass filter |
| `.plot(...)` | Quick matplotlib plot |
| `.save_series(path)` | Save to delimited text file |

---

## Data I/O

### `ac.read_series(path, **kwargs)`

Read a two-column series from a delimited text file.

```python
s = ac.read_series(
    "my_data.csv",
    columns=(0, 1),
    delimiter=",",           # auto, tab, comma, space
    x_unit="m", y_name="GR",
    sort=True,
)
```

### `ac.write_series(series, path, sep="\t")`

Save a Series to a text file.

### `ac.load_example(name)`

Load one of the built-in example datasets (see [Example Datasets](#example-datasets)).

### `ac.load_lr04(start=0, stop=5320, step=None)`

Load the LR04 benthic d18O stack.

### `ac.load_cenogrid(variable="d18o")`

Load CENOGRID data (`"d18o"` or `"d13c"`).

---

## Preprocessing

### Cleaning

```python
s2 = s.clean(
    sort=True,               # sort by ascending x
    ascending=True,
    duplicate="mean",        # "mean" | "first" | "last" | "drop"
    dropna=True,
)
```

### Interpolation

```python
# Uniform grid
s2 = s.interpolate(step=0.33, method="linear")

# Or interpolate onto another Series' grid
s2 = s.interpolate_to(reference_series, method="linear")
```

### Detrending

```python
s2 = s.detrend(
    window=0.35,              # window as fraction of record length
    window_unit="fraction",   # "fraction" or "axis"
    method="lowess",          # "linear" | "polynomial" | "lowess" | "loess" | "rlowess" | "rloess" | "moving_mean"
    poly_order=None,
    return_trend=False,       # if True, also returns the trend line
)
```

### Prewhitening

```python
s2 = s.prewhiten(
    method="robust_ar1",      # "classic_ar1" | "robust_ar1" | "user"
    rho=None,                 # user-specified lag-1 coefficient
    diff_when_rho_one=True,
)
```

### Other Preprocessing

```python
s.select(start=10, stop=50)                 # Sub-range extraction
s.standardize(ddof=0)                       # Z-score
s.log10(handle_nonpositive="mask")          # Base-10 log
s.derivative(order=1, edge_order=1)         # Numerical derivative
```

The following are available via the GUI tools and exposed through the
CLI wrappers (see [CLI Tools](#cli-tools-gui)):

- Data clipping by threshold
- Section removal with time adjustment
- Gap insertion
- Peak removal
- Changepoint detection (Bayesian)
- Column manipulation and merging

---

## Spectral Analysis

### `series.spectral(**kwargs)`

Compute the power spectral density.

```python
psd = s.spectral(
    method="mtm",              # "mtm" | "lomb_scargle" | "periodogram"
    nw=2,                      # time-bandwidth product (MTM only)
    n_tapers=None,             # auto: 2*nw - 1
    pad=None,                  # zero-padding length
    fmin=None,                 # minimum frequency
    fmax="nyquist",            # maximum frequency
    xaxis="frequency",         # "frequency" | "period"
    noise="robust_ar1",        # "classic_ar1" | "robust_ar1" | "power_law" | "swa" | None
    confidence=(0.90, 0.95, 0.99, 0.999),
    median_smooth=0.2,         # smoothing window (fraction of max freq)
    output="power",            # "power" | "amplitude" | "ftest"
    save=False,
)
```

**Returns:** `ac.PSD` with attributes `.frequency`, `.power`, `.period`,
`.noise_power`, `.smoothed_power`, `.settings`.

### Plotting a spectrum

```python
psd.plot(xaxis="period")           # period axis (log scale)
psd.plot(xaxis="frequency")        # frequency axis
```

### Evolutionary spectral analysis (via GUI)

Launch the full evolutionary spectral analysis tool:

```python
ac.launch_spectral(data_file="data.txt")
```

---

## Wavelet Analysis

Available through the GUI wavelet analysis tool:

```
acycle-wavelet  (CLI wrapper)
```

The wavelet API (programmatic access planned for v0.6.0):

```python
# Planned API:
wav = s.wavelet(
    mother="MORLET",
    period_min=None, period_max=None,
    dj=0.1, pad=True,
    sig_level=0.05,
)
wav.plot()
```

---

## Time Series Analysis

### Filtering

```python
result = s.filter(
    kind="bandpass",           # "bandpass" | "lowpass" | "highpass"
    method="gaussian",         # "gaussian" | "taner" | "butter" | "cheby1" | "ellip"
    flow=0.01, fhigh=0.05,    # frequency bounds
    remove_mean=True,
    output_amplitude=True,     # include amplitude/phase for taner
)
```

### COCO / eCOCO (Evolutionary Correlation Coefficient)

Available via GUI (programmatic API planned for v0.6.0):

```python
# Planned:
coco = s.coco(
    median_age=230,
    sed_rate=(4.29, 29.89, 0.2),
    n_sim=2000,
    astronomical_solution="La2004",
)
coco.plot()
```

### Age Modeling & Tuning

Available via GUI tools. Programmatic API for build_age_model, tune,
and sediment rate conversion planned for v0.6.0.

### DYNOT / Sediment Noise Models

Available through the GUI `acycle-dynot` tool.

---

## Astronomical Calculations

### `ac.insolation(start, stop, **kwargs)`

Compute solar insolation from an astronomical solution.

```python
ins = ac.insolation(
    0, 1000, step=1,
    solution="La2004",
    day=80, latitude=65,
    solar_constant=1365,
    time_unit="ka",
)
```

### `ac.astronomical_solution(start, stop, **kwargs)`

Retrieve eccentricity, obliquity, precession, and ETP.

```python
ecc = ac.astronomical_solution(0, 1000, step=1, output="eccentricity")
etp = ac.astronomical_solution(0, 1000, step=1, output="ETP",
                                weights=(1, 1, -1), normalize=True)
```

### `ac.milankovitch_calculator(**kwargs)`

Compute Milankovitch cycle periods for a given geological age.

```python
result = ac.milankovitch_calculator(model="Waltham2015", age=100)
# result["earth_moon_distance"], result["day_length"], etc.
```

### `ac.signal_noise(**kwargs)`

Generate synthetic signals for testing.

```python
sine = ac.signal_noise(start=0, stop=1000, model="sine",
                        amplitude=5, period=100)
red = ac.signal_noise(start=0, stop=1000, model="red_noise",
                       mean=0, std=1, rho=0.5, seed=42)
```

---

## Image Processing & Digitizing

Launch the full image processing GUI:

```python
ac.launch_imageprocessor(image="photo.jpg")
```

Features:
- Image magnification with real-time zoom
- Coordinate calibration (pixel to real-world coordinates)
- Color analysis (dominant color detection, K-means clustering)
- Data point extraction (manual, box-select, freehand drawing)
- Image to grayscale / CIE Lab conversion
- Profile digitization
- Undo/Redo support (Ctrl+Z / Ctrl+Y)

---

## Plotting

### `series.plot(**kwargs)`

Quick visualization of a single series:

```python
s.plot(kind="line", color="steelblue", line_width=1.5,
       xlabel="Depth (m)", ylabel="Value", grid=True)
```

### Multi-series plotting

```python
fig, axes = plt.subplots(2, 1, sharex=True)
s1.plot(ax=axes[0], color="red")
s2.plot(ax=axes[1], color="blue")
```

### PlotPro (GUI)

Launch the full interactive PlotPro tool:

```python
ac.launch_plotpro(files=["data1.txt", "data2.txt"])
```

---

## CLI Tools (GUI)

The package installs these command-line entry points:

| Command | Tool | Description |
|---------|------|-------------|
| `acycle-imageprocessor` | Image Processor | Image digitizing and analysis |
| `acycle-plot` | PlotPro | Interactive plotting |
| `acycle-interpolation [file]` | Interpolation Pro | Advanced interpolation |
| `acycle-data-extractor [file]` | Data Extractor | Extract data segments |
| `acycle-section-remover [file]` | Section Remover | Remove with time adjustment |
| `acycle-gap-adder [file]` | Gap Adder | Insert gaps into series |
| `acycle-data-clipper [file]` | Data Clipper | Clip by threshold |
| `acycle-image-analyzer` | Image Analyzer | Advanced image analysis |

From Python:

```python
ac.launch_imageprocessor(image="path/to/image.png")
ac.launch_plotpro(files=["data.txt"])
ac.launch_interpolation(data_file="data.txt", step=0.5)
ac.launch_data_extractor(data_file="data.txt", start=0, stop=100)
```

---

## Result Objects

All analysis results share a consistent interface:

| Object | Used For | Key Attributes |
|--------|----------|---------------|
| `PSD` | Power spectral density | `.frequency`, `.power`, `.period`, `.noise_power`, `.smoothed_power`, `.settings` |
| `EvolutiveSpectrum` | Evolutionary spectrogram | `.x`, `.frequency`, `.power`, `.settings` |
| `WaveletResult` | Wavelet transform | `.x`, `.period`, `.power`, `.coi`, `.significance` |
| `FilterResult` | Filtered signal | `.filtered`, `.amplitude`, `.phase` |
| `AgeModel` | Age model | `.depth`, `.age`, `.sed_rate` |
| `CocoResult` | COCO/eCOCO | `.sed_rate`, `.rho`, `.p_value` |
| `SedNoiseResult` | DYNOT/rho1 | `.age`, `.median`, `.quantiles` |

Every result object supports:

```python
result.plot(...)       # generate a figure
result.to_dataframe()  # export to pandas DataFrame
result.save("prefix")  # save to files
result.settings        # dict of computation parameters
```

---

## Example Datasets

Bundled example datasets can be loaded with `ac.load_example(name)`:

| Name | File | Content |
|------|------|---------|
| `"wayao_gr"` | Example-WayaoCarnianGR0.txt | Gamma-ray log, Carnian |
| `"newark_depth_rank"` | Example-LateTriassicNewarkDepthRank.txt | Newark Basin depth ranks |
| `"la2004_etp"` | Example-La2004-1E.5T-1P-0-2000.txt | La2004 ETP solution |
| `"petm_logfe"` | Example-SvalbardPETM-logFe.txt | PETM log-Fe data |
| `"rednoise_0.7_2000"` | Example-Rednoise0.7-2000.txt | Synthetic red noise |
| `"guandao_gr"` | Example-Guandao2AnisianGR.txt | Guandao Anisian GR |
| `"lr04"` | LR04stack5320ka.txt | LR04 benthic stack |
| `"cenogrid_d13c"` | Example-cenogrid-d13c.txt | CENOGRID d13C |
| `"cenogrid_d18o"` | Example-cenogrid-d18o.txt | CENOGRID d18O |
| `"launa_loa_co2"` | Example-LaunaLoa-Hawaii-CO2-monthly-mean.txt | Mauna Loa CO2 |
| `"csa_extinction"` | Example-CSA-extinction.txt | Extinction event data |

---

## Package Structure

```
acycle/
  __init__.py         # top-level imports and version
  core.py             # Series, MultiSeries, PSD, WaveletResult, etc.
  io.py               # read_series, write_series, load_example, etc.
  spectral.py         # MTM, Lomb-Scargle, periodogram backends
  basic.py            # insolation, astronomical_solution, signal_noise
  cli.py              # CLI compatibility wrappers for GUI tools
  plot/               # PlotPro — interactive matplotlib-based plotting
  math_menu/          # Data processing tools (interpolation, clipping, etc.)
  time_menu/          # Time series analysis (spectral, wavelet, COCO, age, etc.)
  series_menu/        # Astronomical series (solutions, Milankovitch)
  image/              # Image processing and digitizing
  menu/               # Qt menu handler infrastructure
  util/               # General utilities
  window/             # Multi-pane window layout engine
  resources/          # Icons and bundled assets
```

---

## Contributing

Contributions are welcome! Please:

1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Submit a pull request

Development setup:

```bash
git clone https://github.com/jnccClub/AcyclePy.git
cd AcyclePy
pip install -e ".[dev]"
pytest
```

---

## License

MIT License — see [LICENSE](LICENSE) for details.

## Citation

If AcyclePy contributes to a scientific publication, please cite the
Acycle desktop application:

Li, M., Hinnov, L., & Kump, L. (2019). Acycle: Time-series analysis
software for paleoclimate research and education. *Computers &
Geosciences*, 127, 12-22. https://doi.org/10.1016/j.cageo.2019.02.011
