Skip to content

Commit f48cc88

Browse files
author
Nicolas Legrand
authored
v0.2.4 (#44)
* [viewer] : Fix saving erorr when bad_segments is None. * [doc] : Fix link to Python functions * docstring * docstring * docstring * [viewer] Refactor Viewer and Editor in a way that allows the Editor to be used as a standalone. * [viwer] : Working directly from the BIDS folder * [docs] More doc on the Editor and Viewer * [docs] * [docs] * v0.2.4 * logo * logo
1 parent f3333c3 commit f48cc88

35 files changed

+717
-451
lines changed

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ repos:
55
- id: isort
66
files: ^systole/
77
- repo: https://github.com/ambv/black
8-
rev: 22.6.0
8+
rev: 22.8.0
99
hooks:
1010
- id: black
1111
language_version: python3

docs/source/changelog.rst

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ This page contains information about what has changed in each new version of ``s
2424

2525
<div class="col-md-9">
2626

27+
.. include:: releases/v0.2.4.txt
28+
2729
.. include:: releases/v0.2.3.txt
2830

2931
.. include:: releases/v0.2.2.txt

docs/source/conf.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,18 @@
108108
icon="fas fa-box",
109109
),
110110
],
111-
"logo_link": "https://embodied-computation-group.github.io/systole/#",
112-
}
111+
"logo": {
112+
"text": "Systole",
113+
},}
113114

114-
html_sidebars = {
115-
"api": [],
116-
"changelog": [],
117-
"notebooks/*": []
118-
}
115+
html_sidebars = {"**": []}
119116

120117
# Add any paths that contain custom static files (such as style sheets) here,
121118
# relative to this directory. They are copied after the builtin static files,
122119
# so a file named "default.css" will overwrite the builtin "default.css".
123120
html_static_path = ['_static']
124121
html_css_files = ["https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"]
125-
html_logo = "images/logo.svg"
122+
html_logo = "images/logo_small.svg"
126123
html_favicon = "images/logo_small.svg"
127124

128125
def setup(app):

