Skip to content

Commit 45c9ad9

Browse files
Merge pull request #992 from neuropsychology/dev
0.2.10
2 parents 1aa8dee + d783e40 commit 45c9ad9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+933
-384
lines changed

.github/workflows/docs-build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
pip install EMD-signal
4545
pip install cvxopt
4646
pip install ts2vg
47+
pip install pickleshare
4748
pip install https://github.com/neuropsychology/neurokit/zipball/dev
4849
4950
- name: Build documentation 📜

.github/workflows/docs-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
pip install EMD-signal
3939
pip install cvxopt
4040
pip install ts2vg
41+
pip install pickleshare
4142
pip install https://github.com/neuropsychology/neurokit/zipball/dev
4243
4344
- name: Build documentation 📜

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Contributors
5252
* `Jannik Gut <https://github.com/rostro36>`_
5353
* `Nattapong Thammasan <https://github.com/Nattapong-OnePlanet>`_ *(OnePlanet, Netherlands)*
5454
* `Marek Sokol <https://github.com/sokolmarek>`_ *(Faculty of Biomedical Engineering of the CTU in Prague, Czech Republic)*
55+
* `Johannes Herforth <https://github.com/DerAndereJohannes>`_ *(University of Luxembourg, Luxembourg)*
5556

5657

5758
Thanks also to `Chuan-Peng Hu <https://github.com/hcp4715>`_, `@ucohen <https://github.com/ucohen>`_, `Anthony Gatti <https://github.com/gattia>`_, `Julien Lamour <https://github.com/lamourj>`_, `@renatosc <https://github.com/renatosc>`_, `Nicolas Beaudoin-Gagnon <https://github.com/Fegalf>`_ and `@rubinovitz <https://github.com/rubinovitz>`_ for their contribution in `NeuroKit 1 <https://github.com/neuropsychology/NeuroKit.py>`_.

data/gudb/download_gudb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
# creating class which loads the experiment
2929
ecg_class = ecg_gudb_database.GUDb(participant, experiment)
3030

31-
# Chest Strap Data - only donwload if R-peaks annotations are available
31+
# Chest Strap Data - only download if R-peaks annotations are available
3232
if ecg_class.anno_cs_exists:
3333

3434
data = pd.DataFrame({"ECG": ecg_class.cs_V2_V1})
@@ -41,7 +41,7 @@
4141
anno = pd.DataFrame({"Rpeaks": ecg_class.anno_cs})
4242
anno["Participant"] = "GUDB_%.2i" %(participant)
4343
anno["Sampling_Rate"] = 250
44-
anno["Database"] = "GUDB (" + experiment + ")"
44+
anno["Database"] = "GUDB_" + experiment
4545

4646
# Store with the rest
4747
dfs_ecg.append(data)

