Skip to content

Commit 3994fc7

Browse files
author
Thinh Nguyen
committed
update spikeglx loader to handle spikeglx ver 20230202
1 parent 224b1c7 commit 3994fc7

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

element_array_ephys/readers/spikeglx.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,20 @@ def __init__(self, meta_filepath):
293293
"Probe Serial Number not found in"
294294
' either "imProbeSN" or "imDatPrb_sn"'
295295
)
296+
# Get probe part number
297+
self.probe_PN = self.meta.get("imDatPrb_pn", "3A")
296298

299+
# Parse channel info
297300
self.chanmap = (
298301
self._parse_chanmap(self.meta["~snsChanMap"])
299302
if "~snsChanMap" in self.meta
300303
else None
301304
)
305+
self.geommap = (
306+
self._parse_geommap(self.meta["~snsGeomMap"])
307+
if "~snsGeomMap" in self.meta
308+
else None
309+
)
302310
self.shankmap = (
303311
self._parse_shankmap(self.meta["~snsShankMap"])
304312
if "~snsShankMap" in self.meta
@@ -370,6 +378,39 @@ def _parse_shankmap(raw):
370378

371379
return res
372380

381+
@staticmethod
382+
def _parse_geommap(raw):
383+
"""
384+
The shankmap contains details on the shank info
385+
for each electrode sites of the sites being recorded only
386+
Parsing from the `~snsGeomMap` (available with SpikeGLX 20230202-phase30 and later)
387+
388+
https://github.com/billkarsh/SpikeGLX/blob/master/Markdown/Metadata_30.md
389+
Parse shank map header structure. Converts:
390+
391+
'(x,y,z)(a:b:c:d)...(a:b:c:d)'
392+
a: zero-based shank #
393+
b: x-coordinate (um) of elecrode center
394+
c: z-coordinate (um) of elecrode center
395+
d: 0/1 `used` flag (included in spatial average or not)
396+
e.g:
397+
398+
'(1,2,480)(0:0:192:1)...(0:1:191:1)'
399+
400+
into dict of form:
401+
402+
{'shape': [x,y,z], 'data': [[a,b,c,d],...]}
403+
"""
404+
res = {"shape": None, "data": []}
405+
406+
for u in (i.rstrip(")") for i in raw.split("(") if i != ""):
407+
if "," in u:
408+
res["header"] = [d for d in u.split(",")]
409+
else:
410+
res["data"].append([int(d) for d in u.split(":")])
411+
412+
return res
413+
373414
@staticmethod
374415
def _parse_imrotbl(raw):
375416
"""
@@ -400,6 +441,31 @@ def _parse_imrotbl(raw):
400441

401442
return res
402443

444+
def _transform_geom_to_shank(self):
445+
if self.geommap is None:
446+
raise ValueError("Geometry Map not available")
447+
448+
from . import probe_geometry
449+
450+
probe_params = {
451+
n: v
452+
for n, v in zip(
453+
probe_geometry.geom_param_names, probe_geometry.M[self.probe_PN]
454+
)
455+
}
456+
probe_params["probe_type"] = self.probe_PN
457+
elec_pos_df = probe_geometry.build_npx_probe(**probe_params)
458+
459+
res = {"shape": self.geommap["shape"], "data": []}
460+
for shank, x_coord, y_coord, is_used in self.geommap["data"]:
461+
matched_elec = elec_pos_df.query(
462+
f"x_coord=={x_coord} & y_coord=={y_coord} & shank=={shank}"
463+
)
464+
shank_col, shank_row = matched_elec.shank_col, matched_elec.shank_row
465+
res["data"].append([shank, shank_col, shank_row, is_used])
466+
467+
return res
468+
403469
def get_recording_channels_indices(self, exclude_sync=False):
404470
"""
405471
The indices of recorded channels (in chanmap)

0 commit comments

Comments
 (0)