AcyclePy: Advanced cyclostratigraphy, time series analysis, and paleoclimate toolkit
Project description
AcyclePy — Advanced Cyclostratigraphy and Time Series Analysis Toolkit
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e096ea004a6b21243645b9d4a180dc4ec7da02eb06b31a9470c84e7896e6e60c
|
|
| MD5 |
26afec000733d4d518bd3d1a1ab9b4ba
|
|
| BLAKE2b-256 |
cbc2cde73dcd39ae99e3adc828d12d73449e11ae6291850a9a108658d2a7785e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45b8d100a0ebcfd6b4b6c2018c0950e512baed063f23265e3f78ff9e4dc441ea
|
|
| MD5 |
ace2541fe5fa51bba063b0936c1076ff
|
|
| BLAKE2b-256 |
83b94b594ec76d8dbf83b291afcde3527ede4b299cdc2ae44ae59a705349b7f4
|