data/ludb/download_ludb.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
The database consists of 200 10-second 12-lead ECG signal records representing different morphologies of the ECG signal. The ECGs were collected from healthy volunteers and patients, which had various cardiovascular diseases. The boundaries of P, T waves and QRS complexes were manually annotated by cardiologists for all 200 records.
55
66
Steps:
7-
1. In the command line, run 'pip install gsutil'
8-
2. Then, 'gsutil -m cp -r gs://ludb-1.0.0.physionet.org D:/YOURPATH/NeuroKit/data/ludb'
9-
This will download all the files in a folder named 'ludb-1.0.0.physionet.org' at the
10-
destination you entered.
7+
1. Download zipped data base from https://physionet.org/content/ludb/1.0.1/
8+
2. Unzip the folder so that you have a `lobachevsky-university-electrocardiography-database-1.0.1/` folder'
119
3. Run this script.
1210
"""
1311
import pandas as pd
@@ -16,31 +14,33 @@
1614
import os
1715

1816

19-
files = os.listdir("./ludb-1.0.0.physionet.org/")
20-
2117
dfs_ecg = []
2218
dfs_rpeaks = []
2319

2420

2521
for participant in range(200):
2622
filename = str(participant + 1)
2723

28-
data, info = wfdb.rdsamp("./ludb-1.0.0.physionet.org/" + filename)
24+
data, info = wfdb.rdsamp(
25+
"./lobachevsky-university-electrocardiography-database-1.0.1/data/" + filename
26+
)
2927

3028
# Get signal
3129
data = pd.DataFrame(data, columns=info["sig_name"])
3230
data = data[["i"]].rename(columns={"i": "ECG"})
33-
data["Participant"] = "LUDB_%.2i" %(participant + 1)
31+
data["Participant"] = "LUDB_%.2i" % (participant + 1)
3432
data["Sample"] = range(len(data))
35-
data["Sampling_Rate"] = info['fs']
33+
data["Sampling_Rate"] = info["fs"]
3634
data["Database"] = "LUDB"
3735

3836
# Get annotations
39-
anno = wfdb.rdann("./ludb-1.0.0.physionet.org/" + filename, 'atr_i')
37+
anno = wfdb.rdann(
38+
"./lobachevsky-university-electrocardiography-database-1.0.1/data/" + filename, "i"
39+
)
4040
anno = anno.sample[np.where(np.array(anno.symbol) == "N")[0]]
4141
anno = pd.DataFrame({"Rpeaks": anno})
42-
anno["Participant"] = "LUDB_%.2i" %(participant + 1)
43-
anno["Sampling_Rate"] = info['fs']
42+
anno["Participant"] = "LUDB_%.2i" % (participant + 1)
43+
anno["Sampling_Rate"] = info["fs"]
4444
anno["Database"] = "LUDB"
4545

4646
# Store with the rest

docs/_static/neurokit_codebook.csv

Whitespace-only changes.

docs/codebook.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
Codebook
2+
========
3+
4+
Here you can download the complete codebook which details the variables that you can compute using the NeuroKit package.
5+
6+
.. raw:: html
7+
8+
<div style="text-align: center;">
9+
<a href="_static/neurokit_codebook.csv" download="neurokit_codebook.csv">
10+
<button style="background-color: #4CAF50; color: white; padding: 10px 20px; margin: 10px; border: none; cursor: pointer; width: 50%;">Download Codebook</button>
11+
</a>
12+
</div>
13+
14+
This codebook contains detailed descriptions of all variables, their descriptions, and additional metadata.
15+
16+
17+
Codebook Table
18+
==============
19+
20+
.. raw:: html
21+
22+
<style>
23+
#csvDataTable {
24+
width: 100%;
25+
border-collapse: collapse;
26+
.. background-color: #f8f8f8;
27+
color: white;
28+
}
29+
#csvDataTable th, #csvDataTable td {
30+
padding: 8px 12px;
31+
border: 1px solid #ccc;
32+
text-align: left;
33+
}
34+
</style>
35+
36+
<div id="csv-table">
37+
<table id="csvDataTable">
38+
</table>
39+
</div>
40+
41+
<script>
42+
43+
function parseCSVLine(text) {
44+
const cols = [];
45+
let col = '';
46+
let insideQuotes = false;
47+
48+
for (let i = 0; i < text.length; i++) {
49+
const char = text[i];
50+
51+
if (insideQuotes && char === '"' && text[i + 1] == '"') {
52+
i++;
53+
col += char;
54+
continue;
55+
}
56+
57+
if (char === '"' && text[i - 1] !== '\\') {
58+
insideQuotes = !insideQuotes;
59+
continue;
60+
}
61+
62+
if (char === ',' && !insideQuotes) {
63+
cols.push(col);
64+
col = '';
65+
} else {
66+
col += char;
67+
}
68+
}
69+
cols.push(col);
70+
71+
return cols.map(field => field.replace(/""/g, '"')); // Replace escaped quotes
72+
}
73+
74+
document.addEventListener("DOMContentLoaded", function() {
75+
fetch('_static/neurokit_codebook.csv')
76+
.then(response => response.text())
77+
.then(csv => {
78+
let lines = csv.trim().split('\n');
79+
let html = '<tr><th>' + parseCSVLine(lines[0]).join('</th><th>') + '</th></tr>';
80+
for (let i = 1; i < lines.length; i++) {
81+
html += '<tr><td>' + parseCSVLine(lines[i]).join('</td><td>') + '</td></tr>';
82+
}
83+
document.getElementById('csvDataTable').innerHTML = html;
84+
})
85+
.catch(error => console.error('Error loading the CSV file:', error));
86+
});
87+
88+
89+
</script>
90+

docs/conf.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# add these directories to sys.path here. If the directory is relative to the
2222
# documentation root, use os.path.abspath to make it absolute, like shown here.
2323
#
24-
# sys.path.insert(0, os.path.abspath('.'))
24+
sys.path.insert(0, os.path.abspath('.'))
2525
sys.path.insert(0, os.path.abspath("../"))
2626

2727

@@ -69,6 +69,7 @@ def find_version():
6969
"sphinxemoji.sphinxemoji",
7070
"sphinx_copybutton",
7171
"myst_nb",
72+
"directives.csv_codebook_directive",
7273
]
7374

7475
# Add any paths that contain templates here, relative to this directory.
@@ -131,7 +132,7 @@ def find_version():
131132
"use_issues_button": True,
132133
"path_to_docs": "docs/",
133134
"use_edit_page_button": True,
134-
"logo_only": True,
135+
# "logo_only": True,
135136
"show_toc_level": 1,
136137
"navigation_with_keys": False,
137138
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import csv
2+
import os
3+
from docutils import nodes
4+
from docutils.parsers.rst import Directive
5+
6+
abrv_to_sensor = {
7+
"ecg": "Electrocardiography",
8+
"eda": "Electrodermal Activity",
9+
"rsp": "Respiration",
10+
"ppg": "Photoplethysmography",
11+
"eeg": "Electroencephalography",
12+
"emg": "Electromyography",
13+
"eog": "Electrooculography",
14+
"hrv": "Heart Rate Variability",
15+
}
16+
17+
class CSVDocDirective(Directive):
18+
has_content = True
19+
20+
def run(self):
21+
# Codebook path
22+
csv_file_path = os.path.join(os.path.abspath('.'), "_static", "neurokit_codebook.csv")
23+
24+
# Check if the file exists and whether it is empty
25+
file_empty = not os.path.exists(csv_file_path) or os.stat(csv_file_path).st_size == 0
26+
27+
# List to hold bullet list nodes
28+
bullet_list = nodes.bullet_list()
29+
30+
doc_source_name = self.state.document.settings.env.temp_data.get('object')[0]
31+
32+
maybe_sensor = doc_source_name.split("_")
33+
doc_sensor = "N/A"
34+
35+
if len(maybe_sensor) > 0 and maybe_sensor[0] in abrv_to_sensor:
36+
doc_sensor = abrv_to_sensor[maybe_sensor[0]]
37+
38+
# Open the CSV file and append the content
39+
with open(csv_file_path, 'a', newline='', encoding='utf-8') as csvfile:
40+
writer = csv.writer(csvfile)
41+
42+
# Write header if file is newly created or empty
43+
if file_empty:
44+
header = ['Field Name', 'Field Description', 'Field Category', 'Source File Name']
45+
writer.writerow(header)
46+
47+
# Iterate through rows: add them to the codebook and add them to the page
48+
for line in self.content:
49+
50+
fields = line.split('|')
51+
52+
# Remove multi line long space sequences
53+
for fid in range(len(fields)):
54+
fields[fid] = " ".join(fields[fid].split())
55+
56+
# Append last fields
57+
fields.append(doc_sensor)
58+
fields.append(f"{doc_source_name}.py")
59+
60+
# Write to CSV
61+
writer.writerow([field.strip() for field in fields])
62+
63+
64+
# Prepare the documentation stylization
65+
if len(fields) >= 2:
66+
paragraph = nodes.paragraph()
67+
68+
# Create backtick formatting around the field name
69+
field1 = nodes.literal('', '', nodes.Text(fields[0].strip()))
70+
71+
# Add the remainder of the line
72+
colon_space = nodes.Text(': ')
73+
field2 = nodes.Text(fields[1].strip())
74+
75+
# Add all the parts to the paragraph
76+
paragraph += field1
77+
paragraph += colon_space
78+
paragraph += field2
79+
80+
# Add to the bullet point list
81+
list_item = nodes.list_item()
82+
list_item += paragraph
83+
bullet_list += list_item
84+
85+
return [bullet_list]
86+
87+
88+
def setup(app):
89+
app.add_directive("codebookadd", CSVDocDirective)

docs/examples/eeg_microstates/eeg_microstates.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@
589589
"cell_type": "markdown",
590590
"metadata": {},
591591
"source": [
592-
"Several different clustering algorithms can be used to segment your EEG recordings into microstates. These algorithms mainly differ in how they define cluster membership and the cost functionals to be optimized ([Xu & Tian, 2015](10.1007/s40745-015-0040-1)). The method to use hence depends on your data and the underlying assumptions of the methods (e.g., some methods ignore polarity). There is no one true method that gives the best results but you can refer to [Poulsen et al., 2018](https://www.researchgate.net/publication/331367421_Microstate_EEGlab_toolbox_An_introductory_guide#pf6) if you would like a more detailed review of the different clustering methods."
592+
"Several different clustering algorithms can be used to segment your EEG recordings into microstates. These algorithms mainly differ in how they define cluster membership and the cost functionals to be optimized ([Xu & Tian, 2015](https://doi.org/10.1007/s40745-015-0040-1)). The method to use hence depends on your data and the underlying assumptions of the methods (e.g., some methods ignore polarity). There is no one true method that gives the best results but you can refer to [Poulsen et al., 2018](https://www.researchgate.net/publication/331367421_Microstate_EEGlab_toolbox_An_introductory_guide#pf6) if you would like a more detailed review of the different clustering methods."
593593
]
594594
},
595595
{

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ You can navigate to the different sections using the left panel. We recommend ch
3535
installation
3636
authors
3737
cite_us
38+
codebook
3839
examples/index
3940
functions/index
4041
resources/index

docs/make.bat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ REM Command file for Sphinx documentation
77
@REM SPHINXBUILD="D:\Python3\Scripts\sphinx-build.exe"
88

99
if "%SPHINXBUILD%" == "" (
10-
set SPHINXBUILD==python -m sphinx
10+
set SPHINXBUILD=python -m sphinx
1111
)
1212
set SOURCEDIR="."
1313
set BUILDDIR="_build"
@@ -34,4 +34,4 @@ goto end
3434
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
3535

3636
:end
37-
popd
37+
popd

neurokit2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from .video import *
3434

3535
# Info
36-
__version__ = "0.2.9"
36+
__version__ = "0.2.10"
3737

3838

3939
# Maintainer info

neurokit2/ecg/ecg_eventrelated.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,30 @@ def ecg_eventrelated(epochs, silent=False):
3030
by the `Label` column (if not present, by the `Index` column). The analyzed features
3131
consist of the following:
3232
33-
* ``ECG_Rate_Max``: the maximum heart rate after stimulus onset.
34-
* ``ECG_Rate_Min``: the minimum heart rate after stimulus onset.
35-
* ``ECG_Rate_Mean``: the mean heart rate after stimulus onset.
36-
* ``ECG_Rate_SD``: the standard deviation of the heart rate after stimulus onset.
37-
* ``ECG_Rate_Max_Time``: the time at which maximum heart rate occurs.
38-
* ``ECG_Rate_Min_Time``: the time at which minimum heart rate occurs.
39-
* ``ECG_Phase_Atrial``: indication of whether the onset of the event concurs with
40-
respiratory systole (1) or diastole (0).
41-
* ``ECG_Phase_Ventricular``: indication of whether the onset of the event concurs with
42-
respiratory systole (1) or diastole (0).
43-
* ``ECG_Phase_Atrial_Completion``: indication of the stage of the current cardiac (atrial)
44-
phase (0 to 1) at the onset of the event.
45-
* ``ECG_Phase_Ventricular_Completion``: indication of the stage of the current cardiac
46-
(ventricular) phase (0 to 1) at the onset of the event.
33+
.. codebookadd::
34+
ECG_Rate_Max|The maximum heart rate after stimulus onset.
35+
ECG_Rate_Min|The minimum heart rate after stimulus onset.
36+
ECG_Rate_Mean|The mean heart rate after stimulus onset.
37+
ECG_Rate_SD|The standard deviation of the heart rate after stimulus onset.
38+
ECG_Rate_Max_Time|The time at which maximum heart rate occurs.
39+
ECG_Rate_Min_Time|The time at which minimum heart rate occurs.
40+
ECG_Phase_Atrial|Indication of whether the onset of the event concurs with \
41+
respiratory systole (1) or diastole (0).
42+
ECG_Phase_Ventricular|Indication of whether the onset of the event concurs with \
43+
respiratory systole (1) or diastole (0).
44+
ECG_Phase_Atrial_Completion|Indication of the stage of the current cardiac (atrial) \
45+
phase (0 to 1) at the onset of the event.
46+
ECG_Phase_Ventricular_Completion|Indication of the stage of the current cardiac \
47+
(ventricular) phase (0 to 1) at the onset of the event.
4748
4849
We also include the following *experimental* features related to the parameters of a
4950
quadratic model:
5051
51-
* ``ECG_Rate_Trend_Linear``: The parameter corresponding to the linear trend.
52-
* ``ECG_Rate_Trend_Quadratic``: The parameter corresponding to the curvature.
53-
* ``ECG_Rate_Trend_R2``: the quality of the quadratic model. If too low, the parameters
54-
might not be reliable or meaningful.
52+
.. codebookadd::
53+
ECG_Rate_Trend_Linear|The parameter corresponding to the linear trend.
54+
ECG_Rate_Trend_Quadratic|The parameter corresponding to the curvature.
55+
ECG_Rate_Trend_R2|The quality of the quadratic model. If too low, the parameters \
56+
might not be reliable or meaningful.
5557
5658
See Also
5759
--------

0 commit comments

Comments
 (0)