Skip to content

Commit 22f89e9

Browse files
committed
Merge branch 'no-hypothesis' of https://github.com/yarikoptic/nibabel into no-hypothesis
2 parents 2340a92 + f973ce4 commit 22f89e9

File tree

9 files changed

+140
-95
lines changed

9 files changed

+140
-95
lines changed

.travis.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,31 @@
44
# for it to be on multiple physical lines, so long as you remember: - There
55
# can't be any leading "-"s - All newlines will be removed, so use ";"s
66

7+
dist: xenial
8+
sudo: true
79
language: python
810

9-
# Run jobs on container-based infrastructure, can be overridden per job
10-
sudo: false
11-
1211
cache:
1312
directories:
1413
- $HOME/.cache/pip
1514
env:
1615
global:
17-
- DEPENDS="six numpy scipy matplotlib h5py pillow pydicom hypothesis"
16+
- DEPENDS="six numpy scipy matplotlib h5py pillow pydicom"
1817
- OPTIONAL_DEPENDS=""
1918
- INSTALL_TYPE="setup"
2019
- EXTRA_WHEELS="https://5cf40426d9f06eb7461d-6fe47d9331aba7cd62fc36c7196769e4.ssl.cf2.rackcdn.com"
2120
- PRE_WHEELS="https://7933911d6844c6c53a7d-47bd50c35cd79bd838daf386af554a83.ssl.cf2.rackcdn.com"
2221
- EXTRA_PIP_FLAGS="--find-links=$EXTRA_WHEELS"
2322
- PRE_PIP_FLAGS="--pre $EXTRA_PIP_FLAGS --find-links $PRE_WHEELS"
2423
python:
25-
- 3.4
2624
- 3.5
2725
- 3.6
26+
- 3.7
2827
matrix:
2928
include:
29+
- python: 3.4
30+
dist: trusty
31+
sudo: false
3032
- python: 2.7
3133
env:
3234
- COVERAGE=1
@@ -95,7 +97,7 @@ before_install:
9597
- source venv/bin/activate
9698
- python --version # just to check
9799
- pip install -U pip wheel # needed at one point
98-
- retry pip install nose flake8 mock hypothesis # always
100+
- retry pip install nose flake8 mock # always
99101
- pip install $EXTRA_PIP_FLAGS $DEPENDS $OPTIONAL_DEPENDS
100102
- if [ "${COVERAGE}" == "1" ]; then
101103
pip install coverage;

appveyor.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ environment:
1212
- PYTHON: C:\Python35-x64
1313
- PYTHON: C:\Python36
1414
- PYTHON: C:\Python36-x64
15+
- PYTHON: C:\Python37
16+
- PYTHON: C:\Python37-x64
1517

1618
install:
1719
# Prepend newly installed Python to the PATH of this build (this cannot be
@@ -20,7 +22,7 @@ install:
2022
- SET PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
2123

2224
# Install the dependencies of the project.
23-
- pip install numpy scipy matplotlib nose h5py mock hypothesis pydicom
25+
- pip install numpy scipy matplotlib nose h5py mock pydicom
2426
- pip install .
2527
- SET NIBABEL_DATA_DIR=%CD%\nibabel-data
2628

dev-requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@
22
-r requirements.txt
33
nose
44
mock
5-
hypothesis

nibabel/cmdline/diff.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,53 @@ def get_opt_parser():
6464

6565

6666
def are_values_different(*values):
67-
"""Generically compares values, returns true if different"""
68-
value0 = values[0]
69-
values = values[1:] # to ensure that the first value isn't compared with itself
67+
"""Generically compare values, return True if different
7068
71-
for value in values:
72-
try: # we sometimes don't want NaN values
73-
if np.any(np.isnan(value0)) and np.any(np.isnan(value)): # if they're both NaN
74-
break
75-
elif np.any(np.isnan(value0)) or np.any(np.isnan(value)): # if only 1 is NaN
76-
return True
69+
Note that comparison is targetting reporting of comparison of the headers
70+
so has following specifics:
71+
- even a difference in data types is considered a difference, i.e. 1 != 1.0
72+
- nans are considered to be the "same", although generally nan != nan
73+
"""
74+
value0 = values[0]
7775

