Skip to content

Commit 03bae61

Browse files
authored
Merge pull request #355 from samuelgarcia/some_fix
Better handling of model_name in neuropixels probe to generate the neuropixels library
2 parents b3f3542 + cc88747 commit 03bae61

File tree

6 files changed

+56
-57
lines changed

6 files changed

+56
-57
lines changed

resources/generate_neuropixels_library.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,20 @@ def generate_all_npx():
2525
probe_part_numbers = probe_features['neuropixels_probes'].keys()
2626

2727

28-
for probe_number in probe_part_numbers:
28+
for model_name in probe_part_numbers:
29+
print(model_name)
2930

30-
if probe_number is None:
31+
if model_name is None:
3132
continue
3233

33-
if probe_number == "NP1110":
34+
if model_name == "NP1110":
3435
# the formula by the imrow table is wrong and more complicated
3536
continue
3637

37-
probe_folder = base_folder / probe_number
38+
probe_folder = base_folder / model_name
3839
probe_folder.mkdir(exist_ok=True)
3940

40-
pt_metadata, _, _ = get_probe_metadata_from_probe_features(probe_features, probe_number)
41+
pt_metadata, _, _ = get_probe_metadata_from_probe_features(probe_features, model_name)
4142

4243
num_shank = pt_metadata["num_shanks"]
4344
contact_per_shank = pt_metadata["cols_per_shank"] * pt_metadata["rows_per_shank"]
@@ -48,7 +49,7 @@ def generate_all_npx():
4849
elec_ids = np.concatenate([np.arange(contact_per_shank) for i in range(num_shank)])
4950
shank_ids = np.concatenate([np.zeros(contact_per_shank) + i for i in range(num_shank)])
5051

51-
probe = _make_npx_probe_from_description(pt_metadata, elec_ids, shank_ids)
52+
probe = _make_npx_probe_from_description(pt_metadata, model_name, elec_ids, shank_ids)
5253

5354
# ploting
5455
fig, axs = plt.subplots(ncols=2)
@@ -78,8 +79,8 @@ def generate_all_npx():
7879

7980
n = probe.get_contact_count()
8081

81-
title = probe_number
82-
title += f"\n{probe.manufacturer} - {probe.model_name}"
82+
title = f"{probe.manufacturer} - {model_name}"
83+
title += f"\n{probe.description}"
8384
title += f"\n {n}ch"
8485
if probe.shank_ids is not None:
8586
num_shank = probe.get_shank_count()
@@ -90,9 +91,11 @@ def generate_all_npx():
9091

9192
# plt.show()
9293

93-
fig.savefig(probe_folder / f"{probe_number}.png")
94+
fig.savefig(probe_folder / f"{model_name}.png")
9495

95-
write_probeinterface(probe_folder / f"{probe_number}.json", probe)
96+
write_probeinterface(probe_folder / f"{model_name}.json", probe)
97+
98+
# plt.show()
9699

97100
plt.close(fig)
98101

src/probeinterface/library.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def download_probeinterface_file(manufacturer: str, probe_name: str):
3434
3535
Parameters
3636
----------
37-
manufacturer : "cambridgeneurotech" | "neuronexus"
37+
manufacturer : "cambridgeneurotech" | "neuronexus" | "plexon" | "imec" | "sinaps"
3838
The probe manufacturer
3939
probe_name : str (see probeinterface_libary for options)
4040
The probe name
@@ -53,7 +53,7 @@ def get_from_cache(manufacturer: str, probe_name: str) -> Optional["Probe"]:
5353
5454
Parameters
5555
----------
56-
manufacturer : "cambridgeneurotech" | "neuronexus"
56+
manufacturer : "cambridgeneurotech" | "neuronexus" | "plexon" | "imec" | "sinaps"
5757
The probe manufacturer
5858
probe_name : str (see probeinterface_libary for options)
5959
The probe name
@@ -80,7 +80,7 @@ def get_probe(manufacturer: str, probe_name: str, name: Optional[str] = None) ->
8080
8181
Parameters
8282
----------
83-
manufacturer : "cambridgeneurotech" | "neuronexus"
83+
manufacturer : "cambridgeneurotech" | "neuronexus" | "plexon" | "imec" | "sinaps"
8484
The probe manufacturer
8585
probe_name : str (see probeinterface_libary for options)
8686
The probe name

