Repository: aeye-lab/pymovements
Pull request #458 (2023-07-07 09:36:23)

feat: Add styling arguments to main sequence plot
## Description

Fixes issue #449 

## Implemented changes

- [x] Added styling args to main sequence plot: color, marker_size, ...
- [x] possible to add further kwargs for plot.scatter

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change is or requires a documentation update

## 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
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules
- [ ] I have checked my code and corrected any misspellings


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/aeye-lab/pymovements/pull/458?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 [(`cad2e7a`)](https://app.codecov.io/gh/aeye-lab/pymovements/commit/cad2e7a7ef9ae9bdb9e883294315d00eacc592f0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) 100.00% compared to head [(`3587ef5`)](https://app.codecov.io/gh/aeye-lab/pymovements/pull/458?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      #458   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           55        55           
  Lines         2089      2089           
  Branches       475       475           
=========================================
  Hits          2089      2089           
```


| [Impacted Files](https://app.codecov.io/gh/aeye-lab/pymovements/pull/458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab) | Coverage Δ | |
|---|---|---|
| [src/pymovements/plotting/main\_sequence\_plot.py](https://app.codecov.io/gh/aeye-lab/pymovements/pull/458?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab#diff-c3JjL3B5bW92ZW1lbnRzL3Bsb3R0aW5nL21haW5fc2VxdWVuY2VfcGxvdC5weQ==) | `100.00% <100.00%> (ø)` | |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/aeye-lab/pymovements/pull/458?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aeye-lab).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](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).

SiQube: the type for **kwargs comes from [plt scatter documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html)

Patch:
diff --git a/docs/source/tutorials/plot-main-sequence.ipynb b/docs/source/tutorials/plot-main-sequence.ipynb
index 7192cc7..1bc5dd2 100644
--- a/docs/source/tutorials/plot-main-sequence.ipynb
+++ b/docs/source/tutorials/plot-main-sequence.ipynb
@@ -16,7 +16,7 @@
     "## What you will learn in this tutorial:\n",
     "\n",
     "* how to prepare your data to plot the saccadic main sequence\n",
-    "* how to create a main sequence plot of your saccade events"
+    "* how to create a main sequence plot of your saccade events and style it to your liking"
    ]
   },
   {
@@ -186,12 +186,19 @@
    "outputs": [],
    "source": [
     "# only showing the first three event dataframes here.\n",
+    "# note that you can adjust the styling of the plot, e.g. setting a low\n",
+    "# alpha value allows you to see overlapping data points\n",
     "for event_df in dataset.events[:3]:\n",
-    "    print(\n",
-    "        f'Showing main sequence plot for '\n",
+    "    pm.plotting.main_sequence_plot(\n",
+    "        event_df,\n",
+    "        title='Main sequence plot for '\n",
     "        f'text {event_df[0, \"text_id\"]}, '\n",
-    "        f'page {event_df[0, \"page_id\"]}:')\n",
-    "    pm.plotting.main_sequence_plot(event_df)"
+    "        f'page {event_df[0, \"page_id\"]}',\n",
+    "        alpha=0.3,\n",
+    "        color='green',\n",
+    "        marker='x',\n",
+    "        marker_size=30,\n",
+    "    )"
    ]
   },
   {
diff --git a/src/pymovements/plotting/main_sequence_plot.py b/src/pymovements/plotting/main_sequence_plot.py
index f30761e..f7c9edd 100644
--- a/src/pymovements/plotting/main_sequence_plot.py
+++ b/src/pymovements/plotting/main_sequence_plot.py
@@ -24,6 +24,7 @@ from __future__ import annotations
 
 import matplotlib.pyplot as plt
 import polars as pl
+from matplotlib.collections import Collection
 from polars import ColumnNotFoundError
 
 from pymovements.events import EventDataFrame
@@ -31,18 +32,31 @@ from pymovements.events import EventDataFrame
 
 def main_sequence_plot(
         event_df: EventDataFrame,
+        marker_size: float = 25,
+        color: str = 'purple',
+        alpha: float = 0.5,
+        marker: str = 'o',
         figsize: tuple[int, int] = (15, 5),
         title: str | None = None,
         savepath: str | None = None,
         show: bool = True,
+        **kwargs: Collection,
 ) -> None:
     """
     Plots the saccade main sequence.
 
     Parameters
     ----------
-    event_df:
-        Event dataframe. It must contain columns "peak_velocity" and "amplitude".
+    event_df: Event dataframe
+        It must contain columns "peak_velocity" and "amplitude".
+    marker_size: float
+        Size of the marker symbol.
+    color: str
+        Color of the marker symbol.
+    alpha: float
+        Alpha value (=transparency) of the marker symbol. Between 0 and 1.
+    marker: str
+        Marker symbol. Possible values defined by matplotlib.markers.
     figsize: tuple
         Figure size.
     title: str, optional
@@ -51,6 +65,8 @@ def main_sequence_plot(
         If given, figure will be saved to this path.
     show: bool
         If True, figure will be shown.
+    **kwargs:
+        Additional keyword arguments passed to matplotlib.pyplot.scatter.
 
     Raises
     ------
@@ -90,7 +106,15 @@ def main_sequence_plot(
 
     fig = plt.figure(figsize=figsize)
 
-    plt.scatter(amplitudes, peak_velocities, color='purple', alpha=0.5)
+    plt.scatter(
+        amplitudes,
+        peak_velocities,
+        color=color,
+        alpha=alpha,
+        s=marker_size,
+        marker=marker,
+        **kwargs,
+    )
 
     plt.title(title)
     plt.xlabel('Amplitude [dva]')


Test patch:
diff --git a/tests/plotting/main_sequence_plot_test.py b/tests/plotting/main_sequence_plot_test.py
index ffa6499..2c75283 100644
--- a/tests/plotting/main_sequence_plot_test.py
+++ b/tests/plotting/main_sequence_plot_test.py
@@ -30,7 +30,7 @@ from pymovements.plotting.main_sequence_plot import main_sequence_plot
 
 
 @pytest.mark.parametrize(
-    ('input_df', 'show'),
+    ('input_df', 'show', 'color', 'marker', 'alpha', 'size'),
     [
         pytest.param(
             EventDataFrame(
@@ -44,25 +44,38 @@ from pymovements.plotting.main_sequence_plot import main_sequence_plot
                 ),
             ),
             True,
+            'blue',
+            'x',
+            0.6,
+            30,
             id='show_plot',
         ),
     ],
 )
-def test_main_sequence_plot_show_plot(input_df, show, monkeypatch):
+def test_main_sequence_plot_show_plot(input_df, show, monkeypatch, color, marker, alpha, size):
     mock_show = Mock()
     mock_scatter = Mock()
 
     monkeypatch.setattr(plt, 'show', mock_show)
     monkeypatch.setattr(plt, 'scatter', mock_scatter)
 
-    main_sequence_plot(input_df, show=show)
+    main_sequence_plot(
+        input_df,
+        show=show,
+        color=color,
+        marker=marker,
+        alpha=alpha,
+        marker_size=size,
+    )
     plt.close()
 
     mock_scatter.assert_called_with(
         [1.0, 1.0, 2.0, 2.0, 3.0, 4.0],
         [10.0, 11.0, 12.0, 11.0, 13.0, 13.0],
-        color='purple',
-        alpha=0.5,
+        color='blue',
+        alpha=0.6,
+        s=30,
+        marker='x',
     )
 
     mock_show.assert_called_once()
@@ -99,6 +112,8 @@ def test_main_sequence_plot_filter_out_fixations(input_df, monkeypatch):
         [10.0, 11.0, 12.0, 11.0, 13.0],
         color='purple',
         alpha=0.5,
+        s=25,
+        marker='o',
     )