78-
except TypeError:
79-
pass
76+
# to not recompute over again
77+
if isinstance(value0, np.ndarray):
78+
try:
79+
# np.asarray for elderly numpys, e.g. 1.7.1 where for
80+
# degenerate arrays (shape ()) it would return a pure scalar
81+
value0_nans = np.asanyarray(np.isnan(value0))
82+
value0_nonnans = np.asanyarray(np.logical_not(value0_nans))
83+
# if value0_nans.size == 1:
84+
# import pdb; pdb.set_trace()
85+
if not np.any(value0_nans):
86+
value0_nans = None
87+
except TypeError as exc:
88+
str_exc = str(exc)
89+
# Not implemented in numpy 1.7.1
90+
if "not supported" in str_exc or "ot implemented" in str_exc:
91+
value0_nans = None
92+
else:
93+
raise
8094

95+
for value in values[1:]:
8196
if type(value0) != type(value): # if types are different, then we consider them different
8297
return True
8398
elif isinstance(value0, np.ndarray):
84-
return np.any(value0 != value)
85-
99+
if value0.dtype != value.dtype or \
100+
value0.shape != value.shape:
101+
return True
102+
# there might be nans and they need special treatment
103+
if value0_nans is not None:
104+
value_nans = np.isnan(value)
105+
if np.any(value0_nans != value_nans):
106+
return True
107+
if np.any(value0[value0_nonnans] != value[value0_nonnans]):
108+
return True
109+
elif np.any(value0 != value):
110+
return True
111+
elif value0 is np.nan:
112+
if value is not np.nan:
113+
return True
86114
elif value0 != value:
87115
return True
88116

nibabel/deprecated.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ class FutureWarningMixin(object):
5252
5353
>>> with warnings.catch_warnings(record=True) as warns:
5454
... d = D()
55-
... warns[0].message
56-
FutureWarning("Please, don't use this class",)
55+
... warns[0].message.args[0]
56+
"Please, don't use this class"
5757
"""
5858
warn_message = 'This class will be removed in future versions'
5959

nibabel/freesurfer/io.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,24 @@ def _read_volume_info(fobj):
8181
return volume_info
8282

8383

84-
def _pack_rgba(rgba):
85-
"""Pack an RGBA sequence into a single integer.
84+
def _pack_rgb(rgb):
85+
"""Pack an RGB sequence into a single integer.
8686
8787
Used by :func:`read_annot` and :func:`write_annot` to generate
8888
"annotation values" for a Freesurfer ``.annot`` file.
8989
9090
Parameters
9191
----------
92-
rgba : ndarray, shape (n, 4)
93-
RGBA colors
92+
rgb : ndarray, shape (n, 3)
93+
RGB colors
9494
9595
Returns
9696
-------
9797
out : ndarray, shape (n, 1)
9898
Annotation values for each color.
9999
"""
100-
bitshifts = 2 ** np.array([[0], [8], [16], [24]], dtype=rgba.dtype)
101-
return rgba.dot(bitshifts)
100+
bitshifts = 2 ** np.array([[0], [8], [16]], dtype=rgb.dtype)
101+
return rgb.dot(bitshifts)
102102

103103

