diff --git a/pyproject.toml b/pyproject.toml index b61505f..d57af0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ packages = ["src/epilepsy2bids"] [project] name = "epilepsy2bids" -version = "0.0.2" +version = "0.0.3" authors = [ { name="Jonathan Dan", email="jonathan.dan@epfl.ch" }, { name="PEDESITE" } @@ -28,13 +28,13 @@ description = "Python library for converting EEG datasets of people with epileps readme = "README.md" requires-python = ">=3.10" dependencies = [ - "nptyping>=2.5.0", "numpy>=1.24.3", "pandas>=2.1.3", "pyarrow>=16.1.0", "pyedflib>=0.1.36", "resampy>=0.4.2", - "termcolor>=2.4.0" + "termcolor>=2.4.0", + "timescoring>=v0.0.5" ] classifiers = [ "Programming Language :: Python :: 3", diff --git a/requirements.txt b/requirements.txt index 6b22944..27e7a1a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -nptyping numpy pandas pyarrow diff --git a/src/epilepsy2bids/annotations.py b/src/epilepsy2bids/annotations.py index 9af1867..0872787 100644 --- a/src/epilepsy2bids/annotations.py +++ b/src/epilepsy2bids/annotations.py @@ -2,10 +2,11 @@ import json from datetime import datetime from importlib import resources as impresources -from typing import TypedDict +from typing import List, Tuple, TypedDict import numpy as np import pandas as pd +from timescoring.annotations import Annotation as MaskEvents from . import bids @@ -73,6 +74,36 @@ def loadTsv(cls, filename: str): return annotations + @classmethod + def loadMask(cls, mask, fs): + maskEvent = MaskEvents(mask, fs) + return cls.loadEvents(maskEvent.events, len(mask) / fs) + + @classmethod + def loadEvents(cls, events: List[Tuple[float, float]], duration: float): + annotations = cls() + for event in events: + annotation = Annotation() + annotation["onset"] = event[0] + annotation["duration"] = event[1] - event[0] + annotation["eventType"] = SeizureType.sz + annotation["confidence"] = "n/a" + annotation["channels"] = "n/a" + annotation["dateTime"] = "n/a" + annotation["recordingDuration"] = duration + annotations.events.append(annotation) + if len(events) == 0: + annotation = Annotation() + annotation["onset"] = 0 + annotation["duration"] = duration + annotation["eventType"] = EventType.bckg + annotation["confidence"] = "n/a" + annotation["channels"] = "n/a" + annotation["dateTime"] = "n/a" + annotation["recordingDuration"] = duration + annotations.events.append(annotation) + return annotations + def getEvents(self) -> list[(float, float)]: events = list() for event in self.events: @@ -110,7 +141,10 @@ def saveTsv(self, filename: str): line += "\t" else: line += "{}\t".format(event["channels"]) - line += "{}\t".format(event["dateTime"].strftime("%Y-%m-%d %H:%M:%S")) + if isinstance(event["dateTime"], datetime): + line += "{}\t".format(event["dateTime"].strftime("%Y-%m-%d %H:%M:%S")) + else: + line += "{}\t".format(event["dateTime"]) line += "{:.2f}".format(event["recordingDuration"]) line += "\n" f.write(line) diff --git a/src/epilepsy2bids/eeg.py b/src/epilepsy2bids/eeg.py index d2b9af0..c296cff 100644 --- a/src/epilepsy2bids/eeg.py +++ b/src/epilepsy2bids/eeg.py @@ -10,7 +10,6 @@ import pandas as pd import pyedflib import resampy -from nptyping import Float, NDArray, Shape class FileFormat(str, enum.Enum): @@ -113,7 +112,7 @@ class FileHeader(TypedDict): def __init__( self, - data: NDArray[Shape["*, *"], Float], + data, channels: tuple[str], fs: int, montage: Montage = Montage.UNIPOLAR, @@ -209,18 +208,18 @@ def loadEdfAutoDetectMontage(cls, edfFile: str): with pyedflib.EdfReader(edfFile) as edf: channel = edf.getLabel(0) edf._close() - if channel == Eeg.ELECTRODES_10_20[0]: + if channel == Eeg.ELECTRODES_10_20[0].upper(): montage = Eeg.Montage.UNIPOLAR electrodes = Eeg.ELECTRODES_10_20 - elif channel == Eeg.BIPOLAR_DBANANA[0]: - montage = Eeg.Montage.BIPOLAR_DBANANA + elif channel == Eeg.BIPOLAR_DBANANA[0].upper(): + montage = Eeg.Montage.BIPOLAR electrodes = Eeg.BIPOLAR_DBANANA else: raise ValueError( f"Unrecognized electrode: {channel}. Expected {Eeg.ELECTRODES_10_20[0]} or {Eeg.BIPOLAR_DBANANA[0]}" ) - return Eeg.loadEdf(edfFile, montage, electrodes) + return cls.loadEdf(edfFile, montage, electrodes) def resample(self, newFs: int): """Resample data to a new sampling frequency.