Repository: aeye-lab/pymovements
Pull request #462 (2023-07-13 20:04:27)

chore!: Remove unused event detection args
## Description

Fixes issue #442 

## Implemented changes

- remove `velocities` argument from `idt`
- remove `positions` argument from `ivt`
- remove `positions` argument from `microsaccades`
- remove `velocities` and `positions` argument from `fill`
- adjusted `check_shapes` method for use with single (and multiple) arguments 
- adjusted corresponding tests

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

- also removed described arguments from tests of each event detection method

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules
- [x] I have checked my code and corrected any misspellings


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) Report
Patch coverage: **`100.00%`** and no project coverage change.
> Comparison is base [(`2a6cc39`)](https://app.codecov.io/gh/aeye-lab/pymovements/commit/2a6cc398688cfeb25107d4cb2c7444cc90b69b50?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) 100.00% compared to head [(`07d6267`)](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) 100.00%.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main      #462   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           48        48           
  Lines         2086      2080    -6     
  Branches       500       502    +2     
=========================================
- Hits          2086      2080    -6     
```


| [Files Changed](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) | Coverage Δ | |
|---|---|---|
| [src/pymovements/events/detection/\_microsaccades.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL2V2ZW50cy9kZXRlY3Rpb24vX21pY3Jvc2FjY2FkZXMucHk=) | `100.00% <ø> (ø)` | |
| [src/pymovements/dataset/dataset.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL2RhdGFzZXQvZGF0YXNldC5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/pymovements/events/detection/\_fill.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL2V2ZW50cy9kZXRlY3Rpb24vX2ZpbGwucHk=) | `100.00% <100.00%> (ø)` | |
| [src/pymovements/events/detection/\_idt.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL2V2ZW50cy9kZXRlY3Rpb24vX2lkdC5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/pymovements/events/detection/\_ivt.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL2V2ZW50cy9kZXRlY3Rpb24vX2l2dC5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/pymovements/utils/checks.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL3V0aWxzL2NoZWNrcy5weQ==) | `100.00% <100.00%> (ø)` | |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/aeye-lab/pymovements/pull/462?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab).


Patch:
diff --git a/src/pymovements/dataset/dataset.py b/src/pymovements/dataset/dataset.py
index f5ebf17..727c123 100644
--- a/src/pymovements/dataset/dataset.py
+++ b/src/pymovements/dataset/dataset.py
@@ -477,12 +477,20 @@ class Dataset:
             velocities = gaze_df.frame.select(velocity_columns).to_numpy()
             timesteps = gaze_df.frame.get_column('time').to_numpy()
 
-            if 'events' in inspect.getfullargspec(method).args:
+            method_args = inspect.getfullargspec(method).args
+
+            if 'positions' in method_args:
+                kwargs['positions'] = positions
+
+            if 'velocities' in method_args:
+                kwargs['velocities'] = velocities
+
+            if 'events' in method_args:
                 kwargs['events'] = self.events[file_id]
 
-            new_event_df = method(
-                positions=positions, velocities=velocities, timesteps=timesteps, **kwargs,
-            )
+            kwargs['timesteps'] = timesteps
+
+            new_event_df = method(**kwargs)
 
             new_event_df.frame = dataset_files.add_fileinfo(
                 definition=self.definition,
diff --git a/src/pymovements/events/detection/_fill.py b/src/pymovements/events/detection/_fill.py
index 7765040..21946c3 100644
--- a/src/pymovements/events/detection/_fill.py
+++ b/src/pymovements/events/detection/_fill.py
@@ -27,15 +27,12 @@ import numpy as np
 from pymovements.events.detection._library import register_event_detection
 from pymovements.events.frame import EventDataFrame
 from pymovements.gaze.transforms_numpy import consecutive
-from pymovements.utils import checks
 
 
 @register_event_detection
 def fill(
         events: EventDataFrame,
-        positions: list[list[float]] | list[tuple[float, float]] | np.ndarray,
-        velocities: list[list[float]] | list[tuple[float, float]] | np.ndarray,
-        timesteps: list[int] | np.ndarray | None = None,
+        timesteps: list[int] | np.ndarray,
         minimum_duration: int = 1,
         name: str = 'unclassified',
 ) -> EventDataFrame:
@@ -46,16 +43,10 @@ def fill(
     ----------
     events:
         The already detected events.
-    positions: array-like, shape (N, 2)
-        Continuous 2D position time series.
-    velocities: array-like, shape (N, 2)
-        Corresponding continuous 2D velocity time series.
     timesteps: array-like, shape (N, )
-        Corresponding continuous 1D timestep time series. If None, sample based timesteps are
-        assumed.
+        Continuous 1D timestep time series.
     minimum_duration: int
         Minimum fixation duration. The duration is specified in the units used in ``timesteps``.
-         If ``timesteps`` is None, then ``minimum_duration`` is specified in numbers of samples.
     name:
         Name for detected events in EventDataFrame.
 
@@ -63,28 +54,12 @@ def fill(
     -------
     pl.DataFrame
         A dataframe with detected fixations as rows.
-
-    Raises
-    ------
-    ValueError
-        If positions or velocities are None
-        If positions or velocities do not have shape (N, 2)
-        If positions and velocities have different shapes
-        If velocity threshold is None.
-        If velocity threshold is not greater than 0.
     """
-    positions = np.array(positions)
-    velocities = np.array(velocities)
-
-    checks.check_shapes_positions_velocities(positions=positions, velocities=velocities)
 
-    if timesteps is None:
-        timesteps = np.arange(len(velocities), dtype=np.int64)
     timesteps = np.array(timesteps)
-    checks.check_is_length_matching(velocities=velocities, timesteps=timesteps)
 
     # Create binary mask where each existing event is marked.
-    events_mask = np.zeros(len(positions), dtype=bool)
+    events_mask = np.zeros(len(timesteps), dtype=bool)
 
     for row in events.frame.iter_rows(named=True):
         idx_onset = np.where(timesteps == row['onset'])[0][0]
diff --git a/src/pymovements/events/detection/_idt.py b/src/pymovements/events/detection/_idt.py
index 66f9d0f..72f0cd9 100644
--- a/src/pymovements/events/detection/_idt.py
+++ b/src/pymovements/events/detection/_idt.py
@@ -54,7 +54,6 @@ def dispersion(positions: list[list[float]] | np.ndarray) -> float:
 @register_event_detection
 def idt(
         positions: list[list[float]] | list[tuple[float, float]] | np.ndarray,
-        velocities: list[list[float]] | list[tuple[float, float]] | np.ndarray,
         timesteps: list[int] | np.ndarray | None = None,
         minimum_duration: int = 100,
         dispersion_threshold: float = 1.0,
@@ -77,8 +76,6 @@ def idt(
     ----------
     positions: array-like, shape (N, 2)
         Continuous 2D position time series
-    velocities: array-like, shape (N, 2)
-        Corresponding continuous 2D velocity time series.
     timesteps: array-like, shape (N, )
         Corresponding continuous 1D timestep time series. If None, sample based timesteps are
         assumed.
@@ -107,11 +104,11 @@ def idt(
         If duration_threshold is not greater than 0
     """
     positions = np.array(positions)
-    velocities = np.array(velocities)
-    checks.check_shapes_positions_velocities(positions=positions, velocities=velocities)
+
+    checks.check_shapes(positions=positions)
 
     if timesteps is None:
-        timesteps = np.arange(len(velocities), dtype=np.int64)
+        timesteps = np.arange(len(positions), dtype=np.int64)
     timesteps = np.array(timesteps).flatten()
 
     # Check that timesteps are integers or are floats without a fractional part.
@@ -120,7 +117,7 @@ def idt(
         raise TypeError('timesteps must be of type int')
     timesteps = timesteps_int
 
-    checks.check_is_length_matching(velocities=velocities, timesteps=timesteps)
+    checks.check_is_length_matching(positions=positions, timesteps=timesteps)
 
     if dispersion_threshold <= 0:
         raise ValueError('dispersion_threshold must be greater than 0')
diff --git a/src/pymovements/events/detection/_ivt.py b/src/pymovements/events/detection/_ivt.py
index aec9a52..a34cd47 100644
--- a/src/pymovements/events/detection/_ivt.py
+++ b/src/pymovements/events/detection/_ivt.py
@@ -34,7 +34,6 @@ from pymovements.utils.filters import filter_candidates_remove_nans
 
 @register_event_detection
 def ivt(
-        positions: list[list[float]] | list[tuple[float, float]] | np.ndarray,
         velocities: list[list[float]] | list[tuple[float, float]] | np.ndarray,
         timesteps: list[int] | np.ndarray | None = None,
         minimum_duration: int = 100,
@@ -54,8 +53,6 @@ def ivt(
 
     Parameters
     ----------
-    positions: array-like, shape (N, 2)
-        Continuous 2D position time series.
     velocities: array-like, shape (N, 2)
         Corresponding continuous 2D velocity time series.
     timesteps: array-like, shape (N, )
@@ -80,16 +77,15 @@ def ivt(
     Raises
     ------
     ValueError
-        If positions or velocities are None
-        If positions or velocities do not have shape (N, 2)
-        If positions and velocities have different shapes
+        If velocities is None
+        If velocities does not have shape (N, 2)
         If velocity threshold is None.
         If velocity threshold is not greater than 0.
     """
-    positions = np.array(positions)
     velocities = np.array(velocities)
 
-    checks.check_shapes_positions_velocities(positions=positions, velocities=velocities)
+    checks.check_shapes(velocities=velocities)
+
     if velocity_threshold is None:
         raise ValueError('velocity threshold must not be None')
     if velocity_threshold <= 0:
diff --git a/src/pymovements/events/detection/_microsaccades.py b/src/pymovements/events/detection/_microsaccades.py
index 15f654c..3654da1 100644
--- a/src/pymovements/events/detection/_microsaccades.py
+++ b/src/pymovements/events/detection/_microsaccades.py
@@ -35,7 +35,6 @@ from pymovements.utils.filters import filter_candidates_remove_nans
 
 @register_event_detection
 def microsaccades(
-        positions: list[list[float]] | list[tuple[float, float]] | np.ndarray,
         velocities: list[list[float]] | list[tuple[float, float]] | np.ndarray,
         timesteps: list[int] | np.ndarray | None = None,
         minimum_duration: int = 6,
@@ -56,8 +55,6 @@ def microsaccades(
 
     Parameters
     ----------
-    positions : np.ndarray, shape (N, 2)
-        x and y positions of N samples in chronological order
     velocities : np.ndarray, shape (N, 2)
         x and y velocities of N samples in chronological order
     timesteps: array-like, shape (N, )
@@ -91,11 +88,8 @@ def microsaccades(
         If `threshold` value is below `min_threshold` value.
         If passed `threshold` is either not two-dimensional or not a supported method.
     """
-    positions = np.array(positions)
     velocities = np.array(velocities)
 
-    checks.check_shapes_positions_velocities(positions=positions, velocities=velocities)
-
     if timesteps is None:
         timesteps = np.arange(len(velocities), dtype=np.int64)
     timesteps = np.array(timesteps)
diff --git a/src/pymovements/utils/checks.py b/src/pymovements/utils/checks.py
index 053adfb..4fc06a3 100644
--- a/src/pymovements/utils/checks.py
+++ b/src/pymovements/utils/checks.py
@@ -66,32 +66,30 @@ def check_nan_both_channels(arr: np.ndarray) -> None:
         )
 
 
-def check_shapes_positions_velocities(positions: np.ndarray, velocities: np.ndarray) -> None:
-    """Checks if positions and velocities are of shape ``(N, 2)`` and shape is equal for both.
+def check_shapes(**kwargs: Any) -> None:
+    """Checks if all provided arrays are of shape ``(N, 2)`` and shape is equal for all arrays.
 
     Parameters
     ----------
-    positions : np.ndarray
-        The positions array.
-    velocities : np.ndarray
-        The velocities array.
+    kwargs
+        Keyword argument dictionary with 2 keyword arguments.
 
     Raises
     ------
     ValueError
-        If positions or velocities are not of shape ``(N, 2)`` or the shape is not equal for both.
+        If any of the arrays is not of shape ``(N, 2)`` or if the shapes are not equal.
     """
-    # make sure positions and velocities have shape (N, 2)
-    if positions.ndim != 2 or positions.shape[1] != 2:
-        raise ValueError(f'positions must have shape (N, 2) but have shape {positions.shape}')
-    if velocities.ndim != 2 or velocities.shape[1] != 2:
-        raise ValueError(f'velocities must have shape (N, 2) but have shape {velocities.shape}')
-
-    # Check matching shape for positions and velocities
-    if positions.shape != velocities.shape:
+
+    for key, array in kwargs.items():
+        if array.ndim != 2 or array.shape[1] != 2:
+            raise ValueError(f'{key} must have shape (N, 2) but have shape {array.shape}')
+
+    # Check if shapes are equal, printing the key of the first array that is not equal
+    if not all(array.shape == next(iter(kwargs.values())).shape for array in kwargs.values()):
         raise ValueError(
-            f'shape of positions {positions.shape} does not match'
-            f' shape of velocities {velocities.shape}',
+            f'{", ".join(key for key in kwargs)}'
+            f' must have the same shape, but shapes are '
+            f'{", ".join(str(array.shape) for array in kwargs.values())}',
         )
 
 


Test patch:
diff --git a/tests/dataset/dataset_test.py b/tests/dataset/dataset_test.py
index d1b7c58..c45bc86 100644
--- a/tests/dataset/dataset_test.py
+++ b/tests/dataset/dataset_test.py
@@ -581,6 +581,13 @@ def test_pos2vel(dataset_configuration):
             },
             id='microsaccades_string',
         ),
+        pytest.param(
+            {
+                'method': pm.events.fill,
+                'eye': 'auto',
+            },
+            id='fill_class',
+        ),
         pytest.param(
             {
                 'method': 'fill',
@@ -588,6 +595,38 @@ def test_pos2vel(dataset_configuration):
             },
             id='fill_string',
         ),
+        pytest.param(
+            {
+                'method': 'ivt',
+                'velocity_threshold': 1,
+                'minimum_duration': 1,
+                'eye': 'auto',
+            },
+            id='ivt_string',
+        ),
+        pytest.param(
+            {
+                'method': pm.events.ivt,
+                'velocity_threshold': 1,
+                'minimum_duration': 1,
+                'eye': 'auto',
+            },
+            id='ivt_class',
+        ),
+        pytest.param(
+            {
+                'method': 'idt',
+                'eye': 'auto',
+            },
+            id='idt_string',
+        ),
+        pytest.param(
+            {
+                'method': pm.events.idt,
+                'eye': 'auto',
+            },
+            id='idt_class',
+        ),
     ],
 )
 def test_detect_events_auto_eye(detect_event_kwargs, dataset_configuration):
diff --git a/tests/events/detection/fill_test.py b/tests/events/detection/fill_test.py
index 1fc2c2b..34aebbb 100644
--- a/tests/events/detection/fill_test.py
+++ b/tests/events/detection/fill_test.py
@@ -27,114 +27,13 @@ from polars.testing import assert_frame_equal
 import pymovements as pm
 
 
-@pytest.mark.parametrize(
-    ('kwargs', 'expected_error'),
-    [
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': None,
-                'velocities': np.ones((100, 2)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_none_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 2)),
-                'velocities': None,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='velocities_none_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': 1,
-                'velocities': np.ones((100, 2)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_array_like_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 2)),
-                'velocities': 1,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='velocities_not_array_like_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones(100),
-                'velocities': np.ones((100, 2)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_2d_array_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 2)),
-                'velocities': np.ones(100),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='velocities_not_2d_array_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 3)),
-                'velocities': np.ones((100, 2)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_2_elements_in_second_dimension_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 2)),
-                'velocities': np.ones((100, 3)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='velocities_not_2_elements_in_second_dimension_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'events': pm.EventDataFrame(),
-                'positions': np.ones((100, 2)),
-                'velocities': np.ones((101, 2)),
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_and_velocities_different_lengths_raises_value_error',
-        ),
-    ],
-)
-def test_fill_raise_error(kwargs, expected_error):
-    """Test if ivt raises expected error."""
-    with pytest.raises(expected_error):
-        pm.events.fill(**kwargs)
-
-
 @pytest.mark.parametrize(
     ('kwargs', 'expected'),
     [
         pytest.param(
             {
                 'events': pm.EventDataFrame(name='fixation', onsets=[0], offsets=[100]),
-                'positions': np.stack([np.arange(0, 100), np.arange(0, 100)], axis=1),
+                'timesteps': np.arange(0, 100),
             },
             pm.EventDataFrame(),
             id='fixation_from_start_to_end_no_fill',
@@ -142,7 +41,7 @@ def test_fill_raise_error(kwargs, expected_error):
         pytest.param(
             {
                 'events': pm.EventDataFrame(name='fixation', onsets=[10], offsets=[100]),
-                'positions': np.stack([np.arange(0, 100), np.arange(0, 100)], axis=1),
+                'timesteps': np.arange(0, 100),
             },
             pm.EventDataFrame(
                 name='unclassified',
@@ -154,7 +53,7 @@ def test_fill_raise_error(kwargs, expected_error):
         pytest.param(
             {
                 'events': pm.EventDataFrame(name='fixation', onsets=[0], offsets=[90]),
-                'positions': np.stack([np.arange(0, 100), np.arange(0, 100)], axis=1),
+                'timesteps': np.arange(0, 100),
             },
             pm.EventDataFrame(
                 name='unclassified',
@@ -166,7 +65,7 @@ def test_fill_raise_error(kwargs, expected_error):
         pytest.param(
             {
                 'events': pm.EventDataFrame(name='fixation', onsets=[0, 50], offsets=[40, 100]),
-                'positions': np.stack([np.arange(0, 100), np.arange(0, 100)], axis=1),
+                'timesteps': np.arange(0, 100),
             },
             pm.EventDataFrame(
                 name='unclassified',
@@ -180,7 +79,7 @@ def test_fill_raise_error(kwargs, expected_error):
                 'events': pm.EventDataFrame(
                     name=['fixation', 'saccade'], onsets=[0, 50], offsets=[40, 100],
                 ),
-                'positions': np.stack([np.arange(0, 100), np.arange(0, 100)], axis=1),
+                'timesteps': np.arange(0, 100),
             },
             pm.EventDataFrame(
                 name='unclassified',
@@ -192,9 +91,6 @@ def test_fill_raise_error(kwargs, expected_error):
     ],
 )
 def test_fill_fills_events(kwargs, expected):
-    velocities = pm.gaze.transforms_numpy.pos2vel(
-        kwargs['positions'], sampling_rate=10, method='preceding',
-    )
-    events = pm.events.fill(velocities=velocities, **kwargs)
+    events = pm.events.fill(**kwargs)
 
     assert_frame_equal(events.frame, expected.frame)
diff --git a/tests/events/detection/idt_test.py b/tests/events/detection/idt_test.py
index bca281f..4695df1 100644
--- a/tests/events/detection/idt_test.py
+++ b/tests/events/detection/idt_test.py
@@ -32,7 +32,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': None,
-                'velocities': None,
                 'dispersion_threshold': 1,
                 'minimum_duration': 1,
             },
@@ -42,7 +41,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2], [1, 2]],
-                'velocities': [[1, 2], [1, 2]],
                 'dispersion_threshold': None,
                 'minimum_duration': 1,
             },
@@ -52,7 +50,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2], [1, 2]],
-                'velocities': [[1, 2], [1, 2]],
                 'dispersion_threshold': 1,
                 'minimum_duration': None,
             },
@@ -62,7 +59,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': 1,
-                'velocities': 1,
                 'dispersion_threshold': 1,
                 'minimum_duration': 1,
             },
@@ -72,7 +68,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [1, 2, 3],
-                'velocities': [1, 2, 3],
                 'dispersion_threshold': 1,
                 'minimum_duration': 1,
             },
@@ -82,7 +77,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2, 3], [1, 2, 3]],
-                'velocities': [[1, 2, 3], [1, 2, 3]],
                 'dispersion_threshold': 1,
                 'minimum_duration': 1,
             },
@@ -92,7 +86,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2], [1, 2]],
-                'velocities': [[1, 2], [1, 2]],
                 'dispersion_threshold': 0,
                 'minimum_duration': 1,
             },
@@ -102,7 +95,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2], [1, 2]],
-                'velocities': [[1, 2], [1, 2]],
                 'dispersion_threshold': 1,
                 'minimum_duration': 0,
             },
@@ -112,7 +104,6 @@ from pymovements.synthetic import step_function
         pytest.param(
             {
                 'positions': [[1, 2], [1, 2]],
-                'velocities': [[1, 2], [1, 2]],
                 'dispersion_threshold': 1,
                 'minimum_duration': 1.1,
             },
@@ -269,10 +260,7 @@ def test_idt_raises_error(kwargs, expected_error):
 )
 def test_idt_detects_fixations(kwargs, expected):
     """Test if idt detects fixations."""
-    velocities = pm.gaze.transforms_numpy.pos2vel(
-        kwargs['positions'], sampling_rate=10, method='preceding',
-    )
-    events = pm.events.idt(velocities=velocities, **kwargs)
+    events = pm.events.idt(**kwargs)
 
     assert_frame_equal(events.frame, expected.frame)
 
@@ -324,11 +312,8 @@ def test_idt_detects_fixations(kwargs, expected):
     ],
 )
 def test_idt_timesteps_exceptions(kwargs, exception, msg_substrings):
-    velocities = pm.gaze.transforms_numpy.pos2vel(
-        kwargs['positions'], sampling_rate=10, method='preceding',
-    )
     with pytest.raises(exception) as excinfo:
-        pm.events.idt(velocities=velocities, **kwargs)
+        pm.events.idt(**kwargs)
 
     msg, = excinfo.value.args
     for msg_substring in msg_substrings:
diff --git a/tests/events/detection/ivt_test.py b/tests/events/detection/ivt_test.py
index 9be77f2..c0fac58 100644
--- a/tests/events/detection/ivt_test.py
+++ b/tests/events/detection/ivt_test.py
@@ -33,17 +33,6 @@ from pymovements.synthetic import step_function
     [
         pytest.param(
             {
-                'positions': None,
-                'velocities': np.ones((100, 2)),
-                'velocity_threshold': 1.,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_none_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'positions': np.ones((100, 2)),
                 'velocities': None,
                 'velocity_threshold': 1.,
                 'minimum_duration': 1,
@@ -53,17 +42,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': 1,
-                'velocities': np.ones((100, 2)),
-                'velocity_threshold': 1.,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_array_like_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'positions': np.ones((100, 2)),
                 'velocities': 1,
                 'velocity_threshold': 1.,
                 'minimum_duration': 1,
@@ -73,17 +51,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.ones(100),
-                'velocities': np.ones((100, 2)),
-                'velocity_threshold': 1.,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_2d_array_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'positions': np.ones((100, 2)),
                 'velocities': np.ones(100),
                 'velocity_threshold': 1.,
                 'minimum_duration': 1,
@@ -93,17 +60,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.ones((100, 3)),
-                'velocities': np.ones((100, 2)),
-                'velocity_threshold': 1.,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_not_2_elements_in_second_dimension_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'positions': np.ones((100, 2)),
                 'velocities': np.ones((100, 3)),
                 'velocity_threshold': 1.,
                 'minimum_duration': 1,
@@ -113,17 +69,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.ones((100, 2)),
-                'velocities': np.ones((101, 2)),
-                'velocity_threshold': 1.,
-                'minimum_duration': 1,
-            },
-            ValueError,
-            id='positions_and_velocities_different_lengths_raises_value_error',
-        ),
-        pytest.param(
-            {
-                'positions': np.ones((100, 2)),
                 'velocities': np.ones((100, 2)),
                 'velocity_threshold': None,
                 'minimum_duration': 1,
@@ -133,7 +78,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.ones((100, 2)),
                 'velocities': np.ones((100, 2)),
                 'velocity_threshold': '1.',
                 'minimum_duration': 1,
@@ -143,7 +87,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.ones((100, 2)),
                 'velocities': np.ones((100, 2)),
                 'velocity_threshold': 0.,
                 'minimum_duration': 1,
@@ -275,6 +218,10 @@ def test_ivt_detects_fixations(kwargs, expected):
     velocities = pm.gaze.transforms_numpy.pos2vel(
         kwargs['positions'], sampling_rate=10, method='preceding',
     )
+
+    # Just use positions argument for velocity calculation
+    kwargs.pop('positions')
+
     events = pm.events.ivt(velocities=velocities, **kwargs)
 
     assert_frame_equal(events.frame, expected.frame)
diff --git a/tests/events/detection/microsaccades_test.py b/tests/events/detection/microsaccades_test.py
index c53c60a..3f68ec0 100644
--- a/tests/events/detection/microsaccades_test.py
+++ b/tests/events/detection/microsaccades_test.py
@@ -32,7 +32,6 @@ from pymovements.synthetic import step_function
     [
         pytest.param(
             {
-                'positions': np.zeros(shape=(10, 2)),
                 'velocities': np.zeros(shape=(10, 2)),
                 'threshold': (1, 1, 1),
             },
@@ -41,7 +40,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.zeros(shape=(10, 2)),
                 'velocities': np.random.uniform(size=(10, 2)),
                 'threshold': (0, 100),
             },
@@ -50,7 +48,6 @@ from pymovements.synthetic import step_function
         ),
         pytest.param(
             {
-                'positions': np.zeros(shape=(10, 2)),
                 'velocities': np.random.uniform(size=(10, 2)),
                 'threshold': (100, 0),
             },
@@ -69,7 +66,6 @@ def test_microsaccades_raises_error(kwargs, expected):
     [
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[40, 50],
@@ -83,7 +79,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[40, 50],
@@ -101,7 +96,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[40, 50],
@@ -120,7 +114,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[20, 30, 70, 80],
@@ -138,7 +131,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[20, 25, 28, 30, 70, 80],
@@ -157,7 +149,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[20, 25, 28, 30, 70, 80],
@@ -176,7 +167,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[40, 50],
@@ -190,7 +180,6 @@ def test_microsaccades_raises_error(kwargs, expected):
         ),
         pytest.param(
             {
-                'positions': step_function(length=100, steps=[0], values=[(0, 0)]),
                 'velocities': step_function(
                     length=100,
                     steps=[40, 50],
diff --git a/tests/utils/checks_test.py b/tests/utils/checks_test.py
index 6ed005e..30c0030 100644
--- a/tests/utils/checks_test.py
+++ b/tests/utils/checks_test.py
@@ -118,6 +118,15 @@ def test_check_nan_both_channels_raises_error(arr, expected_error, expected_err_
 @pytest.mark.parametrize(
     ('kwargs', 'expected_error', 'expected_err_msg'),
     [
+        # Test for one array
+        pytest.param(
+            {
+                'positions': np.array([[1, 2], [3, 4]]),
+            },
+            None,
+            '',
+            id='one_array_with_shape_N_2_raises_no_error',
+        ),
         pytest.param(
             {
                 'positions': np.array([[1, 2], [3, 4]]),
@@ -125,7 +134,16 @@ def test_check_nan_both_channels_raises_error(arr, expected_error, expected_err_
             },
             None,
             '',
-            id='positions_and_velocities_shape_N_2_raises_no_error',
+            id='two_arrays_with_shape_N_2_raises_no_error',
+        ),
+        # Test for one wrong array
+        pytest.param(
+            {
+                'positions': np.array([1, 2, 3, 4]),
+            },
+            ValueError,
+            'positions must have shape (N, 2) but have shape (4,)',
+            id='array_not_shape_N_2_raises_value_error',
         ),
         pytest.param(
             {
@@ -160,23 +178,24 @@ def test_check_nan_both_channels_raises_error(arr, expected_error, expected_err_
                 'velocities': np.array([[1, 2], [3, 4], [5, 6]]),
             },
             ValueError,
-            'shape of positions (2, 2) does not match'
-            ' shape of velocities (3, 2)',
+            'positions, velocities'
+            ' must have the same shape, but shapes are '
+            '(2, 2), (3, 2)',
             id='positions_and_velocities_N_2_but_different_lengths_raises_value_error',
         ),
     ],
 )
-def test_check_shapes_positions_velocities_raises_error(kwargs, expected_error, expected_err_msg):
+def test_check_shapes_raises_error(kwargs, expected_error, expected_err_msg):
     """
-    Test that check_shapes_positions_velocities() only raises an Exception if
+    Test that check_shapes() only raises an Exception if
     the shapes of the positions and velocities are not (N, 2) or if the lengths
     of the positions and velocities are not equal.
     """
     if expected_error is None:
-        checks.check_shapes_positions_velocities(**kwargs)
+        checks.check_shapes(**kwargs)
     else:
         with pytest.raises(expected_error) as excinfo:
-            checks.check_shapes_positions_velocities(**kwargs)
+            checks.check_shapes(**kwargs)
         msg, = excinfo.value.args
         assert msg == expected_err_msg