elephant icon indicating copy to clipboard operation
elephant copied to clipboard

[Bug] Creating LFP without generate_lfp?

Open rcpeene opened this issue 2 years ago • 2 comments

Describe the bug I am attempting to use estimate_csd without generate fake LFP data. I extract genuine lfp data from our files, but it looks like it requires a very specific format of input LFP data in the form of a neo.AnalogSignal with specific annotations and units. I have had a little bit of difficulty with manually converting my LFP data (as a np array) into a neo AnalogSignal, as I am new to neo and I'm unsure exactly what information is required as input. I've done my best to try and mimic the output of generate_lfp but at this point, I've encountered an error which I am unsure if it's a bug or not. 'TypeError: len() of unsized object`.

To Reproduce

  1. Run the following code after importing the relevant neo and elephant namespaces.
import quantities as pq
coords = np.array(nwb.electrodes.x)
hz = len(lfp.data) / lfp.timestamps[-1]

neo_lfp = AnalogSignal(lfp.data, units="V", sampling_rate = hz*pq.Hz, coordinates = coords * pq.mm)
csd = estimate_csd(neo_lfp, method="KCSD2D")

where coords is an array of scalar values and hz is a scalar.

Traceback

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [161], line 1
----> 1 csd = estimate_csd(neo_lfp, method="KCSD2D")

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\elephant\utils.py:80, in deprecated_alias.<locals>.deco.<locals>.wrapper(*args, **kwargs)
     77 @wraps(func)
     78 def wrapper(*args, **kwargs):
     79     _rename_kwargs(func.__name__, kwargs, aliases)
---> 80     return func(*args, **kwargs)

File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\elephant\current_source_density.py:139, in estimate_csd(lfp, coordinates, method, process_estimate, **kwargs)
    137     raise ValueError('Number of signals and coords is not same')
    138 for ii in coordinates:  # CHECK for Dimensionality of electrodes
--> 139     if len(ii) > 3:
    140         raise ValueError('Invalid number of coordinate positions')
    141 dim = len(coordinates[0])  # TODO : Generic co-ordinates!

TypeError: len() of unsized object

I suspect that it is the case that either the input coordinates ought to be provided as a 2D list, or the code which checks the length of the coordinates should cast the coordinate item in the input coordinates into a tuple of length 1.

Expected behavior I expect either the CSD analysis to produce valid output or to be given an explanatory error.

Environment Windows 10: Installed elephant with pip install elephant: Python version: 3.9.10 neo==0.12.0 numpy==1.21.5 elephant==0.12.0

rcpeene avatar Mar 22 '23 23:03 rcpeene

Hey @rcpeene , thanks again for the report, these are really helpful hints to further improve the code. Gladly continue.

In the following example the lfp is annotated with the coordinates using lfp.annotate(coordinates=coordinates). (For the example you provided lfp.annotate(coordinates=coords*pq.mm))

See here for the documentation on annotations: https://neo.readthedocs.io/en/latest/core.html?highlight=annotate#annotations

import numpy as np
from elephant.current_source_density import generate_lfp, estimate_csd
from elephant.current_source_density_src.utility_functions import small_source_2D
import quantities as pq


xs=np.linspace(0, 10, 230).reshape(230,1)
ys=np.linspace(0, 10, 230).reshape(230,1)


lfp = generate_lfp(small_source_2D, xs, ys)
coordinates = np.stack((xs[:,0], ys[:,0]), axis=-1)*pq.mm

lfp.annotate(coordinates=coordinates)

print(lfp.annotations['coordinates'])
csd=estimate_csd(lfp, method="KCSD2D")
print(csd)

For the future I'm planning a refactor of the current_source_density module to improve documentation with examples and error messages that are more helpful for troubleshooting.

Moritz-Alexander-Kern avatar Mar 24 '23 09:03 Moritz-Alexander-Kern

The alternative annotation was a part of the solution, but the actual solution appears to be wrapping the elements of coords into tuples. Even when working with 1D data (and 1D coords input), this error arises if each coord element of coordinates aren't tuples of length 1. In your refactor this should probably be handled.

Thanks for your assistance!

rcpeene avatar Mar 27 '23 23:03 rcpeene