Skip to content

Commit adb15a3

Browse files
committed
Merge pull request #293 from Eric89GXL/remove-trace
FIX: Remove trace by default Allows for discarding the trace, and making it the default behavior. It generally seems to be nuisance (non-)data in the analysis process. Add appveyor build and badge.
2 parents b774a9b + 9841c41 commit adb15a3

File tree

5 files changed

+189
-6
lines changed

5 files changed

+189
-6
lines changed

README.rst

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
.. -*- rest -*-
22
.. vim:syntax=rest
33
4+
|Coveralls|_
5+
6+
.. |Coveralls| image:: https://coveralls.io/repos/nipy/nibabel/badge.png?branch=master
7+
.. _Coveralls: https://coveralls.io/r/nipy/nibabel?branch=master
8+
9+
410
=======
511
NiBabel
612
=======

appveyor.yml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# vim ft=yaml
2+
# CI on Windows via appveyor
3+
# This file was based on Olivier Grisel's python-appveyor-demo
4+
5+
environment:
6+
7+
matrix:
8+
- PYTHON: "C:\\Python27-conda32"
9+
PYTHON_VERSION: "2.7"
10+
PYTHON_ARCH: "32"
11+
12+
- PYTHON: "C:\\Python34-conda32"
13+
PYTHON_VERSION: "3.4"
14+
PYTHON_ARCH: "32"
15+
16+
- PYTHON: "C:\\Python34-conda64"
17+
PYTHON_VERSION: "3.4"
18+
PYTHON_ARCH: "64"
19+
20+
install:
21+
# Install miniconda Python
22+
- "powershell ./tools/install_python.ps1"
23+
24+
# Prepend newly installed Python to the PATH of this build (this cannot be
25+
# done from inside the powershell script as it would require to restart
26+
# the parent CMD process).
27+
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
28+
29+
# Check that we have the expected version and architecture for Python
30+
- "python --version"
31+
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
32+
33+
# Install the dependencies of the project.
34+
- "conda install --yes --quiet numpy scipy matplotlib nose h5py"
35+
- "pip install pydicom"
36+
- "python setup.py install"
37+
- "SET NIBABEL_DATA_DIR=%CD%\\nibabel-data"
38+
39+
build: false # Not a C# project, build stuff at the test step instead.
40+
41+
test_script:
42+
# Change into an innocuous directory and find tests from installation
43+
- "mkdir for_testing"
44+
- "cd for_testing"
45+
- "nosetests --with-doctest nibabel"

bin/parrec2nii

