-
Notifications
You must be signed in to change notification settings - Fork 216
Better Neuroscope support. #3862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e073dcb
588c550
36953de
b969a9d
fa30844
d8475eb
9b0595f
963a811
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import warnings | ||
from pathlib import Path | ||
from typing import Union, Optional | ||
from xml.etree import ElementTree as Etree | ||
|
||
import numpy as np | ||
|
||
|
@@ -64,6 +65,8 @@ def __init__( | |
if xml_file_path is not None: | ||
xml_file_path = str(Path(xml_file_path).absolute()) | ||
self._kwargs.update(dict(file_path=str(Path(file_path).absolute()), xml_file_path=xml_file_path)) | ||
self.xml_file_path = xml_file_path if xml_file_path is not None else Path(file_path).with_suffix(".xml") | ||
self._set_groups() | ||
|
||
@classmethod | ||
def map_to_neo_kwargs(cls, file_path, xml_file_path=None): | ||
|
@@ -78,6 +81,64 @@ def map_to_neo_kwargs(cls, file_path, xml_file_path=None): | |
|
||
return neo_kwargs | ||
|
||
def _parse_xml_file(self, xml_file_path): | ||
""" | ||
Comes from NeuroPhy package by Diba Lab | ||
""" | ||
tree = Etree.parse(xml_file_path) | ||
myroot = tree.getroot() | ||
|
||
for sf in myroot.findall("acquisitionSystem"): | ||
n_channels = int(sf.find("nChannels").text) | ||
|
||
channel_groups, skipped_channels, anatomycolors = [], [], {} | ||
for x in myroot.findall("anatomicalDescription"): | ||
for y in x.findall("channelGroups"): | ||
for z in y.findall("group"): | ||
chan_group = [] | ||
for chan in z.findall("channel"): | ||
if int(chan.attrib["skip"]) == 1: | ||
skipped_channels.append(int(chan.text)) | ||
|
||
chan_group.append(int(chan.text)) | ||
if chan_group: | ||
channel_groups.append(np.array(chan_group)) | ||
|
||
for x in myroot.findall("neuroscope"): | ||
for y in x.findall("channels"): | ||
for i, z in enumerate(y.findall("channelColors")): | ||
try: | ||
channel_id = str(z.find("channel").text) | ||
color = z.find("color").text | ||
|
||
except AttributeError: | ||
channel_id = i | ||
color = "#0080ff" | ||
anatomycolors[channel_id] = color | ||
|
||
discarded_channels = [ch for ch in range(n_channels) if all(ch not in group for group in channel_groups)] | ||
kept_channels = [ch for ch in range(n_channels) if ch not in skipped_channels and ch not in discarded_channels] | ||
|
||
return channel_groups, kept_channels, discarded_channels, anatomycolors | ||
|
||
def _set_groups(self): | ||
""" | ||
Set the group ids and colors based on the xml file. | ||
These group ids are usually different brain/body anatomical areas, or shanks from multi-shank probes. | ||
The group ids are set as a property of the recording extractor. | ||
""" | ||
n = self.get_num_channels() | ||
group_ids = np.full(n, -1, dtype=int) # Initialize all positions to -1 | ||
|
||
channel_groups, kept_channels, discarded_channels, colors = self._parse_xml_file(self.xml_file_path) | ||
for group_id, numbers in enumerate(channel_groups): | ||
group_ids[numbers] = group_id # Assign group_id to the positions in `numbers` | ||
self.set_property("group", group_ids) | ||
discarded_ppty = np.full(n, False, dtype=bool) | ||
discarded_ppty[discarded_channels] = True | ||
self.set_property("discarded_channels", discarded_ppty) | ||
self.set_property("colors", values=list(colors.values()), ids=list(colors.keys())) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsure about adding colors here but I think that @samuelgarcia and @alejoe91 are more familiar with viewers so I defer to them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's mostly a gimmick for reproducibility of data visualisation with my lab ahah. I use it later in a custom ephyviewer script (not shown here, but maybe i should share it as well ?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we just need to understand is this something all users should think about or is this super specific. If colors are always generated in a consistent (at least to the user) way then it might be worth adding (again with Heberto's final suggestion to fit this in with Basically we want properties set here to be truly meaningful to all users. Other properties can be set on a per-user basis with our property setting machinery. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! In neuroscope it's always generated in a consistent manner, hardcoded in the paired xml file. |
||
|
||
|
||
class NeuroScopeSortingExtractor(BaseSorting): | ||
""" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does discarded channel mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it just means it wont be shown in the final viewer and was probably considered as noise/unplugged channel on the eib