Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX] mat 7.3 support for SPM.mat files #3650

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions nipype/interfaces/spm/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

# Local imports
from ... import logging
from ...utils.filemanip import ensure_list, simplify_list, split_filename
from ...utils.filemanip import ensure_list, simplify_list, split_filename, load_spm_mat
from ..base import (
Bunch,
traits,
Expand Down Expand Up @@ -313,12 +313,10 @@
return einputs

def _list_outputs(self):
import scipy.io as sio

outputs = self._outputs().get()
pth = os.path.dirname(self.inputs.spm_mat_file)
outtype = "nii" if "12" in self.version.split(".")[0] else "img"
spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False)
spm = load_spm_mat(self.inputs.spm_mat_file, struct_as_record=False)

Check warning on line 319 in nipype/interfaces/spm/model.py

View check run for this annotation

Codecov / codecov/patch

nipype/interfaces/spm/model.py#L319

Added line #L319 was not covered by tests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be cleaner to break out the functionality you have into its own function and put the try/catch logic here.

Suggested change
spm = load_spm_mat(self.inputs.spm_mat_file, struct_as_record=False)
try:
spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False)
except NotImplementedError: # Matlab 7.3+
spm = load_spm_mat(self.inputs.spm_mat_file)


betas = [vbeta.fname[0] for vbeta in spm["SPM"][0, 0].Vbeta[0]]
if (
Expand Down Expand Up @@ -503,6 +501,10 @@
load(jobs{1}.stats{1}.con.spmmat{:});
SPM.swd = '%s';
save(jobs{1}.stats{1}.con.spmmat{:},'SPM');
[msg,id] = lastwarn('');
if strcmp(id,'MATLAB:save:sizeTooBigForMATFile')
save(jobs{1}.stats{1}.con.spmmat{:},'SPM','-v7.3');
end
names = SPM.xX.name;"""
% (self.inputs.spm_mat_file, os.getcwd())
]
Expand Down Expand Up @@ -581,11 +583,9 @@
return "\n".join(script)

def _list_outputs(self):
import scipy.io as sio

outputs = self._outputs().get()
pth, _ = os.path.split(self.inputs.spm_mat_file)
spm = sio.loadmat(self.inputs.spm_mat_file, struct_as_record=False)
spm = load_spm_mat(self.inputs.spm_mat_file, struct_as_record=False)

Check warning on line 588 in nipype/interfaces/spm/model.py

View check run for this annotation

Codecov / codecov/patch

nipype/interfaces/spm/model.py#L588

Added line #L588 was not covered by tests
con_images = []
spmT_images = []
for con in spm["SPM"][0, 0].xCon[0]:
Expand Down
2 changes: 1 addition & 1 deletion nipype/interfaces/tests/test_matlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_run_interface(tmpdir):
# bypasses ubuntu dash issue
mc = mlab.MatlabCommand(script="foo;", paths=[tmpdir.strpath], mfile=True)
assert not os.path.exists(default_script_file), "scriptfile should not exist 4."
with pytest.raises(OSError):
with pytest.raises(RuntimeError):
mc.run()
assert os.path.exists(default_script_file), "scriptfile should exist 4."
if os.path.exists(default_script_file): # cleanup
Expand Down
49 changes: 49 additions & 0 deletions nipype/utils/filemanip.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pathlib import Path
import simplejson as json
from time import sleep, time
import scipy.io as sio

from .. import logging, config, __version__ as version
from .misc import is_container
Expand Down Expand Up @@ -932,3 +933,51 @@
yield
finally:
os.chdir(cwd)

def load_spm_mat(spm_mat_file, **kwargs):
try:
mat = sio.loadmat(spm_mat_file, **kwargs)
except NotImplementedError:
import h5py
import numpy as np
mat = dict(SPM=np.array([[sio.matlab.mat_struct()]]))

Check warning on line 943 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L938-L943

Added lines #L938 - L943 were not covered by tests

# Get Vbeta, Vcon, and Vspm file names
with h5py.File(spm_mat_file, "r") as h5file:
fnames = dict()
try:

Check warning on line 948 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L947-L948

Added lines #L947 - L948 were not covered by tests
fnames["Vbeta"] = [u"".join(chr(c[0]) for c in h5file[obj_ref[0]]) for obj_ref in h5file["SPM"]["Vbeta"]["fname"]]
except Exception:
fnames["Vbeta"] = []

Check warning on line 951 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L950-L951

Added lines #L950 - L951 were not covered by tests
for contr_type in ["Vcon", "Vspm"]:
try:

Check warning on line 953 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L953

Added line #L953 was not covered by tests
fnames[contr_type] = [u"".join(chr(c[0]) for c in h5file[obj_ref[0]]["fname"]) for obj_ref in h5file["SPM"]["xCon"][contr_type]]
except Exception:
fnames[contr_type] = []

Check warning on line 956 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L955-L956

Added lines #L955 - L956 were not covered by tests

# Structure Vbeta as returned by scipy.io.loadmat
obj_list = []

Check warning on line 959 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L959

Added line #L959 was not covered by tests
for i in range(len(fnames["Vbeta"])):
obj = sio.matlab.mat_struct()
setattr(obj, "fname", np.array([fnames["Vbeta"][i]]))
obj_list.append(obj)

Check warning on line 963 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L961-L963

Added lines #L961 - L963 were not covered by tests
if len(obj_list) > 0:
setattr(mat["SPM"][0, 0], "Vbeta", np.array([obj_list]))

Check warning on line 965 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L965

Added line #L965 was not covered by tests
else:
setattr(mat["SPM"][0, 0], "Vbeta", np.empty((0, 0), dtype=object))

Check warning on line 967 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L967

Added line #L967 was not covered by tests

# Structure Vcon and Vspm as returned by scipy.io.loadmat
obj_list = []

Check warning on line 970 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L970

Added line #L970 was not covered by tests
for i in range(len(fnames["Vcon"])):
obj = sio.matlab.mat_struct()

Check warning on line 972 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L972

Added line #L972 was not covered by tests
for contr_type in ["Vcon", "Vspm"]:
temp = sio.matlab.mat_struct()
setattr(temp, "fname", np.array([fnames[contr_type][i]]))
setattr(obj, contr_type, np.array([[temp]]))
obj_list.append(obj)

Check warning on line 977 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L974-L977

Added lines #L974 - L977 were not covered by tests
if len(obj_list) > 0:
setattr(mat["SPM"][0, 0], "xCon", np.array([obj_list]))

Check warning on line 979 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L979

Added line #L979 was not covered by tests
else:
setattr(mat["SPM"][0, 0], "xCon", np.empty((0, 0), dtype=object))

Check warning on line 981 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L981

Added line #L981 was not covered by tests

return mat

Check warning on line 983 in nipype/utils/filemanip.py

View check run for this annotation

Codecov / codecov/patch

nipype/utils/filemanip.py#L983

Added line #L983 was not covered by tests
Loading