Skip to content

Commit 17bd66c

Browse files
committed
Addressed @jchoude's comments.
1 parent ae62594 commit 17bd66c

File tree

3 files changed

+60
-22
lines changed

3 files changed

+60
-22
lines changed

nibabel/streamlines/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ def load(fileobj, lazy_load=False):
7070
of the streamlines file's header).
7171
lazy_load : {False, True}, optional
7272
If True, load streamlines in a lazy manner i.e. they will not be kept
73-
in memory. Otherwise, load all streamlines in memory.
73+
in memory and only be loaded when needed.
74+
Otherwise, load all streamlines in memory.
7475
7576
Returns
7677
-------

nibabel/streamlines/tests/test_tractogram.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,26 @@ def test_tractogram_creation(self):
334334
assert_raises(ValueError, Tractogram, DATA['streamlines'],
335335
data_per_point=data_per_point)
336336

337+
def test_setting_affine_to_rasmm(self):
338+
tractogram = DATA['tractogram'].copy()
339+
affine = np.diag(range(4))
340+
341+
# Test assigning None.
342+
tractogram.affine_to_rasmm = None
343+
assert_true(tractogram.affine_to_rasmm is None)
344+
345+
# Test assigning a valid ndarray (should make a copy).
346+
tractogram.affine_to_rasmm = affine
347+
assert_true(tractogram.affine_to_rasmm is not affine)
348+
349+
# Test assigning a list of lists.
350+
tractogram.affine_to_rasmm = affine.tolist()
351+
assert_array_equal(tractogram.affine_to_rasmm, affine)
352+
353+
# Test assigning a ndarray with wrong shape.
354+
assert_raises(ValueError, setattr, tractogram,
355+
"affine_to_rasmm", affine[::2])
356+
337357
def test_tractogram_getitem(self):
338358
# Retrieve TractogramItem by their index.
339359
for i, t in enumerate(DATA['tractogram']):
@@ -483,6 +503,12 @@ def test_tractogram_apply_affine(self):
483503
for s1, s2 in zip(tractogram.streamlines, DATA['streamlines']):
484504
assert_array_almost_equal(s1, s2)
485505

506+
# Test applying the identity transformation.
507+
tractogram = DATA['tractogram'].copy()
508+
tractogram.apply_affine(np.eye(4))
509+
for s1, s2 in zip(tractogram.streamlines, DATA['streamlines']):
510+
assert_array_almost_equal(s1, s2)
511+
486512
# Test removing affine_to_rasmm
487513
tractogram = DATA['tractogram'].copy()
488514
tractogram.affine_to_rasmm = None

