Skip to content

Commit 8d2ac21

Browse files
Merge branch 'NeuralEnsemble:master' into enh/array_anno_types
2 parents 95d6ad2 + 29d73f6 commit 8d2ac21

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+595
-343
lines changed

codemeta.json

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
{
2+
"@context": "https://doi.org/10.5063/schema/codemeta-2.0",
3+
"@type": "SoftwareSourceCode",
4+
"license": "https://spdx.org/licenses/BSD-3-Clause",
5+
"codeRepository": "https://github.com/NeuralEnsemble/python-neo",
6+
"contIntegration": "https://github.com/NeuralEnsemble/python-neo/actions",
7+
"dateModified": "2023-04-04",
8+
"downloadUrl": "https://files.pythonhosted.org/packages/4d/95/e79e05c9bc8ef61d89a8a6b949db03adb2046b9fca38422d570c7add543d/neo-0.12.0.tar.gz",
9+
"issueTracker": "https://github.com/NeuralEnsemble/python-neo/issues",
10+
"name": "Neo",
11+
"version": "0.12.0",
12+
"identifier": "RRID:SCR_000634",
13+
"description": "Neo is a Python package for working with electrophysiology data in Python, together with support for reading a wide range of neurophysiology file formats, including Spike2, NeuroExplorer, AlphaOmega, Axon, Blackrock, Plexon, Tdt, and support for writing to a subset of these formats plus non-proprietary formats including HDF5.\n\nThe goal of Neo is to improve interoperability between Python tools for analyzing, visualizing and generating electrophysiology data by providing a common, shared object model. In order to be as lightweight a dependency as possible, Neo is deliberately limited to represention of data, with no functions for data analysis or visualization.\n\nNeo is used by a number of other software tools, including SpykeViewer (data analysis and visualization), Elephant (data analysis), the G-node suite (databasing), PyNN (simulations), tridesclous_ (spike sorting) and ephyviewer (data visualization).\n\nNeo implements a hierarchical data model well adapted to intracellular and extracellular electrophysiology and EEG data with support for multi-electrodes (for example tetrodes). Neo's data objects build on the quantities package, which in turn builds on NumPy by adding support for physical dimensions. Thus Neo objects behave just like normal NumPy arrays, but with additional metadata, checks for dimensional consistency and automatic unit conversion.",
14+
"applicationCategory": "neuroscience",
15+
"releaseNotes": "https://neo.readthedocs.io/en/stable/releases/0.12.0.html",
16+
"funding": "https://cordis.europa.eu/project/id/945539",
17+
"developmentStatus": "active",
18+
"referencePublication": "https://doi.org/10.3389/fninf.2014.00010",
19+
"funder": {
20+
"@type": "Organization",
21+
"name": "European Commission"
22+
},
23+
"programmingLanguage": ["Python"],
24+
"operatingSystem": ["Linux", "Windows", "macOS"],
25+
"softwareRequirements": [
26+
"Python (version 3.8+)",
27+
"see https://github.com/NeuralEnsemble/python-neo/blob/master/pyproject.toml"
28+
],
29+
"relatedLink": [
30+
"https://neo.readthedocs.io",
31+
"https://neuralensemble.org/community"
32+
],
33+
"author": [
34+
{ "@type": "Person", "givenName": "Samuel", "familyName": "Garcia" },
35+
{
36+
"@type": "Person",
37+
"@id": "http://orcid.org/0000-0002-4793-7541",
38+
"givenName": "Andrew P.",
39+
"familyName": "Davison"
40+
},
41+
{ "@type": "Person", "givenName": "Chris", "familyName": "Rodgers" },
42+
{ "@type": "Person", "givenName": "Pierre", "familyName": "Yger" },
43+
{ "@type": "Person", "givenName": "Yann", "familyName": "Mahnoun" },
44+
{ "@type": "Person", "givenName": "Luc", "familyName": "Estabanez" },
45+
{ "@type": "Person", "givenName": "Andrey", "familyName": "Sobolev" },
46+
{ "@type": "Person", "givenName": "Thierry", "familyName": "Brizzi" },
47+
{ "@type": "Person", "givenName": "Florent", "familyName": "Jaillet" },
48+
{ "@type": "Person", "givenName": "Philipp", "familyName": "Rautenberg" },
49+
{ "@type": "Person", "givenName": "Thomas", "familyName": "Wachtler" },
50+
{ "@type": "Person", "givenName": "Cyril", "familyName": "Dejean" },
51+
{ "@type": "Person", "givenName": "Robert", "familyName": "Pröpper" },
52+
{ "@type": "Person", "givenName": "Domenico", "familyName": "Guarino" },
53+
{ "@type": "Person", "givenName": "Achilleas", "familyName": "Koutsou" },
54+
{ "@type": "Person", "givenName": "Erik", "familyName": "Li" },
55+
{ "@type": "Person", "givenName": "Georg", "familyName": "Raiser" },
56+
{ "@type": "Person", "givenName": "Joffrey", "familyName": "Gonin" },
57+
{ "@type": "Person", "givenName": "Kyler", "familyName": "Brown" },
58+
{ "@type": "Person", "givenName": "Mikkel Elle", "familyName": "Lepperød" },
59+
{ "@type": "Person", "givenName": "C Daniel", "familyName": "Meliza" },
60+
{ "@type": "Person", "givenName": "Julia", "familyName": "Sprenger" },
61+
{ "@type": "Person", "givenName": "Maximilian", "familyName": "Schmidt" },
62+
{ "@type": "Person", "givenName": "Johanna", "familyName": "Senk" },
63+
{ "@type": "Person", "givenName": "Carlos", "familyName": "Canova" },
64+
{ "@type": "Person", "givenName": "Hélissande", "familyName": "Fragnaud" },
65+
{ "@type": "Person", "givenName": "Mark", "familyName": "Hollenbeck" },
66+
{ "@type": "Person", "givenName": "Mieszko", "familyName": "Grodzicki" },
67+
{ "@type": "Person", "givenName": "Rick", "familyName": "Gerkin" },
68+
{ "@type": "Person", "givenName": "Matthieu", "familyName": "Sénoville" },
69+
{ "@type": "Person", "givenName": "Chadwick", "familyName": "Boulay" },
70+
{ "@type": "Person", "givenName": "Björn", "familyName": "Müller" },
71+
{ "@type": "Person", "givenName": "William", "familyName": "Hart" },
72+
{ "@type": "Person", "alternateName": "erikli(github)" },
73+
{ "@type": "Person", "givenName": "Jeffrey", "familyName": "Gill" },
74+
{
75+
"@type": "Person",
76+
"givenName": "Lucas",
77+
"alternateName": "lkoelman@github"
78+
},
79+
{ "@type": "Person", "givenName": "Mark", "familyName": "Histed" },
80+
{ "@type": "Person", "givenName": "Mike", "familyName": "Sintsov" },
81+
{ "@type": "Person", "givenName": "Scott W", "familyName": "Harden" },
82+
{
83+
"@type": "Person",
84+
"givenName": "Chek Yin",
85+
"familyName": "Choi",
86+
"alternateName": "hkchekc@github"
87+
},
88+
{ "@type": "Person", "givenName": "Corentin", "familyName": "Fragnaud" },
89+
{
90+
"@type": "Person",
91+
"givenName": "Alexander",
92+
"familyName": "Kleinjohann"
93+
},
94+
{ "@type": "Person", "givenName": "Christian", "familyName": "Kothe" },
95+
{ "@type": "Person", "alternateName": "rishidhingra@github" },
96+
{ "@type": "Person", "givenName": "Hugo", "familyName": "van Kemenade" },
97+
{
98+
"@type": "Person",
99+
"givenName": "Aitor",
100+
"familyName": "Morales-Gregorio"
101+
},
102+
{ "@type": "Person", "givenName": "Peter N", "familyName": "Steinmetz" },
103+
{ "@type": "Person", "givenName": "Shashwat", "familyName": "Sridhar" },
104+
{ "@type": "Person", "givenName": "Alessio", "familyName": "Buccino" },
105+
{ "@type": "Person", "givenName": "Regimantas", "familyName": "Jurkus" },
106+
{ "@type": "Person", "givenName": "Steffen", "familyName": "Buergers" },
107+
{ "@type": "Person", "givenName": "Etienne", "familyName": "Combrisson" },
108+
{ "@type": "Person", "givenName": "Ben", "familyName": "Dichter" },
109+
{ "@type": "Person", "givenName": "Elodie", "familyName": "Legouée" },
110+
{ "@type": "Person", "givenName": "Heberto", "familyName": "Mayorquin" },
111+
{ "@type": "Person", "givenName": "Thomas", "familyName": "Perret" }
112+
]
113+
}

