Skip to content
This repository was archived by the owner on Sep 12, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
52118a9
Merge pull request #2 from AdvPyS22/new-modifs
AxelGiottonini May 18, 2022
93b69a5
change main.py to __main__.py
NoahHenrikKleinschmidt May 19, 2022
6a5ed11
update readme
NoahHenrikKleinschmidt May 19, 2022
5bfc4a2
added some unittests
May 21, 2022
c32584b
Merge remote-tracking branch 'origin/main' into dev
May 21, 2022
3e1b800
Merge branch 'dev' of github.com:AdvPyS22/EEGToolkit into dev
May 21, 2022
538f9c5
extract now checks for valid timewindow and raises ValueErrors
NoahHenrikKleinschmidt May 28, 2022
39fa7bf
add axes unit functions
NoahHenrikKleinschmidt May 28, 2022
828d5e6
update test figure
NoahHenrikKleinschmidt May 28, 2022
e1518f2
update docs
NoahHenrikKleinschmidt May 28, 2022
488fcdc
fix the tests +++ exclude tests from doc
NoahHenrikKleinschmidt May 28, 2022
e58c636
update version to v2.0.2
NoahHenrikKleinschmidt May 28, 2022
5d3fd07
add latest v2.0.1
NoahHenrikKleinschmidt May 28, 2022
6537919
add v.2.0.2
NoahHenrikKleinschmidt May 28, 2022
248d1b1
update gitignore
NoahHenrikKleinschmidt May 28, 2022
b3f7749
update PKG-INFOs for v2.0.2
NoahHenrikKleinschmidt May 28, 2022
ef641cf
add installation instructions
NoahHenrikKleinschmidt May 28, 2022
2a4da5f
add presentation notebook
NoahHenrikKleinschmidt May 28, 2022
b4c24c5
fix presentation image links
NoahHenrikKleinschmidt May 28, 2022
b240db8
add output example image to readme
NoahHenrikKleinschmidt May 28, 2022
cf4c4ba
Create LICENSE.md
AxelGiottonini May 29, 2022
a8a5f16
add Close Button to app
NoahHenrikKleinschmidt May 30, 2022
78aad95
add newest compiled
NoahHenrikKleinschmidt May 30, 2022
690fce4
Merge branch 'dev' of https://github.com/AdvPyS22/EEGToolkit into dev
NoahHenrikKleinschmidt May 30, 2022
241023a
update version to v2.0.3
NoahHenrikKleinschmidt May 30, 2022
5a0d4fa
update version to v.2.0.3
NoahHenrikKleinschmidt May 30, 2022
309dd9b
update doc_and_build to add optional additional install + testpypi di…
NoahHenrikKleinschmidt May 30, 2022
30915a0
final binary compiled
NoahHenrikKleinschmidt Jun 2, 2022
7ad2a13
Presentation further ideas
AxelGiottonini Jun 2, 2022
7ee7543
Merge branch 'dev' of https://github.com/AdvPyS22/EEGToolkit into dev
AxelGiottonini Jun 2, 2022
2400b75
beluga <3
AxelGiottonini Jun 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
test.ipynb
.ipynb_checkpoints/
EEGToolkit/__pycache__/
.vscode/settings.json
65 changes: 61 additions & 4 deletions EEGToolkit.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: EEGToolkit
Version: 2.0.0
Version: 2.0.3
Summary: A package for EEG data analysis of reaction time-delay experiments.
Home-page: https://github.com/AxelGiottonini/AP-EEG.git
Author: Axel Giottonini, Noah Kleinschmidt, Kalvin Dobler
Expand All @@ -12,10 +12,67 @@ Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE.md

# AP-EEG

## Project description
This package offers a quick way to analyse EEG data for reaction time-delay experiments. The package comes not just with an API, but additionally with both a direct command-line interface as well as a web-app based graphical user interface.

Two types of datafiles are required to run: one with the raw EEG signal data, and one with meta data about the timepoints of different types of events. Supported filetypes are `csv`, `txt`, `tsv`, and `npy`.

The output is a summary figure that compares the EEG signal of different event types between each other as well as for each event against the baseline through a position-wise t-test, and highlights significant differences in signal responses.

### Installation
This package can be installed via `pip` from the TestPyPi Index using
```bash
pip install -i https://test.pypi.org/simple/ EEGToolkit
```

### Example Usage
#### CLI
```bash
EEGToolkit --eeg ./data/eeg.txt
--event ./data/events.tsv
# the frequency at which data was recorded
-f 500
# start and end of the time
# window around each event timepoint
-s -0.5 -e 1.2
```
#### GUI
```bash
EEGToolkit --viewer
# or
EEGToolkit -i
```
#### API
```python
import EEGToolkit as eeg

# setup the EEGData object
e = eeg.EEGData(
signal_path = "./data/eeg.txt",
event_path = "./data/events.tsv",
sampling_frequency = 500
)

# extract event time-windows
e.extract( start_sec = -0.5, stop_sec = 1.2 )

# perform baseline comparison for each signal
e.baseline()

# change the labelling scales of the data
timescale = 1000 # milliseconds
signalscale = 1000 # millivolts

# generate a summary figure
e.summary( x_scale = timescale, y_scale = signalscale )
```
### Example Output
![](./test.png)

