Skip to content

Commit 77b4c7e

Browse files
authored
Merge pull request #21 from spm/enh-type-system
[Enhancement] Matlab-like type system
2 parents a9bf909 + 6e5ff8b commit 77b4c7e

3,927 files changed

Lines changed: 9430 additions & 4730 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.mpython/templates/class_header.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from <pkgname>.__wrapper__ import Runtime, MatlabClass
2+
3+
4+
class <classname>(MatlabClass):
5+
def __init__(self, *args, **kwargs):
6+
<docstring>
7+
super().__init__()

.mpython/templates/docstring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
44
[Matlab code]( https://github.com/spm/spm/blob/main/<rfilepath> )
55
6-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
6+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
77
"""

examples/DCM_ERP.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""
2+
analyse some ERP data (mismatch negativity ERP SPM file from SPM-webpages)
3+
This is an example batch script to analyse two evoked responses with an
4+
assumed 5 sources.
5+
To try this out on your data (the date of this example don't exist in your SPM8 distribution),
6+
you have to change 'Pbase' to your own analysis-directory, and choose a name ('DCM.xY.Dfile')
7+
of an existing SPM for M/EEG-file with at least two evoked responses.
8+
"""
9+
import os
10+
import spm
11+
12+
num = spm.Array.from_any
13+
14+
# Please replace filenames etc. by your own.
15+
# ----------------------------------------------------------------------
16+
spm.spm('defaults', 'EEG')
17+
18+
# Data and analysis directories
19+
# ----------------------------------------------------------------------
20+
21+
Pbase = os.path.dirname(__file__) # directory with your data,
22+
23+
Pdata = os.path.join(Pbase, '.') # data directory in Pbase
24+
Panalysis = os.path.join(Pbase, '.') # analysis directory in Pbase
25+
26+
os.chdir(Pbase)
27+
28+
# Data filename
29+
# ----------------------------------------------------------------------
30+
DCM = spm.Struct()
31+
DCM.xY.Dfile = 'maeMdfspm8_subject1'
32+
33+
# Parameters and options used for setting up model
34+
# ----------------------------------------------------------------------
35+
DCM.options.analysis = 'ERP' # analyze evoked responses
36+
DCM.options.model = 'ERP' # ERP model
37+
DCM.options.spatial = 'IMG' # spatial model
38+
DCM.options.trials = num([1, 2]) # index of ERPs within ERP/ERF file
39+
DCM.options.Tdcm[0] = 0 # start of peri-stimulus time to be modelled
40+
DCM.options.Tdcm[1] = 200 # end of peri-stimulus time to be modelled
41+
DCM.options.Nmodes = 8 # nr of modes for data selection
42+
DCM.options.h = 1 # nr of DCT components
43+
DCM.options.onset = 60 # selection of onset (prior mean)
44+
DCM.options.D = 1 # downsampling
45+
46+
# ----------------------------------------------------------------------
47+
# Data and spatial model
48+
# ----------------------------------------------------------------------
49+
DCM = spm.spm_dcm_erp_data(DCM)
50+
51+
# ----------------------------------------------------------------------
52+
# Location priors for dipoles
53+
# ----------------------------------------------------------------------
54+
DCM.Lpos = num([
55+
[-42, -22, 7],
56+
[46, -14, 8],
57+
[-61, -32, 8],
58+
[59, -25, 8],
59+
[46, 20, 8]
60+
]).T
61+
DCM.Sname = ['left AI', 'right A1', 'left STG', 'right STG', 'right IFG']
62+
Nareas = DCM.Lpos.shape[1]
63+
64+
# ----------------------------------------------------------------------
65+
# Spatial model
66+
# ----------------------------------------------------------------------
67+
DCM = spm.spm_dcm_erp_dipfit(DCM)
68+
69+
# ----------------------------------------------------------------------
70+
# Specify connectivity model
71+
# ----------------------------------------------------------------------
72+
os.chdir(Panalysis)
73+
74+
DCM.A = spm.Cell()
75+
DCM.B = spm.Cell()
76+
77+
DCM.A[0] = spm.Array(Nareas, Nareas)
78+
DCM.A[0][2, 0] = 1
79+
DCM.A[0][3, 1] = 1
80+
DCM.A[0][4, 3] = 1
81+
82+
DCM.A[1] = spm.Array(Nareas, Nareas)
83+
DCM.A[1][0, 2] = 1
84+
DCM.A[1][1, 3] = 1
85+
DCM.A[1][3, 4] = 1
86+
87+
DCM.A[2] = spm.Array(Nareas, Nareas)
88+
DCM.A[2][3, 2] = 1
89+
DCM.A[2][2, 3] = 1
90+
91+
DCM.B[0] = DCM.A[0] + DCM.A[1]
92+
DCM.B[0][0, 0] = 1
93+
DCM.B[0][1, 1] = 1
94+
95+
DCM.C = num([[1, 1, 0, 0, 0]]).T
96+
97+
# ----------------------------------------------------------------------
98+
# Between trial effects
99+
# ----------------------------------------------------------------------
100+
DCM.xU.X = num([[0, 1]]).T
101+
DCM.xU.name = ['rare']
102+
103+
# ----------------------------------------------------------------------
104+
# Invert
105+
# ----------------------------------------------------------------------
106+
DCM.name = 'DCMexample'
107+
108+
DCM = spm.spm_dcm_erp(DCM)

examples/auditory_batch.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
This batch script analyses the Auditory fMRI dataset available from the
3+
SPM website:
4+
http://www.fil.ion.ucl.ac.uk/spm/data/auditory/
5+
as described in the SPM manual:
6+
http://www.fil.ion.ucl.ac.uk/spm/doc/manual.pdf#Chap:data:auditory
7+
________________________________________________________________________
8+
Copyright (C) 2014 Wellcome Trust Centre for Neuroimaging
9+
10+
Matlab: Guillaume Flandin
11+
Python: Yael Balbastre
12+
"""
13+
14+
import zipfile
15+
import os.path as op
16+
import spm
17+
18+
num = spm.Array.from_any
19+
20+
# Directory containing the Auditory data
21+
# ----------------------------------------------------------------------
22+
23+
url = 'https://www.fil.ion.ucl.ac.uk/spm/download/data/MoAEpilot/MoAEpilot.zip'
24+
data_path = op.dirname(__file__)
25+
zip_path = op.join(data_path, 'MoAEpilot.zip')
26+
27+
print(f'{"Downloading Auditory dataset...":<40s}')
28+
spm.Runtime.call("urlwrite", url, zip_path)
29+
with zipfile.ZipFile(zip_path, 'r') as f:
30+
f.extractall(data_path)
31+
print(f" {'...done':30s}\n")
32+
33+
34+
# Initialise SPM
35+
# ----------------------------------------------------------------------
36+
spm.spm('Defaults', 'fMRI')
37+
spm.spm_jobman('initcfg', nargout=0)
38+
# spm.spm_get_defaults('cmdline', true)
39+
40+
# ======================================================================
41+
# PREAMBLE: DUMMY SCANS
42+
# ======================================================================
43+
44+
f = spm.spm_select('FPList', op.join(data_path, 'fM00223'), r'^f.*\.img$')
45+
46+
matlabbatch = spm.Cell()
47+
48+
matlabbatch(0).cfg_basicio.file_dir.dir_ops.cfg_mkdir.parent = [data_path]
49+
matlabbatch(0).cfg_basicio.file_dir.dir_ops.cfg_mkdir.name = 'dummy'
50+
51+
matlabbatch(0).cfg_basicio.file_dir.file_ops.file_move.files = f[:12]
52+
matlabbatch(0).cfg_basicio.file_dir.file_ops.file_move.action.moveto = [op.join(data_path, 'dummy')]
53+
54+
spm.spm_jobman('run', matlabbatch, nargout=0)
55+
56+
# ======================================================================
57+
# SPATIAL PREPROCESSING
58+
# ======================================================================
59+
60+
f = spm.spm_select('FPList', op.join(data_path,'fM00223'), r'^f.*\.img$')
61+
a = spm.spm_select('FPList', op.join(data_path,'sM00223'), r'^s.*\.img$')
62+
63+
matlabbatch = spm.Cell()
64+
65+
# Realign
66+
# ----------------------------------------------------------------------
67+
matlabbatch(0).spm.spatial.realign.estwrite.data = [f]
68+
matlabbatch(0).spm.spatial.realign.estwrite.roptions.which = num([0, 1])
69+
70+
# Coregister
71+
# ----------------------------------------------------------------------
72+
matlabbatch(1).spm.spatial.coreg.estimate.ref = [spm.spm_file(f[0, 0], 'prefix', 'mean')]
73+
matlabbatch(1).spm.spatial.coreg.estimate.source = [a]
74+
75+
# Segment
76+
# ----------------------------------------------------------------------
77+
matlabbatch(2).spm.spatial.preproc.channel.vols = [a]
78+
matlabbatch(2).spm.spatial.preproc.channel.write = num([0, 1])
79+
matlabbatch(2).spm.spatial.preproc.warp.write = num([0, 1])
80+
81+
# Normalise: Write
82+
# ----------------------------------------------------------------------
83+
matlabbatch(3).spm.spatial.normalise.write.subj["def"] = [spm.spm_file(a, 'prefix', 'y_', 'ext', 'nii')]
84+
matlabbatch(3).spm.spatial.normalise.write.subj.resample = f
85+
matlabbatch(3).spm.spatial.normalise.write.woptions.vox = num([3, 3, 3])
86+
87+
matlabbatch(4).spm.spatial.normalise.write.subj["def"] = [spm.spm_file(a, 'prefix', 'y_', 'ext', 'nii')]
88+
matlabbatch(4).spm.spatial.normalise.write.subj.resample = [spm.spm_file(a, 'prefix', 'm', 'ext', 'nii')]
89+
matlabbatch(4).spm.spatial.normalise.write.woptions.vox = num([1, 1, 3])
90+
91+
# Smooth
92+
# ----------------------------------------------------------------------
93+
matlabbatch(5).spm.spatial.smooth.data = spm.spm_file(f, 'prefix', 'w')[:, None]
94+
matlabbatch(5).spm.spatial.smooth.fwhm = num([6, 6, 6])
95+
96+
spm.spm_jobman('run', matlabbatch, nargout=0)
97+
98+
# ======================================================================
99+
# GLM SPECIFICATION, ESTIMATION, INFERENCE, RESULTS
100+
# ======================================================================
101+
102+
f = spm.spm_select('FPList', op.join(data_path,'fM00223'), r'^swf.*\.img$')
103+
104+
matlabbatch = spm.Cell()
105+
106+
# Output Directory
107+
# ----------------------------------------------------------------------
108+
matlabbatch(0).cfg_basicio.file_dir.dir_ops.cfg_mkdir.parent = [data_path]
109+
matlabbatch(0).cfg_basicio.file_dir.dir_ops.cfg_mkdir.name = 'GLM'
110+
111+
# Model Specification
112+
# ----------------------------------------------------------------------
113+
matlabbatch(1).spm.stats.fmri_spec.dir = [op.join(data_path, 'GLM')]
114+
matlabbatch(1).spm.stats.fmri_spec.timing.units = 'scans'
115+
matlabbatch(1).spm.stats.fmri_spec.timing.RT = 7
116+
matlabbatch(1).spm.stats.fmri_spec.sess.scans = f
117+
matlabbatch(1).spm.stats.fmri_spec.sess.cond.name = 'active'
118+
matlabbatch(1).spm.stats.fmri_spec.sess.cond.onset = num(range(6, 86, 12))
119+
matlabbatch(1).spm.stats.fmri_spec.sess.cond.duration = 6
120+
121+
# Model Estimation
122+
# ----------------------------------------------------------------------
123+
matlabbatch(2).spm.stats.fmri_est.spmmat = [op.join(data_path, 'GLM', 'SPM.mat')]
124+
125+
# Contrasts
126+
# ----------------------------------------------------------------------
127+
matlabbatch(3).spm.stats.con.spmmat = [op.join(data_path, 'GLM', 'SPM.mat')]
128+
matlabbatch(3).spm.stats.con.consess(0).tcon.name = 'Listening > Rest'
129+
matlabbatch(3).spm.stats.con.consess(0).tcon.weights = num([1, 0])
130+
matlabbatch(3).spm.stats.con.consess(1).tcon.name = 'Rest > Listening'
131+
matlabbatch(3).spm.stats.con.consess(1).tcon.weights = num([-1, 0])
132+
133+
# Inference Results
134+
# ----------------------------------------------------------------------
135+
matlabbatch(4).spm.stats.results.spmmat = [op.join(data_path, 'GLM', 'SPM.mat')]
136+
matlabbatch(4).spm.stats.results.conspec.contrasts = 1
137+
matlabbatch(4).spm.stats.results.conspec.threshdesc = 'FWE'
138+
matlabbatch(4).spm.stats.results.conspec.thresh = 0.05
139+
matlabbatch(4).spm.stats.results.conspec.extent = 0
140+
matlabbatch(4).spm.stats.results.print = False
141+
142+
# Rendering
143+
# ----------------------------------------------------------------------
144+
matlabbatch(5).spm.util.render.display.rendfile = [op.join(spm.spm('Dir'), 'canonical', 'cortex_20484.surf.gii')]
145+
matlabbatch(5).spm.util.render.display.conspec.spmmat = [op.join(data_path, 'GLM', 'SPM.mat')]
146+
matlabbatch(5).spm.util.render.display.conspec.contrasts = 1
147+
matlabbatch(5).spm.util.render.display.conspec.threshdesc = 'FWE'
148+
matlabbatch(5).spm.util.render.display.conspec.thresh = 0.05
149+
matlabbatch(5).spm.util.render.display.conspec.extent = 0
150+
151+
spm.spm_jobman('run', matlabbatch, nargout=0)

spm/__compat/loadxml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ def loadxml(*args, **kwargs):
2929
3030
[Matlab code]( https://github.com/spm/spm/blob/main/compat/loadxml.m )
3131
32-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
32+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
3333
"""
3434
return Runtime.call("loadxml", *args, **kwargs)

spm/__compat/savexml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ def savexml(*args, **kwargs):
2525
2626
[Matlab code]( https://github.com/spm/spm/blob/main/compat/savexml.m )
2727
28-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
28+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
2929
"""
3030
return Runtime.call("savexml", *args, **kwargs, nargout=0)

spm/__compat/spm_add.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ def spm_add(*args, **kwargs):
2525
2626
[Matlab code]( https://github.com/spm/spm/blob/main/compat/spm_add.m )
2727
28-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
28+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
2929
"""
3030
return Runtime.call("spm_add", *args, **kwargs)

spm/__compat/spm_adjmean_fmri_ui.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,6 @@ def spm_adjmean_fmri_ui(*args, **kwargs):
198198
199199
[Matlab code]( https://github.com/spm/spm/blob/main/compat/spm_adjmean_fmri_ui.m )
200200
201-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
201+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
202202
"""
203203
return Runtime.call("spm_adjmean_fmri_ui", *args, **kwargs, nargout=0)

spm/__compat/spm_adjmean_ui.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,6 @@ def spm_adjmean_ui(*args, **kwargs):
184184
185185
[Matlab code]( https://github.com/spm/spm/blob/main/compat/spm_adjmean_ui.m )
186186
187-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
187+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
188188
"""
189189
return Runtime.call("spm_adjmean_ui", *args, **kwargs, nargout=0)

spm/__compat/spm_atranspa.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ def spm_atranspa(*args, **kwargs):
1717
1818
[Matlab code]( https://github.com/spm/spm/blob/main/compat/spm_atranspa.m )
1919
20-
Copyright (C) 2024-2024 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
20+
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
2121
"""
2222
return Runtime.call("spm_atranspa", *args, **kwargs)

0 commit comments

Comments
 (0)