Skip to content

Timeseries chainable - #71

Merged
lbusoni merged 14 commits into
masterfrom
timeseries-chainable
Mar 12, 2026
Merged

Timeseries chainable#71
lbusoni merged 14 commits into
masterfrom
timeseries-chainable

Conversation

@lbusoni

@lbusoni lbusoni commented Mar 10, 2026

Copy link
Copy Markdown
Member

Fluent API for TimeSeries

📋 Summary

Implements a chainable fluent API for TimeSeries analysis, replacing method-based operations with property-based chainable operations. All statistical reductions now return TimeSeries objects that can be chained together, with a .value property for final extraction.

🎯 Motivation

Before:

rms_array = ts.ensemble_rms(modes=[2,3,4])
mean_rms = np.mean(rms_array)

After:

mean_rms = ts.filter(modes=[2,3,4]).ensemble_rms.time_mean.value

✨ Features

Chainable Properties

All reduction operations are now chainable properties returning TimeSeries:

Ensemble reductions:

  • ensemble_rms - RMS across ensemble
  • ensemble_mean - Mean (renamed from ensemble_average)
  • ensemble_std - Standard deviation
  • ensemble_median - Median
  • ensemble_ptp - Peak-to-peak

Time reductions:

  • time_mean - Mean (renamed from time_average)
  • time_std - Standard deviation
  • time_rms - RMS
  • time_median - Median
  • time_ptp - Peak-to-peak

New Capabilities

  • .value property: Extract final values (like pandas .values)
  • Bidirectional chaining: ts.ensemble_rms.time_mean and ts.time_mean.ensemble_rms both work
  • filter(**kwargs): Generic upstream filtering
    • Accepts any Indexer kwargs: modes=, elements=, rows=, cols=, times=, etc.
  • with_times(times): Convenient alias for filter(times=...)

📝 Examples

# Basic chaining
mean_rms = ts.ensemble_rms.time_mean.value  # → scalar

# Upstream filtering
result = ts.filter(modes=[2,3,4], times=[1.0, 2.0]).ensemble_rms.time_mean.value

# Time-then-ensemble (NEW!)
long_exposure_ptp = ts.time_mean.ensemble_ptp.value

# Intermediate chainable results
rms_series = ts.filter(modes=[2,3,4]).ensemble_rms  # → TimeSeries
mean = rms_series.time_mean.value  # → scalar

⚠️ Breaking Changes

All reduction methods renamed with get_ prefix:

Old Method Deprecated Method New Property
ts.ensemble_rms() ts.get_ensemble_rms() ts.ensemble_rms.value
ts.ensemble_average() ts.get_ensemble_average() ts.ensemble_mean.value
ts.time_average() ts.get_time_average() ts.time_mean.value
(same for all reductions)

Migration:

  1. Quick fix: ts.method()ts.get_method() (shows DeprecationWarning)
  2. Recommended: Migrate to new property API

🔄 Migration Guide

# Old → Deprecated → New
ts.ensemble_rms()                    → ts.get_ensemble_rms()           → ts.ensemble_rms.value
ts.ensemble_rms(modes=[2,3])        → ts.get_ensemble_rms(modes=[2,3]) → ts.filter(modes=[2,3]).ensemble_rms.value
np.mean(ts.ensemble_rms())          → np.mean(ts.get_ensemble_rms())   → ts.ensemble_rms.time_mean.value
ts.ensemble_average()                → ts.get_ensemble_average()        → ts.ensemble_mean.value
ts.time_average()                    → ts.get_time_average()            → ts.time_mean.value

🧪 Testing

  • 72 tests passing (68 original + 4 new)
  • ⚠️ 21 DeprecationWarnings (expected from legacy methods)
  • Coverage:
    • All ensemble/time reductions
    • 1D ensemble (modal coefficients)
    • 2D ensemble (wavefront maps)
    • Bidirectional chaining
    • Filter combinations
    • MaskedArray support

