Skip to main content

AcyclePy: Advanced cyclostratigraphy, time series analysis, and paleoclimate toolkit

Project description

AcyclePy — Advanced Cyclostratigraphy and Time Series Analysis Toolkit

PyPI Python License

AcyclePy is the Python library companion to the Acycle desktop application for cyclostratigraphy, time series analysis, and paleoclimate research. It provides both a programmatic API for scripting and batch processing, and the full suite of Acycle desktop GUI tools.

Reference: Li, M., Hinnov, L., & Kump, L. (2019). Acycle: Time-series analysis software for paleoclimate research and education. Computers & Geosciences, 127, 12-22.


Installation

Requirements

  • Python >= 3.8
  • numpy >= 1.20.0
  • scipy >= 1.6.0
  • pandas >= 1.3.0
  • matplotlib >= 3.3.0
  • PySide6 >= 6.0.0 (GUI tools)
  • scikit-image >= 0.18.0
  • scikit-learn >= 0.24.0
  • Pillow >= 8.0.0
  • qt-material >= 2.0.0 (GUI theming)
  • astropy >= 5.0 (Lomb-Scargle periodogram)

From PyPI

ash pip install acycle

From Source

ash git clone https://github.com/mingsongli/AcyclePy.git cd AcyclePy pip install -e .

Optional Dependencies

`ash

Development tools (testing, linting)

pip install "acycle[dev]"

Full installation with additional I/O support

pip install "acycle[full]"

Includes: sounddevice, h5py, netCDF4

`

Verify Installation

`python import acycle as ac print(ac.version) # e.g., 0.6.7

s = ac.Series(x=[1,2,3], y=[10,20,30]) print(s) # Series(n=3, x=[1, 3] , y_name='y') `


Quick Start

`python import acycle as ac import numpy as np

1. Read time series data

Auto-detect whitespace, tab, or comma-delimited files

s = ac.read_series("data.txt") # whitespace-delimited s = ac.read_series("data.csv", delimiter=",") # comma-delimited s = ac.read_series("data.tsv", delimiter="\t") # tab-delimited

2. Chain operations (fluent API)

s2 = s.clean(sort=True)
.interpolate(step=0.33)
.detrend(window=80)
.standardize()

3. Spectral analysis

from acycle import spectral freq, power = spectral._periodogram(s2.y) # classical freq, power = spectral._mtm_spectrum(s2.y, nw=3) # multitaper freq, power = spectral._lomb_scargle_spectrum( # uneven spacing s2.x, s2.y, fmin=0.001, fmax=0.5)

4. Wavelet analysis

from acycle import wavelet period, power, coi, sig = wavelet.cwt(s2.y, dt=s2.dt) coh = wavelet.wavelet_coherence(s1.y, s2.y, dt=s1.dt)

5. Filtering

from acycle import filter as ft result = ft.apply_filter(y, dt=0.2, kind="bandpass", flow=0.01, fhigh=0.05, method="gaussian") filtered = result["filtered"]

6. Age modeling

from acycle import age model = age.build_age_model(depth, y, cycle_period=405) tuned_x, tuned_y = age.tune(depth, y, model)

7. Load built-in datasets

lr04 = ac.load_example("lr04") # LR04 benthic d18O stack (2115 pts) ceno = ac.load_example("cenogrid_d18o") # CENOGRID d18O la2004 = ac.load_example("la2004_etp") # La2004 ETP solution petm = ac.load_example("petm_logfe") # Svalbard PETM logFe `


Detailed Examples

Example 1: Full Cyclostratigraphic Workflow

`python import acycle as ac import numpy as np

Load LR04 benthic stack

s = ac.load_example("lr04") print(f"Loaded: {s.n} points, dt={s.dt:.2f} ka")

Clean and preprocess

s = s.clean(sort=True, dropna=True)

Interpolate to uniform 1-kyr grid

s = s.interpolate(step=1.0, method="linear")

Detrend with 400-kyr window

s_dt, trend = s.detrend(window=400, method="lowess", return_trend=True)

Spectral analysis (MTM)

from acycle import spectral, PSD freq, power = spectral._mtm_spectrum(s_dt.y, dt=s_dt.dt, nw=3) psd = PSD(frequency=freq, power=power, method="MTM") psd.save("lr04_spectrum") # -> lr04_spectrum_spectrum.csv psd.plot()

Wavelet analysis

from acycle import wavelet period, pow_wav, coi, sig = wavelet.cwt(s_dt.y, dt=s_dt.dt, period_min=2, period_max=500, dj=0.05)

Filter 100-kyr eccentricity band

from acycle import filter as ft, FilterResult fres = ft.apply_filter(s.y, dt=s.dt, kind="bandpass", flow=1/120, fhigh=1/95, method="gaussian") fr = FilterResult(filtered=ac.Series(x=s.x, y=fres["filtered"])) fr.to_dataframe() `

