Skip to content

Commit 8a3b9b7

Browse files
authored
Merge pull request #1435 from zm711/axonrawio
AxonRawIO: Change Strings Parsing for additional formats.
2 parents fe22ba5 + c0089de commit 8a3b9b7

File tree

1 file changed

+30
-18
lines changed

1 file changed

+30
-18
lines changed

neo/rawio/axonrawio.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@
1414
and available here:
1515
http://www.mathworks.com/matlabcentral/fileexchange/22114-abf2load
1616
17+
18+
The StringsSection parsing (parse_axon_soup) now relies on an idea
19+
presented in pyABF MIT License Copyright (c) 2018 Scott W Harden
20+
written by Scott Harden. His unofficial documentation for the formats
21+
is here:
22+
https://swharden.com/pyabf/abf2-file-format/
23+
strings section:
24+
[uModifierNameIndex, uCreatorNameIndex, uProtocolPathIndex, lFileComment, lADCCChannelNames, lADCUnitsIndex
25+
lDACChannelNameIndex, lDACUnitIndex, lDACFilePath, nLeakSubtractADC]
26+
['', 'Clampex', '', 'C:/path/protocol.pro', 'some comment', 'IN 0', 'mV', 'IN 1', 'mV', 'Cmd 0', 'pA',
27+
'Cmd 1', 'pA', 'Cmd 2', 'mV', 'Cmd 3', 'mV']
28+
1729
Information on abf 1 and 2 formats is available here:
1830
http://www.moleculardevices.com/pages/software/developer_info.html
1931
@@ -461,21 +473,21 @@ def parse_axon_soup(filename):
461473
# strings sections
462474
# hack for reading channels names and units
463475
# this section is not very detailed and so the code
464-
# not very robust. The idea is to remove the first
465-
# part by finding one of th following KEY
466-
# unfortunately the later part contains a the file
467-
# that can contain by accident also one of theses keys...
476+
# not very robust.
468477
f.seek(sections["StringsSection"]["uBlockIndex"] * BLOCKSIZE)
469478
big_string = f.read(sections["StringsSection"]["uBytes"])
470-
goodstart = -1
471-
for key in [b"AXENGN", b"clampex", b"Clampex", b"EDR3", b"CLAMPEX", b"axoscope", b"AxoScope", b"Clampfit"]:
472-
# goodstart = big_string.lower().find(key)
473-
goodstart = big_string.find(b"\x00" + key)
474-
if goodstart != -1:
475-
break
476-
assert goodstart != -1, "This file does not contain clampex, axoscope or clampfit in the header"
477-
big_string = big_string[goodstart + 1 :]
478-
strings = big_string.split(b"\x00")
479+
# this idea comes from pyABF https://github.com/swharden/pyABF
480+
# previously we searched for clampex, Clampex etc, but this was
481+
# brittle. pyABF believes that looking for the \x00\x00 is more
482+
# robust. We find these values, replace mu->u, then split into
483+
# a set of strings
484+
indexed_string = big_string[big_string.rfind(b'\x00\x00'):]
485+
# replace mu -> u for easy display
486+
indexed_string = indexed_string.replace(b'\xb5', b'\x75')
487+
# we need to remove one of the \x00 to have the indices be
488+
# the correct order
489+
indexed_string = indexed_string.split(b'\x00')[1:]
490+
strings = indexed_string
479491

480492
# ADC sections
481493
header["listADCInfo"] = []
@@ -489,8 +501,8 @@ def parse_axon_soup(filename):
489501
ADCInfo[key] = val[0]
490502
else:
491503
ADCInfo[key] = np.array(val)
492-
ADCInfo["ADCChNames"] = strings[ADCInfo["lADCChannelNameIndex"] - 1]
493-
ADCInfo["ADCChUnits"] = strings[ADCInfo["lADCUnitsIndex"] - 1]
504+
ADCInfo["ADCChNames"] = strings[ADCInfo["lADCChannelNameIndex"]]
505+
ADCInfo["ADCChUnits"] = strings[ADCInfo["lADCUnitsIndex"]]
494506
header["listADCInfo"].append(ADCInfo)
495507

496508
# protocol sections
@@ -503,7 +515,7 @@ def parse_axon_soup(filename):
503515
else:
504516
protocol[key] = np.array(val)
505517
header["protocol"] = protocol
506-
header["sProtocolPath"] = strings[header["uProtocolPathIndex"] - 1]
518+
header["sProtocolPath"] = strings[header["uProtocolPathIndex"]]
507519

508520
# tags
509521
listTag = []
@@ -532,8 +544,8 @@ def parse_axon_soup(filename):
532544
DACInfo[key] = val[0]
533545
else:
534546
DACInfo[key] = np.array(val)
535-
DACInfo["DACChNames"] = strings[DACInfo["lDACChannelNameIndex"] - 1]
536-
DACInfo["DACChUnits"] = strings[DACInfo["lDACChannelUnitsIndex"] - 1]
547+
DACInfo["DACChNames"] = strings[DACInfo["lDACChannelNameIndex"]]
548+
DACInfo["DACChUnits"] = strings[DACInfo["lDACChannelUnitsIndex"]]
537549

538550
header["listDACInfo"].append(DACInfo)
539551

0 commit comments

Comments
 (0)