src/probeinterface/neuropixels_tools.py

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,6 @@ def _load_np_probe_features():
8989
"bankB": "bankB",
9090
}
9191

92-
# Map from ProbeInterface to ProbeTable naming conventions
93-
pi_to_pt_names = {
94-
"x_pitch": "electrode_pitch_horz_um",
95-
"y_pitch": "electrode_pitch_vert_um",
96-
"contact_width": "electrode_size_horz_direction_um",
97-
"shank_pitch": "shank_pitch_um",
98-
"shank_number": "num_shanks",
99-
"ncols_per_shank": "cols_per_shank",
100-
"nrows_per_shank": "rows_per_shank",
101-
"adc_bit_depth": "adc_bit_depth",
102-
"model_name": "description",
103-
"num_readout_channels": "num_readout_channels",
104-
"shank_width_um": "shank_width_um",
105-
"tip_length_um": "tip_length_um",
106-
}
107-
10892

10993
def get_probe_length(probe_part_number: str) -> int:
11094
"""
@@ -241,11 +225,9 @@ def read_imro(file_path: Union[str, Path]) -> Probe:
241225
return _read_imro_string(imro_str, imDatPrb_pn)
242226

243227

244-
def _make_npx_probe_from_description(probe_description, elec_ids, shank_ids, mux_table=None) -> Probe:
228+
def _make_npx_probe_from_description(probe_description, model_name, elec_ids, shank_ids, mux_table=None) -> Probe:
245229
# used by _read_imro_string and for generating the NP library
246230

247-
model_name = probe_description["description"]
248-
249231
# compute position
250232
y_idx, x_idx = np.divmod(elec_ids, probe_description["cols_per_shank"])
251233
x_pitch = probe_description["electrode_pitch_horz_um"]
@@ -257,8 +239,8 @@ def _make_npx_probe_from_description(probe_description, elec_ids, shank_ids, mux
257239
)
258240

259241
stagger = np.mod(y_idx + 1, 2) * raw_stagger
260-
x_pos = x_idx * x_pitch + stagger
261-
y_pos = y_idx * y_pitch
242+
x_pos = (x_idx * x_pitch + stagger).astype("float64")
243+
y_pos = (y_idx * y_pitch).astype("float64")
262244

263245
# if probe_description["shank_number"] > 1:
264246
if shank_ids is not None:
@@ -273,7 +255,8 @@ def _make_npx_probe_from_description(probe_description, elec_ids, shank_ids, mux
273255
positions = np.stack((x_pos, y_pos), axis=1)
274256

275257
# construct Probe object
276-
probe = Probe(ndim=2, si_units="um", model_name=model_name, manufacturer="IMEC")
258+
probe = Probe(ndim=2, si_units="um", model_name=model_name, manufacturer="imec")
259+
probe.description = probe_description["description"]
277260
probe.set_contacts(
278261
positions=positions,
279262
shapes="square",
@@ -386,7 +369,7 @@ def _read_imro_string(imro_str: str, imDatPrb_pn: Optional[str] = None) -> Probe
386369
else:
387370
shank_ids = None
388371

389-
probe = _make_npx_probe_from_description(pt_metadata, elec_ids, shank_ids, mux_table)
372+
probe = _make_npx_probe_from_description(pt_metadata, imDatPrb_pn, elec_ids, shank_ids, mux_table)
390373

391374
# scalar annotations
392375
probe.annotate(
@@ -905,14 +888,12 @@ def read_openephys(
905888
)
906889
num_shanks = pt_metadata["num_shanks"]
907890

908-
model_name = pt_metadata.get("description")
909-
if model_name is None:
910-
model_name = "Unknown"
891+
description = pt_metadata.get("description")
911892

912893
elec_ids = []
913894
for i, pos in enumerate(positions):
914895
# Do not calculate contact ids if the model name is not known
915-
if model_name == "Unknown":
896+
if description is None:
916897
elec_ids = None
917898
break
918899

@@ -1056,8 +1037,11 @@ def read_openephys(
10561037
if elec_ids is not None:
10571038
elec_ids = np.array(elec_ids)[chans_saved]
10581039

1059-
probe = _make_npx_probe_from_description(pt_metadata, elec_ids, shank_ids=shank_ids, mux_table=mux_table)
1040+
probe = _make_npx_probe_from_description(
1041+
pt_metadata, probe_part_number, elec_ids, shank_ids=shank_ids, mux_table=mux_table
1042+
)
10601043
probe.serial_number = np_probe_info["serial_number"]
1044+
probe.name = np_probe_info["name"]
10611045

10621046
probe.annotate(
10631047
part_number=np_probe_info["part_number"],

src/probeinterface/probe.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,18 @@ def manufacturer(self, value):
201201
# we remove the annotation if it exists
202202
_ = self.annotations.pop("manufacturer", None)
203203

204+
@property
205+
def description(self):
206+
return self.annotations.get("description", None)
207+
208+
@description.setter
209+
def description(self, value):
210+
if value is not None:
211+
self.annotate(description=value)
212+
else:
213+
# we remove the annotation if it exists
214+
_ = self.annotations.pop("description", None)
215+
204216
def get_title(self) -> str:
205217
if self.contact_positions is None:
206218
txt = "Undefined probe"

tests/test_io/test_openephys.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ def test_NP1_subset():
8585
validate_probe_dict(probe_dict)
8686

8787
assert probe_ap.get_shank_count() == 1
88-
assert "1.0" in probe_ap.model_name
88+
assert "1.0" in probe_ap.description
8989
assert probe_ap.get_contact_count() == 200
9090

9191
probe_lf = read_openephys(data_path / "OE_Neuropix-PXI-subset" / "settings.xml", stream_name="ProbeA-LFP")
9292
probe_dict = probe_lf.to_dict(array_as_list=True)
9393
validate_probe_dict(probe_dict)
9494

9595
assert probe_lf.get_shank_count() == 1
96-
assert "1.0" in probe_lf.model_name
96+
assert "1.0" in probe_lf.description
9797
assert len(probe_lf.contact_positions) == 200
9898

9999
# Not specifying the stream_name should raise an Exception, because both the ProbeA-AP and
@@ -109,7 +109,7 @@ def test_multiple_probes():
109109
validate_probe_dict(probe_dict)
110110

111111
assert probeA.get_shank_count() == 1
112-
assert "1.0" in probeA.model_name
112+
assert "1.0" in probeA.description
113113

114114
probeB = read_openephys(
115115
data_path / "OE_Neuropix-PXI-multi-probe" / "settings.xml",

tests/test_io/test_spikeglx.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ def test_get_saved_channel_indices_from_spikeglx_meta():
4343

4444
def test_NP1():
4545
probe = read_spikeglx(data_path / "Noise_g0_t0.imec0.ap.meta")
46-
assert "1.0" in probe.model_name
46+
assert "1.0" in probe.description
4747

4848

4949
def test_NP_phase3A():
5050
# Data provided by rtraghavan
5151
probe = read_spikeglx(data_path / "phase3a.imec.ap.meta")
5252

53-
assert probe.manufacturer == "IMEC"
53+
assert probe.manufacturer == "imec"
5454

5555
assert probe.ndim == 2
5656
assert probe.get_shank_count() == 1
@@ -66,14 +66,14 @@ def test_NP_phase3A():
6666

6767
def test_NP2_1_shanks():
6868
probe = read_spikeglx(data_path / "p2_g0_t0.imec0.ap.meta")
69-
assert "2.0" in probe.model_name
69+
assert "2.0" in probe.description
7070
assert probe.get_shank_count() == 1
7171

7272

7373
def test_NP2_4_shanks():
7474
probe = read_spikeglx(data_path / "NP2_4_shanks.imec0.ap.meta")
7575

76-
assert probe.manufacturer == "IMEC"
76+
assert probe.manufacturer == "imec"
7777

7878
assert probe.ndim == 2
7979
assert probe.get_shank_count() == 4
@@ -95,7 +95,7 @@ def test_NP2_2013_all():
9595
# Data provided by Jennifer Colonell
9696
probe = read_spikeglx(data_path / "NP2_2013_all_channels.imec0.ap.meta")
9797

98-
assert probe.manufacturer == "IMEC"
98+
assert probe.manufacturer == "imec"
9999

100100
assert probe.ndim == 2
101101
# all channels are from the first shank
@@ -118,7 +118,7 @@ def test_NP2_2013_subset():
118118
# Data provided by Jennifer Colonell
119119
probe = read_spikeglx(data_path / "NP2_2013_subset_channels.imec0.ap.meta")
120120

121-
assert probe.manufacturer == "IMEC"
121+
assert probe.manufacturer == "imec"
122122

123123
assert probe.ndim == 2
124124
# all channels are from the first shank
@@ -141,7 +141,7 @@ def test_NP2_4_shanks_with_different_electrodes_saved():
141141
# Data provided by Jennifer Colonell
142142
probe = read_spikeglx(data_path / "NP2_4_shanks_save_different_electrodes.imec0.ap.meta")
143143

144-
assert probe.manufacturer == "IMEC"
144+
assert probe.manufacturer == "imec"
145145

146146
assert probe.ndim == 2
147147
assert probe.get_shank_count() == 4
@@ -163,7 +163,7 @@ def test_NP2_4_shanks_with_different_electrodes_saved():
163163
def test_NP1_large_depth_span():
164164
# Data provided by Tom Bugnon NP1 with large Depth span
165165
probe = read_spikeglx(data_path / "allan-longcol_g0_t0.imec0.ap.meta")
166-
assert "1.0" in probe.model_name
166+
assert "1.0" in probe.description
167167
assert probe.get_shank_count() == 1
168168
ypos = probe.contact_positions[:, 1]
169169
assert (np.max(ypos) - np.min(ypos)) > 7600
@@ -173,7 +173,7 @@ def test_NP1_other_example():
173173
# Data provided by Tom Bugnon NP1
174174
probe = read_spikeglx(data_path / "doppio-checkerboard_t0.imec0.ap.meta")
175175
print(probe)
176-
assert "1.0" in probe.model_name
176+
assert "1.0" in probe.description
177177
assert probe.get_shank_count() == 1
178178
ypos = probe.contact_positions[:, 1]
179179
assert (np.max(ypos) - np.min(ypos)) > 7600
@@ -191,7 +191,7 @@ def test_NPH_long_staggered():
191191
# Data provided by Nate Dolensek
192192
probe = read_spikeglx(data_path / "non_human_primate_long_staggered.imec0.ap.meta")
193193

194-
assert probe.manufacturer == "IMEC"
194+
assert probe.manufacturer == "imec"
195195

196196
assert probe.ndim == 2
197197
assert probe.get_shank_count() == 1
@@ -245,7 +245,7 @@ def test_NPH_short_linear_probe_type_0():
245245
# Data provided by Jonathan A Michaels
246246
probe = read_spikeglx(data_path / "non_human_primate_short_linear_probe_type_0.meta")
247247

248-
assert probe.manufacturer == "IMEC"
248+
assert probe.manufacturer == "imec"
249249

250250
assert probe.ndim == 2
251251
assert probe.get_shank_count() == 1
@@ -293,7 +293,7 @@ def test_ultra_probe():
293293
# Data provided by Alessio
294294
probe = read_spikeglx(data_path / "npUltra.meta")
295295

296-
assert probe.manufacturer == "IMEC"
296+
assert probe.manufacturer == "imec"
297297

298298
# Test contact geometry
299299
contact_width = 5.0
@@ -317,7 +317,7 @@ def test_ultra_probe():
317317

318318
def test_CatGT_NP1():
319319
probe = read_spikeglx(data_path / "catgt.meta")
320-
assert "1.0" in probe.model_name
320+
assert "1.0" in probe.description
321321

322322

323323
def test_snsGeomMap():

0 commit comments

Comments
 (0)