Example 2: Unevenly-Spaced Data

`python import acycle as ac import numpy as np

Generate uneven synthetic data

x = np.sort(np.random.uniform(0, 1000, 200)) y = np.sin(2np.pix/100) + np.sin(2np.pix/41) + 0.5*np.random.randn(200)

Lomb-Scargle for uneven spacing

from acycle import spectral freq, power = spectral._lomb_scargle_spectrum(x, y, fmin=0.001, fmax=0.1, pad=2000)

Find dominant periods

periods = 1.0 / freq peak_idx = np.argsort(power)[-5:] for i in peak_idx[::-1]: print(f"Period: {periods[i]:.1f}, Power: {power[i]:.3f}") `

Example 3: COCO/eCOCO Sedimentation Rate Analysis

`python import acycle as ac import numpy as np

Load data

s = ac.load_example("la2004_etp")

Interpolate to uniform grid

s = s.interpolate(step=1.0)

ETP has eccentricity (~405, ~100 kyr), obliquity (~41 kyr), precession

freq, power = ac.spectral._mtm_spectrum(s.y, dt=s.dt, nw=3)

Build age model by counting 405-kyr cycles

model = ac.age.build_age_model(s.x, s.y, cycle_period=405) print(f"Tie points: {len(model['tie_points'])}")

Tune the series

tuned_x, tuned_y = ac.age.tune(s.x, s.y, model) tuned = ac.Series(x=tuned_x, y=tuned_y, x_name="Age", x_unit="ka") `

Example 4: Merge and Compare Multiple Series

`python import acycle as ac import numpy as np

Load multiple datasets

lr04 = ac.load_example("lr04") ceno = ac.load_example("cenogrid_d18o")

Resample to common grid

lr04_r = lr04.select(0, 5320).interpolate(step=1.0) ceno_r = ceno.select(0, 5320).interpolate(step=1.0)

Merge into DataFrame

from acycle import merge_series df = merge_series([ (lr04_r.x, lr04_r.y, "LR04"), (ceno_r.x, ceno_r.y, "CENOGRID"), ])

Multiply two series

x, y = ac.multiply_series(lr04_r.x, lr04_r.y, ceno_r.y, require_same_x=True) `

Example 5: Data Preprocessing Pipeline

`python import acycle as ac import numpy as np

x = np.arange(0, 100, 0.2) y = np.sin(2np.pix/20) + 0.1x + 0.3np.random.randn(len(x)) s = ac.Series(x=x, y=y, x_name="Depth", x_unit="m", y_name="GR")

Remove outliers above threshold

s_clipped = s.clip_by_threshold(threshold=2.5, side="above", mode="delete")

Remove a known bad section (20-25 m)

s_clean, _ = ac.remove_sections(s_clipped.x, s_clipped.y, [(20, 25)])

Detrend with polynomial

s_dt_lin, trend_lin = ac.detrend(s_clean[0], s_clean[1], window=None, method="polynomial", poly_order=1)

Standardize

s_final = ac.Series(x=s_clean[0], y=s_dt_lin) s_final = s_final.standardize() `


Result Objects

All analysis functions return structured result objects with a consistent interface:

Class Description Key Attributes
PSD Power spectral density requency, power, period
EvolutiveSpectrum Evolutionary (time-varying) spectrum x, requency, power
WaveletResult Wavelet transform x, period, power, coi, significance
FilterResult Filtered signal iltered, mplitude, phase
AgeModel Age-depth model depth, ge, sed_rate, ie_points
CocoResult COCO/eCOCO correlation sed_rate,
ho, p_value
SedNoiseResult DYNOT sedimentation noise ge, median, quantiles

All result classes support:

