python-neo icon indicating copy to clipboard operation
python-neo copied to clipboard

[NixIO] [BUG] Spiketrains with t_start > 0 dissapear

Open morales-gregorio opened this issue 4 years ago • 4 comments

Hey,

I was slicing some spiketrains and wanted to store them in the nix format. However, when I load the .nix file all spiketrains that did not have t_start = 0 are completely gone.

There was no warnings or errors while saving nor loading.

I am using neo 0.8.0 and nixio 1.5.0b4.

All best, Aitor

morales-gregorio avatar Apr 24 '20 15:04 morales-gregorio

This isn't an issue with the t_start, that works fine. The issue is that when slicing spiketrains, the annotations don't get copied but just the reference, so the sliced spiketrain and the original have the same annotation object. NixIO uses annotations (specifically nix_name) to identify objects and since the two spiketrains share the same annotation object, only one gets written.

The same issue came up a couple of years ago with the time_slice() method of the AnalogSignal (see #536). The solution would likely be the same: Deep copy the annotations when slicing.

Check the following script for a demonstration of the issue:

import neo
import nixio as nix


print("Using versions:")
print(f"Neo:   {neo.__version__}")
print(f"NIXIO: {nix.__version__}")


def create():
    print("Writing")
    blk = neo.Block("Block")
    seg = neo.Segment("seg")
    blk.segments.append(seg)

    st = neo.SpikeTrain(name="spikes", times=[1.3, 2.9, 10.1, 13.4, 15.1],
                        t_stop=100, units="s")
    st.t_start = 0.1

    seg.spiketrains.append(st)
    print(repr(st))
    print(id(st.annotations))

    slst = st[1:-1]
    print(repr(slst))
    print(id(slst.annotations))

    seg.spiketrains.append(slst)


    with neo.NixIO("./file.nix", mode="ow") as nf:
        nf.write_block(blk)


def read():
    print("Reading")
    with neo.NixIO("./file.nix", mode="ro") as nf:
        blk = nf.read_block()

    for st in blk.segments[0].spiketrains:
        print(repr(st))


if __name__ == "__main__":
    create()
    read()

achilleas-k avatar Apr 24 '20 21:04 achilleas-k

Hey @achilleas-k thanks for the quick reponse! I see, so this is indeed due to the annotations. I will take it into account.

However, I would still argue that this behavior is unexpected and you should consider changing it to something else. What is the reason that two objects should not have the same annotations? I can imagine many circumstances where this can happen, the signals can still be distinguishable from their names, starting times, array annotations...

morales-gregorio avatar Apr 27 '20 08:04 morales-gregorio

I agree that the behaviour is unexpected, but I'm not sure if this should be somehow detected and handled in NIXIO or if a more general behaviour change is required in core. Much like with array annotations, the plain annotations could be deep copied when slicing a spiketrain https://github.com/NeuralEnsemble/python-neo/blob/a562f239b5e5c3e0d08608fa276e03c5b82f73bf/neo/core/spiketrain.py#L506-L517

But that's a design choice of the core Neo devs that I can't decide on. If it stays the way it is, I'll have to make changes to the IO to detect when multiple objects share a reference to the same annotations and perhaps throw a warning and do the copy during writing.

achilleas-k avatar Apr 27 '20 10:04 achilleas-k

Hi @morales-gregorio, thanks for raising the issue. I agree with @achilleas-k, on a first glance this looks like it should be fixed in the neo core. To avoid drifting to another discussion topic here, I opened a new issue (https://github.com/NeuralEnsemble/python-neo/issues/811) to discuss the implementation of that fix

JuliaSprenger avatar Apr 29 '20 07:04 JuliaSprenger