+21-3
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ def get_opt_parser():
103103
store the corresponding settings in the NIfTI header, unless
104104
non-uniform scaling is used, in which case the data is
105105
stored in the file in scaled form. Default: 'dv'""")))
106+
p.add_option(
107+
Option('--keep-trace', action="store_true", dest='keep_trace',
108+
default=False,
109+
help=one_line("""Do not discard the diagnostic Philips DTI
110+
trace volume, if it exists in the data.""")))
106111
p.add_option(
107112
Option("--overwrite", action="store_true", dest="overwrite",
108113
default=False,
@@ -171,12 +176,26 @@ def proc_file(infile, opts):
171176
ornt = io_orientation(np.diag([-1, 1, 1, 1]).dot(affine))
172177
if np.all(ornt == [[0, 1],
173178
[1, 1],
174-
[2, 1]]): # already in LAS+
179+
[2, 1]]): # already in LAS+
175180
t_aff = np.eye(4)
176-
else: # Not in LAS+
181+
else: # Not in LAS+
177182
t_aff = inv_ornt_aff(ornt, pr_img.shape)
178183
affine = np.dot(affine, t_aff)
179184
in_data = apply_orientation(in_data, ornt)
185+
186+
bvals, bvecs = pr_hdr.get_bvals_bvecs()
187+
if not opts.keep_trace: # discard Philips DTI trace if present
188+
if bvals is not None:
189+
bad_mask = np.logical_and(bvals != 0, (bvecs == 0).all(axis=1))
190+
if bad_mask.sum() > 0:
191+
pl = 's' if bad_mask.sum() != 1 else ''
192+
verbose('Removing %s DTI trace volume%s'
193+
% (bad_mask.sum(), pl))
194+
good_mask = ~bad_mask
195+
in_data = in_data[..., good_mask]
196+
bvals = bvals[good_mask]
197+
bvecs = bvecs[good_mask]
198+
180199
# Make corresponding NIfTI image
181200
nimg = nifti1.Nifti1Image(in_data, affine, pr_hdr)
182201
nhdr = nimg.header
@@ -208,7 +227,6 @@ def proc_file(infile, opts):
208227

209228
# write out bvals/bvecs if requested
210229
if opts.bvs:
211-
bvals, bvecs = pr_hdr.get_bvals_bvecs()
212230
if bvals is None and bvecs is None:
213231
verbose('No DTI volumes detected, bvals and bvecs not written')
214232
else:

nibabel/tests/test_scripts.py

+24-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def script_test(func):
5252

5353
DATA_PATH = abspath(pjoin(dirname(__file__), 'data'))
5454

55+
5556
@script_test
5657
def test_nib_ls():
5758
# test nib-ls script
@@ -84,7 +85,7 @@ def test_nib_nifti_dx():
8485

8586

8687
def vox_size(affine):
87-
return np.sqrt(np.sum(affine[:3,:3] ** 2, axis=0))
88+
return np.sqrt(np.sum(affine[:3, :3] ** 2, axis=0))
8889

8990

9091
def check_conversion(cmd, pr_data, out_fname):
@@ -184,7 +185,7 @@ def test_parrec2nii_with_data():
184185
par_root, ext = splitext(basename(par))
185186
# NA.PAR appears to be a localizer, with three slices in each of
186187
# the three orientations: sagittal; coronal, transverse
187-
if par_root == 'NA':
188+
if par_root == 'NA':
188189
continue
189190
# Do conversion
190191
run_command(['parrec2nii', par])
@@ -226,8 +227,12 @@ def test_parrec2nii_with_data():
226227
check_code=False)
227228
assert_equal(code, 1)
228229
# Writes bvals, bvecs files if asked
229-
run_command(['parrec2nii', '--overwrite', '--bvs', dti_par])
230+
run_command(['parrec2nii', '--overwrite', '--keep-trace',
231+
'--bvs', dti_par])
230232
assert_almost_equal(np.loadtxt('DTI.bvals'), DTI_PAR_BVALS)
233+
img = load('DTI.nii')
234+
data = img.get_data().copy()
235+
del img
231236
# Bvecs in header, transposed from PSL to LPS
232237
bvecs_LPS = DTI_PAR_BVECS[:, [2, 0, 1]]
233238
# Adjust for output flip of Y axis in data and bvecs
@@ -247,3 +252,19 @@ def test_parrec2nii_with_data():
247252
with open('DTI.dwell_time', 'rt') as fobj:
248253
contents = fobj.read().strip()
249254
assert_almost_equal(float(contents), exp_dwell)
255+
# ensure trace is removed by default
256+
run_command(['parrec2nii', '--overwrite', '--bvs', dti_par])
257+
assert_true(exists('DTI.bvals'))
258+
assert_true(exists('DTI.bvecs'))
259+
img = load('DTI.nii')
260+
bvecs_notrace = np.loadtxt('DTI.bvecs').T
261+
bvals_notrace = np.loadtxt('DTI.bvals')
262+
data_notrace = img.get_data().copy()
263+
assert_equal(data_notrace.shape[-1], len(bvecs_notrace))
264+
del img
265+
# ensure correct volume was removed
266+
good_mask = np.logical_or((bvecs_notrace != 0).any(axis=1),
267+
bvals_notrace == 0)
268+
assert_almost_equal(data_notrace, data[..., good_mask])
269+
assert_almost_equal(bvals_notrace, np.array(DTI_PAR_BVALS)[good_mask])
270+
assert_almost_equal(bvecs_notrace, bvecs_LAS[good_mask])

tools/install_python.ps1

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Sample script to install Python and pip under Windows
2+
# Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner
3+
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
4+
5+
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
6+
$BASE_URL = "https://www.python.org/ftp/python/"
7+
8+
9+
function DownloadMiniconda ($python_version, $platform_suffix) {
10+
$webclient = New-Object System.Net.WebClient
11+
if ($python_version -eq "3.4") {
12+
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
13+
} else {
14+
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
15+
}
16+
$url = $MINICONDA_URL + $filename
17+
18+
$basedir = $pwd.Path + "\"
19+
$filepath = $basedir + $filename
20+
if (Test-Path $filename) {
21+
Write-Host "Reusing" $filepath
22+
return $filepath
23+
}
24+
25+
# Download and retry up to 3 times in case of network transient errors.
26+
Write-Host "Downloading" $filename "from" $url
27+
$retry_attempts = 2
28+
for($i=0; $i -lt $retry_attempts; $i++){
29+
try {
30+
$webclient.DownloadFile($url, $filepath)
31+
break
32+
}
33+
Catch [Exception]{
34+
Start-Sleep 1
35+
}
36+
}
37+
if (Test-Path $filepath) {
38+
Write-Host "File saved at" $filepath
39+
} else {
40+
# Retry once to get the error message if any at the last try
41+
$webclient.DownloadFile($url, $filepath)
42+
}
43+
return $filepath
44+
}
45+
46+
47+
function InstallMiniconda ($python_version, $architecture, $python_home) {
48+
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
49+
if (Test-Path $python_home) {
50+
Write-Host $python_home "already exists, skipping."
51+
return $false
52+
}
53+
if ($architecture -eq "32") {
54+
$platform_suffix = "x86"
55+
} else {
56+
$platform_suffix = "x86_64"
57+
}
58+
$filepath = DownloadMiniconda $python_version $platform_suffix
59+
Write-Host "Installing" $filepath "to" $python_home
60+
$install_log = $python_home + ".log"
61+
$args = "/S /D=$python_home"
62+
Write-Host $filepath $args
63+
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
64+
if (Test-Path $python_home) {
65+
Write-Host "Python $python_version ($architecture) installation complete"
66+
} else {
67+
Write-Host "Failed to install Python in $python_home"
68+
Get-Content -Path $install_log
69+
Exit 1
70+
}
71+
}
72+
73+
74+
function InstallMinicondaPip ($python_home) {
75+
$pip_path = $python_home + "\Scripts\pip.exe"
76+
$conda_path = $python_home + "\Scripts\conda.exe"
77+
if (-not(Test-Path $pip_path)) {
78+
Write-Host "Installing pip..."
79+
$args = "install --yes pip"
80+
Write-Host $conda_path $args
81+
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
82+
} else {
83+
Write-Host "pip already installed."
84+
}
85+
}
86+
87+
88+
function main () {
89+
InstallMiniconda $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
90+
InstallMinicondaPip $env:PYTHON
91+
}
92+
93+
main

0 commit comments

Comments
 (0)