Skip to content

Commit

Permalink
Merge pull request #158 from pynapple-org/new_io
Browse files Browse the repository at this point in the history
New io
  • Loading branch information
gviejo authored Aug 8, 2023
2 parents ef8db9a + f8f664d commit 9d2dfc4
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 122 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ PYthon Neural Analysis Package.

pynapple is a light-weight python library for neurophysiological data analysis. The goal is to offer a versatile set of tools to study typical data in the field, i.e. time series (spike times, behavioral events, etc.) and time intervals (trials, brain states, etc.). It also provides users with generic functions for neuroscience such as tuning curves and cross-correlograms.

- Free software: GNU General Public License v3
- Free software: MIT License
- __Documentation__: <https://pynapple-org.github.io/pynapple>
- __Notebooks and tutorials__ : <https://pynapple-org.github.io/pynapple/notebooks/pynapple-quick-start/>
- __Collaborative repository__: <https://github.com/pynapple-org/pynacollada>
<!-- - __Collaborative repository__: <https://github.com/pynapple-org/pynacollada> -->


> **Note**
Expand Down
8 changes: 8 additions & 0 deletions docs/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ Around 2016-2017, Luke Sjulson started *TSToolbox2*, still in Matlab and which i
In 2018, Francesco started neuroseries, a Python package built on Pandas. It was quickly adopted in Adrien's lab, especially by Guillaume Viejo, a postdoc in the lab. Gradually, the majority of the lab was using it and new functions were constantly added.
In 2021, Guillaume and other trainees in Adrien's lab decided to fork from neuroseries and started *pynapple*. The core of pynapple is largely built upon neuroseries. Some of the original changes to TSToolbox made by Luke were included in this package, especially the *time_support* property of all ts/tsd objects.

0.3.5 (2023-08-08)
------------------

- NWB reader class
- NPZ reader class
- Folder class for navigating a dataset.
- Cross-correlograms function can take tuple
- New doc with mkdocs-gallery

0.3.4 (2023-06-29)
------------------
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ PYthon Neural Analysis Package.

pynapple is a light-weight python library for neurophysiological data analysis. The goal is to offer a versatile set of tools to study typical data in the field, i.e. time series (spike times, behavioral events, etc.) and time intervals (trials, brain states, etc.). It also provides users with generic functions for neuroscience such as tuning curves and cross-correlograms.

- Free software: GNU General Public License v3
- Free software: MIT License
- __Documentation__: <https://pynapple-org.github.io/pynapple>
- __Notebooks and tutorials__ : <https://pynapple-org.github.io/pynapple/notebooks/pynapple-quick-start/>
- __Collaborative repository__: <https://github.com/PeyracheLab/pynacollada>
<!-- - __Collaborative repository__: <https://github.com/PeyracheLab/pynacollada> -->


> **Note**
Expand Down
2 changes: 1 addition & 1 deletion pynapple/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.3.4"
__version__ = "0.3.5"
from .core import *
from .io import *
from .process import *
7 changes: 6 additions & 1 deletion pynapple/io/interface_nwb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# @Author: Guillaume Viejo
# @Date: 2023-08-01 11:54:45
# @Last Modified by: gviejo
# @Last Modified time: 2023-08-07 21:38:08
# @Last Modified time: 2023-08-07 22:34:26