doc/old_stuffs/grouping.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ Using :class:`ChannelIndex`::
3434

3535
block = Block()
3636
segment = Segment()
37-
segment.block = block
3837
block.segments.append(segment)
3938

4039
for i in (0, 1):
@@ -55,7 +54,6 @@ Using array annotations, we annotate the channels of the :class:`AnalogSignal` d
5554

5655
block = Block()
5756
segment = Segment()
58-
segment.block = block
5957
block.segments.append(segment)
6058

6159
for i in (0, 1):
@@ -77,7 +75,6 @@ Each :class:`ChannelIndex` also contains the list of channels on which that neur
7775

7876
block = Block(name="probe data")
7977
segment = Segment()
80-
segment.block = block
8178
block.segments.append(segment)
8279

8380
# create 4-channel AnalogSignal with dummy data
@@ -119,7 +116,6 @@ Using :class:`ChannelView` and :class:`Group`::
119116

120117
block = Block(name="probe data")
121118
segment = Segment()
122-
segment.block = block
123119
block.segments.append(segment)
124120

125121
# create 4-channel AnalogSignal with dummy data

doc/old_stuffs/io_developers_guide.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ Miscellaneous
3838
=============
3939

4040
* If your IO supports several versions of a format (like ABF1, ABF2), upload to the gin.g-node.org test file repository all file versions possible. (for test coverage).
41-
* :py:func:`neo.core.Block.create_many_to_one_relationship` offers a utility to complete the hierarchy when all one-to-many relationships have been created.
4241
* In the docstring, explain where you obtained the file format specification if it is a closed one.
4342
* If your IO is based on a database mapper, keep in mind that the returned object MUST be detached,
4443
because this object can be written to another url for copying.

