diff --git a/docs/source/bibliography.bib b/docs/source/bibliography.bib index 3a7ab8bbd..f240e2163 100644 --- a/docs/source/bibliography.bib +++ b/docs/source/bibliography.bib @@ -74,5 +74,5 @@ @article{GazeOnFaces number={14}, pages={16--16}, year={2016}, - publisher={The Association for Research in Vision and Ophthalmology} + publisher={The Association for Research in Vision and Ophthalmology}, } diff --git a/src/pymovements/gaze/__init__.py b/src/pymovements/gaze/__init__.py index 0e2ceed5a..dc7d3cf18 100644 --- a/src/pymovements/gaze/__init__.py +++ b/src/pymovements/gaze/__init__.py @@ -63,6 +63,7 @@ from pymovements.gaze.integration import from_numpy from pymovements.gaze.integration import from_pandas from pymovements.gaze.io import from_csv +from pymovements.gaze.io import from_ipc from pymovements.gaze.screen import Screen @@ -75,4 +76,5 @@ 'transforms_numpy', 'transforms', 'from_csv', + 'from_ipc', ] diff --git a/src/pymovements/gaze/io.py b/src/pymovements/gaze/io.py index 81bd391f7..9135864a1 100644 --- a/src/pymovements/gaze/io.py +++ b/src/pymovements/gaze/io.py @@ -106,14 +106,14 @@ def from_csv( │ i64 ┆ i64 ┆ i64 │ ╞══════╪════════════╪════════════╡ │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ + │ 1 ┆ 0 ┆ 0 │ + │ 2 ┆ 0 ┆ 0 │ + │ 3 ┆ 0 ┆ 0 │ │ … ┆ … ┆ … │ - │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ - │ 0 ┆ 0 ┆ 0 │ + │ 6 ┆ 0 ┆ 0 │ + │ 7 ┆ 0 ┆ 0 │ + │ 8 ┆ 0 ┆ 0 │ + │ 9 ┆ 0 ┆ 0 │ └──────┴────────────┴────────────┘ We can now load the data into a ``GazeDataFrame`` by specyfing the experimental setting @@ -132,14 +132,14 @@ def from_csv( │ i64 ┆ list[i64] │ ╞══════╪═══════════╡ │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ + │ 1 ┆ [0, 0] │ + │ 2 ┆ [0, 0] │ + │ 3 ┆ [0, 0] │ │ … ┆ … │ - │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ - │ 0 ┆ [0, 0] │ + │ 6 ┆ [0, 0] │ + │ 7 ┆ [0, 0] │ + │ 8 ┆ [0, 0] │ + │ 9 ┆ [0, 0] │ └──────┴───────────┘ """ @@ -158,3 +158,58 @@ def from_csv( acceleration_columns=acceleration_columns, ) return gaze_df + + +def from_ipc( + file: str | Path, + experiment: Experiment | None = None, + **read_ipc_kwargs: Any, +) -> GazeDataFrame: + """Initialize a :py:class:`pymovements.gaze.gaze_dataframe.GazeDataFrame`. + + Parameters + ---------- + file: + Path of IPC/feather file. + experiment : Experiment + The experiment definition. + **read_ipc_kwargs: + Additional keyword arguments to be passed to polars to read in the ipc file. + + Examples + -------- + Let's assume we have an IPC file stored at `tests/gaze/io/files/monocular_example.feather`. + We can then load the data into a ``GazeDataFrame``: + + >>> from pymovements.gaze.io import from_ipc + >>> gaze = from_ipc( + ... file='tests/gaze/io/files/monocular_example.feather', + ... ) + >>> gaze.frame + shape: (10, 2) + ┌──────┬───────────┐ + │ time ┆ pixel │ + │ --- ┆ --- │ + │ i64 ┆ list[i64] │ + ╞══════╪═══════════╡ + │ 0 ┆ [0, 0] │ + │ 1 ┆ [0, 0] │ + │ 2 ┆ [0, 0] │ + │ 3 ┆ [0, 0] │ + │ … ┆ … │ + │ 6 ┆ [0, 0] │ + │ 7 ┆ [0, 0] │ + │ 8 ┆ [0, 0] │ + │ 9 ┆ [0, 0] │ + └──────┴───────────┘ + + """ + # read data + gaze_data = pl.read_ipc(file, **read_ipc_kwargs) + + # create gaze data frame + gaze_df = GazeDataFrame( + gaze_data, + experiment=experiment, + ) + return gaze_df diff --git a/tests/gaze/io/files/binocular_example.csv b/tests/gaze/io/files/binocular_example.csv index ddfd55ab4..a1f3c95f6 100644 --- a/tests/gaze/io/files/binocular_example.csv +++ b/tests/gaze/io/files/binocular_example.csv @@ -1,11 +1,11 @@ time,x_left_pix,y_left_pix,x_right_pix,y_right_pix,x_left_pos,y_left_pos,x_right_pos,y_right_pos 0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 -0,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +1,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +2,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +3,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +4,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +5,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +6,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +7,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +8,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 +9,0,0,0,0,-23.104783, -13.489493,-23.104783, -13.489493 diff --git a/tests/gaze/io/files/binocular_example.feather b/tests/gaze/io/files/binocular_example.feather new file mode 100644 index 000000000..e52e31be2 Binary files /dev/null and b/tests/gaze/io/files/binocular_example.feather differ diff --git a/tests/gaze/io/files/monocular_example.csv b/tests/gaze/io/files/monocular_example.csv index 5493f10e4..461d3e5f9 100644 --- a/tests/gaze/io/files/monocular_example.csv +++ b/tests/gaze/io/files/monocular_example.csv @@ -1,11 +1,11 @@ time,x_left_pix,y_left_pix 0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 -0,0,0 +1,0,0 +2,0,0 +3,0,0 +4,0,0 +5,0,0 +6,0,0 +7,0,0 +8,0,0 +9,0,0 diff --git a/tests/gaze/io/files/monocular_example.feather b/tests/gaze/io/files/monocular_example.feather new file mode 100644 index 000000000..cdb352ff8 Binary files /dev/null and b/tests/gaze/io/files/monocular_example.feather differ diff --git a/tests/gaze/io/ipc_test.py b/tests/gaze/io/ipc_test.py new file mode 100644 index 000000000..7a91817fa --- /dev/null +++ b/tests/gaze/io/ipc_test.py @@ -0,0 +1,48 @@ +# Copyright (c) 2023 The pymovements Project Authors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Test read from IPC/feather.""" +import pytest + +import pymovements as pm + + +@pytest.mark.parametrize( + ('kwargs', 'shape'), + [ + pytest.param( + { + 'file': 'tests/gaze/io/files/monocular_example.feather', + }, + (10, 2), + id='feather_mono_shape', + ), + pytest.param( + { + 'file': 'tests/gaze/io/files/binocular_example.feather', + }, + (10, 3), + id='feather_bino_shape', + ), + ], +) +def test_shapes(kwargs, shape): + gaze_dataframe = pm.gaze.from_ipc(**kwargs) + + assert gaze_dataframe.frame.shape == shape