104104
def read_geometry(filepath, read_metadata=False, read_stamp=False):
@@ -333,9 +333,13 @@ def read_annot(filepath, orig_ids=False):
333333
Annotation file format versions 1 and 2 are supported, corresponding to
334334
the "old-style" and "new-style" color table layout.
335335
336+
Note that the output color table ``ctab`` is in RGBT form, where T
337+
(transparency) is 255 - alpha.
338+
336339
See:
337340
* https://surfer.nmr.mgh.harvard.edu/fswiki/LabelsClutsAnnotationFiles#Annotation
338341
* https://github.com/freesurfer/freesurfer/blob/dev/matlab/read_annotation.m
342+
* https://github.com/freesurfer/freesurfer/blob/8b88b34/utils/colortab.c
339343
340344
Parameters
341345
----------
@@ -352,7 +356,7 @@ def read_annot(filepath, orig_ids=False):
352356
Annotation id at each vertex. If a vertex does not belong
353357
to any label and orig_ids=False, its id will be set to -1.
354358
ctab : ndarray, shape (n_labels, 5)
355-
RGBA + label id colortable array.
359+
RGBT + label id colortable array.
356360
names : list of str (python 2), list of bytes (python 3)
357361
The names of the labels. The length of the list is n_labels.
358362
"""
@@ -384,7 +388,7 @@ def read_annot(filepath, orig_ids=False):
384388
ctab, names = _read_annot_ctab_new_format(fobj, -n_entries)
385389

386390
# generate annotation values for each LUT entry
387-
ctab[:, [4]] = _pack_rgba(ctab[:, :4])
391+
ctab[:, [4]] = _pack_rgb(ctab[:, :3])
388392

389393
if not orig_ids:
390394
ord = np.argsort(ctab[:, -1])
@@ -397,6 +401,9 @@ def read_annot(filepath, orig_ids=False):
397401
def _read_annot_ctab_old_format(fobj, n_entries):
398402
"""Read in an old-style Freesurfer color table from `fobj`.
399403
404+
Note that the output color table ``ctab`` is in RGBT form, where T
405+
(transparency) is 255 - alpha.
406+
400407
This function is used by :func:`read_annot`.
401408
402409
Parameters
@@ -412,7 +419,7 @@ def _read_annot_ctab_old_format(fobj, n_entries):
412419
-------
413420
414421
ctab : ndarray, shape (n_entries, 5)
415-
RGBA colortable array - the last column contains all zeros.
422+
RGBT colortable array - the last column contains all zeros.
416423
names : list of str
417424
The names of the labels. The length of the list is n_entries.
418425
"""
@@ -430,7 +437,7 @@ def _read_annot_ctab_old_format(fobj, n_entries):
430437
name_length = np.fromfile(fobj, dt, 1)[0]
431438
name = np.fromfile(fobj, "|S%d" % name_length, 1)[0]
432439
names.append(name)
433-
# read RGBA for this entry
440+
# read RGBT for this entry
434441
ctab[i, :4] = np.fromfile(fobj, dt, 4)
435442

436443
return ctab, names
@@ -439,6 +446,9 @@ def _read_annot_ctab_old_format(fobj, n_entries):
439446
def _read_annot_ctab_new_format(fobj, ctab_version):
440447
"""Read in a new-style Freesurfer color table from `fobj`.
441448
449+
Note that the output color table ``ctab`` is in RGBT form, where T
450+
(transparency) is 255 - alpha.
451+
442452
This function is used by :func:`read_annot`.
443453
444454
Parameters
@@ -454,7 +464,7 @@ def _read_annot_ctab_new_format(fobj, ctab_version):
454464
-------
455465
456466
ctab : ndarray, shape (n_labels, 5)
457-
RGBA colortable array - the last column contains all zeros.
467+
RGBT colortable array - the last column contains all zeros.
458468
names : list of str
459469
The names of the labels. The length of the list is n_labels.
460470
"""
@@ -480,7 +490,7 @@ def _read_annot_ctab_new_format(fobj, ctab_version):
480490
name_length = np.fromfile(fobj, dt, 1)[0]
481491
name = np.fromfile(fobj, "|S%d" % name_length, 1)[0]
482492
names.append(name)
483-
# RGBA
493+
# RGBT
484494
ctab[idx, :4] = np.fromfile(fobj, dt, 4)
485495

486496
return ctab, names
@@ -489,9 +499,13 @@ def _read_annot_ctab_new_format(fobj, ctab_version):
489499
def write_annot(filepath, labels, ctab, names, fill_ctab=True):
490500
"""Write out a "new-style" Freesurfer annotation file.
491501
502+
Note that the color table ``ctab`` is in RGBT form, where T (transparency)
503+
is 255 - alpha.
504+
492505
See:
493506
* https://surfer.nmr.mgh.harvard.edu/fswiki/LabelsClutsAnnotationFiles#Annotation
494507
* https://github.com/freesurfer/freesurfer/blob/dev/matlab/write_annotation.m
508+
* https://github.com/freesurfer/freesurfer/blob/8b88b34/utils/colortab.c
495509
496510
Parameters
497511
----------
@@ -500,7 +514,7 @@ def write_annot(filepath, labels, ctab, names, fill_ctab=True):
500514
labels : ndarray, shape (n_vertices,)
501515
Annotation id at each vertex.
502516
ctab : ndarray, shape (n_labels, 5)
503-
RGBA + label id colortable array.
517+
RGBT + label id colortable array.
504518
names : list of str
505519
The names of the labels. The length of the list is n_labels.
506520
fill_ctab : {True, False} optional
@@ -523,8 +537,8 @@ def write_string(s):
523537