doc/source/images/generate_diagram.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ def get_rect_height(name, obj):
2828
nlines = 1.5
2929
nlines += len(getattr(obj, '_all_attrs', []))
3030
nlines += len(getattr(obj, '_single_child_objects', []))
31-
nlines += len(getattr(obj, '_multi_child_objects', []))
3231
return nlines * line_heigth
3332

3433

@@ -74,9 +73,7 @@ def generate_diagram(rect_pos, rect_width, figsize):
7473
alpha = [1., 1., 0.3]
7574
for name, pos in rect_pos.items():
7675
obj = objs[name]
77-
relationships = [getattr(obj, '_single_child_objects', []),
78-
getattr(obj, '_multi_child_objects', []),
79-
getattr(obj, '_child_properties', [])]
76+
relationships = [getattr(obj, '_single_child_objects', [])]
8077

8178
for r in range(3):
8279
for ch_name in relationships[r]:
@@ -122,16 +119,6 @@ def generate_diagram(rect_pos, rect_width, figsize):
122119
facecolor='c', edgecolor='k', alpha=.5)
123120
ax.add_patch(rect)
124121

125-
# multi relationship
126-
relationship = list(getattr(obj, '_multi_child_objects', []))
127-
pos2 = (pos[1] + htotal - line_heigth * (1.5 + len(relationship))
128-
- rect_height)
129-
rect_height = len(relationship) * line_heigth
130-
131-
rect = Rectangle((pos[0], pos2), rect_width, rect_height,
132-
facecolor='m', edgecolor='k', alpha=.5)
133-
ax.add_patch(rect)
134-
135122
# necessary attr
136123
pos2 = (pos[1] + htotal
137124
- line_heigth * (1.5 + len(allrelationship) + len(obj._necessary_attrs)))

