Skip to content

Commit

Permalink
Add elementary support for open datasets and epoch-based analysis wit…
Browse files Browse the repository at this point in the history
…hout raw data
  • Loading branch information
teekuningas committed Mar 28, 2024
1 parent c9f53ce commit 438ed54
Show file tree
Hide file tree
Showing 23 changed files with 283 additions and 63 deletions.
3 changes: 2 additions & 1 deletion meggie/actions/epochs_create/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "epochs_create",
"name": "Create epochs",
"entry": "CreateEpochs",
"description": "Create a new epoch collection for the current subject."
"description": "Create a new epoch collection for the current subject.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_event_info/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_event_info",
"name": "Event info",
"entry": "Info",
"description": "Extract event information from the raw data."
"description": "Extract event information from the raw data.",
"tags": ["raw"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_events_from_annotations",
"name": "Events from annotations",
"entry": "EventsFromAnnotations",
"description": "Create events from annotations for further analysis."
"description": "Create events from annotations for further analysis.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_filter/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_filter",
"name": "Filter",
"entry": "Filter",
"description": "Apply low-pass, high-pass, band-pass, and band-stop filters to raw data to isolate specific frequency ranges or remove unwanted frequencies."
"description": "Apply low-pass, high-pass, band-pass, and band-stop filters to raw data to isolate specific frequency ranges or remove unwanted frequencies.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_ica/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_ica",
"name": "Artifact removal",
"entry": "ICA",
"description": "Apply Independent Component Analysis (ICA) to raw data to identify and remove artifacts such as heartbeats and eye blinks."
"description": "Apply Independent Component Analysis (ICA) to raw data to identify and remove artifacts such as heartbeats and eye blinks.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_measurement_info/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_measurement_info",
"name": "Measurement info",
"entry": "Info",
"description": "Extract measurement information from the raw data."
"description": "Extract measurement information from the raw data.",
"tags": ["raw"]
}
2 changes: 1 addition & 1 deletion meggie/actions/raw_montage/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"name": "Montage",
"entry": "Montage",
"description": "Apply a montage to the EEG dataset, enabling the creation of topographical plots.",
"tags": ["eeg"]
"tags": ["eeg", "raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_plot/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_plot",
"name": "Plot raw",
"entry": "PlotRaw",
"description": "Produce a time series plot of the raw data."
"description": "Produce a time series plot of the raw data.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_plot_projections/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_plot_projections",
"name": "Plot projections",
"entry": "PlotProjections",
"description": "Generate a plot to visualize the projection vectors contained within the raw data."
"description": "Generate a plot to visualize the projection vectors contained within the raw data.",
"tags": ["raw"]
}
2 changes: 1 addition & 1 deletion meggie/actions/raw_rereference/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"name": "Rereference",
"entry": "Rereference",
"description": "Re-reference the raw data to an average reference, which can be computed from one or more selected channels or all channels.",
"tags": ["eeg"]
"tags": ["eeg", "raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/raw_resample/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "raw_resample",
"name": "Resample",
"entry": "Resample",
"description": "Adjust the dataset by resampling it to a different sampling frequency."
"description": "Adjust the dataset by resampling it to a different sampling frequency.",
"tags": ["raw"]
}
3 changes: 2 additions & 1 deletion meggie/actions/spectrum_create/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"id": "spectrum_create",
"name": "Create spectrum",
"entry": "CreateSpectrum",
"description": "Calculate the spectral data at specified time intervals for the current subject."
"description": "Calculate the spectral data at specified time intervals for the current subject.",
"tags": ["raw"]
}
42 changes: 29 additions & 13 deletions meggie/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ def activate_subject(self, subject_name):
self.active_subject = self.subjects[subject_name]

# test validity
self.active_subject.get_raw(preload=False)
if self.active_subject.has_raw:
self.active_subject.get_raw(preload=False)

return self.active_subject

