Skip to content

Commit b76672a

Browse files
committed
now handles all Neo objects, including ChannelViews and RegionsOfInterest
1 parent 74e9415 commit b76672a

File tree

8 files changed

+426
-218
lines changed

8 files changed

+426
-218
lines changed

neo/core/baseneo.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ class BaseNeo:
180180
class must have. The tuple can have 2-4 elements.
181181
The first element is the attribute name.
182182
The second element is the attribute type.
183-
The third element is the number of dimensions
183+
The third element is the number of dimensions
184184
(only for numpy arrays and quantities).
185185
The fourth element is the dtype of array
186186
(only for numpy arrays and quantities).
@@ -253,6 +253,8 @@ class attributes. :_recommended_attrs: should append
253253
# Attributes that are used for pretty-printing
254254
_repr_pretty_attrs_keys_ = ("name", "description", "annotations")
255255

256+
is_view = False
257+
256258
def __init__(self, name=None, description=None, file_origin=None,
257259
**annotations):
258260
"""

neo/core/container.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,16 +251,19 @@ def _data_child_containers(self):
251251
"""
252252
Containers for child objects that have data and have a single parent.
253253
"""
254-
return tuple([_container_name(child) for child in
255-
self._data_child_objects])
254+
# the following construction removes the duplicate 'regionsofinterest'
255+
# while preserving the child order (which `set()` would not do)
256+
# I don't know if preserving the author is important, but I'm playing it safe
257+
return tuple({_container_name(child): None for child in
258+
self._data_child_objects}.keys())
256259

257260
@property
258261
def _child_containers(self):
259262
"""
260263
Containers for child objects with a single parent.
261264
"""
262-
return tuple([_container_name(child) for child in
263-
self._child_objects])
265+
return tuple({_container_name(child): None for child in
266+
self._child_objects}.keys())
264267

265268
@property
266269
def _single_children(self):

neo/core/regionofinterest.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ class RegionOfInterest(BaseNeo):
1010
_parent_objects = ('Group',)
1111
_parent_attrs = ('group',)
1212
_necessary_attrs = (
13-
('obj', ('ImageSequence', ), 1),
13+
('image_sequence', ('ImageSequence', ), 1),
1414
)
15+
is_view = True
1516

1617
def __init__(self, image_sequence, name=None, description=None, file_origin=None, **annotations):
1718
super().__init__(name=name, description=description,
@@ -22,6 +23,16 @@ def __init__(self, image_sequence, name=None, description=None, file_origin=None
2223
raise ValueError("Can only take a RegionOfInterest of an ImageSequence")
2324
self.image_sequence = image_sequence
2425

26+
def _get_obj(self):
27+
# for consistency with ChannelView
28+
return self.image_sequence
29+
30+
def _set_obj(self, value):
31+
assert isinstance(value, ImageSequence)
32+
self.image_sequence = value
33+
34+
obj = property(fget=_get_obj, fset=_set_obj)
35+
2536
def resolve(self):
2637
"""
2738
Return a signal from within this region of the underlying ImageSequence.
@@ -44,6 +55,13 @@ class CircularRegionOfInterest(RegionOfInterest):
4455
Radius of the ROI in pixels
4556
"""
4657

58+
_necessary_attrs = (
59+
('image_sequence', ('ImageSequence', ), 1),
60+
('x', int),
61+
('y', int),
62+
('radius', int)
63+
)
64+
4765
def __init__(self, image_sequence, x, y, radius, name=None, description=None,
4866
file_origin=None, **annotations):
4967
super().__init__(image_sequence, name, description, file_origin, **annotations)
@@ -94,6 +112,14 @@ class RectangularRegionOfInterest(RegionOfInterest):
94112
Height (y-direction) of the ROI in pixels
95113
"""
96114

115+
_necessary_attrs = (
116+
('image_sequence', ('ImageSequence', ), 1),
117+
('x', int),
118+
('y', int),
119+
('width', int),
120+
('height', int)
121+
)
122+
97123
def __init__(self, image_sequence, x, y, width, height, name=None, description=None,
98124
file_origin=None, **annotations):
99125
super().__init__(image_sequence, name, description, file_origin, **annotations)
@@ -139,6 +165,11 @@ class PolygonRegionOfInterest(RegionOfInterest):
139165
of the vertices of the polygon
140166
"""
141167

168+
_necessary_attrs = (
169+
('image_sequence', ('ImageSequence', ), 1),
170+
('vertices', list),
171+
)
172+
142173
def __init__(self, image_sequence, *vertices, name=None, description=None,
143174
file_origin=None, **annotations):
144175
super().__init__(image_sequence, name, description, file_origin, **annotations)

neo/core/view.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ class ChannelView(BaseNeo):
3030
Note: Any other additional arguments are assumed to be user-specific
3131
metadata and stored in :attr:`annotations`.
3232
"""
33-
_parent_objects = ('Segment',)
34-
_parent_attrs = ('segment',)
33+
_parent_objects = ('Group',)
34+
_parent_attrs = ('group',)
3535
_necessary_attrs = (
36+
('obj', ('AnalogSignal', 'IrregularlySampledSignal'), 1),
3637
('index', np.ndarray, 1, np.dtype('i')),
37-
('obj', ('AnalogSignal', 'IrregularlySampledSignal'), 1)
3838
)
39+
is_view = True
40+
3941
# "mask" would be an alternative name, proposing "index" for
4042
# backwards-compatibility with ChannelIndex
4143

@@ -73,7 +75,7 @@ def shape(self):
7375
return (self.obj.shape[0], self.index.size)
7476

7577
def _get_arr_ann_length(self):
76-
return self.shape[-1]
78+
return self.index.size
7779

7880
def array_annotate(self, **array_annotations):
7981
self.array_annotations.update(array_annotations)

0 commit comments

Comments
 (0)