Skip to content

Commit

Permalink
Support channel groups for rawless subjects
Browse files Browse the repository at this point in the history
  • Loading branch information
teekuningas committed Apr 3, 2024
1 parent 1afa50d commit 1c00c51
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 36 deletions.
5 changes: 5 additions & 0 deletions meggie/datatypes/epochs/epochs.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ def params(self):
"""Returns additional information stored."""
return self._params

@property
def info(self):
"""Returns info."""
return self.content.info

def delete_content(self):
"""Deletes the fif file from the files system"""
os.remove(self._path)
Expand Down
30 changes: 17 additions & 13 deletions meggie/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from meggie.utilities.filemanager import open_raw
from meggie.utilities.filemanager import save_raw
from meggie.utilities.channels import get_default_channel_groups
from meggie.utilities.channels import find_montage_info
from meggie.utilities.validators import validate_name
from meggie.utilities.uid import generate_uid

Expand Down Expand Up @@ -81,23 +82,26 @@ def channel_groups(self):
"""Returns channel groups for experiment. If not set,
uses defaults."""
channel_groups = self._channel_groups.copy()
specs = find_all_datatype_specs()

# if channel groups not found, use defaults..
# if channel groups not found, look for defaults..
if not channel_groups.get("eeg"):
if self.active_subject and self.active_subject.has_raw:
raw = self.active_subject.get_raw(preload=False)
try:
channel_groups["eeg"] = get_default_channel_groups(raw, "eeg")
except Exception:
pass
if self.active_subject:
info = find_montage_info(self.active_subject, specs.keys(), "eeg")
if info:
try:
channel_groups["eeg"] = get_default_channel_groups(info, "eeg")
except Exception:
pass

if not channel_groups.get("meg"):
if self.active_subject and self.active_subject.has_raw:
raw = self.active_subject.get_raw(preload=False)
try:
channel_groups["meg"] = get_default_channel_groups(raw, "meg")
except Exception:
pass
if self.active_subject:
info = find_montage_info(self.active_subject, specs.keys(), "meg")
if info:
try:
channel_groups["meg"] = get_default_channel_groups(info, "meg")
except Exception:
pass

return channel_groups

Expand Down
27 changes: 16 additions & 11 deletions meggie/mainwindow/dialogs/channelGroupsDialogMain.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from meggie.utilities.messaging import exc_messagebox
from meggie.utilities.channels import get_default_channel_groups
from meggie.utilities.channels import get_triplet_from_mag
from meggie.utilities.channels import find_montage_info
from meggie.mainwindow.dynamic import find_all_datatype_specs

from meggie.mainwindow.dialogs.channelGroupsDialogUi import Ui_channelGroupsDialog

Expand Down Expand Up @@ -93,17 +95,18 @@ def on_pushButtonReset_clicked(self, checked=None):
messagebox(self.parent, "To reset, active subject is needed")
return

raw = subject.get_raw()
specs = find_all_datatype_specs()

if self.ui.radioButtonEEG.isChecked():
self.eeg_channel_groups = get_default_channel_groups(raw, "eeg")
info = find_montage_info(subject, specs.keys(), "eeg")
self.eeg_channel_groups = get_default_channel_groups(info, "eeg")
self.ui.listWidgetChannelGroups.clear()
for ch_name in sorted(self.eeg_channel_groups.keys()):
self.ui.listWidgetChannelGroups.addItem(ch_name)

else:
meg_defaults = get_default_channel_groups(raw, "meg")
self.meg_channel_groups = meg_defaults
info = find_montage_info(subject, specs.keys(), "meg")
self.meg_channel_groups = get_default_channel_groups(info, "meg")
self.ui.listWidgetChannelGroups.clear()
for ch_name in sorted(self.meg_channel_groups.keys()):
self.ui.listWidgetChannelGroups.addItem(ch_name)
Expand All @@ -123,16 +126,17 @@ def on_pushButtonSetChannels_clicked(self, checked=None):
messagebox(self.parent, "Select a channel group first")
return

raw = subject.get_raw()
specs = find_all_datatype_specs()

if self.ui.radioButtonEEG.isChecked():
if mne.pick_types(raw.info, meg=False, eeg=True).size == 0:
info = find_montage_info(subject, specs.keys(), "eeg")
if mne.pick_types(info, meg=False, eeg=True).size == 0:
messagebox(self.parent, "No EEG channels found")
return