Expand All @@ -196,25 +197,41 @@ def create_subject(self, subject_name, raw_path):
----------
subject_name : str
Name of the new subject.
raw_path : str
raw_path : str | None
Path to the data file.
Returns
-------
meggie.subject.Subject
The activated subject.
"""
bname = os.path.basename(raw_path)
stem, ext = os.path.splitext(bname)
new_fname = stem + ".fif"

uid = generate_uid()

subject = Subject(self, subject_name, new_fname, uid)
subject.ensure_folders()
# it is possible to add "placeholder" subjects with only e.g epochs data
if raw_path:
bname = os.path.basename(raw_path)
stem, ext = os.path.splitext(bname)
new_fname = stem + ".fif"

raw = open_raw(raw_path)
subject = Subject(self, subject_name, new_fname, uid)
subject.ensure_folders()

new_path = os.path.join(subject.path, new_fname)
save_raw(raw, new_path)
raw = open_raw(raw_path)

new_path = os.path.join(subject.path, new_fname)
save_raw(raw, new_path)

else:
subject = Subject(self, subject_name, "", uid)

subject.ensure_folders()

self.add_subject(subject)

return subject

def save_experiment_settings(self):
"""
Saves the experiment settings into a file in the root of
Expand All @@ -225,7 +242,7 @@ def save_experiment_settings(self):
for subject in self.subjects.values():
subject_dict = {
"subject_name": subject.name,
"raw_fname": subject.raw_fname,
"raw_fname": subject.raw_fname if subject.raw_fname else "",
"uid": subject.uid,
"ica_applied": subject.ica_applied,
"rereferenced": subject.rereferenced,
Expand Down Expand Up @@ -401,11 +418,10 @@ def open_existing_experiment(prefs, path=None):
subject_name = subject_data["subject_name"]

raw_fname = subject_data.get("raw_fname")

# for backwards compatibility
if not raw_fname:
raw_fname = subject_data.get("working_file_name")
if not raw_fname:
raise Exception("raw_fname not set in the exp file")

uid = subject_data.get("uid")
if not uid:
Expand Down
19 changes: 14 additions & 5 deletions meggie/mainWindowMain.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,18 +273,27 @@ def update_ui(self):
def reconstruct_tabs(self):
"""Reconstructs the tabs."""

if self.experiment and self.experiment.active_subject:
include_eeg = self.experiment.active_subject.has_eeg
else:
include_eeg = True
include_eeg = True
has_raw = True
if self.experiment:
active_subject = self.experiment.active_subject
if active_subject:
has_raw = active_subject.has_raw
if has_raw:
include_eeg = active_subject.has_eeg

if self.experiment:
selected_pipeline = self.experiment.selected_pipeline
else:
selected_pipeline = "classic"

try:
self.tabs = construct_tabs(
selected_pipeline, self, self.prefs, include_eeg=include_eeg
selected_pipeline,
self,
self.prefs,
include_eeg=include_eeg,
has_raw=has_raw,
)
except Exception as exc:
self.tabs = []
Expand Down
28 changes: 23 additions & 5 deletions meggie/mainwindow/dialogs/createExperimentDialogMain.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from meggie.mainwindow.dynamic import find_all_package_specs

from meggie.utilities.threading import threaded
from meggie.utilities.datasets import get_open_datasets
from meggie.utilities.messaging import exc_messagebox
from meggie.utilities.messaging import messagebox

Expand All @@ -27,6 +29,11 @@ def __init__(self, parent):

self.active_plugins = prefs.active_plugins

self.ui.comboBoxOpenData.addItem("")
self.datasets = sorted(get_open_datasets().items(), key=lambda x: x[1]["title"])
for key, dataset in self.datasets:
self.ui.comboBoxOpenData.addItem(dataset["title"])

# read all pipeline ids and names to a list
pipelines = []
package_specs = find_all_package_specs()
Expand Down Expand Up @@ -78,12 +85,23 @@ def accept(self):
selected_pipeline = self.pipelines[button_idx][0]
break

name = self.ui.lineEditExperimentName.text()
author = self.ui.lineEditAuthor.text()
prefs = self.parent.prefs

try:
experiment = initialize_new_experiment(
self.ui.lineEditExperimentName.text(),
self.ui.lineEditAuthor.text(),
self.parent.prefs,
)
open_data_index = self.ui.comboBoxOpenData.currentIndex()

@threaded
def threaded_initialize():
if open_data_index == 0:
experiment = initialize_new_experiment(name, author, prefs)
else:
item = self.datasets[open_data_index - 1]
experiment = item[1]["constructor"](name, author, prefs)
return experiment

experiment = threaded_initialize(do_meanwhile=self.parent.update_ui)

experiment.selected_pipeline = selected_pipeline
experiment.save_experiment_settings()
Expand Down
32 changes: 24 additions & 8 deletions meggie/mainwindow/dialogs/createExperimentDialogUi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

# Form implementation generated from reading ui file 'createExperimentDialogUi.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtWidgets
Expand All @@ -27,10 +28,6 @@ def setupUi(self, CreateExperimentDialog):
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
self.gridLayout.setObjectName("gridLayout")
spacerItem = QtWidgets.QSpacerItem(
20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding
)
self.gridLayout.addItem(spacerItem, 2, 1, 1, 1)
self.groupBoxInfo = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBoxInfo.setObjectName("groupBoxInfo")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBoxInfo)
Expand All @@ -53,6 +50,21 @@ def setupUi(self, CreateExperimentDialog):
self.gridLayoutPipeline = QtWidgets.QGridLayout(self.groupBoxPipeline)
self.gridLayoutPipeline.setObjectName("gridLayoutPipeline")
self.gridLayout.addWidget(self.groupBoxPipeline, 1, 1, 1, 1)
spacerItem = QtWidgets.QSpacerItem(
20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding
)
self.gridLayout.addItem(spacerItem, 3, 1, 1, 1)
self.groupBoxOpenData = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBoxOpenData.setObjectName("groupBoxOpenData")
self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBoxOpenData)
self.gridLayout_4.setObjectName("gridLayout_4")
self.labelOpenData = QtWidgets.QLabel(self.groupBoxOpenData)
self.labelOpenData.setObjectName("labelOpenData")
self.gridLayout_4.addWidget(self.labelOpenData, 0, 0, 1, 1)
self.comboBoxOpenData = QtWidgets.QComboBox(self.groupBoxOpenData)
self.comboBoxOpenData.setObjectName("comboBoxOpenData")
self.gridLayout_4.addWidget(self.comboBoxOpenData, 0, 1, 1, 1)
self.gridLayout.addWidget(self.groupBoxOpenData, 2, 1, 1, 1)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout_3.addWidget(self.scrollArea, 0, 0, 1, 1)
self.horizontalLayoutButtons = QtWidgets.QHBoxLayout()
Expand All @@ -70,8 +82,8 @@ def setupUi(self, CreateExperimentDialog):
self.gridLayout_3.addLayout(self.horizontalLayoutButtons, 2, 0, 1, 1)

