From 4edba55a69ab7b733cfb011f99c9834540e5aa3c Mon Sep 17 00:00:00 2001 From: prassepaul Date: Fri, 22 Sep 2023 18:25:25 +0200 Subject: [PATCH] feat: Add gaze.from_ipc() (#568) --- docs/source/bibliography.bib | 2 +- src/pymovements/gaze/__init__.py | 2 + src/pymovements/gaze/io.py | 83 +++++++++++++++--- tests/gaze/io/files/binocular_example.csv | 18 ++-- tests/gaze/io/files/binocular_example.feather | Bin 0 -> 2239 bytes tests/gaze/io/files/monocular_example.csv | 18 ++-- tests/gaze/io/files/monocular_example.feather | Bin 0 -> 1295 bytes tests/gaze/io/ipc_test.py | 48 ++++++++++ 8 files changed, 138 insertions(+), 33 deletions(-) create mode 100644 tests/gaze/io/files/binocular_example.feather create mode 100644 tests/gaze/io/files/monocular_example.feather create mode 100644 tests/gaze/io/ipc_test.py 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 0000000000000000000000000000000000000000..e52e31be25c842e5c9a709640379f21d53dfa3c2 GIT binary patch literal 2239 zcmeHJy-EW?5S}DwyqpJ~Q6Y#$3JVbgt+Wv?ot+_#K7c6>j0u<`r4L|XV=KOhaPN?J zun;S;kRZhG+uf1lh~f`wlR5TgXXe|Py_vh&YqVMihub1!&}Biy6Ol*Em%u%NLIRl+ zA9qilp%0<)anV}By#~mIkwhL~?_qvSJw{rN; z1YA+dxIA1UNx$8p{snq!xRYM@Ea@lRQ|jq=0Dgk;nLX?RS66It@*bYxGX{p)@TFp+ zPTI>1?7d{rW^C@`C%*ehrwuozF8c_qIWrUJZGB1-%A(0z2*Vv>23!P6F^I7gVD14M zp^ooU)0xh55S5Qq&qQR&$+2?eF-x(Nb$yz%tE}s}mbuLDH7~DcgG|8Z?OC`!f^LQH zGKqO6F+Qnmnan!Q_l;Ds?Av#ZqyG3^ks{09YFBges^fLX*Bt-o869NGejx+@Rlmk& zd49OEliu%L4X;NV=~Vt&KF}h^d>!<=W1o&8vsc@mD(I6{e1|++?0I$LnnhEah87=d SNYiuikI%(h6ry2%TwVb)SUQOS literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..cdb352ff82b8cf8a51e2ff5652e445dbc9dc9558 GIT binary patch literal 1295 zcmd^9J5B>J5PcyAoMnYJ3z1TC1qvj}J-=zu?GYIFVv4I1L#1314MoU-smssiTo+L!|z?v zfG5V5)Ni=PT)h!cp(d-sF!9TjP5H$=r##_GTqf#r8Nw@h6G~MPF<`F91+`b%_SKRVu$O3x1w`Gt&)A9c25r z!uR$4d>>7m;Ahbs3Wp}xVMCqePiM@Oe- UOpf3)ZWgxZy`QlW)AUF90T5$zi~s-t literal 0 HcmV?d00001 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