Skip to content

Commit 67aea5c

Browse files
committed
feat: add top_coordinate
1 parent 04b6fbb commit 67aea5c

File tree

2 files changed

+54
-36
lines changed

2 files changed

+54
-36
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dynamic = ["version"]
1818

1919
dependencies = [
2020
'probeinterface',
21+
'numpy',
2122
]
2223

2324
[dependency-groups]

src/probe_library/probe_generator.py

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import csv
1212
from pathlib import Path
1313
from typing import List, Tuple, Optional, Dict, Any
14+
import json
15+
import numpy as np
1416

1517
from probeinterface import get_probe, Probe
1618
from 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

Comments
 (0)