self.retranslateUi(CreateExperimentDialog)
self.pushButtonAccept.clicked.connect(CreateExperimentDialog.accept)
self.pushButtonCancel.clicked.connect(CreateExperimentDialog.reject)
self.pushButtonAccept.clicked.connect(CreateExperimentDialog.accept) # type: ignore
self.pushButtonCancel.clicked.connect(CreateExperimentDialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(CreateExperimentDialog)

def retranslateUi(self, CreateExperimentDialog):
Expand All @@ -91,5 +103,9 @@ def retranslateUi(self, CreateExperimentDialog):
self.groupBoxPipeline.setTitle(
_translate("CreateExperimentDialog", "Select a pipeline for the analysis:")
)
self.groupBoxOpenData.setTitle(
_translate("CreateExperimentDialog", "Create from open data:")
)
self.labelOpenData.setText(_translate("CreateExperimentDialog", "Dataset:"))
self.pushButtonCancel.setText(_translate("CreateExperimentDialog", "Cancel"))
self.pushButtonAccept.setText(_translate("CreateExperimentDialog", "Ok"))
45 changes: 32 additions & 13 deletions meggie/mainwindow/dialogs/createExperimentDialogUi.ui
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,6 @@
</size>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBoxInfo">
<property name="title">
Expand Down Expand Up @@ -91,6 +78,38 @@
<layout class="QGridLayout" name="gridLayoutPipeline"/>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QGroupBox" name="groupBoxOpenData">
<property name="title">
<string>Create from open data:</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="labelOpenData">
<property name="text">
<string>Dataset:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxOpenData"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
Expand Down
Loading

0 comments on commit 438ed54

Please sign in to comment.