python-neo
python-neo copied to clipboard
Object description metadata lost/wrong when saving NWB files
When saving Neo objects to NWB files using the NWBIO, the information in the description
metadata field of several objects is lost or wrongly changed:
- If two blocks are saved, when they are reloaded from the NWB file, the description of the second will be equal to the one from the first;
- Descriptions of
AnalogSignal
are replaced by a generic stringno description
; - Descriptions of
Segment
andSpikeTrain
are lost.
When saving a single block, the behavior for AnalogSignals, Segments and SpikeTrains is similar.
The code below reproduces the behavior:
from datetime import datetime
import numpy as np
import quantities as pq
import neo
from elephant.spike_train_generation import StationaryPoissonProcess
def print_metadata(block):
print(f"Block: {block.name}, description: {block.description}")
seg = block.segments[0]
print(f"\tSegment: {seg.name}, description: {seg.description}")
signal = seg.analogsignals[0]
print(f"\t\tSignal: {signal.name}, description: {signal.description}")
for idx, st in enumerate(seg.spiketrains):
print(f"\t\tST {idx}: {st.name}, description: {st.description}")
start_time = datetime.now()
blocks = []
for i in range(1, 3):
block = neo.Block(name=f"Data {i}", description=f"The block {i}",
session_start_time=start_time)
signal = neo.AnalogSignal(np.random.normal(size=(1000, 5)), units=pq.mV,
name=f"Signal {i}",
description=f"The signal of block {i}",
sampling_rate=1000*pq.Hz)
segment = neo.Segment(name=f"Segment {i}",
description=f"The segment of block {i}")
spiketrains = StationaryPoissonProcess(rate=10*pq.Hz).generate_n_spiketrains(3)
for idx, st in enumerate(spiketrains, start=1):
st.name = f"SpikeTrain {idx}"
st.description = f"SpikeTrain {idx} of block {i}"
segment.add(signal)
segment.add(*spiketrains)
block.add(segment)
blocks.append(block)
# Inspect the metadata
print_metadata(blocks[0])
print_metadata(blocks[1])
print("\nSaving\n\n")
# Save and load as NWB
nwb_file = "test.nwb"
io = neo.NWBIO(nwb_file, 'w')
io.write_all_blocks(blocks)
print("\nLoading\n\n")
io = neo.NWBIO(nwb_file, 'r')
read_blocks = io.read_all_blocks()
# Inspect the metadata
print_metadata(read_blocks[0])
print_metadata(read_blocks[1])
Output (warnings on existing AnalogSignal names removed):
Block: Data 1, description: The block 1
Segment: Segment 1, description: The segment of block 1
Signal: Signal 1, description: The signal of block 1
ST 0: SpikeTrain 1, description: SpikeTrain 1 of block 1
ST 1: SpikeTrain 2, description: SpikeTrain 2 of block 1
ST 2: SpikeTrain 3, description: SpikeTrain 3 of block 1
Block: Data 2, description: The block 2
Segment: Segment 2, description: The segment of block 2
Signal: Signal 2, description: The signal of block 2
ST 0: SpikeTrain 1, description: SpikeTrain 1 of block 2
ST 1: SpikeTrain 2, description: SpikeTrain 2 of block 2
ST 2: SpikeTrain 3, description: SpikeTrain 3 of block 2
Saving
Loading
Block: Data 1, description: The block 1
Segment: Segment 1, description: None
Signal: Segment 1 Signal 1 0, description: no description
ST 0: SpikeTrain 1, description: None
ST 1: SpikeTrain 2, description: None
ST 2: SpikeTrain 3, description: None
Block: Data 2, description: The block 1
Segment: Segment 2, description: None
Signal: Segment 2 Signal 2 0, description: no description
ST 0: SpikeTrain 1, description: None
ST 1: SpikeTrain 2, description: None
ST 2: SpikeTrain 3, description: None
Expected behaviour Preserve metadata when saving to NWB, only changing names to guarantee uniqueness
Environment:
- OS: Ubuntu
- Python 3.10
- neo==0.13.0
- numpy==1.26.4
- quantities==0.15.0