doc/source/scripts/multi_tetrode_example.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
# Create dummy data, one segment at a time
3737
for segment in block.segments:
38-
segment.block = block
3938

4039
# create two 4-channel AnalogSignals with dummy data
4140
signals = {
@@ -46,8 +45,6 @@
4645
}
4746
if store_signals:
4847
segment.analogsignals.extend(signals.values())
49-
for signal in signals:
50-
signal.segment = segment
5148

5249
# create spike trains with dummy data
5350
# we will pretend the spikes have been extracted from the dummy signal
@@ -56,7 +53,6 @@
5653
spiketrain = SpikeTrain(np.random.uniform(0, 100, size=30) * ms, t_stop=100 * ms)
5754
# assign each spiketrain to the appropriate segment
5855
segment.spiketrains.append(spiketrain)
59-
spiketrain.segment = segment
6056
# assign each spiketrain to a given neuron
6157
current_group = next(iter_group)
6258
current_group.add(spiketrain)

examples/generated_data.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ def generate_block(n_segments=3, n_channels=4, n_units=3,
5858
seg.spiketrains.append(train)
5959
u.spiketrains.append(train)
6060

61-
block.create_many_to_one_relationship()
6261
return block
6362

6463

neo/core/block.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
from datetime import datetime
1111

1212
from neo.core.container import Container, unique_objs
13+
from neo.core.group import Group
14+
from neo.core.objectlist import ObjectList
15+
from neo.core.regionofinterest import RegionOfInterest
16+
from neo.core.segment import Segment
1317

1418

1519
class Block(Container):
@@ -64,7 +68,6 @@ class Block(Container):
6468
'''
6569

6670
_container_child_objects = ('Segment', 'Group')
67-
_child_properties = ()
6871
_recommended_attrs = ((('file_datetime', datetime),
6972
('rec_datetime', datetime),
7073
('index', int)) +
@@ -86,9 +89,27 @@ def __init__(self, name=None, description=None, file_origin=None,
8689
self.file_datetime = file_datetime
8790
self.rec_datetime = rec_datetime
8891
self.index = index
89-
self.regionsofinterest = [] # temporary workaround.
90-
# the goal is to store all sub-classes of RegionOfInterest in a single list
91-
# but this will need substantial changes to container handling
92+
self._segments = ObjectList(Segment, parent=self)
93+
self._groups = ObjectList(Group, parent=self)
94+
self._regionsofinterest = ObjectList(RegionOfInterest, parent=self)
95+
96+
segments = property(
97+
fget=lambda self: self._get_object_list("_segments"),
98+
fset=lambda self, value: self._set_object_list("_segments", value),
99+
doc="list of Segments contained in this block"
100+
)
101+
102+
groups = property(
103+
fget=lambda self: self._get_object_list("_groups"),
104+
fset=lambda self, value: self._set_object_list("_groups", value),
105+
doc="list of Groups contained in this block"
106+
)
107+
108+
regionsofinterest = property(
109+
fget=lambda self: self._get_object_list("_regionsofinterest"),
110+
fset=lambda self, value: self._set_object_list("_regionsofinterest", value),
111+
doc="list of RegionOfInterest objects contained in this block"
112+
)
92113

93114
@property
94115
def data_children_recur(self):

0 commit comments

Comments
 (0)