Skip to content

Commit 9621b35

Browse files
Address issue #39 - tested and made sure all feats have a call method.
1 parent a73c7c0 commit 9621b35

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

pyeyesweb/analysis_primitives/bilateral_symmetry.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,5 +229,23 @@ def analyze_frame(self, mocap_frame):
229229
'cca_correlation': overall_cca,
230230
'joint_symmetries': joint_symmetries
231231
}
232-
232+
233+
def __call__(self, mocap_frame):
234+
"""
235+
Compute bilateral symmetry metrics for motion capture frame.
236+
237+
This method provides a standardized API interface by delegating to analyze_frame.
238+
239+
Args:
240+
mocap_frame: (n_joints, 3) array of joint positions for one frame
241+
242+
Returns:
243+
dict: Symmetry metrics containing:
244+
- overall_symmetry: Overall bilateral symmetry score (0-1)
245+
- phase_sync: Phase synchronization value
246+
- cca_correlation: Canonical correlation coefficient
247+
- joint_symmetries: Per-joint-pair symmetry metrics
248+
"""
249+
return self.analyze_frame(mocap_frame)
250+
233251

pyeyesweb/low_level/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
from pyeyesweb.low_level.equilibrium import Equilibrium
1+
from pyeyesweb.low_level.equilibrium import Equilibrium
2+
from pyeyesweb.low_level.contraction_expansion import ContractionExpansion, analyze_movement

pyeyesweb/low_level/contraction_expansion.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,66 @@ def _process_timeseries_3d(data, baseline_frame):
194194
return metrics, indices, states
195195

196196

197+
class ContractionExpansion:
198+
"""Analyze body movement contraction/expansion patterns.
199+
200+
This class provides a standardized API for computing area (2D) or volume (3D)
201+
metrics for body point configurations and tracking expansion/contraction
202+
relative to a baseline.
203+
204+
Parameters
205+
----------
206+
mode : {"2D", "3D", None}, optional
207+
Analysis mode. If None, auto-detects from data dimensions.
208+
baseline_frame : int, optional
209+
Frame index to use as baseline for time series (default: 0).
210+
211+
Examples
212+
--------
213+
>>> # Create analyzer
214+
>>> ce = ContractionExpansion(mode="2D")
215+
>>>
216+
>>> # Single frame analysis
217+
>>> points_2d = np.array([[0, 0], [1, 0], [1, 1], [0, 1]])
218+
>>> result = ce(points_2d)
219+
>>> print(result['metric']) # Area of square
220+
1.0
221+
222+
>>> # Time series analysis
223+
>>> ce_3d = ContractionExpansion(mode="3D", baseline_frame=0)
224+
>>> frames = np.random.randn(100, 4, 3)
225+
>>> result = ce_3d(frames)
226+
>>> print(result['states'][:10]) # First 10 frame states
227+
"""
228+
229+
def __init__(self, mode=None, baseline_frame=0):
230+
self.mode = mode
231+
self.baseline_frame = baseline_frame
232+
233+
def __call__(self, data):
234+
"""Analyze movement data using the configured settings.
235+
236+
Parameters
237+
----------
238+
data : ndarray
239+
Either single frame (4, 2) or (4, 3) for 2D/3D points,
240+
or time series (n_frames, 4, 2) or (n_frames, 4, 3).
241+
242+
Returns
243+
-------
244+
dict
245+
For single frame:
246+
- 'metric': area or volume value
247+
- 'dimension': "2D" or "3D"
248+
For time series:
249+
- 'metrics': array of area/volume values
250+
- 'indices': array of expansion indices relative to baseline
251+
- 'states': array of states (-1=contraction, 0=neutral, 1=expansion)
252+
- 'dimension': "2D" or "3D"
253+
"""
254+
return analyze_movement(data, mode=self.mode, baseline_frame=self.baseline_frame)
255+
256+
197257
def analyze_movement(data, mode=None, baseline_frame=0):
198258
"""Analyze body movement contraction/expansion patterns.
199259

0 commit comments

Comments
 (0)