> ## EEG data analysis
> Students who choose this task ill be provided with the raw EEG recording of one channel, sampled at $500 [Hz]$ which was recorded from a participant presented with auditory stimuli. The students will also receive an events file describing when during the recording one out of two possible sounds were presented to the subject.
> ### Task 1
Expand Down Expand Up @@ -47,8 +104,8 @@ a desirable extention.
- [x] re-factoring for private methods ...
- [x] requirements.txt
- [x] setup.py
- [ ] (optional but kinda cool) adding EEGData to PYTHONPATH to allow direct CLI calling...
- [ ] `testpypi` distribution
- [x] (optional but kinda cool) a cool Entrypoint to allow direct CLI calling...
- [x] `testpypi` distribution
- [x] HTML documentation

#### CLI TODOs:
Expand All @@ -64,7 +121,7 @@ a desirable extention.

##### Task 2:
- [x] plotting is pretty much finished already...
- [ ] Add units to the figure axes labels
- [x] Add units to the figure axes labels
- [x] (optional) adjust color scheme ...

##### Task 3:
Expand Down
5 changes: 4 additions & 1 deletion EEGToolkit.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
LICENSE.md
README.md
setup.py
EEGToolkit/__init__.py
EEGToolkit/main.py
EEGToolkit/__main__.py
EEGToolkit/test_procedure.py
EEGToolkit.egg-info/PKG-INFO
EEGToolkit.egg-info/SOURCES.txt
EEGToolkit.egg-info/dependency_links.txt
EEGToolkit.egg-info/entry_points.txt
EEGToolkit.egg-info/top_level.txt
EEGToolkit/EEGData/EEGData.py
EEGToolkit/EEGData/__init__.py
EEGToolkit/EEGData/__main__.py
EEGToolkit/EEGStats/EEGStats.py
EEGToolkit/EEGStats/__init__.py
EEGToolkit/auxiliary/__init__.py
Expand Down
5 changes: 4 additions & 1 deletion EEGToolkit/EEGData/EEGData.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ def extract(self,
self._extracted_events = events_to_extract
return data

if start_sec is None or stop_sec is None:
raise ValueError( f"A valid timewindow needs to be specified as float values! Received start_sec = {start_sec} and stop_sec = {stop_sec}" )

# now the part for extracting only a
# single event type data
data = self._extract_window(start_sec, stop_sec, event_type)
Expand Down Expand Up @@ -730,7 +733,7 @@ def main():
inspect.getfile( plot_signal )
)
directory = os.path.dirname( directory )
main_file = f"{directory}/main.py"
main_file = f"{directory}/__main__.py"

# then we call the web interface
print( "Starting the \033[94mEEGToolKit \033[96mViewer" )
Expand Down
Binary file modified EEGToolkit/EEGData/__pycache__/EEGData.cpython-38.pyc
Binary file not shown.
Binary file modified EEGToolkit/EEGData/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
72 changes: 64 additions & 8 deletions EEGToolkit/EEGStats/EEGStats.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,58 @@
from matplotlib.lines import Line2D
from matplotlib.patches import Patch


# ----------------------------------------------------------------
# Data Statistics
# Default Settings
# ----------------------------------------------------------------

timescale = 1
eegscale = 1

def get_unit_scale( scale : int, ref_scale : float, ref_unit : str ):
"""
Generates a scaled unit axis label

Parameters
----------
scale : int
The scaling factor of the given reference unit.
ref_scale : foat
The scaling factor for the base data units.
E.g. use 0.01 if the data was recorded in milli-seconds rather than seconds, ect.
ref_unit : str
The unit name. E.g. `"V"` for Volts or `"s"` for seconds etc.

Returns
-------
s : str
A scaled representation of the given unit for figure axis labelling.
E.g. `"[mV]"`, `"[ns]"`, or `"[$10^{-4}$s]" etc.
"""

scale_units = {
1 * ref_scale : "",
10 * ref_scale : "d",
100 * ref_scale : "c",
1000 * ref_scale : "m",
10**6 * ref_scale : "n",
}

# try to get the appropriate scale unit
s = scale_units.get( scale, None )

# if no unit is pre-defined, just use 10^n notation
if s is None:
s = int( np.log10( 1/scale ) )
s = "$10^{" + str(s) + "}$"

# now format to e.g. [mV] or [10^-4s] etc. for use in axis labels...
s = f"[{s}{ref_unit}]"
return s

# ----------------------------------------------------------------
# Data Statistics
# ----------------------------------------------------------------