"""
Pynapple class to interface with NWB files.
Expand Down Expand Up @@ -195,6 +195,11 @@ def _make_tsd_frame(obj):
else:
columns = np.arange(obj.data.shape[1])

if len(columns) >= d.shape[1]: # Weird sometimes if background ID added
columns = columns[0 : obj.data.shape[1]]
else:
columns = np.arange(obj.data.shape[1])

data = nap.TsdFrame(t=t, d=d, columns=columns)

return data
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"

[project]
name = "pynapple"
version = "0.3.4"
version = "0.3.5"
description = "PYthon Neural Analysis Package Pour Laboratoires d’Excellence"
readme = "README.md"
authors = [{ name = "Guillaume Viejo", email = "[email protected]" }]
license = { file = "LICENSE" }
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
Expand All @@ -24,7 +24,7 @@ dependencies = [
"numpy>=1.17.4",
"scipy>=1.3.2",
"numba>=0.46.0",
"pynwb",
"pynwb>=2.0.0",
"tabulate",
"h5py",
"tifffile",
Expand Down
8 changes: 4 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
'numba>=0.46.0',
'numpy>=1.17.4',
'scipy>=1.3.2',
'pynwb',
'pynwb>=2.0.0',
'tabulate',
'h5py',
'tifffile',
Expand All @@ -39,7 +39,7 @@
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
Expand All @@ -62,8 +62,8 @@
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/pynapple-org/pynapple',
version='v0.3.4',
version='v0.3.5',
zip_safe=False,
long_description_content_type='text/markdown',
download_url='https://github.com/pynapple-org/pynapple/archive/refs/tags/v0.3.4.tar.gz'
download_url='https://github.com/pynapple-org/pynapple/archive/refs/tags/v0.3.5.tar.gz'
)
226 changes: 117 additions & 109 deletions tests/test_nwb.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# @Author: gviejo
# @Date: 2022-04-04 21:32:10
# @Last Modified by: Guillaume Viejo
# @Last Modified time: 2023-08-03 15:46:24
# @Last Modified by: gviejo
# @Last Modified time: 2023-08-07 22:57:50

"""Tests of nwb reading for `pynapple` package."""

Expand Down Expand Up @@ -221,55 +221,58 @@ def test_add_Ecephys():
mock_SpikeEventSeries,
)

nwbfile = mock_NWBFile()
nwbfile.add_electrode_group(mock_ElectrodeGroup())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 0
with warnings.catch_warnings():
warnings.simplefilter("ignore")

name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_ElectricalSeries())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "ElectricalSeries" in nwb.keys()
data = nwb["ElectricalSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["ElectricalSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values, obj.starting_time + np.arange(obj.num_samples) / obj.rate
)
np.testing.assert_array_almost_equal(data.columns.values, obj.electrodes["id"][:])
nwbfile = mock_NWBFile()
nwbfile.add_electrode_group(mock_ElectrodeGroup())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 0

# Try ElectrialSeries without channel mapping
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_ElectricalSeries(electrodes=None))
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "ElectricalSeries" in nwb.keys()
data = nwb["ElectricalSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["ElectricalSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values, obj.starting_time + np.arange(obj.num_samples) / obj.rate
)
np.testing.assert_array_almost_equal(data.columns.values, np.arange(obj.data.shape[1]))
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_ElectricalSeries())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "ElectricalSeries" in nwb.keys()
data = nwb["ElectricalSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["ElectricalSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values, obj.starting_time + np.arange(obj.num_samples) / obj.rate
)
np.testing.assert_array_almost_equal(data.columns.values, obj.electrodes["id"][:])

# Try ElectrialSeries without channel mapping
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_ElectricalSeries(electrodes=None))
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "ElectricalSeries" in nwb.keys()
data = nwb["ElectricalSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["ElectricalSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values, obj.starting_time + np.arange(obj.num_samples) / obj.rate
)
np.testing.assert_array_almost_equal(data.columns.values, np.arange(obj.data.shape[1]))

name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_SpikeEventSeries())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "SpikeEventSeries" in nwb.keys()
data = nwb["SpikeEventSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["SpikeEventSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(data.index.values, obj.timestamps[:])
np.testing.assert_array_almost_equal(data.columns.values, obj.electrodes["id"][:])

name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(mock_SpikeEventSeries())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "SpikeEventSeries" in nwb.keys()
data = nwb["SpikeEventSeries"]
assert isinstance(data, nap.TsdFrame)
obj = nwbfile.acquisition["SpikeEventSeries"]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(data.index.values, obj.timestamps[:])
np.testing.assert_array_almost_equal(data.columns.values, obj.electrodes["id"][:])


def test_add_Icephys():
Expand All @@ -283,42 +286,45 @@ def test_add_Icephys():
mock_IZeroClampSeries,
)

name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_icephys_electrode(mock_IntracellularElectrode())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 0
with warnings.catch_warnings():
warnings.simplefilter("ignore")

for name, Series in zip(
[
"VoltageClampStimulusSeries",
"VoltageClampSeries",
"CurrentClampSeries",
"CurrentClampStimulusSeries",
"IZeroClampSeries",
],
[
mock_VoltageClampStimulusSeries,
mock_VoltageClampSeries,
mock_CurrentClampSeries,
mock_CurrentClampStimulusSeries,
mock_IZeroClampSeries,
],
):
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(Series())
nwbfile.add_icephys_electrode(mock_IntracellularElectrode())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert name in nwb.keys()
data = nwb[name]
assert isinstance(data, nap.Tsd)
obj = nwbfile.acquisition[name]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values,
obj.starting_time + np.arange(obj.num_samples) / obj.rate,
)
assert len(nwb) == 0

for name, Series in zip(
[
"VoltageClampStimulusSeries",
"VoltageClampSeries",
"CurrentClampSeries",
"CurrentClampStimulusSeries",
"IZeroClampSeries",
],
[
mock_VoltageClampStimulusSeries,
mock_VoltageClampSeries,
mock_CurrentClampSeries,
mock_CurrentClampStimulusSeries,
mock_IZeroClampSeries,
],
):
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(Series())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert name in nwb.keys()
data = nwb[name]
assert isinstance(data, nap.Tsd)
obj = nwbfile.acquisition[name]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values,
obj.starting_time + np.arange(obj.num_samples) / obj.rate,
)
except:
# Doesn't work for all versions.
pass
Expand Down Expand Up @@ -363,40 +369,42 @@ def test_add_Ophys():
mock_DfOverF,
mock_Fluorescence,
)
with warnings.catch_warnings():
warnings.simplefilter("ignore")

name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_imaging_plane(mock_ImagingPlane())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 0

for Series in [
# mock_OnePhotonSeries,
# mock_TwoPhotonSeries,
mock_RoiResponseSeries,
mock_DfOverF,
mock_Fluorescence,
]:
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(Series())
nwbfile.add_imaging_plane(mock_ImagingPlane())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "RoiResponseSeries" in nwb.keys()
data = nwb["RoiResponseSeries"]
assert isinstance(data, nap.TsdFrame)
if "DfOverF" in nwbfile.acquisition.keys():
obj = nwbfile.acquisition["DfOverF"]["RoiResponseSeries"]
elif "Fluorescence" in nwbfile.acquisition.keys():
obj = nwbfile.acquisition["Fluorescence"]["RoiResponseSeries"]
else:
obj = nwbfile.acquisition[list(nwbfile.acquisition.keys())[0]]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values,
obj.starting_time + np.arange(obj.num_samples) / obj.rate,
)
np.testing.assert_array_almost_equal(data.columns.values, obj.rois["id"][:])
assert len(nwb) == 0

for Series in [
# mock_OnePhotonSeries,
# mock_TwoPhotonSeries,
mock_RoiResponseSeries,
mock_DfOverF,
mock_Fluorescence,
]:
name_generator_registry.clear()
nwbfile = mock_NWBFile()
nwbfile.add_acquisition(Series())
nwb = nap.NWBFile(nwbfile)
assert len(nwb) == 1
assert "RoiResponseSeries" in nwb.keys()
data = nwb["RoiResponseSeries"]
assert isinstance(data, nap.TsdFrame)
if "DfOverF" in nwbfile.acquisition.keys():
obj = nwbfile.acquisition["DfOverF"]["RoiResponseSeries"]
elif "Fluorescence" in nwbfile.acquisition.keys():
obj = nwbfile.acquisition["Fluorescence"]["RoiResponseSeries"]
else:
obj = nwbfile.acquisition[list(nwbfile.acquisition.keys())[0]]
np.testing.assert_array_almost_equal(data.values, obj.data[:])
np.testing.assert_array_almost_equal(
data.index.values,
obj.starting_time + np.arange(obj.num_samples) / obj.rate,
)
np.testing.assert_array_almost_equal(data.columns.values, obj.rois["id"][:])

except:
pass # some issues with pynwb version
Expand Down

0 comments on commit 9d2dfc4

Please sign in to comment.