ch_names = self.eeg_channel_groups[selected_item.text()]
try:
ch_idxs = [raw.info["ch_names"].index(ch_name) for ch_name in ch_names]
ch_idxs = [info["ch_names"].index(ch_name) for ch_name in ch_names]
except ValueError:
messagebox(
self.parent,
Expand All @@ -144,7 +148,7 @@ def on_pushButtonSetChannels_clicked(self, checked=None):

try:
fig, selection = mne.viz.plot_sensors(
raw.info,
info,
kind="select",
ch_type="eeg",
ch_groups=ch_groups,
Expand All @@ -156,13 +160,14 @@ def on_pushButtonSetChannels_clicked(self, checked=None):
return

else:
if mne.pick_types(raw.info, meg=True, eeg=False).size == 0:
info = find_montage_info(subject, specs.keys(), "meg")
if mne.pick_types(info, meg=True, eeg=False).size == 0:
messagebox(self.parent, "No MEG channels found")
return

ch_names = self.meg_channel_groups[selected_item.text()]
try:
ch_idxs = [raw.info["ch_names"].index(ch_name) for ch_name in ch_names]
ch_idxs = [info["ch_names"].index(ch_name) for ch_name in ch_names]
except ValueError:
messagebox(
self.parent,
Expand All @@ -173,7 +178,7 @@ def on_pushButtonSetChannels_clicked(self, checked=None):
ch_groups = [[], ch_idxs]

fig, selection = mne.viz.plot_sensors(
raw.info,
info,
kind="select",
ch_type="mag",
ch_groups=ch_groups,
Expand Down
54 changes: 45 additions & 9 deletions meggie/utilities/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def is_montage_set(info, ch_type):
ch_names = [ch_name for idx, ch_name in enumerate(info["ch_names"]) if idx in picks]

if not ch_names:
raise Exception("Data does not contain channels of type " + str(ch_type))
return False

info_filt = filter_info(info, ch_names)

Expand All @@ -52,7 +52,45 @@ def ensure_montage(subject, inst, ch_type):
inst.set_montage(montage)


def get_default_channel_groups(raw, ch_type):
def find_montage_info(subject, datatypes, ch_type):
"""Try to find channel locations first from raw and then from any dataobject.
Parameters
----------
subject : meggie.subject.Subject
The subject to find the montage info in
ch_type : str
Should be 'meg' or 'eeg'.
datatypes : list
List of datatypes to look into
Returns
-------
info : mne.Info | None
Info containing channel locations.
"""

if subject.has_raw:
raw = subject.get_raw(preload=False)
if is_montage_set(raw.info, ch_type):
return raw.info

for datatype in datatypes:
objects = getattr(subject, datatype, {})
for key, item in objects.items():
try:
info = item.info
except NotImplementedError:
continue

if is_montage_set(info, ch_type):
return info

# Did not find anything..
return None


def get_default_channel_groups(info, ch_type):
"""Returns channels grouped by standard locations
(Left-frontal, Right-occipital, etc.). Grouping is done via
geometric division from mne, to have a generic ability
Expand All @@ -74,21 +112,19 @@ def get_default_channel_groups(raw, ch_type):
"""

if ch_type == "meg":
picks = mne.pick_types(raw.info, meg=True, eeg=False)
picks = mne.pick_types(info, meg=True, eeg=False)
else:
picks = mne.pick_types(raw.info, meg=False, eeg=True)
picks = mne.pick_types(info, meg=False, eeg=True)

ch_names = [
ch_name for idx, ch_name in enumerate(raw.info["ch_names"]) if idx in picks
]
ch_names = [ch_name for idx, ch_name in enumerate(info["ch_names"]) if idx in picks]
if not ch_names:
return {}

# check if there is no montage set..
if not is_montage_set(raw.info, ch_type):
if not is_montage_set(info, ch_type):
return {}

info_filt = filter_info(raw.info, ch_names)
info_filt = filter_info(info, ch_names)

regions = _divide_to_regions(info_filt, add_stim=False)

Expand Down
6 changes: 3 additions & 3 deletions meggie/utilities/tests/test_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_default_channel_groups():

raw = mne.io.read_raw_fif(sample_fname)

assert get_default_channel_groups(raw, "eeg")["Left-frontal"] == [
assert get_default_channel_groups(raw.info, "eeg")["Left-frontal"] == [
"EEG 001",
"EEG 004",
"EEG 005",
Expand Down Expand Up @@ -77,8 +77,8 @@ def test_average_to_channel_groups():

ch_names = info["ch_names"][:20]

meg_channel_groups = get_default_channel_groups(raw, "meg")
eeg_channel_groups = get_default_channel_groups(raw, "eeg")
meg_channel_groups = get_default_channel_groups(raw.info, "meg")
eeg_channel_groups = get_default_channel_groups(raw.info, "eeg")

# find out to which channel group each of the channels belongs to
results = []
Expand Down

0 comments on commit 1c00c51

Please sign in to comment.