Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

MRG: refactor of time slice routines #308

Merged
merged 12 commits into from

2 participants

@matthew-brett

I hadn't really thought through selecting the slice axis for time-slice
routine utilties or for the diagnostic screening utilities.

Refactor the nipy_tsdiffana and nipy_diagnose command line utilties to
use a common interface for selecting slice and time axes. Put command
logic in a commands module and test more. Generalize diagnostic
screening utilities to any time axis rather than assuming time is the
last axis (the pca module explicitly allows this). Deprecate guess at
slice axis for screening function (but continue to guess for Nifti-like
images from the command line).

matthew-brett added some commits
@matthew-brett matthew-brett NF: error if time diff slice axis is time axis
Running time_slice_diff on an array allowed the slice and the time axes
to be the same.  Test that they aren't.
7224b61
@matthew-brett matthew-brett NF: function giving time difference for images
New function that accepts an image as input and returns time series
difference analysis on the image.
4f1a61f
@matthew-brett matthew-brett WIP: refactor tsdiffana script to select slice axis 27cf49c
@matthew-brett matthew-brett WIP: refactoring diagnostics commands into modules def0732
@matthew-brett matthew-brett RF: refuse to load / convert MINC for now
Nibabel can load MINC, but now we need an API to get the axis names for
MINC, otherwise, the axes can be anywhere, but are most likely to be in
the opposite order to the ones the NIfTI needs.  Raise an error until we
have worked out how to do this right.
9aecb4a
@matthew-brett matthew-brett TST: skip test for non-analyze types for now
In fact it turns out we can't sensibly load the non-analyze types, so
skip this test.
3f7a8b5
@matthew-brett matthew-brett TST: develop tests for tsdiffana command function
Use command function to test the tsdiffana interface.
144497a
@matthew-brett matthew-brett TST: extend tests for nipy_tsdiffana script
Smoke test for time and slice axis command line options.
fde2c71
@matthew-brett matthew-brett NF: tsdiffana option to save results volumes
Add option for tsdiffana to be able to save the results volumes created
during the analysis.
4eca2c3
@matthew-brett matthew-brett BF+TST: test+fix bugs for PCA on reordered images
The `screen` and `write_screen_res` functions were assuming time-last
ordering in a couple of places.  Test and fix.
9027633
@matthew-brett matthew-brett RF+TST: refactor nipy_diagnose into module, test
Put logic for nipy_diagnose into commands module.

Use time and slice axis testing function developed for tsdiffana.

Extend tests of diagnose outputs.
188bd29
@matthew-brett matthew-brett RF: deprecate guessed slice axis for screens func
The command line utilities nipy_tsdiffana and nipy_diagnose guess the
slice axis for Analyze-like files (like Nifti) - so the `screens`
function doesn't need to do that, and it doesn't match the API for --
say -- `pca_image`.  So deprecate the slice axis guess in `screens` and
test.
3625690
@matthew-brett

Any comments here?

@bthirion
Collaborator

LGTM. Nice coverage by tests. Works like a charm on my data.

@matthew-brett

Thanks for the review - merging then.

@matthew-brett matthew-brett merged commit 788674f into nipy:master
@matthew-brett matthew-brett deleted the matthew-brett:refactor-image-time-diff branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 6, 2014
  1. @matthew-brett

    NF: error if time diff slice axis is time axis

    matthew-brett authored
    Running time_slice_diff on an array allowed the slice and the time axes
    to be the same.  Test that they aren't.
Commits on Feb 7, 2014
  1. @matthew-brett

    NF: function giving time difference for images

    matthew-brett authored
    New function that accepts an image as input and returns time series
    difference analysis on the image.
  2. @matthew-brett
Commits on Feb 8, 2014
  1. @matthew-brett
Commits on Feb 12, 2014
  1. @matthew-brett

    RF: refuse to load / convert MINC for now

    matthew-brett authored
    Nibabel can load MINC, but now we need an API to get the axis names for
    MINC, otherwise, the axes can be anywhere, but are most likely to be in
    the opposite order to the ones the NIfTI needs.  Raise an error until we
    have worked out how to do this right.
  2. @matthew-brett

    TST: skip test for non-analyze types for now

    matthew-brett authored
    In fact it turns out we can't sensibly load the non-analyze types, so
    skip this test.
Commits on Feb 13, 2014
  1. @matthew-brett

    TST: develop tests for tsdiffana command function

    matthew-brett authored
    Use command function to test the tsdiffana interface.
  2. @matthew-brett

    TST: extend tests for nipy_tsdiffana script

    matthew-brett authored
    Smoke test for time and slice axis command line options.
Commits on Feb 14, 2014
  1. @matthew-brett

    NF: tsdiffana option to save results volumes

    matthew-brett authored
    Add option for tsdiffana to be able to save the results volumes created
    during the analysis.
  2. @matthew-brett

    BF+TST: test+fix bugs for PCA on reordered images

    matthew-brett authored
    The `screen` and `write_screen_res` functions were assuming time-last
    ordering in a couple of places.  Test and fix.
Commits on Feb 15, 2014
  1. @matthew-brett

    RF+TST: refactor nipy_diagnose into module, test

    matthew-brett authored
    Put logic for nipy_diagnose into commands module.
    
    Use time and slice axis testing function developed for tsdiffana.
    
    Extend tests of diagnose outputs.
  2. @matthew-brett

    RF: deprecate guessed slice axis for screens func

    matthew-brett authored
    The command line utilities nipy_tsdiffana and nipy_diagnose guess the
    slice axis for Analyze-like files (like Nifti) - so the `screens`
    function doesn't need to do that, and it doesn't match the API for --
    say -- `pca_image`.  So deprecate the slice axis guess in `screens` and
    test.
