diff --git a/src/pymovements/__init__.py b/src/pymovements/__init__.py index fd52b4827..d7591775a 100644 --- a/src/pymovements/__init__.py +++ b/src/pymovements/__init__.py @@ -21,6 +21,7 @@ from pymovements import _version from pymovements import datasets from pymovements import events +from pymovements import exceptions from pymovements import gaze from pymovements import plotting from pymovements import synthetic @@ -56,6 +57,7 @@ 'Screen', 'GazeDataFrame', + 'exceptions', 'plotting', 'synthetic', 'utils', diff --git a/src/pymovements/events/processing.py b/src/pymovements/events/processing.py index 15a51bf86..5f8b57970 100644 --- a/src/pymovements/events/processing.py +++ b/src/pymovements/events/processing.py @@ -26,10 +26,10 @@ import polars as pl +import pymovements as pm # pylint: disable=cyclic-import from pymovements.events.frame import EventDataFrame from pymovements.events.properties import EVENT_PROPERTIES from pymovements.exceptions import InvalidProperty -from pymovements.gaze.gaze_dataframe import GazeDataFrame class EventProcessor: @@ -140,7 +140,7 @@ def __init__( def process( self, events: EventDataFrame, - gaze: GazeDataFrame, + gaze: pm.GazeDataFrame, identifiers: str | list[str], name: str | None = None, ) -> pl.DataFrame: diff --git a/src/pymovements/gaze/integration.py b/src/pymovements/gaze/integration.py index ec7b5f70a..0d3554ccf 100644 --- a/src/pymovements/gaze/integration.py +++ b/src/pymovements/gaze/integration.py @@ -26,6 +26,7 @@ import pandas as pd import polars as pl +from pymovements.events.frame import EventDataFrame from pymovements.gaze.experiment import Experiment from pymovements.gaze.gaze_dataframe import GazeDataFrame from pymovements.utils import checks @@ -33,13 +34,15 @@ def from_numpy( data: np.ndarray | None = None, + experiment: Experiment | None = None, + events: EventDataFrame | None = None, + *, time: np.ndarray | None = None, pixel: np.ndarray | None = None, position: np.ndarray | None = None, velocity: np.ndarray | None = None, acceleration: np.ndarray | None = None, schema: list[str] | None = None, - experiment: Experiment | None = None, orient: Literal['col', 'row'] = 'col', time_column: str | None = None, pixel_columns: list[str] | None = None, @@ -63,6 +66,10 @@ def from_numpy( ---------- data: Two-dimensional data represented as a numpy ndarray. + experiment : Experiment + The experiment definition. + events: EventDataFrame + A dataframe of events in the gaze signal. time: Array of timestamps. pixel: @@ -77,9 +84,6 @@ def from_numpy( A list of column names. orient: Whether to interpret the two-dimensional data as columns or as rows. - experiment : Experiment - The experiment definition. - time_column: str | None = None, time_column: The name of the timestamp column in the input data frame. pixel_columns: @@ -200,6 +204,7 @@ def from_numpy( return GazeDataFrame( data=df, experiment=experiment, + events=events, time_column=time_column, pixel_columns=pixel_columns, position_columns=position_columns, @@ -245,6 +250,7 @@ def from_numpy( return GazeDataFrame( data=df, experiment=experiment, + events=events, time_column=time_column, pixel_columns=pixel_columns, position_columns=position_columns, @@ -256,6 +262,8 @@ def from_numpy( def from_pandas( data: pd.DataFrame, experiment: Experiment | None = None, + events: EventDataFrame | None = None, + *, time_column: str | None = None, pixel_columns: list[str] | None = None, position_columns: list[str] | None = None, @@ -270,6 +278,8 @@ def from_pandas( Data represented as a pandas DataFrame. experiment : Experiment The experiment definition. + events: EventDataFrame + A dataframe of events in the gaze signal. time_column: The name of the timestamp column in the input data frame. pixel_columns: @@ -289,6 +299,7 @@ def from_pandas( return GazeDataFrame( data=df, experiment=experiment, + events=events, time_column=time_column, pixel_columns=pixel_columns, position_columns=position_columns, diff --git a/tests/gaze/integration_numpy_test.py b/tests/gaze/integration_numpy_test.py index ae39855d2..ed61afedf 100644 --- a/tests/gaze/integration_numpy_test.py +++ b/tests/gaze/integration_numpy_test.py @@ -20,6 +20,7 @@ """Test from gaze.from_numpy.""" import numpy as np import polars as pl +import pytest from polars.testing import assert_frame_equal import pymovements as pm @@ -164,7 +165,7 @@ def test_from_numpy_explicit_columns(): assert gaze.n_components == 2 -def test_init_all_none(): +def test_from_numpy_all_none(): gaze = pm.gaze.from_numpy( data=None, schema=None, @@ -185,3 +186,41 @@ def test_init_all_none(): assert_frame_equal(gaze.frame, expected) assert gaze.n_components is None + + +@pytest.mark.parametrize( + 'events', + [ + pytest.param( + None, + id='events_none', + ), + + pytest.param( + pm.EventDataFrame(), + id='events_empty', + ), + + pytest.param( + pm.EventDataFrame(name='fixation', onsets=[123], offsets=[345]), + id='fixation', + ), + + pytest.param( + pm.EventDataFrame(name='saccade', onsets=[34123], offsets=[67345]), + id='saccade', + ), + + ], +) +def test_from_numpy_events(events): + if events is None: + expected_events = pm.EventDataFrame().frame + else: + expected_events = events.frame + + gaze = pm.gaze.from_numpy(events=events) + + assert_frame_equal(gaze.events.frame, expected_events) + # We don't want the events point to the same reference. + assert gaze.events.frame is not expected_events diff --git a/tests/gaze/integration_pandas_test.py b/tests/gaze/integration_pandas_test.py index 2d1dc2808..082c3b85b 100644 --- a/tests/gaze/integration_pandas_test.py +++ b/tests/gaze/integration_pandas_test.py @@ -20,6 +20,7 @@ """Test from gaze.from_pandas.""" import pandas as pd import polars as pl +import pytest from polars.testing import assert_frame_equal import pymovements as pm @@ -35,15 +36,7 @@ def test_from_pandas(): }, ) - experiment = pm.Experiment( - screen_width_px=1280, - screen_height_px=1024, - screen_width_cm=38, - screen_height_cm=30, - distance_cm=68, - origin='lower left', - sampling_rate=1000.0, - ) + experiment = pm.Experiment(1280, 1024, 38, 30, 68, 'lower left', 1000.0) gaze = pm.gaze.from_pandas( data=pandas_df, @@ -64,15 +57,7 @@ def test_from_pandas_explicit_columns(): }, ) - experiment = pm.Experiment( - screen_width_px=1280, - screen_height_px=1024, - screen_width_cm=38, - screen_height_cm=30, - distance_cm=68, - origin='lower left', - sampling_rate=1000.0, - ) + experiment = pm.Experiment(1280, 1024, 38, 30, 68, 'lower left', 1000.0) gaze = pm.gaze.from_pandas( data=pandas_df, @@ -87,3 +72,45 @@ def test_from_pandas_explicit_columns(): }) assert_frame_equal(gaze.frame, expected) + + +@pytest.mark.parametrize( + ('df', 'events'), + [ + pytest.param( + pd.DataFrame(), + None, + id='events_none', + ), + + pytest.param( + pd.DataFrame(), + pm.EventDataFrame(), + id='events_empty', + ), + + pytest.param( + pd.DataFrame(), + pm.EventDataFrame(name='fixation', onsets=[123], offsets=[345]), + id='fixation', + ), + + pytest.param( + pd.DataFrame(), + pm.EventDataFrame(name='saccade', onsets=[34123], offsets=[67345]), + id='saccade', + ), + + ], +) +def test_from_pandas_events(df, events): + if events is None: + expected_events = pm.EventDataFrame().frame + else: + expected_events = events.frame + + gaze = pm.gaze.from_pandas(data=df, events=events) + + assert_frame_equal(gaze.events.frame, expected_events) + # We don't want the events point to the same reference. + assert gaze.events.frame is not expected_events