def mean(extracted_EEGData:np.ndarray) -> np.ndarray:
"""
Expand Down Expand Up @@ -124,7 +172,7 @@ def plot_signal(
baseline : np.ndarray = None,
significance_level:float = 0.05,
make_legend = False,
ax = None ) -> None:
ax = None ) -> np.ndarray:
"""
Visualises a single EGG signal dataset from an `m x n numpy ndarray`
with `m` repeated datasets and `n` entries per set. It generates a solid
Expand Down Expand Up @@ -206,7 +254,7 @@ def difference_plot(extracted_EEGData_1:np.ndarray,
x_scale=10**3,
y_scale=10**3,
make_legend = False,
ax = None ) -> None:
ax = None ) -> np.ndarray:

"""
Visualises the difference between two EEG signals and tests
Expand Down Expand Up @@ -351,8 +399,10 @@ def _plot_(

# and some axes formatting...
ax.set_title("Average EEG Signal (Shaded area SEM)")
ax.set_ylabel("Signal\namplitude")
ax.set_xlabel("Time relative to event (ms)")
yunit = get_unit_scale( y_scale, ref_scale = eegscale, ref_unit = "V" )
ax.set_ylabel(f"Signal\namplitude {yunit}")
xunit = get_unit_scale( x_scale, ref_scale = timescale, ref_unit = "s" )
ax.set_xlabel(f"Time relative to event {xunit}")

if make_legend:
handles = [
Expand Down Expand Up @@ -439,8 +489,10 @@ def _difference_plot_(ax,

# and some axes formatting...
ax.set_title("Average EEG Signal (Shaded area significant regions)")
ax.set_ylabel("Signal\namplitude")
ax.set_xlabel("Time relative to event (ms)")
yunit = get_unit_scale( y_scale, ref_scale = eegscale, ref_unit = "V" )
ax.set_ylabel(f"Signal\namplitude {yunit}")
xunit = get_unit_scale( x_scale, ref_scale = timescale, ref_unit = "s" )
ax.set_xlabel(f"Time relative to event {xunit}")

if make_legend:
# now add a custom legend
Expand Down Expand Up @@ -516,4 +568,8 @@ def _scale_yboundries(y_scale, max_y, min_y, pad = 1 ):
"""
max_y *= y_scale * pad
min_y *= y_scale * pad
return min_y, max_y
return min_y, max_y


if __name__ == "__main__":
get_unit_scale( 10000, 1, "V" )
Binary file modified EEGToolkit/EEGStats/__pycache__/EEGStats.cpython-38.pyc
Binary file not shown.
Binary file modified EEGToolkit/EEGStats/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
6 changes: 5 additions & 1 deletion EEGToolkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@
```
"""
from .EEGData import *
from .EEGStats import *
from .EEGStats import *

__pdoc__ = {
"EEGToolkit.test_procedure": False
}
14 changes: 13 additions & 1 deletion EEGToolkit/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"""
import sys
import os
import signal
from time import sleep

import streamlit as st
import pandas as pd
Expand All @@ -16,6 +18,7 @@
from auxiliary import Session, stEEGData

if __name__ == "__main__":
pid = os.getpid()
session = Session()

# =================================================================
Expand Down Expand Up @@ -128,6 +131,10 @@
"Compute",
help = "Perform computations and output a figure",
)
kill_button = lower_ctrl_col1.button(
"Close App",
help = "Close the App",
)

# =================================================================
# Computational Section
Expand Down Expand Up @@ -156,4 +163,9 @@
significance_level = significance_level
)

figure_container.pyplot( fig )
figure_container.pyplot( fig )

if kill_button:
st.info( "Shutting down...\nThis window can now be closed.")
sleep(0.5)
os.kill( pid, signal.SIGINT )
Binary file modified EEGToolkit/auxiliary/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
Binary file modified EEGToolkit/auxiliary/__pycache__/auxiliary.cpython-38.pyc
Binary file not shown.
28 changes: 28 additions & 0 deletions EEGToolkit/test_procedure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
This script performs some unit testing.
"""

import unittest
from EEGToolkit.EEGData import EEGData

signal_path = 'data/eeg.npy'
event_path = 'data/events.npy'
sampling_frequency = 500
data = EEGData(signal_path, event_path, sampling_frequency)

# General class for performing some unit tests
class Testclass(unittest.TestCase):

def test_adjust_timsteps(self):
self.assertTupleEqual(data._adjust_timesteps(-0.5, 1), (-250, 500), "Start frame and stop frame should be -250 and 500")

def test_set_nevents(self):
self.assertListEqual(data.events, [0, 1], "The list should be [0, 1]")

def test_suffix(self):
self.assertTrue(data._filesuffix(signal_path) == 'npy', "The suffix should be 'npy'")
self.assertTrue(data._filesuffix(event_path) == 'npy', "The suffix should be 'npy'")


if __name__ == "__main__":
unittest.main()
Loading