python result.to_dataframe() # export to pandas DataFrame result.save("prefix") # save to CSV result.plot() # matplotlib figure result.settings # dict of computation parameters


CLI Tools (Acycle Desktop GUI)

These commands launch the original Acycle desktop GUI tools bundled with the package:

ash acycle-imageprocessor # Image digitizing and data extraction acycle-plot # PlotPro — publication-quality plotting acycle-interpolation # Advanced interpolation with gap filling acycle-data-extractor # Extract data segments by range acycle-section-remover # Remove sections from time series acycle-gap-adder # Insert gaps into data acycle-data-clipper # Clip data by threshold acycle-image-analyzer # Advanced image analysis


API Reference

Series Operations

Method Description
Series(x, y) Construct from arrays
Series.from_file(path, ...) Read from delimited text file
.clean(sort, duplicate, dropna) Sort, deduplicate, drop NaN
.interpolate(step, method) Interpolate to uniform grid
.interpolate_pro(step, method) Advanced interpolation with gap filling
.interpolate_to(reference) Interpolate onto another series' x-grid
.detrend(window, method, return_trend) Remove trend
.standardize(ddof) Z-score standardization
.log10(handle_nonpositive) Base-10 logarithm
.derivative(order) Numerical derivative
.prewhiten(method) Prewhitening
.select(start, stop) Sub-range selection
.moving_average(n) Moving average smoothing
.gaussian_smooth(n, sigma) Gaussian smoothing
.moving_median(n) Moving median smoothing
.multiply(other_series) Element-wise multiply with another series
.clip_by_threshold(threshold, side, mode) Clip or remove data by threshold
.to_dataframe() Export to pandas DataFrame
.copy() Deep copy
.dt Median sampling interval (property)
.n Number of points (property)
.history Chain of operations applied

Spectral Analysis (cycle.spectral)

Function Description
_periodogram(y, dt, pad) Classical periodogram
_mtm_spectrum(y, dt, nw, n_tapers, pad) Multitaper method
_lomb_scargle_spectrum(x, y, fmin, fmax, pad) Lomb-Scargle periodogram
_estimate_ar1_rho(y, method) AR(1) lag-1 autocorrelation
_estimate_ar1_noise(y, dt, noise, confidence) AR(1) noise background
_ftest_mtm(y, dt, nw, n_tapers) F-test for significant peaks

Wavelet Analysis (cycle.wavelet)

Function Description
cwt(y, dt, period_min, period_max, dj, mother, param, pad) Continuous wavelet transform
wavelet_coherence(y1, y2, dt, swap, cross_spectrum) Wavelet coherence and phase

Filtering (cycle.filter)

Function Description
pply_filter(y, dt, kind, method, flow, fhigh, fcenter, cutoff, order) Bandpass/lowpass/highpass
dynamic_filter(x, y, window, step, fmin, fmax, lower_bound, upper_bound) Sliding-window dynamic filter
mplitude_modulation(x, y, flow, fhigh, method, interpolate_step) Amplitude envelope extraction

Age Modeling (cycle.age)

Function Description
uild_age_model(x, y, cycle_period, anchor, start_age, age_direction) Cycle-counting age model
sedrate_to_age_model(depth, sedrate, start_age, sedrate_unit) Sed rate to age model
une(depth, y, age_model, direction, interpolation) Depth-to-time conversion
stratigraphic_correlation(reference, target, tie_points) Stratigraphic correlation

Preprocessing (cycle.preprocess)

Function Description
detrend(x, y, window, method, poly_order) Remove trend
clip_by_threshold(x, y, threshold, side, mode) Clip by value

| emove_sections(x, y, sections, adjust_time) | Remove data ranges | | dd_gaps(x, y, gaps) | Insert NaN-filled gaps | | emove_peaks(y, ymin, ymax, mode) | Remove or cap peaks | | multiply_series(x, y1, y2, require_same_x) | Element-wise multiply two series | | merge_series(series_list, require_same_x) | Merge multiple series by x grid | | interpolate_pro(x, y, step, method, fill_large_gaps) | Advanced interpolation | | pca(data, x_col, value_cols, n_components) | Principal component analysis | | changepoint(y, method, penalty, min_size) | Changepoint detection | | ransform_xy(x, y, a, b, c, d) | Affine coordinate transform | | ind_extreme(x, y, start, stop, kind) | Find max or min in range |

