@@ -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