This page is out of date. Refresh to see the latest.
View
177 nipy/algorithms/diagnostics/commands.py
@@ -0,0 +1,177 @@
+""" Implementation of diagnostic command line tools
+
+Tools are:
+
+* nipy_diagnose
+* nipy_tsdiffana
+
+This module has the logic for each command.
+
+The command script files deal with argument parsing and any custom imports.
+The implementation here accepts the ``args`` object from ``argparse`` and does
+the work.
+"""
+from os.path import split as psplit, join as pjoin
+
+import numpy as np
+
+from nibabel import AnalyzeHeader
+from nibabel.filename_parser import splitext_addext
+
+import nipy
+
+from .tsdiffplot import plot_tsdiffs
+from .timediff import time_slice_diffs_image
+from .screens import screen, write_screen_res
+
+
+def parse_fname_axes(img_fname, time_axis, slice_axis):
+ """ Load `img_fname`, check `time_axis`, `slice_axis` or use default
+
+ Parameters
+ ----------
+ img_fname : str
+ filename of image on which to do diagnostics
+ time_axis : None or str or int, optional
+ Axis indexing time-points. None is default, will be replaced by a value
+ of 't'. If `time_axis` is an integer, gives the index of the input
+ (domain) axis of `img`. If `time_axis` is a str, can be an input
+ (domain) name, or an output (range) name, that maps to an input
+ (domain) name.
+ slice_axis : None or str or int, optional
+ Axis indexing MRI slices. If `slice_axis` is an integer, gives the
+ index of the input (domain) axis of `img`. If `slice_axis` is a str,
+ can be an input (domain) name, or an output (range) name, that maps to
+ an input (domain) name. If None (the default) then 1) try the name
+ 'slice' to select the axis - if this fails, and `fname` refers to an
+ Analyze type image (such as Nifti), then 2) default to the third image
+ axis, otherwise 3) raise a ValueError
+
+ Returns
+ -------
+ img : ``Image`` instance
+ Image as loaded from `img_fname`
+ time_axis : int or str
+ Time axis, possibly filled with default
+ slice_axis : int or str
+ Slice axis, possibly filled with default
+ """
+ # Check whether this is an Analyze-type image
+ img = nipy.load_image(img_fname)
+ # Check for axes
+ if not time_axis is None:
+ # Try converting to an integer in case that was what was passed
+ try:
+ time_axis = int(time_axis)
+ except ValueError:
+ # Maybe a string
+ pass
+ else: # was None
+ time_axis = 't'
+ if not slice_axis is None:
+ # Try converting to an integer in case that was what was passed
+ try:
+ slice_axis = int(slice_axis)
+ except ValueError:
+ # Maybe a string
+ pass
+ else: # slice axis was None - search for default
+ input_names = img.coordmap.function_domain.coord_names
+ is_analyze = ('header' in img.metadata and
+ isinstance(img.metadata['header'], AnalyzeHeader))
+ if 'slice' in input_names:
+ slice_axis = 'slice'
+ elif is_analyze and img.ndim == 4:
+ slice_axis = 2
+ else:
+ raise ValueError('No slice axis specified, not analyze type '
+ 'image; refusing to guess')
+ return img, time_axis, slice_axis
+
+
+def tsdiffana(args):
+ """ Generate tsdiffana plots from command line params `args`
+
+ Parameters
+ ----------
+ args : object
+ object with attributes
+
+ * filename : str - 4D image filename
+ * out_file : str - graphics file to write to instead of leaving
+ graphics on screen
+ * time_axis : str - name or number of time axis in `filename`
+ * slice_axis : str - name or number of slice axis in `filename`
+ * write_results : bool - if True, write images and plots to files
+ * out_path : None or str - path to which to write results
+ * out_fname_label : None or filename - suffix of output results files
+
+ Returns
+ -------
+ axes : Matplotlib axes
+ Axes on which we have done the plots.
+ """
+ if not args.out_file is None and args.write_results:
+ raise ValueError("Cannot have OUT_FILE and WRITE_RESULTS options "
+ "together")
+ img, time_axis, slice_axis = parse_fname_axes(args.filename,
+ args.time_axis,
+ args.slice_axis)
+ results = time_slice_diffs_image(img, time_axis, slice_axis)
+ axes = plot_tsdiffs(results)
+ if args.out_file is None and not args.write_results:
+ # interactive mode
+ return axes
+ if not args.out_file is None:
+ # plot only mode
+ axes[0].figure.savefig(args.out_file)
+ return axes
+ # plot and images mode
+ froot, ext, addext = splitext_addext(args.filename)
+ fpath, fbase = psplit(froot)
+ fpath = fpath if args.out_path is None else args.out_path
+ fbase = fbase if args.out_fname_label is None else args.out_fname_label
+ axes[0].figure.savefig(pjoin(fpath, 'tsdiff_' + fbase + '.png'))
+ # Save image volumes
+ for key, prefix in (('slice_diff2_max_vol', 'dv2_max_'),
+ ('diff2_mean_vol', 'dv2_mean_')):
+ fname = pjoin(fpath, prefix + fbase + ext + addext)
+ nipy.save_image(results[key], fname)
+ # Save time courses into npz
+ np.savez(pjoin(fpath, 'tsdiff_' + fbase + '.npz'),
+ volume_means=results['volume_means'],
+ slice_mean_diff2=results['slice_mean_diff2'],
+ )
+ return axes
+
+
+def diagnose(args):
+ """ Calculate, write results from diagnostic screen
+
+ Parameters
+ ----------
+ args : object
+ object with attributes:
+
+ * filename : str - 4D image filename
+ * time_axis : str - name or number of time axis in `filename`
+ * slice_axis : str - name or number of slice axis in `filename`
+ * out_path : None or str - path to which to write results
+ * out_fname_label : None or filename - suffix of output results files
+ * ncomponents : int - number of PCA components to write images for
+
+ Returns
+ -------
+ res : dict
+ Results of running :func:`screen` on `filename`
+ """
+ img, time_axis, slice_axis = parse_fname_axes(args.filename,
+ args.time_axis,
+ args.slice_axis)
+ res = screen(img, args.ncomponents, time_axis, slice_axis)
+ froot, ext, addext = splitext_addext(args.filename)
+ fpath, fbase = psplit(froot)
+ fpath = fpath if args.out_path is None else args.out_path
+ fbase = fbase if args.out_fname_label is None else args.out_fname_label
+ write_screen_res(res, fpath, fbase, ext + addext)
+ return res
View
31 nipy/algorithms/diagnostics/screens.py
@@ -3,9 +3,11 @@
''' Diagnostic 4d image screen '''
from os.path import join as pjoin
+import warnings
+
import numpy as np
-from ...core.api import Image, drop_io_dim, append_io_dim
+from ...core.api import Image, drop_io_dim
from ...core.reference.coordinate_map import input_axis_index, AxisError
from ...io.api import save_image
from ..utils import pca
@@ -28,8 +30,10 @@ def screen(img4d, ncomp=10, time_axis='t', slice_axis=None):
Axis over which to do PCA, time difference analysis. Defaults to `t`
slice_axis : None or str or int, optional
Name or index of input axis over which to do slice analysis for time
- difference analysis. If None, look for input axis ``slice``, otherwise,
- assume slice is the last non-time axis.
+ difference analysis. If None, look for input axis ``slice``. At the
+ moment we then assume slice is the last non-time axis, but this last
+ guess we will remove in future versions of nipy. The default will then
+ be 'slice' and you'll get an error if there is no axis named 'slice'.
Returns
-------
@@ -66,6 +70,13 @@ def screen(img4d, ncomp=10, time_axis='t', slice_axis=None):
try:
slice_axis = input_axis_index(cmap, 'slice')
except AxisError:
+ warnings.warn(
+ 'Future versions of nipy will not guess the slice axis '
+ 'from position, but only from axis name == "slice"; '
+ 'Please specify the slice axis by name or index to avoid '
+ 'this warning',
+ FutureWarning,
+ stacklevel=2)
slice_axis = 2 if time_axis == 3 else 3
else:
slice_axis = input_axis_index(cmap, slice_axis)
@@ -78,13 +89,11 @@ def screen(img4d, ncomp=10, time_axis='t', slice_axis=None):
screen_res['max'] = Image(np.max(data, axis=time_axis), cmap_3d)
screen_res['min'] = Image(np.min(data, axis=time_axis), cmap_3d)
# PCA
- screen_res['pca_res'] = pca.pca(data,
- axis=time_axis,
- standardize=False,
- ncomp=ncomp)
- cmap_4d = append_io_dim(cmap_3d, 'l' , 't')
- screen_res['pca'] = Image(screen_res['pca_res']['basis_projections'],
- cmap_4d)
+ screen_res['pca_res'] = pca.pca_image(img4d,
+ axis=time_axis,
+ standardize=False,
+ ncomp=ncomp)
+ screen_res['pca'] = screen_res['pca_res']['basis_projections']
# tsdiffana
screen_res['ts_res'] = time_slice_diffs(data,
time_axis=time_axis,
@@ -126,7 +135,7 @@ def write_screen_res(res, out_path, out_root,
out_img_ext))
save_image(res[key], fname)
# plot, save component time courses and some tsdiffana stuff
- ncomp = res['pca'].shape[-1]
+ ncomp = res['pca_res']['axis']
vectors = res['pca_res']['basis_vectors']
pcnt_var = res['pca_res']['pcnt_var']
np.savez(pjoin(out_path, 'vectors_components_%s.npz' % out_root),
View
248 nipy/algorithms/diagnostics/tests/test_commands.py
@@ -0,0 +1,248 @@
+""" Testing diagnostics.command module
+"""
+
+import os
+from os.path import dirname, join as pjoin, isfile
+import shutil
+
+import numpy as np
+
+import nibabel as nib
+from nibabel import AnalyzeImage, Spm2AnalyzeImage, Nifti1Pair, Nifti1Image
+from nibabel.tmpdirs import InTemporaryDirectory
+
+from nipy import load_image
+from nipy.io.nifti_ref import NiftiError
+from ..commands import parse_fname_axes, tsdiffana, diagnose
+from ..timediff import time_slice_diffs_image
+
+from numpy.testing import (assert_almost_equal, assert_array_equal, decorators)
+
+from nibabel.optpkg import optional_package
+
+matplotlib, HAVE_MPL, _ = optional_package('matplotlib')
+needs_mpl = decorators.skipif(not HAVE_MPL, "Test needs matplotlib")
+
+from nose import SkipTest
+from nose.tools import (assert_true, assert_false, assert_raises,
+ assert_equal, assert_not_equal)
+
+from nipy.testing import funcfile
+
+def test_parse_fname_axes():
+ # Test logic for setting time and slice axis defaults
+ # We need real images for the tests because nipy will load them
+ # For simplicity, we can create them
+ shape = (4, 5, 6, 20)
+ arr = np.arange(np.prod(shape), dtype=float).reshape(shape)
+ zooms = (2., 3., 4., 2.1)
+ with InTemporaryDirectory():
+ for (img_class, ext) in ((AnalyzeImage, '.img'),
+ (Spm2AnalyzeImage, '.img'),
+ (Nifti1Pair, '.img'),
+ (Nifti1Image, '.nii')):
+ hdr = img_class.header_class()
+ hdr.set_data_shape(shape)
+ hdr.set_zooms(zooms)
+ hdr.set_data_dtype(np.dtype(np.float64))
+ nibabel_img = img_class(arr, None, hdr)
+ # We so far haven't set any slice axis information
+ for z_ext in ('', '.gz'):
+ fname = 'image' + ext + z_ext
+ nib.save(nibabel_img, fname)
+ for in_time, in_sax, out_time, out_sax in (
+ (None, None, 't', 2),
+ (None, '0', 't', 0),
+ (None, 'i', 't', 'i'),
+ (None, '1', 't', 1),
+ (None, 'j', 't', 'j'),
+ ('k', 'j', 'k', 'j'),
+ ('k', None, 'k', 2)):
+ img, time_axis, slice_axis = parse_fname_axes(
+ fname,
+ in_time,
+ in_sax)
+ assert_equal(time_axis, out_time)
+ assert_equal(slice_axis, out_sax)
+ del img
+ # For some images, we can set the slice dimension. This becomes the
+ # default if input slice_axis is None
+ if hasattr(hdr, 'set_dim_info'):
+ for ax_no in range(3):
+ nibabel_img.get_header().set_dim_info(slice=ax_no)
+ nib.save(nibabel_img, fname)
+ img, time_axis, slice_axis = parse_fname_axes(fname,
+ None,
+ None)
+ assert_equal(time_axis, 't')
+ assert_equal(slice_axis, 'slice')
+ del img
+ # Images other than 4D don't get the slice axis default
+ for new_arr in (arr[..., 0], arr[..., None]):
+ new_nib = img_class(new_arr, None, hdr)
+ nib.save(new_nib, fname)
+ assert_raises(ValueError, parse_fname_axes, fname, None, None)
+ # But you can still set slice axis
+ img, time_axis, slice_axis = parse_fname_axes(fname, None, 'j')
+ assert_equal(time_axis, 't')
+ assert_equal(slice_axis, 'j')
+ # Non-analyze image types don't get the slice default
+ nib_data = pjoin(dirname(nib.__file__), 'tests', 'data')
+ mnc_4d_fname = pjoin(nib_data, 'minc1_4d.mnc')
+ if isfile(mnc_4d_fname):
+ assert_raises(ValueError, parse_fname_axes, mnc_4d_fname, None, None)
+ # At the moment we can't even load these guys
+ try:
+ img, time_axis, slice_axis = parse_fname_axes(
+ mnc_4d_fname, None, 'j')
+ except ValueError: # failed load
+ raise SkipTest('Hoping for a time when we can use MINC')
+ # But you can still set slice axis (if we can load them)
+ assert_equal(time_axis, 't')
+ assert_equal(slice_axis, 'j')
+
+
+class Args(object): pass
+
+
+def check_axes(axes, img_shape, time_axis, slice_axis):
+ # Check axes as expected for plot
+ assert_equal(len(axes), 4)
+ # First x axis is time point differences
+ assert_array_equal(axes[0].xaxis.get_data_interval(),
+ [0, img_shape[time_axis]-2])
+ # Last x axis is over slices
+ assert_array_equal(axes[-1].xaxis.get_data_interval(),
+ [0, img_shape[slice_axis]-1])
+
+
+@needs_mpl
+def test_tsdiffana():
+ # Test tsdiffana command
+ args = Args()
+ img = load_image(funcfile)
+ with InTemporaryDirectory() as tmpdir:
+ args.filename = funcfile
+ args.time_axis = None
+ args.slice_axis = None
+ args.write_results = False
+ args.out_path = None
+ args.out_fname_label = None
+ args.out_file = 'test.png'
+ check_axes(tsdiffana(args), img.shape, -1, -2)
+ assert_true(isfile('test.png'))
+ args.time_axis = 't'
+ check_axes(tsdiffana(args), img.shape, -1, -2)
+ args.time_axis = '3'
+ check_axes(tsdiffana(args), img.shape, -1, -2)
+ args.slice_axis = 'k'
+ check_axes(tsdiffana(args), img.shape, -1, -2)
+ args.slice_axis = '2'
+ check_axes(tsdiffana(args), img.shape, -1, -2)
+ args.time_axis = '0'
+ check_axes(tsdiffana(args), img.shape, 0, -2)
+ args.slice_axis = 't'
+ check_axes(tsdiffana(args), img.shape, 0, -1)
+ # Check absolute path works
+ args.slice_axis = 'j'
+ args.time_axis = 't'
+ args.out_file = pjoin(tmpdir, 'test_again.png')
+ check_axes(tsdiffana(args), img.shape, -1, -3)
+ # Check that --out-images incompatible with --out-file
+ args.write_results=True
+ assert_raises(ValueError, tsdiffana, args)
+ args.out_file=None
+ # Copy the functional file to a temporary writeable directory
+ os.mkdir('mydata')
+ tmp_funcfile = pjoin(tmpdir, 'mydata', 'myfunc.nii.gz')
+ shutil.copy(funcfile, tmp_funcfile)
+ args.filename = tmp_funcfile
+ # Check write-results generates expected images
+ check_axes(tsdiffana(args), img.shape, -1, -3)
+ assert_true(isfile(pjoin('mydata', 'tsdiff_myfunc.png')))
+ max_img = load_image(pjoin('mydata', 'dv2_max_myfunc.nii.gz'))
+ assert_equal(max_img.shape, img.shape[:-1])
+ mean_img = load_image(pjoin('mydata', 'dv2_max_myfunc.nii.gz'))
+ assert_equal(mean_img.shape, img.shape[:-1])
+ exp_results = time_slice_diffs_image(img, 't', 'j')
+ saved_results = np.load(pjoin('mydata', 'tsdiff_myfunc.npz'))
+ for key in ('volume_means', 'slice_mean_diff2'):
+ assert_array_equal(exp_results[key], saved_results[key])
+ # That we can change out-path
+ os.mkdir('myresults')
+ args.out_path = 'myresults'
+ check_axes(tsdiffana(args), img.shape, -1, -3)
+ assert_true(isfile(pjoin('myresults', 'tsdiff_myfunc.png')))
+ max_img = load_image(pjoin('myresults', 'dv2_max_myfunc.nii.gz'))
+ assert_equal(max_img.shape, img.shape[:-1])
+ # And out-fname-label
+ args.out_fname_label = 'vr2'
+ check_axes(tsdiffana(args), img.shape, -1, -3)
+ assert_true(isfile(pjoin('myresults', 'tsdiff_vr2.png')))
+ max_img = load_image(pjoin('myresults', 'dv2_max_vr2.nii.gz'))
+ assert_equal(max_img.shape, img.shape[:-1])
+ del max_img, mean_img
+
+
+def check_diag_results(results, img_shape,
+ time_axis, slice_axis, ncomps,
+ out_path, froot, ext='.nii.gz'):
+
+ S = img_shape[slice_axis]
+ T = img_shape[time_axis]
+ pca_shape = list(img_shape)
+ pca_shape[time_axis] = ncomps
+ assert_equal(results['pca'].shape, tuple(pca_shape))
+ assert_equal(results['pca_res']['basis_projections'].shape,
+ tuple(pca_shape))
+ # Roll pca axis last to test shape of output image
+ ax_order = list(range(4))
+ ax_order.remove(time_axis)
+ ax_order.append(time_axis)
+ rolled_shape = tuple(pca_shape[i] for i in ax_order)
+ pca_img = load_image(pjoin(out_path, 'pca_' + froot + ext))
+ assert_equal(pca_img.shape, rolled_shape)
+ for prefix in ('mean', 'min', 'max', 'std'):
+ fname = pjoin(out_path, prefix + '_' + froot + ext)
+ img = load_image(fname)
+ assert_equal(img.shape, rolled_shape[:-1])
+ vars = np.load(pjoin(out_path, 'vectors_components_' + froot + '.npz'))
+ assert_equal(set(vars),
+ set(['basis_vectors', 'pcnt_var', 'volume_means',
+ 'slice_mean_diff2']))
+ assert_equal(vars['volume_means'].shape, (T,))
+ assert_equal(vars['basis_vectors'].shape, (T, T-1))
+ assert_equal(vars['slice_mean_diff2'].shape, (T-1, S))
+
+
+@needs_mpl
+def test_diagnose():
+ args = Args()
+ img = load_image(funcfile)
+ with InTemporaryDirectory() as tmpdir:
+ # Copy the functional file to a temporary writeable directory
+ os.mkdir('mydata')
+ tmp_funcfile = pjoin(tmpdir, 'mydata', 'myfunc.nii.gz')
+ shutil.copy(funcfile, tmp_funcfile)
+ args.filename = tmp_funcfile
+ args.time_axis = None
+ args.slice_axis = None
+ args.out_path = None
+ args.out_fname_label = None
+ args.ncomponents = 10
+ res = diagnose(args)
+ check_diag_results(res, img.shape, 3, 2, 10, 'mydata', 'myfunc')
+ args.slice_axis = 'j'
+ res = diagnose(args)
+ check_diag_results(res, img.shape, 3, 1, 10, 'mydata', 'myfunc')
+ # Time axis is not going to work because we'd have to use up one of the
+ # needed spatial axes
+ args.time_axis = 'i'
+ assert_raises(NiftiError, diagnose, args)
+ args.time_axis = 't'
+ # Check that output works
+ os.mkdir('myresults')
+ args.out_path = 'myresults'
+ args.out_fname_label = 'myana'
+ res = diagnose(args)
+ check_diag_results(res, img.shape, 3, 1, 10, 'myresults', 'myana')
View
72 nipy/algorithms/diagnostics/tests/test_screen.py
@@ -3,21 +3,33 @@
""" Testing diagnostic screen
"""
+import os
+from os.path import join as pjoin
+
+from warnings import catch_warnings, simplefilter
+
import numpy as np
import nipy as ni
from nipy.core.api import rollimg
-from ..screens import screen
+from ..screens import screen, write_screen_res
from ..timediff import time_slice_diffs
from ...utils.pca import pca
from ...utils.tests.test_pca import res2pos1
+from nibabel.tmpdirs import InTemporaryDirectory
+
from nose.tools import (assert_true, assert_false, assert_equal, assert_raises)
from numpy.testing import (assert_array_equal, assert_array_almost_equal,
- assert_almost_equal)
+ assert_almost_equal, decorators)
-from nipy.testing import funcfile, anatfile
+from nibabel.optpkg import optional_package
+
+matplotlib, HAVE_MPL, _ = optional_package('matplotlib')
+needs_mpl = decorators.skipif(not HAVE_MPL, "Test needs matplotlib")
+
+from nipy.testing import funcfile
def _check_pca(res, pca_res):
@@ -35,6 +47,10 @@ def _check_ts(res, data, time_axis, slice_axis):
def test_screen():
img = ni.load_image(funcfile)
+ # rename third axis to slice to match default of screen
+ # This avoids warnings about future change in default; see the tests for
+ # slice axis below
+ img = img.renamed_axes(k='slice')
res = screen(img)
assert_equal(res['mean'].ndim, 3)
assert_equal(res['pca'].ndim, 4)
@@ -88,7 +104,55 @@ def test_screen():
_check_ts(res, data, 3, 2)
assert_raises(AssertionError, _check_ts, res, data, 3, 0)
# Then specify, get non-default
- slicey_img = img.renamed_axes(i='slice')
+ slicey_img = img.renamed_axes(slice='k', i='slice')
res = screen(slicey_img)
_check_ts(res, data, 3, 0)
assert_raises(AssertionError, _check_ts, res, data, 3, 2)
+
+
+def test_screen_slice_axis():
+ img = ni.load_image(funcfile)
+ # Default screen raises a FutureWarning because of the default slice_axis
+ exp_res = screen(img, slice_axis='k')
+ with catch_warnings():
+ simplefilter('error')
+ assert_raises(FutureWarning, screen, img)
+ assert_raises(FutureWarning, screen, img, slice_axis=None)
+ explicit_img = img.renamed_axes(k='slice')
+ # Now the analysis works without warning
+ res = screen(explicit_img)
+ # And is the expected analysis
+ assert_array_equal(res['pca'].get_data(), exp_res['pca'].get_data())
+ assert_array_equal(res['ts_res']['slice_mean_diff2'],
+ exp_res['ts_res']['slice_mean_diff2'])
+ # Turn off warnings, also get expected analysis
+ simplefilter('ignore')
+ res = screen(img)
+ assert_array_equal(res['ts_res']['slice_mean_diff2'],
+ exp_res['ts_res']['slice_mean_diff2'])
+
+
+@needs_mpl
+def test_write_screen_res():
+ img = ni.load_image(funcfile)
+ with InTemporaryDirectory():
+ res = screen(img)
+ os.mkdir('myresults')
+ write_screen_res(res, 'myresults', 'myana')
+ pca_img = ni.load_image(pjoin('myresults', 'pca_myana.nii'))
+ assert_equal(pca_img.shape, img.shape[:-1] + (10,))
+ # Make sure we get the same output image even from rolled image
+ # Do fancy roll to put time axis first, and slice axis last. This does
+ # a stress test on the axis ordering, but also makes sure that we are
+ # getting the number of components from the right place. If we were
+ # getting the number of components from the length of the last axis,
+ # instead of the length of the 't' axis in the returned pca image, this
+ # would be wrong (=21) which would also be more than the number of
+ # basis vectors (19) so raise an error
+ rimg = img.reordered_axes([3, 2, 0, 1])
+ os.mkdir('rmyresults')
+ rres = screen(rimg)
+ write_screen_res(rres, 'rmyresults', 'myana')
+ rpca_img = ni.load_image(pjoin('rmyresults', 'pca_myana.nii'))
+ assert_equal(rpca_img.shape, img.shape[:-1] + (10,))
+ del pca_img, rpca_img
View
69 nipy/algorithms/diagnostics/tests/test_time_difference.py
@@ -10,7 +10,9 @@
import scipy.io as sio
-from nipy.core.api import rollimg
+from ....core.api import rollimg
+from ....core.reference.coordinate_map import AxisError
+
from .. import timediff as tsd
from nose.tools import (assert_true, assert_false, assert_equal,
@@ -70,6 +72,7 @@ def test_time_slice_diffs():
def test_time_slice_axes():
# Test time and slice axes work as expected
fimg = load_image(funcfile)
+ # Put into array
data = fimg.get_data()
orig_results = tsd.time_slice_diffs(data)
t0_data = np.rollaxis(data, 3)
@@ -84,6 +87,11 @@ def test_time_slice_axes():
bad_s0_results = tsd.time_slice_diffs(s0_data)
assert_not_equal(orig_results['slice_mean_diff2'].shape,
bad_s0_results['slice_mean_diff2'].shape)
+ # Slice axis equal to time axis - ValueError
+ assert_raises(ValueError, tsd.time_slice_diffs, data, -1, -1)
+ assert_raises(ValueError, tsd.time_slice_diffs, data, -1, 3)
+ assert_raises(ValueError, tsd.time_slice_diffs, data, 1, 1)
+ assert_raises(ValueError, tsd.time_slice_diffs, data, 1, -3)
def test_against_matlab_results():
@@ -106,3 +114,62 @@ def test_against_matlab_results():
assert_array_almost_equal(results['slice_diff2_max_vol'],
tsd_results['slice_diff2_max_vol'],
decimal=1)
+
+
+def assert_arr_img_res(arr_res, img_res):
+ for key in ('volume_mean_diff2',
+ 'slice_mean_diff2',
+ 'volume_means'):
+ assert_array_equal(arr_res[key], img_res[key])
+ for key in ('slice_diff2_max_vol', 'diff2_mean_vol'):
+ assert_array_almost_equal(arr_res[key], img_res[key].get_data())
+
+
+def test_tsd_image():
+ # Test image version of time slice diff
+ fimg = load_image(funcfile)
+ data = fimg.get_data()
+ tsda = tsd.time_slice_diffs
+ tsdi = tsd.time_slice_diffs_image
+ arr_results = tsda(data)
+ # image routine insists on named slice axis, no default
+ assert_raises(AxisError, tsdi, fimg)
+ # Works when specifying slice axis as keyword argument
+ img_results = tsdi(fimg, slice_axis='k')
+ assert_arr_img_res(arr_results, img_results)
+ ax_names = fimg.coordmap.function_domain.coord_names
+ # Test against array version
+ for time_ax in range(4):
+ time_name = ax_names[time_ax]
+ for slice_ax in range(4):
+ slice_name = ax_names[slice_ax]
+ if time_ax == slice_ax:
+ assert_raises(ValueError, tsda, data, time_ax, slice_ax)
+ assert_raises(ValueError, tsdi, fimg, time_ax, slice_ax)
+ assert_raises(ValueError, tsdi, fimg, time_name, slice_ax)
+ assert_raises(ValueError, tsdi, fimg, time_ax, slice_name)
+ assert_raises(ValueError, tsdi, fimg, time_name, slice_name)
+ continue
+ arr_res = tsda(data, time_ax, slice_ax)
+ assert_arr_img_res(arr_res, tsdi(fimg, time_ax, slice_ax))
+ assert_arr_img_res(arr_res, tsdi(fimg, time_name, slice_ax))
+ assert_arr_img_res(arr_res, tsdi(fimg, time_ax, slice_name))
+ img_results = tsdi(fimg, time_name, slice_name)
+ assert_arr_img_res(arr_res, img_results)
+ exp_ax_names = tuple(n for n in ax_names if n != time_name)
+ for key in ('slice_diff2_max_vol', 'diff2_mean_vol'):
+ img = img_results[key]
+ assert_equal(img.coordmap.function_domain.coord_names,
+ exp_ax_names)
+ # Test defaults on rolled image
+ fimg_rolled = rollimg(fimg, 't')
+ # Still don't have a slice axis specified
+ assert_raises(AxisError, tsdi, fimg_rolled)
+ # Test default time axis
+ assert_arr_img_res(arr_results, tsdi(fimg_rolled, slice_axis='k'))
+ # Test axis named slice overrides default guess
+ time_ax = -1
+ for sa_no, sa_name in ((0, 'i'), (1, 'j'), (2, 'k')):
+ fimg_renamed = fimg.renamed_axes(**{sa_name: 'slice'})
+ arr_res = tsda(data, time_ax, sa_no)
+ assert_arr_img_res(arr_res, tsdi(fimg_renamed, time_ax))
View
89 nipy/algorithms/diagnostics/timediff.py
@@ -11,6 +11,10 @@
import numpy as np
+from ...io.api import as_image
+
+from ...core.reference.coordinate_map import (io_axis_indices, drop_io_dim, AxisError)
+
def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
''' Time-point to time-point differences over volumes and slices
@@ -41,9 +45,12 @@ def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
-------
results : dict
- Here ``T`` is the number of time points
- (``arr.shape[time_axis]``) and ``S`` is the number of slices
- (``arr.shape[slice_axis]``), ``v`` is the shape of a volume, and
+ ``T`` is the number of time points (``arr.shape[time_axis]``)
+
+ ``S`` is the number of slices (``arr.shape[slice_axis]``)
+
+ ``v`` is the shape of a volume (``rollimg(arr, time_axis)[0].shape``)
+
``d2[t]`` is the volume of squared differences between voxels at
time point ``t`` and time point ``t+1``
@@ -65,6 +72,10 @@ def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
from a different difference time point.
* 'diff2_mean_vol`` : v[:] array
volume with the mean of ``d2[t]`` across t for t in 0:T-1.
+
+ Raises
+ ------
+ ValueError : if `time_axis` refers to same axis as `slice_axis`
'''
arr = np.asarray(arr)
ndim = arr.ndim
@@ -75,6 +86,8 @@ def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
slice_axis = ndim-2 if time_axis == ndim-1 else ndim-1
elif slice_axis < 0:
slice_axis += ndim
+ if time_axis == slice_axis:
+ raise ValueError('Time axis refers to same axis as slice axis')
arr = np.rollaxis(arr, time_axis)
# we may have changed the position of slice_axis
if time_axis > slice_axis:
@@ -116,3 +129,73 @@ def time_slice_diffs(arr, time_axis=-1, slice_axis=None):
'volume_means': means,
'diff2_mean_vol': diff_mean_vol,
'slice_diff2_max_vol': slice_diff_max_vol}
+
+
+def time_slice_diffs_image(img, time_axis='t', slice_axis='slice'):
+ """ Time-point to time-point differences over volumes and slices of image
+
+ Parameters
+ ----------
+ img : Image
+ The image on which to perform time-point differences
+ time_axis : str or int, optional
+ Axis indexing time-points. Default is 't'. If `time_axis` is an integer,
+ gives the index of the input (domain) axis of `img`. If `time_axis` is a str,
+ can be an input (domain) name, or an output (range) name, that maps to
+ an input (domain) name.
+ slice_axis : str or int, optional
+ Axis indexing MRI slices. If `slice_axis` is an integer, gives the
+ index of the input (domain) axis of `img`. If `slice_axis` is a str,
+ can be an input (domain) name, or an output (range) name, that maps to
+ an input (domain) name.
+
+ Returns
+ -------
+ results : dict
+
+ `arr` refers to the array as loaded from `img`
+
+ ``T`` is the number of time points (``img.shape[time_axis]``)
+
+ ``S`` is the number of slices (``img.shape[slice_axis]``)
+
+ ``v`` is the shape of a volume (``rollimg(img, time_axis)[0].shape``)
+
+ ``d2[t]`` is the volume of squared differences between voxels at
+ time point ``t`` and time point ``t+1``
+
+ `results` has keys:
+
+ * 'volume_mean_diff2' : (T-1,) array
+ array containing the mean (over voxels in volume) of the
+ squared difference from one time point to the next
+ * 'slice_mean_diff2' : (T-1, S) array
+ giving the mean (over voxels in slice) of the difference from
+ one time point to the next, one value per slice, per
+ timepoint
+ * 'volume_means' : (T,) array
+ mean over voxels for each volume ``vol[t] for t in 0:T``
+ * 'slice_diff2_max_vol' : v[:] image
+ image volume, of same shape as input time point volumes, where each
+ slice is is the slice from ``d2[t]`` for t in 0:T-1, that has the
+ largest variance across ``t``. Thus each slice in the volume may
+ well result from a different difference time point.
+ * 'diff2_mean_vol`` : v[:] image
+ image volume with the mean of ``d2[t]`` across t for t in 0:T-1.
+ """
+ img = as_image(img)
+ img_class = img.__class__
+ time_in_ax, time_out_ax = io_axis_indices(img.coordmap, time_axis)
+ if None in (time_in_ax, time_out_ax):
+ raise AxisError('Cannot identify matching input output axes with "%s"'
+ % time_axis)
+ slice_in_ax, slice_out_ax = io_axis_indices(img.coordmap, slice_axis)
+ if None in (slice_in_ax, slice_out_ax):
+ raise AxisError('Cannot identify matching input output axes with "%s"'
+ % slice_axis)
+ vol_coordmap = drop_io_dim(img.coordmap, time_axis)
+ results = time_slice_diffs(img.get_data(), time_in_ax, slice_in_ax)
+ for key in ('slice_diff2_max_vol', 'diff2_mean_vol'):
+ vol = img_class(results[key], vol_coordmap)
+ results[key] = vol
+ return results
View
10 nipy/algorithms/diagnostics/tsdiffplot.py
@@ -77,9 +77,17 @@ def xmax_labels(ax, val, xlabel, ylabel):
return axes
+@np.deprecate_with_doc('Please see docstring for alternative code')
def plot_tsdiffs_image(img, axes=None, show=True):
''' Plot time series diagnostics for image
+ This function is deprecated; please use something like::
+
+ results = time_slice_diff_image(img, slice_axis=2)
+ plot_tsdiffs(results)
+
+ instead.
+
Parameters
----------
img : image-like or filename str
@@ -110,3 +118,5 @@ def plot_tsdiffs_image(img, axes=None, show=True):
import matplotlib.pyplot as plt
plt.show()
return axes
+
+
View
2  nipy/io/files.py
@@ -49,6 +49,8 @@ def load(filename):
>>> img.shape
(33, 41, 25)
"""
+ if filename.endswith('.mnc'):
+ raise ValueError("Sorry, we can't get the MINC axis names right yet")
img = nib.load(filename)
ni_img = nib.Nifti1Image(img._data, img.get_affine(), img.get_header())
return nifti2nipy(ni_img)
View
10 nipy/io/tests/test_image_io.py
@@ -1,9 +1,10 @@
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
-from __future__ import with_statement
+from os.path import dirname, join as pjoin
import numpy as np
+import nibabel as nib
from nibabel.spatialimages import ImageFileError, HeaderDataError
from nibabel import Nifti1Header
@@ -260,3 +261,10 @@ def test_as_image():
assert_equal(img.affine, img1.affine)
assert_array_equal(img.get_data(), img1.get_data())
assert_true(img is img2)
+
+
+def test_no_minc():
+ # We can't yet get good axis names for MINC files. Check we reject these
+ assert_raises(ValueError, load_image, 'nofile.mnc')
+ data_path = pjoin(dirname(nib.__file__), 'tests', 'data')
+ assert_raises(ValueError, load_image, pjoin(data_path, 'tiny.mnc'))
View
35 nipy/tests/test_scripts.py
@@ -21,7 +21,7 @@
from nipy import load_image, save_image
from nipy.core.api import rollimg
-from nose.tools import assert_true, assert_false, assert_equal
+from nose.tools import assert_true, assert_false, assert_equal, assert_raises
from ..testing import funcfile
from numpy.testing import decorators, assert_almost_equal
@@ -119,11 +119,36 @@ def test_nipy_diagnose():
def test_nipy_tsdiffana():
# Test nipy_tsdiffana script
out_png = 'ts_out.png'
+ # Quotes in case of space in arguments
+ cmd_template = 'nipy_tsdiffana "{0}" --out-file="{1}"'
with InTemporaryDirectory():
- # Quotes in case of space in arguments
- cmd = 'nipy_tsdiffana "%s" --out-file="%s"' % (funcfile, out_png)
- run_command(cmd)
- assert_true(isfile(out_png))
+ for i, cmd in enumerate((cmd_template,
+ cmd_template + ' --time-axis=0',
+ cmd_template + ' --slice-axis=0',
+ cmd_template + ' --slice-axis=0 ' +
+ '--time-axis=1')):
+ out_png = 'ts_out{0}.png'.format(i)
+ run_command(cmd.format(funcfile, out_png))
+ assert_true(isfile(out_png))
+ # Out-file and write-results incompatible
+ assert_raises(RuntimeError,
+ run_command,
+ cmd_template.format(funcfile, out_png) + '--write-results')
+ # Can save images
+ cmd_root = 'nipy_tsdiffana "{0}" '.format(funcfile)
+ with InTemporaryDirectory():
+ os.mkdir('myresults')
+ run_command(cmd_root + '--out-path=myresults --write-results')
+ assert_true(isfile(pjoin('myresults', 'tsdiff_functional.png')))
+ assert_true(isfile(pjoin('myresults', 'tsdiff_functional.npz')))
+ assert_true(isfile(pjoin('myresults', 'dv2_max_functional.nii.gz')))
+ assert_true(isfile(pjoin('myresults', 'dv2_mean_functional.nii.gz')))
+ run_command(cmd_root + '--out-path=myresults --write-results '
+ '--out-fname-label=vr2')
+ assert_true(isfile(pjoin('myresults', 'tsdiff_vr2.png')))
+ assert_true(isfile(pjoin('myresults', 'tsdiff_vr2.npz')))
+ assert_true(isfile(pjoin('myresults', 'dv2_max_vr2.nii.gz')))
+ assert_true(isfile(pjoin('myresults', 'dv2_mean_vr2.nii.gz')))
@script_test
View
33 scripts/nipy_diagnose
@@ -29,17 +29,12 @@ generate filenames of the form ``/some/path/components_fname.png,
/some/path/max_fname.img`` etc.
'''
-import os
-
import matplotlib
matplotlib.use('Agg')
-from nibabel.filename_parser import splitext_addext
-
-import nipy
from nipy.externals.argparse import (ArgumentParser,
RawDescriptionHelpFormatter)
-import nipy.algorithms.diagnostics.screens as nads
+import nipy.algorithms.diagnostics.commands as nadc
def main():
@@ -60,31 +55,7 @@ def main():
help='Image axis for slice')
# parse the command line
args = parser.parse_args()
- # process inputs
- filename = args.filename
- out_path = args.out_path
- out_root = args.out_fname_label
- ncomps = args.ncomponents
- # collect extension for output images
- froot, ext, gz = splitext_addext(filename)
- pth, fname = os.path.split(froot)
- if out_path is None:
- out_path = pth
- if out_root is None:
- out_root = fname
- img = nipy.load_image(filename)
- # Unpack axis arguments
- try:
- args.time_axis = int(args.time_axis)
- except ValueError:
- pass
- if not args.slice_axis is None:
- try:
- args.slice_axis = int(args.slice_axis)
- except ValueError:
- pass
- res = nads.screen(img, ncomps, args.time_axis, args.slice_axis)
- nads.write_screen_res(res, out_path, out_root, ext + gz)
+ nadc.diagnose(args)
if __name__ == '__main__':
View
95 scripts/nipy_tsdiffana
@@ -1,31 +1,102 @@
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
-''' Analyze, plot time series difference metrics'''
+DESCRIP = ' Analyze, plot time series difference metrics'
+EPILOG = \
+'''nipy_tsdiffana runs the time series diference algorithm over a 4D
+image volume, often and FMRI volume.
-import nipy.externals.argparse as argparse
+It works in one of three modes:
+
+* interactive : the time series difference plot appears on screen. This is the
+ default mode
+* non-interactive, plot only : write time series difference plot to graphic
+ file. Use the "--out-file=<myfilename>" option to activate this mode
+* non-interactive, write plot, images and variables : write plot to file, and
+ write generated diagnostic images and variables to files as well. Use the
+ "--write-results" flag to activate this option. The generated filenames come
+ from the results of the "--out-path" and "--out-fname-label" options (see
+ help).
+
+Write-results option, generated files
+-------------------------------------
+
+When doing the time point analysis, we will make a difference volume between
+each time point and the next time point in the series. If we have T volumes
+then there will be (T-1) difference volumes. Call the vector of difference
+volumes DV and the first difference volume DV[0]. So DV[0] results from
+subtraction of the second volume in the 4D input image from the first volume in
+the 4D input image. The element-wise squared values from DV[0] is *DV2[0]*.
+
+The following images will be generated. <ext> is the input filename extension
+(e.g. '.nii'):
+
+* "dv2_max_<label><ext>" : 3D image volume, where each slice S is slice from
+ all of DV2[0] (slice S) throudh DV2[T-1] (slice S) that has the maximum
+ summed squared values. This volume gives an idea of the worst (highest
+ difference) slices across the whole time series.
+* "dv2_mean_<label><ext>" : the mean of all DV2 volumes DV2[0] .. DV[T-1]
+ across the volume (time) dimension. Higher voxel values in this volume mean
+ that time-point to time point differences tended to be high in this voxel.
+
+We also write the mean signal at each time point, and the mean squared
+difference between each slice in time, as variables to a 'npz' file named
+"tsdiff_<label>.npz"
+
+The filenames for the outputs are of the form
+<out-path>/<some_prefix><label><file-ext> where <out-path> is the path
+specified by the --out-path option, or the path of the input filename;
+<some_prefix> is one of the standard prefixes above, <label> is given by
+--out-label, or by the filename of the input image (with path and extension
+removed), and <file-ext> is '.png' for graphics, or the extension of the input
+filename for volume images. For example, specifying only the input filename
+``/some/path/fname.img`` will generate filenames of the form
+``/some/path/tsdiff_fname.png, /some/path/dv2_max_fname.img`` etc.
+'''
+
+from nipy.externals.argparse import (ArgumentParser,
+ RawDescriptionHelpFormatter)
def main():
- # create the parser
- parser = argparse.ArgumentParser()
+ parser = ArgumentParser(description=DESCRIP,
+ epilog=EPILOG,
+ formatter_class=RawDescriptionHelpFormatter)
# add the arguments
+ parser.add_argument('filename', type=str,
+ help='4D image filename')
parser.add_argument('--out-file', type=str,
help='graphics file to write to instead '
'of leaving image on screen')
- parser.add_argument('filename', type=str,
- help='4D image filename')
+ parser.add_argument('--write-results', action='store_true',
+ help='if specified, write diagnostic images and '
+ 'analysis variables, plot to OUT_PATH. Mutually '
+ 'incompatible with OUT_FILE')
+ parser.add_argument('--out-path', type=str,
+ help='path for output image files (default from '
+ 'FILENAME path')
+ parser.add_argument('--out-fname-label', type=str,
+ help='mid part of output image / plot filenames')
+ parser.add_argument('--time-axis', type=str, default='t',
+ help='Image axis for time')
+ parser.add_argument('--slice-axis', type=str, default=None,
+ help='Image axis for slice')
# parse the command line
args = parser.parse_args()
- show = args.out_file is None
+ if not args.out_file is None and args.write_results == True:
+ raise RuntimeError("OUT_FILE option not compatible with WRITE_RESULTS"
+ " option")
+ show = args.out_file is None and args.write_results == False
if not show:
import matplotlib
matplotlib.use('Agg')
- # Import late to allow setting Agg backend
- import nipy.algorithms.diagnostics as nad
- axes = nad.plot_tsdiffs_image(args.filename, show=show)
- if args.out_file:
- axes[0].figure.savefig(args.out_file)
+ else:
+ import matplotlib.pylab as plt
+ # Import late to give set of mpl backend best chance of working
+ from nipy.algorithms.diagnostics.commands import tsdiffana
+ tsdiffana(args)
+ if show:
+ plt.show()
if __name__ == '__main__':
Something went wrong with that request. Please try again.