I/O (cycle.io)

Function Description

| ead_series(path, columns, delimiter, header, ...) | Read Series from file | | write_series(series, path, sep, header) | Write Series to file | | load_example(name) | Load built-in dataset | | load_lr04(start, stop, step) | Load LR04 benthic stack | | load_cenogrid(variable) | Load CENOGRID isotope data | | extract_columns(path, x_col, y_col) | Extract columns from multi-column file |


Notes & Common Pitfalls

pandas Version Compatibility

This package has been tested with pandas >= 2.0. The delim_whitespace parameter (removed in pandas 2.0) has been replaced with sep=r"\s+" throughout the codebase.

GUI Tools Dependencies

The Acycle desktop GUI tools require a display server (X11, Wayland, or Windows GUI). On headless Linux servers, the programmatic API works without any display. Install with:

`ash

Headless/server: skip GUI dependencies

pip install numpy scipy pandas matplotlib astropy

Desktop: full installation

pip install acycle `

Lomb-Scargle Periodogram

The Lomb-Scargle implementation prefers stropy.timeseries.LombScargle (faster, more features). If astropy is not installed, falls back to scipy.signal.lombscargle.

Lowess/Loess Detrending

The detrend(method="lowess") function prefers statsmodels for robust locally weighted regression. If statsmodels is not installed, falls back to a pure-SciPy implementation. Install for better performance:

ash pip install statsmodels

File Encoding

By default, ead_series() and load_example() use the system locale encoding (commonly cp936/GBK on Chinese Windows). For UTF-8 files, pass encoding="utf-8" explicitly:

python s = ac.read_series("data.txt", encoding="utf-8")

Large Files

For files > 100 MB, consider loading with pandas directly and constructing Series objects:

`python import pandas as pd import acycle as ac

df = pd.read_csv("large_file.csv", usecols=[0, 1]) s = ac.Series(x=df.iloc[:,0].values, y=df.iloc[:,1].values) `


Built-in Datasets

Name Description Points Reference
lr04 LR04 benthic d18O stack 2,115 Lisiecki & Raymo (2005)
cenogrid_d18o CENOGRID benthic d18O 23,659 Westerhold et al. (2020)
cenogrid_d13c CENOGRID benthic d13C 23,666 Westerhold et al. (2020)
la2004_etp La2004 ETP solution 2,001 Laskar et al. (2004)
petm_logfe Svalbard PETM logFe 392 Charles et al. (2011)
wayao_gr Wayao Carnian GR 499 Li et al. (2018)
guandao_gr Guandao Anisian GR 1,071 Li et al. (2018)

| ewark_depth_rank | Newark Basin Depth Rank | — | Olsen & Kent (1999) | | ednoise_0.7_2000 | Synthetic red noise (rho=0.7) | 2,000 | — | | launa_loa_co2 | Mauna Loa CO2 monthly mean | 722 | NOAA | | csa_extinction | CSA extinction data | 10 | — |


Citation

If you use AcyclePy in your research, please cite:

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

License

MIT License — see LICENSE file for details.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

acycle-0.6.8.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

acycle-0.6.8-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file acycle-0.6.8.tar.gz.

File metadata

  • Download URL: acycle-0.6.8.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for acycle-0.6.8.tar.gz
Algorithm Hash digest
SHA256 e096ea004a6b21243645b9d4a180dc4ec7da02eb06b31a9470c84e7896e6e60c
MD5 26afec000733d4d518bd3d1a1ab9b4ba
BLAKE2b-256 cbc2cde73dcd39ae99e3adc828d12d73449e11ae6291850a9a108658d2a7785e

See more details on using hashes here.

File details

Details for the file acycle-0.6.8-py3-none-any.whl.

File metadata

  • Download URL: acycle-0.6.8-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for acycle-0.6.8-py3-none-any.whl
Algorithm Hash digest
SHA256 45b8d100a0ebcfd6b4b6c2018c0950e512baed063f23265e3f78ff9e4dc441ea
MD5 ace2541fe5fa51bba063b0936c1076ff
BLAKE2b-256 83b94b594ec76d8dbf83b291afcde3527ede4b299cdc2ae44ae59a705349b7f4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page