Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Creating LFP without generate_lfp? #552

Open
rcpeene opened this issue Mar 22, 2023 · 2 comments
Open

[Bug] Creating LFP without generate_lfp? #552

rcpeene opened this issue Mar 22, 2023 · 2 comments
Labels
bug Indicates an unexpected problem or unintended behavior documentation Indicates a need for improvements or additions to documentation

Comments

@rcpeene
Copy link

rcpeene commented Mar 22, 2023

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

@Moritz-Alexander-Kern Moritz-Alexander-Kern added the bug Indicates an unexpected problem or unintended behavior label Mar 23, 2023
@Moritz-Alexander-Kern
Copy link
Member

Moritz-Alexander-Kern commented Mar 24, 2023

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.

@rcpeene
Copy link
Author

rcpeene commented Mar 27, 2023

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!

@Moritz-Alexander-Kern Moritz-Alexander-Kern added the documentation Indicates a need for improvements or additions to documentation label May 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior documentation Indicates a need for improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants