1111import csv
1212from pathlib import Path
1313from typing import List , Tuple , Optional , Dict , Any
14+ import json
15+ import numpy as np
1416
1517from probeinterface import get_probe , Probe
1618from probeinterface import (
@@ -240,6 +242,54 @@ def probe_to_obj(
240242 print (f"✗ Failed to generate OBJ for { filename } : { e } " )
241243 return False
242244
245+ def _calculate_tip_coords (self , probe : Probe ) -> list :
246+ """Calculate tip coordinates for a probe."""
247+ contour = np .array (getattr (probe , "probe_planar_contour" , []))
248+ tip_coords = []
249+ if contour .shape [0 ] > 0 :
250+ # Find all points with the minimum y value (the tips)
251+ min_y = np .min (contour [:, 1 ])
252+ tip_points = contour [np .isclose (contour [:, 1 ], min_y )]
253+ # If multiple tips at same y, group by unique x
254+ unique_x = np .unique (np .round (tip_points [:, 0 ], decimals = 2 ))
255+ for x in unique_x :
256+ tip = tip_points [
257+ np .isclose (np .round (tip_points [:, 0 ], decimals = 2 ), x )
258+ ][0 ]
259+ tip_coords .append ([float (tip [0 ]), float (tip [1 ]), 0.0 ])
260+ else :
261+ # fallback: use lowest y contact for each shank
262+ positions = np .array (probe .contact_positions )
263+ shank_ids = np .array (probe .shank_ids )
264+ unique_shanks = np .unique (shank_ids )
265+ ndim = probe .ndim
266+ for shank in unique_shanks :
267+ shank_positions = positions [shank_ids == shank ]
268+ if shank_positions .shape [0 ] == 0 :
269+ tip_coords .append (None )
270+ continue
271+ tip_elec = shank_positions [
272+ np .argmin (shank_positions [:, 1 ])
273+ ]
274+ if ndim == 2 :
275+ x , y = tip_elec
276+ z = 0.0
277+ else :
278+ x , y , z = tip_elec
279+ tip_coords .append ([float (x ), float (y ), float (z )])
280+ return tip_coords
281+
282+ def _get_top_coordinate (self , probe : Probe ) -> list :
283+ """Compute the top coordinate as midpoint of min/max X and max Y from probe contour."""
284+ contour = np .array (getattr (probe , "probe_planar_contour" , []))
285+ if contour .shape [0 ] == 0 :
286+ return [None , None , None ]
287+ min_x = np .min (contour [:, 0 ])
288+ max_x = np .max (contour [:, 0 ])
289+ max_y = np .max (contour [:, 1 ])
290+ mid_x = (min_x + max_x ) / 2.0
291+ return [float (mid_x ), float (max_y ), 0.0 ]
292+
243293 def generate_metadata_json (
244294 self ,
245295 probe : Probe ,
@@ -248,49 +298,16 @@ def generate_metadata_json(
248298 manufacturer : str = "unknown" ,
249299 ) -> bool :
250300 try :
251- import json
252- import numpy as np
253-
254- contour = np .array (getattr (probe , "probe_planar_contour" , []))
255- tip_coords = []
256- if contour .shape [0 ] > 0 :
257- # Find all points with the minimum y value (the tips)
258- min_y = np .min (contour [:, 1 ])
259- tip_points = contour [np .isclose (contour [:, 1 ], min_y )]
260- # If multiple tips at same y, group by unique x
261- unique_x = np .unique (np .round (tip_points [:, 0 ], decimals = 2 ))
262- for x in unique_x :
263- tip = tip_points [
264- np .isclose (np .round (tip_points [:, 0 ], decimals = 2 ), x )
265- ][0 ]
266- tip_coords .append ([float (tip [0 ]), float (tip [1 ]), 0.0 ])
267- else :
268- # fallback: use lowest y contact for each shank
269- positions = np .array (probe .contact_positions )
270- shank_ids = np .array (probe .shank_ids )
271- unique_shanks = np .unique (shank_ids )
272- ndim = probe .ndim
273- for shank in unique_shanks :
274- shank_positions = positions [shank_ids == shank ]
275- if shank_positions .shape [0 ] == 0 :
276- tip_coords .append (None )
277- continue
278- tip_elec = shank_positions [
279- np .argmin (shank_positions [:, 1 ])
280- ]
281- if ndim == 2 :
282- x , y = tip_elec
283- z = 0.0
284- else :
285- x , y , z = tip_elec
286- tip_coords .append ([float (x ), float (y ), float (z )])
301+ tip_coords = self ._calculate_tip_coords (probe )
302+ top_coord = self ._get_top_coordinate (probe )
287303 metadata = {
288304 "name" : filename .replace ("_" , " " ).title (),
289305 "type" : probe_type ,
290306 "producer" : manufacturer ,
291307 "sites" : probe .get_contact_count (),
292308 "shanks" : probe .get_shank_count (),
293309 "tip_coordinates" : tip_coords ,
310+ "top_coordinate" : top_coord ,
294311 "references" : "Generated using probeinterface library" ,
295312 "spec" : "https://probeinterface.readthedocs.io/" ,
296313 }
0 commit comments