nibabel/streamlines/tractogram.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ class TractogramItem(object):
188188
where N is the number of points.
189189
data_for_streamline : dict
190190
Dictionary containing some data associated to this particular
191-
streamline. Each key `k` is mapped to a ndarray of shape (Pk,), where
191+
streamline. Each key `k` is mapped to a ndarray of shape (Pt,), where
192192
`Pt` is the dimension of the data associated with key `k`.
193193
data_for_points : dict
194194
Dictionary containing some data associated to each point of this
@@ -225,17 +225,17 @@ class Tractogram(object):
225225
streamline $t$.
226226
data_per_streamline : :class:`PerArrayDict` object
227227
Dictionary where the items are (str, 2D array).
228-
Each key represents an information $i$ to be kept along side every
228+
Each key represents an information $i$ to be kept alongside every
229229
streamline, and its associated value is a 2D array of shape
230230
($T$, $P_i$) where $T$ is the number of streamlines and $P_i$ is
231-
the number scalar values to store for that particular information $i$.
231+
the number of values to store for that particular information $i$.
232232
data_per_point : :class:`PerArraySequenceDict` object
233233
Dictionary where the items are (str, :class:`ArraySequence`).
234-
Each key represents an information $i$ to be kept along side every
234+
Each key represents an information $i$ to be kept alongside every
235235
point of every streamline, and its associated value is an iterable
236236
of ndarrays of shape ($N_t$, $M_i$) where $N_t$ is the number of
237237
points for a particular streamline $t$ and $M_i$ is the number
238-
scalar values to store for that particular information $i$.
238+
values to store for that particular information $i$.
239239
"""
240240
def __init__(self, streamlines=None,
241241
data_per_streamline=None,
@@ -250,13 +250,13 @@ def __init__(self, streamlines=None,
250250
streamline $t$.
251251
data_per_streamline : dict of iterable of ndarrays, optional
252252
Dictionary where the items are (str, iterable).
253-
Each key represents an information $i$ to be kept along side every
253+
Each key represents an information $i$ to be kept alongside every
254254
streamline, and its associated value is an iterable of ndarrays of
255-
shape ($P_i$,) where $P_i$ is the number scalar values to store
255+
shape ($P_i$,) where $P_i$ is the number of scalar values to store
256256
for that particular information $i$.
257257
data_per_point : dict of iterable of ndarrays, optional
258258
Dictionary where the items are (str, iterable).
259-
Each key represents an information $i$ to be kept along side every
259+
Each key represents an information $i$ to be kept alongside every
260260
point of every streamline, and its associated value is an iterable
261261
of ndarrays of shape ($N_t$, $M_i$) where $N_t$ is the number of
262262
points for a particular streamline $t$ and $M_i$ is the number
@@ -303,6 +303,13 @@ def affine_to_rasmm(self):
303303

304304
@affine_to_rasmm.setter
305305
def affine_to_rasmm(self, value):
306+
if value is not None:
307+
value = np.array(value)
308+
if value.shape != (4, 4):
309+
msg = ("Affine matrix has a shape of (4, 4) but a ndarray with"
310+
"shape {} was provided instead.").format(value.shape)
311+
raise ValueError(msg)
312+
306313
self._affine_to_rasmm = value
307314

308315
def __iter__(self):
@@ -362,6 +369,9 @@ def apply_affine(self, affine, lazy=False):
362369
if len(self.streamlines) == 0:
363370
return self
364371

372+
if np.all(affine == np.eye(4)):
373+
return self # No transformation.
374+
365375
BUFFER_SIZE = 10000000 # About 128 Mb since pts shape is 3.
366376
for start in range(0, len(self.streamlines.data), BUFFER_SIZE):
367377
end = start + BUFFER_SIZE
@@ -408,7 +418,7 @@ class LazyTractogram(Tractogram):
408418
409419
This container behaves lazily as it uses generator functions to manage
410420
streamlines and their data information. This container is thus memory
411-
friendly since it doesn't require having all those data loaded in memory.
421+
friendly since it doesn't require having all this data loaded in memory.
412422
413423
Streamlines of a lazy tractogram can be in any coordinate system of your
414424
choice as long as you provide the correct `affine_to_rasmm` matrix, at
@@ -424,23 +434,26 @@ class LazyTractogram(Tractogram):
424434
streamline $t$.
425435
data_per_streamline : :class:`LazyDict` object
426436
Dictionary where the items are (str, instantiated generator).
427-
Each key represents an information $i$ to be kept along side every
437+
Each key represents an information $i$ to be kept alongside every
428438
streamline, and its associated value is a generator function
429439
yielding that information via ndarrays of shape ($P_i$,) where
430-
$P_i$ is the number scalar values to store for that particular
440+
$P_i$ is the number of values to store for that particular
431441
information $i$.
432442
data_per_point : :class:`LazyDict` object
433443
Dictionary where the items are (str, instantiated generator).
434-
Each key represents an information $i$ to be kept along side every
444+
Each key represents an information $i$ to be kept alongside every
435445
point of every streamline, and its associated value is a generator
436446
function yielding that information via ndarrays of shape
437447
($N_t$, $M_i$) where $N_t$ is the number of points for a particular
438-
streamline $t$ and $M_i$ is the number scalar values to store for
448+
streamline $t$ and $M_i$ is the number of values to store for
439449
that particular information $i$.
440450
441451
Notes
442452
-----
443453
LazyTractogram objects do not support indexing currently.
454+
LazyTractogram objects are suited for operations that can be linearized
455+
such as applying an affine transformation or converting streamlines from
456+
one file format to another.
444457
"""
445458
def __init__(self, streamlines=None,
446459
data_per_streamline=None,
@@ -455,18 +468,18 @@ def __init__(self, streamlines=None,
455468
streamline $t$.
456469
data_per_streamline : dict of generator functions, optional
457470
Dictionary where the items are (str, generator function).
458-
Each key represents an information $i$ to be kept along side every
471+
Each key represents an information $i$ to be kept alongside every
459472
streamline, and its associated value is a generator function
460473
yielding that information via ndarrays of shape ($P_i$,) where
461-
$P_i$ is the number scalar values to store for that particular
474+
$P_i$ is the number of values to store for that particular
462475
information $i$.
463476
data_per_point : dict of generator functions, optional
464477
Dictionary where the items are (str, generator function).
465-
Each key represents an information $i$ to be kept along side every
478+
Each key represents an information $i$ to be kept alongside every
466479
point of every streamline, and its associated value is a generator
467480
function yielding that information via ndarrays of shape
468481
($N_t$, $M_i$) where $N_t$ is the number of points for a particular
469-
streamline $t$ and $M_i$ is the number scalar values to store for
482+
streamline $t$ and $M_i$ is the number of values to store for
470483
that particular information $i$.
471484
affine_to_rasmm : ndarray of shape (4, 4) or None, optional
472485
Transformation matrix that brings the streamlines contained in
@@ -525,7 +538,7 @@ def create_from(cls, data_func):
525538
Parameters
526539
----------
527540
data_func : generator function yielding :class:`TractogramItem` objects
528-
Generator function that whenever it is called starts yielding
541+
Generator function that whenever is called starts yielding
529542
:class:`TractogramItem` objects that will be used to instantiate a
530543
:class:`LazyTractogram`.
531544
@@ -650,9 +663,7 @@ def __len__(self):
650663
warn("Number of streamlines will be determined manually by looping"
651664
" through the streamlines. If you know the actual number of"
652665
" streamlines, you might want to set it beforehand via"
653-
" `self.header.nb_streamlines`."
654-
" Note this will consume any generators used to create this"
655-
" `LazyTractogram` object.", Warning)
666+
" `self.header.nb_streamlines`.", Warning)
656667
# Count the number of streamlines.
657668
self._nb_streamlines = sum(1 for _ in self.streamlines)
658669

0 commit comments

Comments
 (0)