docs/source/notebooks/3-DetectingAndCorrectingArtefacts.ipynb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@
11611161
"id": "dd627eb6-aa7f-4d66-a763-594d4a03611d",
11621162
"metadata": {},
11631163
"source": [
1164-
"Because most heart rate variability metrics require continuous interval time series, we cannot simply remove the invalid intervals and concatenate everything, we have to extract valid segments and compute the HRD indices from there. Systole comes with the py:func`systole.utils.get_valid_segments()` function that will return the valid portion of the physiological recording, sorted according to the signal length."
1164+
"Because most heart rate variability metrics require continuous interval time series, we cannot simply remove the invalid intervals and concatenate everything, we have to extract valid segments and compute the HRD indices from there. Systole comes with the:py:func`systole.utils.get_valid_segments()` function that will return the valid portion of the physiological recording, sorted according to the signal length."
11651165
]
11661166
},
11671167
{

docs/source/notebooks/3-DetectingAndCorrectingArtefacts.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ plot_raw(signal=signal, show_heart_rate=True, figsize=(18, 6), bad_segments=[(60
272272
plt.tight_layout()
273273
```
274274

275-
Because most heart rate variability metrics require continuous interval time series, we cannot simply remove the invalid intervals and concatenate everything, we have to extract valid segments and compute the HRD indices from there. Systole comes with the py:func`systole.utils.get_valid_segments()` function that will return the valid portion of the physiological recording, sorted according to the signal length.
275+
Because most heart rate variability metrics require continuous interval time series, we cannot simply remove the invalid intervals and concatenate everything, we have to extract valid segments and compute the HRD indices from there. Systole comes with the:py:func`systole.utils.get_valid_segments()` function that will return the valid portion of the physiological recording, sorted according to the signal length.
276276

277277
```{code-cell} ipython3
278278
from systole.utils import get_valid_segments

docs/source/notebooks/6-WorkingWithBIDSFolders.ipynb

+137-39
Large diffs are not rendered by default.

docs/source/notebooks/6-WorkingWithBIDSFolders.md

+122-34
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ if 'google.colab' in sys.modules:
2525
! pip install systole
2626
```
2727

28-
Starting in version `0.2.3`, Systole provides tools to interact efficiently with large datasets containing physiological recordings. Most of the functionalities interface with folders structured following the [BIDS standards](https://bids-specification.readthedocs.io/en/stable/) and this is the format we recommend using if you are following this tutorial.
28+
Starting in version `0.2.3`, Systole provides tools to interact with large datasets of physiological recordings. The functionalities interface with folders that are structured following the [BIDS standards](https://bids-specification.readthedocs.io/en/stable/) and this is the format we recommend using if you are following this tutorial.
2929

30-
Under BIDS standards, physiological recordings, sometimes associated with behavioural tasks or neural recordings, are stored with a filename ending with `*_physio.tsv.gz` and are always accompanied with sidecar a `*_physio.json` file containing metadata like the recording modality or the sampling frequency. Accessing both the times series and its accompanying metadata will help Systole automate the preprocessing by finding the correct parameters for peaks detection and reports.
30+
Following the BIDS specifications, physiological recordings, sometimes associated with behavioural tasks or neural recordings, are stored with a filename ending with `*_physio.tsv.gz` and are always accompanied with sidecar a `*_physio.json` file containing metadata like the recording modality or the sampling frequency. Accessing both the times series and its accompanying metadata will help Systole automate the preprocessing by finding the correct parameters for peaks detection and reports.
3131

32-
Once you have organized your folder, you should have a structure resembling this one:
32+
A valid BIDS folder should be structured like the following:
3333

3434
```
3535
└─ BIDS/
@@ -46,17 +46,22 @@ Once you have organized your folder, you should have a structure resembling this
4646

4747
Here, we have physiological recordings associated with a behavioural task for `n` participants in the folder.
4848

49+
```{tip}
50+
We recommend using tools like [BIDS validator](https://bids-standard.github.io/bids-validator/) to ensure that your folder complies with BIDS specification before trying to preprocess your data, or to use the editor.
51+
```
52+
4953
+++
5054

51-
## Signal preprocessing and creation of subject and group-level reports
55+
(preprocessing)=
56+
## Preprocessing
5257

5358
+++
5459

5560
The first step will be to preprocess the raw data and store the signal and peaks detection in a new derivative folder. During this step, we can also decide to create HTML reports for each participants, so we can visualize the signal quality and peaks detection.
5661

57-
### Preprocessing the physiological recording from one participant
62+
### Preprocessing the physiological data from one participant
5863

59-
The py:func:`systole.reports` sub-module contains tools to directly interact with BIDS formatted folders, preprocess and save individual reports in a BIDS consistent way. Those functionalities are built on the top of the py:func:`systole.reports.subject_level_report` function. This function will simply take a signal as input and will save as output the preprocessed signal with peaks detection (`_physio.tsv.gz` with the `_physio.json`), an `.html` reports adapted to the kind of signal that was provided, and a `features.tsv` file containing heart rate or respiratory rate variability features.
64+
The :py:func:`systole.reports` sub-module contains tools to directly interact with BIDS formatted folders, preprocess and save individual reports in a BIDS consistent way. Those functionalities are built on the top of the:py:func:`systole.reports.subject_level_report` function. This function will simply take a signal as input and will save as output the preprocessed signal with peaks detection (`_physio.tsv.gz` with the `_physio.json`), an `.html` reports adapted to the kind of signal that was provided, and a `features.tsv` file containing heart rate or respiratory rate variability features.
6065

6166
For example, running the following code:
6267

@@ -88,7 +93,7 @@ will save these four new files in the file folder.
8893

8994
### Preprocessing the entire BIDS folder
9095

91-
The previous function call can be automated for each participant and each file of a given BIDS folder and to extract the physiological features using the information provided in the `json` metadata automatically. This can be done using the py:func:`systole.reports.wrapper` function, or directly from the command line. For example, the following command:
96+
The previous function call can be automated for each participant and each file of a given BIDS folder and to extract the physiological features using the information provided in the `json` metadata automatically. This can be done using the:py:func:`systole.reports.wrapper` function, or directly from the command line. For example, the following command:
9297

9398
```bash
9499
systole --bids_folder="/path/to/BIDS/folder/" \
@@ -99,7 +104,31 @@ systole --bids_folder="/path/to/BIDS/folder/" \
99104
--html_reports==False
100105
```
101106

102-
will preprocess the data for all participants with a physiological recording in the session `ses-session1` (default), for the behavioural modality (`beh`) and the task `mytask`. We set `n_jobs=10`, meaning that we will run 40 processes in parallel, and `overwrite=True` to overwrite previous data with the same ID in the derivative folder. Note that we also set `html_reports` to `False` as these files can be quite large, it is often preferable to only create it for the participant we want to review, or to use the {ref}`viewer`.
107+
will preprocess the data for all participants with a physiological recording in the session `ses-session1` (default), for the behavioural modality (`beh`) and the task `mytask`. We set `n_jobs=10`, meaning that we will run 40 processes in parallel, and `overwrite=True` to overwrite previous data with the same ID in the derivative folder. Note that we also set `html_reports` to `False` as these files can be quite large, it is often preferable to only create it for the participant we want to review, or to use the {ref}`viewer`. The possible arguments are:
108+
109+
```{list-table} Command line arguments
110+
:header-rows: 1
111+
:name: label-to-reference
112+
113+
* - Argument
114+
- Description
115+
* - --bids_folder (-i)
116+
- Path to the BIDS folder containing the physiological recordings.
117+
* - --participant_id (-p)
118+
- The id of the participant that should be preprocessed. If this argument is not provided, all the participants will be preprocessed.
119+
* - --patern (-t)
120+
- Only the files that contains the pattern string will be preprocessed. If the number of files matching is not exactly 1, the files are not processed.
121+
* - --html_reports (-r)
122+
- Create subject-level HTML reports if `True`.
123+
* - --result_folder (-o)
124+
- Path to the result folder. If not provided, the default will be ./derivatives/systole/.
125+
* - --n_jobs (-n)
126+
- The number of jobs to run concurrently.
127+
* - --modality (-d)
128+
- The modality of the recording (i.e. `"beh"`, `"func"`...).
129+
* - --overwrite (-w)
130+
- If `True`, overwrite preexisting files in the result folder (DOES NOT include the corrected files).
131+
```
103132

104133
+++
105134

@@ -136,59 +165,124 @@ Once the preprocessing is completed, and if you did not asked for an external re
136165
+++
137166

138167
(viewer)=
139-
## Manual edition of peaks vector and labelling bad segments using the Viewer
168+
## Manual edition of peaks vector and bad segments labelling
140169

141170
While we hope that the peaks detection function used by [Systole](https://embodied-computation-group.github.io/systole/#) is sufficiently robust to extract peak vectors without errors for most of the uses cases, you might still encounter noisy or invalid recording that you will want to manually inspect and sometimes edit.
142171

143-
The py:func:`systole.viewer` sub-module is built on the top of Matplotlib widgets and can help for manual peaks edition or bad segments labelling. For example, running the following cells in a Jupyter notebook:
172+
The :py:mod:`systole.interact` sub-module provides two classes (:py:class:`systole.interact.Editor` and :py:class:`systole.interact.Viewer`) built on the top of Matplotlib widgets that can help for manual edition, and interactive visualization of BIDS fodlers directly in the notebook.
173+
174+
### Using the Editor to inspect raw signal
175+
176+
The :py:mod:`systole.interact.Editor` can be use alone (apart from a BISD structured folder) to edit peaks detection from a raw ECG, PPG or respiratory signal.
144177

145178
```python
179+
from systole import import_dataset1
180+
from systole.interact import Viewer, Editor
146181
from IPython.display import display
147-
from systole.viewer import Viewer
148182

149183
%matplotlib ipympl
150184
```
151185

152186
```python
153-
view = Viewer(
187+
# Load a ray ECG time series
188+
ecg = import_dataset1(modalities=['ECG'], disable=True).ecg.to_numpy()
189+
```
190+
191+
```python
192+
editor = Editor(
193+
signal=ecg,
194+
sfreq=1000,
195+
corrected_json="./corrected.json",
154196
figsize=(15, 5),
155-
input_folder="/BIDS_folder/derivatives/systole/",
156-
pattern="task-hrd", # A string long enough to disambiguate in case of mmultiple recordings
157-
modality="beh",
158197
signal_type="ECG"
159198
)
199+
display(editor.commands_box)
160200
```
161201

162-
```python
163-
display(view.io_box, view.commands_box, view.output)
202+
+++
203+
204+
```{note}
205+
Note that we are using the package [ipympl](https://matplotlib.org/ipympl/), and activating it using the magic cell `%matplotlib ipympl` so we can render Matplotlib interactive widgets in the Notebook. If you are working in another IDE, you can also render the same windows using a different backend like PyQt.
164206
```
165207

166-
will create an interactive windows from which all the preprocessed recordings and peaks detection can be inspected.
208+
This windows will automatically apply peaks detection given the `signal_type` parameter, and plot the raw signal with the instantaneous heart / respiration rate to check for artefacts. The class embed a `command_box` that can be used for edition.
167209

168-
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/editor.gif'/></p>
210+
* When using the **Correction** mode:
211+
* Use the *left* mouse button to select segment where all the peaks should be removed.
212+
* Use the *right* mouse button to select segment where peak will be added at the local maximum.
213+
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/peaks.gif'/></p>
214+
215+
* When using the **Rejection** mode:
216+
* Use the *right* mouse button to select a segment that should be marked as bad.
217+
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/segments.gif'/></p>
218+
219+
* By deselecting the check box, you can mark the entire signal as **invalid**.
220+
221+
* Once that the signal has been edited, you can **save** the modification using the `Save modification` button, or directly use the method from the class.
169222

170223
+++
171224

172-
### Inserting / deleting peaks
225+
This function will create a JSON file (using the path specified in the `corrected_json` parameter) with all the information about bad segments labelling, peaks deletion and peaks insertion. The JSON file contains the following entries for each modality (ECG, PPG and respiration)
226+
227+
* `valid` : is the recording valid or should it be discared (`True` unless otherwise stated).
228+
* `corrected_peaks` : the peaks indexes after correction.
229+
* `bad_segments` : a list of `start` and `end` indexed of bad segments.
173230

174-
Peaks can be inserted (using the local maxima of the selected range) or deleted.
231+
+++ {"tags": []}
175232

176-
* Left mouse button : remove all the peaks in the selected interval.
177-
* Right mouse button : add one new peaks where the signal local maximum is found.
233+
### Using the Viewer to navigate preprocessed folder
178234

179-
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/editor_peaks.gif'/></p>
235+
The :py:mod:`systole.interact.Viewer` class wrap the Editor and allows to easily navigate and edit folder that contains large number of recoring. You can for example simply read the results generated by the command line (see {ref}`preprocessing`). Considering that the files were create in the folder `"/path/to/BIDS/folder/derivatives/systole/"` (which is the default behavior if `--result _folder is not provided`), the Viewer can be called using:
236+
237+
```python
238+
from IPython.display import display
239+
from systole.interact import Viewer
240+
241+
%matplotlib ipympl
242+
```
243+
244+
```python
245+
view = Viewer(
246+
figsize=(15, 5),
247+
preprocessed_folder="/path/to/BIDS/folder/derivatives/systole/",
248+
pattern="task-my_task", # A string long enough to disambiguate in case of mmultiple recordings
249+
modality="beh",
250+
signal_type="ECG"
251+
)
252+
```
253+
254+
```python
255+
display(view.io_box, view.editor.commands_box, view.output)
256+
```
257+
258+
This will create an interactive windows where all the preprocessed ECG recordings from the behavioral task `my_task` can be inspected and further edited.
259+
260+
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/editor.gif'/></p>
261+
262+
```{note}
263+
If the signal was previously edited, the Viewer will automatically load the edited version and display bad segment (if any).
264+
```
180265

181266
+++
182267

183-
### Bad segments labelling
268+
### Using the Viewer to navigate BIDS folder
269+
270+
Using the same logic, the :py:mod:`systole.interact.Viewer` can also work with the raw BIDS folder, instead of the derivatives, and preprocess data on the fly. This mode is more appropriate if you want to quickly inspect the data and do not want to generate subject or group level reports. The only different is that the input path should be parameter using the `bids_folder` argument, instead of `preprocessed_folder`. This will make the viewer aware that the signal are located in this folder, but that previously edited signal might also be located in `./derivatives/systole/corrected/`.
184271

185-
In case a whole segment of the recording contain noise and should be entirely removed from future analysis, it can be labelled by swiching the edition mode from `Correction` to `Rejection`.
186272

187-
<p align='center'><img src='https://github.com/embodied-computation-group/systole/raw/dev/docs/source/images/editor_peaks.gif'/></p>
273+
```python
274+
view = Viewer(
275+
figsize=(15, 5),
276+
bids_folder="/path/to/BIDS/folder/",
277+
pattern="task-my_task", # A string long enough to disambiguate in case of mmultiple recordings
278+
modality="beh",
279+
signal_type="ECG"
280+
)
281+
```
188282

189283
+++
190284

191-
### Working with corrected signals
285+
### Importing signals after manual edition
192286

193287
After manual peaks correction and segments labelling, a new `corrected` subfolder will be appended to the systole derivatives:
194288

@@ -218,9 +312,3 @@ After manual peaks correction and segments labelling, a new `corrected` subfolde
218312
├─ sub-0003/
219313
└─ ...
220314
```
221-
222-
The logs of artefacts correction are located in the new `_physio.json` file and contains all information about bad segments labelling, peaks deletion and peaks insertion. The JSON file contains the following entries for each modality (ECG, PPG and respiration)
223-
224-
* `valid` : is the recording valid or should it be discared (`True` unless otherwise stated).
225-
* `corrected_peaks` : the peaks indexes after correction.
226-
* `bad_segments` : a list of `start` and `end` indexed of bad segments.

docs/source/releases/v0.0.1.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
v0.0.1 (January 2020)
3-
---------------------
2+
v0.0.1
3+
------
44

55
Alpha release.

docs/source/releases/v0.1.0.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
v0.1.0 (January 2020)
3-
---------------------
2+
v0.1.0
3+
------
44

55
Initial release.
66

docs/source/releases/v0.1.1.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.1.1 (June 2020)
2-
------------------
1+
v0.1.1
2+
------
33

44
**New functions**
55

docs/source/releases/v0.1.2.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.1.2 (September 2020)
2-
-----------------------
1+
v0.1.2
2+
------
33

44
**New functions**
55

docs/source/releases/v0.1.3.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.1.3 (April 2021)
2-
-------------------
1+
v0.1.3
2+
------
33

44
- |Enhancement| :py:func:`systole.plotly.plot_raw()`: add `ecg_method` parameter to control the ECG peak detection method used.
55
- |Enhancement| Download dataset directly from GitHub instead of copying the files at install.

docs/source/releases/v0.2.0.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.2.0 (October 2021)
2-
-----------------------
1+
v0.2.0
2+
------
33

44
Highlights
55
++++++++++

docs/source/releases/v0.2.1.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.2.1 - December 2021
2-
----------------------
1+
v0.2.1
2+
------
33

44
Highlights
55
++++++++++

docs/source/releases/v0.2.2.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
v0.2.2 (December 2021)
2-
----------------------
1+
v0.2.2
2+
------
33

44
Highlights
55
++++++++++

0 commit comments

Comments
 (0)