Skip to content

Commit 00c490c

Browse files
authored
Merge pull request #3650 from adamnarai/master
[FIX] mat 7.3 support for SPM.mat files
2 parents 8bffa93 + bd0d585 commit 00c490c

File tree

3 files changed

+65
-8
lines changed

3 files changed

+65
-8
lines changed

nipype/interfaces/spm/model.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
# Local imports
1414
from ... import logging
15-
from ...utils.filemanip import ensure_list, simplify_list, split_filename
15+
from ...utils.filemanip import ensure_list, simplify_list, split_filename, load_spm_mat
1616
from ..base import (
1717
Bunch,
1818
traits,
@@ -313,12 +313,10 @@ def _parse_inputs(self):
313313
return einputs
314314

315315
def _list_outputs(self):
316-
import scipy.io as sio
317-
318316
outputs = self._outputs().get()
319317
pth = os.path.dirname(self.inputs.spm_mat_file)
320318
outtype = "nii" if "12" in self.version.split(".")[0] else "img"
321-
spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False)
319+
spm = load_spm_mat(self.inputs.spm_mat_file, struct_as_record=False)
322320

323321
betas = [vbeta.fname[0] for vbeta in spm["SPM"][0, 0].Vbeta[0]]
324322
if (
@@ -503,6 +501,10 @@ def _make_matlab_command(self, _):
503501
load(jobs{1}.stats{1}.con.spmmat{:});
504502
SPM.swd = '%s';
505503
save(jobs{1}.stats{1}.con.spmmat{:},'SPM');
504+
[msg,id] = lastwarn('');
505+
if strcmp(id,'MATLAB:save:sizeTooBigForMATFile')
506+
save(jobs{1}.stats{1}.con.spmmat{:},'SPM','-v7.3');
507+
end
506508
names = SPM.xX.name;"""
507509
% (self.inputs.spm_mat_file, os.getcwd())
508510
]
@@ -581,11 +583,9 @@ def _make_matlab_command(self, _):
581583
return "\n".join(script)
582584

583585
def _list_outputs(self):
584-
import scipy.io as sio
585-
586586
outputs = self._outputs().get()
587587
pth, _ = os.path.split(self.inputs.spm_mat_file)
588-
spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False)
588+
spm = load_spm_mat(self.inputs.spm_mat_file, struct_as_record=False)
589589
con_images = []
590590
spmT_images = []
591591
for con in spm["SPM"][0, 0].xCon[0]:

nipype/interfaces/tests/test_matlab.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def test_run_interface(tmpdir):
102102
# bypasses ubuntu dash issue
103103
mc = mlab.MatlabCommand(script="foo;", paths=[tmpdir.strpath], mfile=True)
104104
assert not os.path.exists(default_script_file), "scriptfile should not exist 4."
105-
with pytest.raises(OSError):
105+
with pytest.raises(RuntimeError):
106106
mc.run()
107107
assert os.path.exists(default_script_file), "scriptfile should exist 4."
108108
if os.path.exists(default_script_file): # cleanup

nipype/utils/filemanip.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from pathlib import Path
2020
import simplejson as json
2121
from time import sleep, time
22+
import scipy.io as sio
2223

2324
from .. import logging, config, __version__ as version
2425
from .misc import is_container
@@ -927,3 +928,59 @@ def indirectory(path):
927928
yield
928929
finally:
929930
os.chdir(cwd)
931+
932+
933+
def load_spm_mat(spm_mat_file, **kwargs):
934+
try:
935+
mat = sio.loadmat(spm_mat_file, **kwargs)
936+
except NotImplementedError:
937+
import h5py
938+
import numpy as np
939+
940+
mat = dict(SPM=np.array([[sio.matlab.mat_struct()]]))
941+
942+
# Get Vbeta, Vcon, and Vspm file names
943+
with h5py.File(spm_mat_file, "r") as h5file:
944+
fnames = dict()
945+
try:
946+
fnames["Vbeta"] = [
947+
u"".join(chr(c[0]) for c in h5file[obj_ref[0]])
948+
for obj_ref in h5file["SPM"]["Vbeta"]["fname"]
949+
]
950+
except Exception:
951+
fnames["Vbeta"] = []
952+
for contr_type in ["Vcon", "Vspm"]:
953+
try:
954+
fnames[contr_type] = [
955+
u"".join(chr(c[0]) for c in h5file[obj_ref[0]]["fname"])
956+
for obj_ref in h5file["SPM"]["xCon"][contr_type]
957+
]
958+
except Exception:
959+
fnames[contr_type] = []
960+
961+
# Structure Vbeta as returned by scipy.io.loadmat
962+
obj_list = []
963+
for i in range(len(fnames["Vbeta"])):
964+
obj = sio.matlab.mat_struct()
965+
setattr(obj, "fname", np.array([fnames["Vbeta"][i]]))
966+
obj_list.append(obj)
967+
if len(obj_list) > 0:
968+
setattr(mat["SPM"][0, 0], "Vbeta", np.array([obj_list]))
969+
else:
970+
setattr(mat["SPM"][0, 0], "Vbeta", np.empty((0, 0), dtype=object))
971+
972+
# Structure Vcon and Vspm as returned by scipy.io.loadmat
973+
obj_list = []
974+
for i in range(len(fnames["Vcon"])):
975+
obj = sio.matlab.mat_struct()
976+
for contr_type in ["Vcon", "Vspm"]:
977+
temp = sio.matlab.mat_struct()
978+
setattr(temp, "fname", np.array([fnames[contr_type][i]]))
979+
setattr(obj, contr_type, np.array([[temp]]))
980+
obj_list.append(obj)
981+
if len(obj_list) > 0:
982+
setattr(mat["SPM"][0, 0], "xCon", np.array([obj_list]))
983+
else:
984+
setattr(mat["SPM"][0, 0], "xCon", np.empty((0, 0), dtype=object))
985+
986+
return mat

0 commit comments

Comments
 (0)