📚 Documentation

  • Main TimeSeries docstring updated with fluent API examples
  • All properties have comprehensive docstrings
  • Deprecation notices on all legacy get_*() methods

🔧 Implementation Details

  • _create_reduced_series(): Handles ensemble reductions (preserves time axis)
  • _create_temporal_reduced_series(): Handles time reductions (time_size=1)
  • Time vector for temporal reductions: single timestamp = mean of parent times
  • Compatible with MaskedArray and astropy.units

📦 Next Steps

  • Update external packages (membranemirror, KADAT, CiaoCiao, etc.) to use get_*() or new API
  • Add fluent API examples to user documentation

@lbusoni

lbusoni commented Mar 11, 2026

Copy link
Copy Markdown
Member Author

I think that there may be a weird API now. Now ts.value returns the _get_not_indexed_data. If these data is a masked_array then we have to call ts.value.value to access the undelining numpy array. Which is ugly.

@lbusoni
lbusoni requested a review from Copilot March 11, 2026 11:45
@codecov

codecov Bot commented Mar 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.88608% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.49%. Comparing base (7dddca9) to head (e4d3552).
⚠️ Report is 15 commits behind head on master.

Files with missing lines Patch % Lines
arte/time_series/time_series.py 89.08% 25 Missing ⚠️
test/time_series/time_series_test.py 99.63% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #71      +/-   ##
==========================================
+ Coverage   76.49%   77.49%   +1.00%     
==========================================
  Files         185      185              
  Lines       12727    13325     +598     
==========================================
+ Hits         9735    10326     +591     
- Misses       2992     2999       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a fluent/chainable API for TimeSeries reductions and filtering, shifting statistical operations from method calls to chainable properties with a final .value extractor.

Changes:

  • Add chainable reduction properties (ensemble_*, time_*), plus .value and NumPy interoperability (__array__, __array_ufunc__) on TimeSeries.
  • Add upstream filtering via filter(**kwargs) and with_times(...) to enable fluent chaining.
  • Update tests and documentation (incl. a new tutorial notebook) to cover the new fluent API and legacy get_* deprecations.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
arte/time_series/time_series.py Implements fluent API properties, filtering, .value, and NumPy protocol support; adds deprecated get_* wrappers.
arte/time_series/multi_time_series.py Updates docs and adds fluent ensemble-property homogeneity checks + deprecated get_* wrappers for some ensemble ops.
test/time_series/time_series_test.py Updates legacy calls to get_* and adds extensive fluent API tests (chaining, .value, filtering, numpy compatibility).
test/time_series/time_series_ma_test.py Migrates masked-array tests to the fluent API (.time_mean.value, etc.).
test/time_series/multi_time_series_test.py Adjusts tests for fluent properties and homogeneity checks; adds deprecation-warning assertions.
docs/tutorial.rst Adds a Time Series tutorial entry to the docs toctree.
docs/time_series.rst Documents the new fluent API and legacy deprecations.
docs/notebook/time_series/time_series_examples.ipynb Adds a notebook demonstrating the fluent API usage and migration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread arte/time_series/time_series.py
Comment thread arte/time_series/time_series.py
Comment thread arte/time_series/time_series.py
Comment thread arte/time_series/time_series.py
Comment thread arte/time_series/time_series.py
Comment thread arte/time_series/multi_time_series.py

Copilot AI commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

@lbusoni I've opened a new pull request, #72, to work on those changes. Once the pull request is ready, I'll request review from you.

@lbusoni
lbusoni requested a review from alfiopuglisi March 11, 2026 16:20
Comment thread arte/time_series/time_series.py Outdated
Examples
--------
>>> ts = MyTimeSeries(data)
>>> rms = ts.ensemble_rms_property # Returns TimeSeries

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of all things, it is the example that is wrong...

@lbusoni
lbusoni merged commit 4a76487 into master Mar 12, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants