Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 5
Getting started
importspmimportnumpyasnpTo get help on a function or class, you can use the help function as you would in Matlab. For instance,
help(spm.spm_dcm_erp)Help on function spm_dcm_erp in module spm.__toolbox.__dcm_meeg.spm_dcm_erp:
spm_dcm_erp(*args, **kwargs)
Estimate parameters of a DCM model (Variational Lapalce)
FORMAT [DCM,dipfit] = spm_dcm_erp(DCM)
DCM
name: name string
Lpos: Source locations
xY: data [1x1 struct]
xU: design [1x1 struct]
Sname: cell of source name strings
A: {[nr x nr double] [nr x nr double] [nr x nr double]}
B: {[nr x nr double], ...} Connection constraints
C: [nr x 1 double]
options.trials - indices of trials
options.Tdcm - [start end] time window in ms
options.D - time bin decimation (usually 1 or 2)
options.h - number of DCT drift terms (usually 1 or 2)
options.Nmodes - number of spatial models to invert
options.analysis - 'ERP', 'SSR' or 'IND'
options.model - 'ERP', 'SEP', 'CMC', 'CMM', 'NMM' or 'MFM'
options.spatial - 'ECD', 'LFP' or 'IMG'
options.onset - stimulus onset (ms)
options.dur - and dispersion (sd)
options.CVA - use CVA for spatial modes [default = 0]
options.Nmax - maxiumum number of iterations [default = 64]
dipfit - Dipole structure (for electromagnetic forward model)
See spm_dcm_erp_dipfit: this field is removed from DCM.M to save
memory - and is offered as an output argument if needed
The scheme can be initialised with parameters for the neuronal model
and spatial (observer) model by specifying the fields DCM.P and DCM.Q,
respectively. If previous priors (DCM.M.pE and pC or DCM.M.gE and gC or
DCM.M.hE and hC) are specified, they will be used. Explicit priors can be
useful for Bayesian parameter averaging - but would not normally be
called upon - because prior constraints are specified by DCM.A, DCM.B,...
__________________________________________________________________________
[Matlab code]( https://github.com/spm/spm/blob/main/toolbox/dcm_meeg/spm_dcm_erp.m )
Copyright (C) 1995-2025 Functional Imaging Laboratory, Department of Imaging Neuroscience, UCL
It also works for classes, either to get more info on the class itself...
help(spm.meeg)Help on class meeg in module spm.meeg:
class meeg(mpython.matlab_class.MatlabClass)
| meeg(*args, **kwargs)
|
| Method resolution order:
| meeg
| mpython.matlab_class.MatlabClass
| mpython.core.base_types.MatlabType
| builtins.object
... or learn how to construct an object from it:
help(spm.meeg.__init__)Help on function __init__ in module spm.meeg:
__init__(self, *args, **kwargs)
Function for creating meeg objects.
FORMAT
D = meeg;
returns an empty object
D = meeg(D);
converts a D struct to object or does nothing if already
object
SPM Python provides you with a type system that allows to reuse Matlab syntax without too much worries. The following classes are available:
spm.Cell, for cell arraysspm.Struct, for struct arraysspm.Array, for general arrays
We've got cell arrays:
# Create an empty 1D Cell array with a shape of (3,)c=spm.Cell(3)
# Populate the Cell array with datac[0] ="Hello"c[1] ="World"c[2] =42# Print the Cell arrayprint("Initial Cell array:", c.tolist())
# Add a new element in (undefined) index 4c[4] ="New Element"# Print the updated Cell arrayprint("Updated Cell array:", c.tolist())Initial Cell array: ['Hello', 'World', 42]
Updated Cell array: ['Hello', 'World', 42, Array([]), 'New Element']
Some struct arrays as well:
# Create an empty Structexample_struct=spm.Struct()
example_struct.name="Example"example_struct.value=42print("Single Struct example:", example_struct)
# Create a 1D Struct arraystruct_array_1d=spm.Struct(3)
struct_array_1d[0].name="First"struct_array_1d[1].name="Second"struct_array_1d[2].name="Third"print("1D Struct array example:", struct_array_1d)
# Create a 2D Struct arraystruct_array_2d=spm.Struct(2, 2)
struct_array_2d[0, 0].name="Top Left"struct_array_2d[0, 1].name="Top Right"struct_array_2d[1, 0].name="Bottom Left"struct_array_2d[1, 1].name="Bottom Right"print("2D Struct array example:")
print(struct_array_2d)
# Add a new field to the Structexample_struct.new_field="New Field Value"print("Updated Struct with new field:", example_struct)Single Struct example: {'name': 'Example', 'value': 42}
1D Struct array example: [{'name': 'First'}, {'name': 'Second'}, {'name': 'Third'}]
2D Struct array example:
[[{'name': 'Top Left'}, {'name': 'Top Right'}],
[{'name': 'Bottom Left'}, {'name': 'Bottom Right'}]]
Updated Struct with new field: {'name': 'Example', 'value': 42, 'new_field': 'New Field Value'}
And some generic arrays too:
# Create an empty array (scalar)a=spm.Array()
print("Empty array:", a, "Shape:", a.shape)
# Create a 1D array of length 3a1d=spm.Array(3)
print("1D array:", a1d)
# Create a 2D array (3 rows, 2 columns)a2d=spm.Array(3, 2)
print("2D array:\n", a2d)Empty array: 0.0 Shape: ()
1D array: [0.0, 0.0, 0.0]
2D array:
[[0.0, 0.0],
[0.0, 0.0],
[0.0, 0.0]]
All of these types are derived from np.ndarray (thank you, Yael), which makes them really nice to work with if you're confortable with Numpy.
# Create a 1D struct arrays=spm.Struct(4)
# Populate the struct array with dataforiinrange(4):
s[i].value=is[i].label=f"item{i}"print("Original Struct:", s)
# Reshape the struct array to 2x2s_reshaped=s.reshape((2, 2))
print("Reshaped Struct (2x2):\n", s_reshaped)
# Transpose the struct arrays_transposed=np.transpose(s_reshaped)Original Struct: [{'value': 0, 'label': 'item0'}, {'value': 1, 'label': 'item1'},
{'value': 2, 'label': 'item2'}, {'value': 3, 'label': 'item3'}]
Reshaped Struct (2x2):
[[{'value': 0, 'label': 'item0'}, {'value': 1, 'label': 'item1'}],
[{'value': 2, 'label': 'item2'}, {'value': 3, 'label': 'item3'}]]
Concatenated Struct (1D): [{'value': 0, 'label': 'item0'} {'value': 1, 'label': 'item1'}
{'value': 2, 'label': 'item2'} {'value': 3, 'label': 'item3'}
{'value': 10, 'label': 'item10'} {'value': 11, 'label': 'item11'}
{'value': 12, 'label': 'item12'} {'value': 13, 'label': 'item13'}]
# Concatenate along the first axiss2=spm.Struct(4)
foriinrange(4):
s2[i].value=i+10s2[i].label=f"item{i+10}"s_concat=np.concatenate([s, s2])
print("Concatenated Struct (1D):", s_concat)Concatenated Struct (1D): [{'value': 0, 'label': 'item0'} {'value': 1, 'label': 'item1'}
{'value': 2, 'label': 'item2'} {'value': 3, 'label': 'item3'}
{'value': 10, 'label': 'item10'} {'value': 11, 'label': 'item11'}
{'value': 12, 'label': 'item12'} {'value': 13, 'label': 'item13'}]
# Concatenate along the first axiss2=spm.Struct(4)
foriinrange(4):
s2[i].value=i+10s2[i].label=f"item{i+10}"s_concat=np.concatenate([s, s2])
print("Concatenated Struct (1D):", s_concat)# Create a 1D Cell arrayc=spm.Cell(4)
c[:] = ["hello", 123, {"a": 1}, [1, 2, 3]]
print("Original Cell:", c)
# Create a 1D Cell arrayc_extra=spm.Cell(2)
c_extra[:] = ["more", "cells"]
# Concatenate the Cell arraysc_concat=np.concatenate([c, c_extra])
print("Concatenated Cell (1D):", c_concat.tolist())Original Cell: [hello, 123, [a], [1, 2, 3]]
Concatenated Cell (1D): ['hello', 123, Cell(['a']), Cell([1, 2, 3]), 'more', 'cells']
One of the nice feature these types have is type inference at construction time. This enables accessing undefined field of an array, as long as the indexing sequence ends up with an assignment. There are a few extra rules:
.: Use dot indexing to create a new field, as you'd use.in Matlab,[]: Use square brackets for array indexing, as you'd use()in Matlab,(): Use round brackets for cell indexing, as you'd use{}in Matlab,
For example, to create a struct array with a field containing a cell array with, in third position, a struct array with a 2-by-2 random matrix in fifth position (showcasing all three rules):
S=spm.Struct()
S.field(3).struct[5].elem=np.random.rand(2, 2)
S{'field': Cell([Array([]), Array([]), Array([]),
{'struct': Struct([{'elem': Array([])}, {'elem': Array([])}, {'elem': Array([])},
{'elem': Array([])}, {'elem': Array([])},
{'elem': Array([[0.38339607, 0.55686198],
[0.53678757, 0.5828017 ]])} ])} ])}
There is one caveat though: elements of unfinalised cell arrays cannot be specified:
>>>S=spm.Struct()
>>>S.field(3) ='test'S.field(3) ='test'^SyntaxError: cannotassigntofunctioncallhere. Maybeyoumeant'=='insteadof'='?This is why we need one additional rule:
as_cell[]: Initialising an element of an unfinalised cell array needs to useas_cell.
Using as_cell solves exactly this problem:
S=spm.Struct()
S.field.as_cell[3] ="test"S{'field': Cell([Array([]), Array([]), Array([]), 'test'])}