524538
# Generate annotation values for each ctab entry
525539
if fill_ctab:
526-
ctab = np.hstack((ctab[:, :4], _pack_rgba(ctab[:, :4])))
527-
elif not np.array_equal(ctab[:, [4]], _pack_rgba(ctab[:, :4])):
540+
ctab = np.hstack((ctab[:, :4], _pack_rgb(ctab[:, :3])))
541+
elif not np.array_equal(ctab[:, [4]], _pack_rgb(ctab[:, :3])):
528542
warnings.warn('Annotation values in {} will be incorrect'.format(
529543
filepath))
530544

nibabel/freesurfer/tests/test_io.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from .. import (read_geometry, read_morph_data, read_annot, read_label,
1818
write_geometry, write_morph_data, write_annot)
19-
from ..io import _pack_rgba
19+
from ..io import _pack_rgb
2020

2121
from ...tests.nibabel_data import get_nibabel_data, needs_nibabel_data
2222
from ...fileslice import strided_scalar
@@ -236,8 +236,7 @@ def test_read_write_annot():
236236
# Generate the annotation values for each LUT entry
237237
rgbal[:, 4] = (rgbal[:, 0] +
238238
rgbal[:, 1] * (2 ** 8) +
239-
rgbal[:, 2] * (2 ** 16) +
240-
rgbal[:, 3] * (2 ** 24))
239+
rgbal[:, 2] * (2 ** 16))
241240
annot_path = 'c.annot'
242241
with InTemporaryDirectory():
243242
write_annot(annot_path, labels, rgbal, names, fill_ctab=False)
@@ -287,8 +286,7 @@ def test_write_annot_fill_ctab():
287286
rgbal = np.hstack((rgba, np.zeros((nlabels, 1), dtype=np.int32)))
288287
rgbal[:, 4] = (rgbal[:, 0] +
289288
rgbal[:, 1] * (2 ** 8) +
290-
rgbal[:, 2] * (2 ** 16) +
291-
rgbal[:, 3] * (2 ** 24))
289+
rgbal[:, 2] * (2 ** 16))
292290
with clear_and_catch_warnings() as w:
293291
write_annot(annot_path, labels, rgbal, names, fill_ctab=False)
294292
assert_true(
@@ -307,7 +305,7 @@ def gen_old_annot_file(fpath, nverts, labels, rgba, names):
307305
dt = '>i'
308306
vdata = np.zeros((nverts, 2), dtype=dt)
309307
vdata[:, 0] = np.arange(nverts)
310-
vdata[:, [1]] = _pack_rgba(rgba[labels, :])
308+
vdata[:, [1]] = _pack_rgb(rgba[labels, :3])
311309
fbytes = b''
312310
# number of vertices
313311
fbytes += struct.pack(dt, nverts)

0 commit comments

Comments
 (0)