PyAims high-level functions and classes

This section is the “useful” part, what you need to know first.

IO system

soma.aims.read(filename, border=0, frame=-1, dtype=None, allocmode=None, options=None)[source]

Equivalent to:

r = Reader( allocmode=allocmode, options=options )
return r.read( filename, border=border, frame=frame, dtype=dtype )
soma.aims.write(obj, filename, format=None, options={})[source]

Equivalent to:

w = Writer()
w.write( obj, filename, format=format, options=options )

Neuroimaging data structures

soma.aims.Volume(*args, **kwargs)[source]

Create an instance of Aims Volume (Volume_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type. The default type is ‘FLOAT’. Type definitions should match those accepted by typeCode(). Volume may also use a numpy array, or another Volume or AimsData_* as unique argument.

Note that Volume( Volume_* ) or Volume( AimsData_* ) actually performs a copy of the data, whereas AimsData( Volume_* ) or AimsData( AimsData_* ) share the input data.

Volume classes bindings are instantiated on a number of types: U8, S16, U16, S32, U32, FLOAT, DOUBLE, RGB, RGBA. For an example of the volumes API, see the soma.aims.Volume_FLOAT class.

soma.aims.AimsData(*args, **kwargs)[source]

Create an instance of the older Aims volumes (AimsData_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

The default type is ‘FLOAT’.

Type definitions should match those accepted by typeCode(). AimsData may also use a numpy array, or another Volume or AimsData_* as unique argument.

Note that Volume( Volume_* ) or Volume( AimsData_* ) actually performs a copy of the data, whereas AimsData( Volume_* ) or AimsData( AimsData_* ) share the input data.

AimsData classes bindings are instantiated on a number of types: U8, S16, U16, S32, U32, FLOAT, DOUBLE, RGB, RGBA. For an example of the AimsData API, see the soma.aims.AimsData_FLOAT class.

soma.aims.AimsTimeSurface(*args, **kwargs)[source]

Create an instance of Aims mesh (AimsTimeSurface_<dim>_<dtype>) from a dimension parameter, or copies a mesh, or build it from arrays.

See for instance AimsTimeSurface_3_VOID

Usages:

mesh1 = AimsTimeSurface()
mesh2 = AimsTimeSurface(3)
mesh3 = AimsTimeSurface(3, 'VOID')
mesh4 = AimsTimeSurface(3, dtype='VOID')
mesh5 = AimsTimeSurface(dim=3, dtype='VOID')
mesh6 = AimsTimeSurface(mesh)
mesh7 = AimsTimeSurface(vertices=[[1,2,3], [3,4,5.6]],
                        polygons=[[0,1]])
mesh8 = AimsTimeSurface([[1,2,3], [3,4,5.6]], polygons=[[0,1]])
mesh9 = AimsTimeSurface([[1,2,3], [3,4,5.6]], None, [[0,1]])
mesh10 = AimsTimeSurface([[1,2,3], [3,4,5.6]], [[0,1]], normals=[])

For an example of mesh surface classes, see the soma.aims.AimsTimeSurface_3_VOID class.

soma.aims.TimeTexture(*args, **kwargs)[source]

Create an instance of Aims texture (TimeTexture_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

The default type is ‘FLOAT’.

Type definitions should match those accepted by typeCode(). TimeTexture may also use a numpy array, or another TimeTexture_* or Textrue_* as unique argument.

Building from a numpy arrays uses the 1st dimension as vertex, the 2nd as time (if any).

TimeTexture classes bindings are instantiated on a number of types: S16, S32, U32, FLOAT, POINT2DF. For an example of the TimeTexture API, see the soma.aims.TimeTexture_FLOAT class.

soma.aims.Texture(*args, **kwargs)[source]

Create an instance of Aims low-level texture (Texture_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

The default type is ‘FLOAT’.

Type definitions should match those accepted by typeCode().

Texture may also use a numpy array, or another Textrue_* as unique argument.

Texture classes bindings are instantiated on a number of types: S16, S32, U32, FLOAT, POINT2DF. For an example of the Texture API, see the soma.aims.Texture_FLOAT class.

Note

You normally seldom use the Texture classes directly: most of the time they are (and should be) used through the higher-level soma.aims.TimeTexture() function and classes.

soma.aims.BucketMap(*args, **kwargs)[source]

Create an instance of Aims bucket (BucketMap_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

The default type is ‘VOID’.

Type definitions should match those accepted by typeCode().

For an example of bucket classes, see the soma.aims.BucketMap_VOID class, which is actually the only instantiation bound to Python, because textured buckets are not used directly.

Transformations and coordinates systems

class soma.aims.AffineTransformation3d(*args)

See the AffineTransformation3d C++ documentation

toMatrix(s)

This function return a copy of the transformation matrix

class soma.aims.Quaternion
buildFromMatrix(m)
Parameters:m (vector_FLOAT) – 4x4 matrix in columns (OpenGL-style). Be careful that it is not the expected order for a numpy array using ravel(), which have to be transposed.
compose

x.__mul__(y) <==> x*y

class soma.aims.StandardReferentials

General purpose C++ containers

class soma.aims.Object

Generic dynamic polymorphic object proxy.

Object is a proxy and a reference counter to a GenericObject. In most cases, Object and GenericObject are interchangeable and play the same role, there are two objects for technical reasons in the C++ layer, but in Python it whould make no difference.

The C++ generic object is an implementation of a mutable dynamic container which can hold any type of concrete data, with a generic access API which abstracts the concrete type of the object stored within it.

According to the underlying object type, Object can behave like a number, a string, or a container: sequence or dictionary. The python bindings can therefore support the sequence protocol, or the dictionary protocol, like a ‘real’ python object.

The only part which makes it visibly different from a python object is the conversions with stored objects, which are generally C++ objects (but can also be any python objects). Transparent conversions are done when possible.

We will take an example to show how to use it: a volume header. Suppose the files volume.img/volume.hdr[/volume.img.minf] represent a 3D volume (a MRI volume, typically, here in Analyze/SPM or Nifti format). We will read it using aims, and access its header data, which comes as a generic object.

>>> from __future__ import print_function # work using python 2 or 3
>>> from soma import aims
>>> vol = aims.read('volume.img')
>>> hdr = vol.header()

Now vol is the volume, and hdr its header, of type Object.

>>> type(hdr)
<class 'soma.aims.Object'>
>>> print(hdr)
{ 'voxel_size' : [ 1.875, 1.875, 4, 1 ], 'file_type' : 'SPM',
'byte_swapping' : 0, 'volume_dimension' : [ 128, 128, 16, 1 ],
'vox_units' : 'mm  ', 'cal_units' : '', 'data_type' : 'S16',
'disk_data_type' : 'S16', 'bits_allocated' : 2, 'tr' : 1,
'minimum' : 0, 'maximum' : 13645, 'scale_factor' : 1,
'scale_factor_applied' : 0, 'db_name' : '',
'aux_file' : '', 'orient' : 3, 'generated' : '', 'scannum' : '',
'patient_id' : '', 'exp_date' : '', 'exp_time' : '', 'views' : 0,
'start_field' : 32768, 'field_skip' : 8192, 'omax' : 0,
'omin' : 0, 'smax' : 32, 'smin' : 0, 'SPM_data_type' : '',
'possible_data_types' : [ 'S16' ], 'spm_radio_convention' : 1,
'spm_origin' : [ 65, 65, 9 ], 'origin' : [ 64, 63, 7 ] }

hdr prints like a dictionary, but is not really a python dictionary object. However it behaves like a dictionary:

>>> print(hdr['voxel_size'])
[ 1.875, 1.875, 4, 1 ]
>>> print(hdr['data_type'])
S16
>>> print(hdr['voxel_size'][0])
1.875
>>> for x in hdr:
>>>     print(x)
>>>
voxel_size
file_type
byte_swapping
volume_dimension
vox_units
cal_units
data_type
disk_data_type
bits_allocated
tr
minimum
maximum
scale_factor
scale_factor_applied
db_name
aux_file
orient
generated
scannum
patient_id
exp_date
exp_time
views
start_field
field_skip
omax
omin
smax
smin
SPM_data_type
possible_data_types
spm_radio_convention
spm_origin
origin
>>> for x,y in hdr.items():
>>>     print(x, ':', y)
>>>
voxel_size : [ 1.875, 1.875, 4, 1 ]
file_type : 'SPM'
byte_swapping : 0
volume_dimension : [ 128, 128, 16, 1 ]
vox_units : 'mm  '
cal_units : ''
data_type : 'S16'
disk_data_type : 'S16'
bits_allocated : 2
tr : 1
minimum : 0
maximum : 13645
scale_factor : 1
scale_factor_applied : 0
db_name : ''
aux_file : ''
orient : 3
generated : ''
scannum : ''
patient_id : ''
exp_date : ''
exp_time : ''
views : 0
start_field : 32768
field_skip : 8192
omax : 0
omin : 0
smax : 32
smin : 0
SPM_data_type : ''
possible_data_types : [ 'S16' ]
spm_radio_convention : 1
spm_origin : [ 65, 65, 9 ]
origin : [ 64, 63, 7 ]

Elements returned by the dictionary queries can have various types, althrough they are all stored internally in a C++ structure through soma.aims.Object wrappers. But when the underlying type of the element is known and can be retreived as a python object (either a standard python type or a python binding of a C++ class), it is done automatically. Such conversion is not possible when the underlying object has no python binding and is a pure C++ object, or when there is no conversion function. In this case, an Object is returned and contains the selected data.

Conversions are done using conversion methods that you generally do not need to call by hand: getScalar(), getString(), or the more general conversion method soma.aims.Object.getPython(). Elements types that cannot be converted to python concrete types are retreived in their Object container.

The generic conversion function in Object: getPython, is a static method and can be extended.

Elements in Object containers can generally be read and written:

>>> hdr['data_type'] = 'FLOAT'
>>> hdr['data_type']
'FLOAT'

This generally suits your needs. But in a few cases there will be a problem in internal types handling in the C++ layer.

Here, the underlying C++ generic object which did hold a C++ string (std::string) 'S16' is now replaced by another generic object built from the python string 'FLOAT', and which now wraps an element of type PyObject (or PyString). It just behaves the same way, so this operation is perfectly valid, but if C++ programs expect it to be a C++ std::string, they may fail.

Moreover, when writing back to existing concrete objects, some additional conversions may take place: for instance hdr['voxel_size'] is a C++ object of type std::vector<float>, so writing to hdr['voxel_size'][0] needs to enure we are actually writing a float, and if not, convert to it if possible.

You can query a type identifier for a generic object via the type() method:

>>> hdr.type()
'PropertySet'

Objects that can be converted from C++ generic objects to python are not necessarily known in advance. A conversion table is kept in the global variable soma.aims.convertersObjectToPython (in the aims module) and can be extended. Therefore other python modules using aims (such as sigraph) can extend this conversion table.

Details and tricks

There are some limitations and “unexpected behaviours” caused by the underlying C++ implementation of generic objects, and general behaviour differences between Python and C++. The following is expert-level details, so read it only if you have problems or you are a C++ expert with good knowledge of the cartobase C++ library...

Generic object - specialized object conversions

Putting a specific object in a generic Object makes a copy of it the first time it is done, because C++ generic objects contain the specialized elements. Once this has been done once, generic objects are shared and not copied anymore, which is consistent with the normal python behaviour. The non-pythonic thing is the first insertion in a generic object:

>>> a = aims.vector_FLOAT([12.6, -5.7])
>>> print(a)
[ 12.6, -5.7 ]
>>> hdr['foo'] = a # here a is copied into hdr['foo']
>>> a.append( 6.8 ) # a is changed but not hdr
>>> print(a)
[ 12.6, -5.7, 6.8 ]
>>> print(hdr['foo'])
[ 12.6, -5.7 ]
>>> hdr['dummy'] = hdr['foo']
>>> hdr['foo'].append(4.2)
>>> print(hdr['dummy']) # this time hdr['dummy'] is changed
[ 12.6, -5.7, 4.2 ]

To overcome the first copy problem, you may have to reassign the initial variable to the copy instance:

>>> a = aims.vector_FLOAT([1.2, 2.3, 3.4])
>>> hdr['foo'] = a
>>> a = hdr['foo']
>>> print(hdr['foo'])
[ 1.2, 2.3, 3.4 ]
>>> a[1] = 12.8
>>> print(a)
[ 1.2, 12.8, 3.4 ]
>>> print(hdr['foo'])
[ 1.2, 12.8, 3.4 ]

There are exceptions to this behaviour:

  • pure python objects, like lists or dictionaries are never copied since it is only a pointer to them (the C PyObject * pointer) which is stored.
  • small builtin types: numbers and strings are always copied since they are always converted and copied, not wrapped, when passed from python to C++ and vice versa.

The get() method

On Object the get method is ambiguous and has 2 meanings:

  • get() without arguments is a wrapping to the C++ rc_ptr::get() which returns the underlying wrapped object (here, a GenericObject)
  • get(key, default=None) is the dict-like method that is available on GenericObject since aims 4.6.1.

Depending on the arguments the Object method will redirect to the right one, thus:

myobject.get()            # gets the GenericObject
myobject.get('key')       # gets the dict item under keyt 'key'
myobject.get().get('key') # does both, but this is what the previous line
                          # already does, so the result is the same

To avoid this ambiguity, Object.get() and rc_ptr.get() have been renamed _get() years ago (in aims 4.0 I think) but get() is still present for compatibility. This use (without argument) is obsolete and may be removed in the future.

See the Object C++ documentation

getPython()

Conversion to python types: extracts what is in the Object (when possible). The global dictionary soma.aims.convertersObjectToPython stores converters

soma.aims.AimsVector(*args, **kwargs)[source]

Create an AimsVector instance from type and dimension arguments. Types may be passed as the keyword argument dtype. Otherwise the arguments are parsed to find types arguments. Dimension should be passed as the keyword argument dim, or is guessed from the input value(s).

Types may be specified as allowed by typeCode().

If unspecified, type is guessed from the 1st element of the vector data.

soma.aims.stdVector(*args, **kwargs)[source]

Create an instance of STL C++ vector (vector_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

Type definitions should match those accepted by typeCode().

soma.aims.stdSet(*args, **kwargs)[source]

Create an instance of STL C++ set (set_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

Type definitions should match those accepted by typeCode().

soma.aims.stdList(*args, **kwargs)[source]

Create an instance of STL C++ list (list_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

Type definitions should match those accepted by typeCode().

soma.aims.rc_ptr(*args, **kwargs)[source]

Create an instance of aims reference-counting object (rc_ptr_<type>) from a type parameter, which may be specified as the dtype keyword argument, or as one of the arguments if one is identitied as a type.

Type definitions should match those accepted by typeCode().

Conversion classes and functions

soma.aims.Converter(*args, **kwargs)[source]

Create a Converter instance from input and output types. Types may be passed as keyword arguments intype and outtype, or dtype if both are the same (not very useful for a converter). Otherwise the arguments are parsed to find types arguments.

Types may be specified as allowed by typeCode().

soma.aims.ShallowConverter(*args, **kwargs)[source]

Create a ShallowConverter instance from input and output types. Types may be passed as keyword arguments intype and outtype, or dtype if both are the same (not very useful for a converter). Otherwise the arguments are parsed to find types arguments.

Types may be specified as allowed by typeCode().

Graphs and ROIs

class soma.aims.GraphManip

Graph manipulation, which make things easier than the direct use of Graph. See the GraphManip C++ documentation

class soma.aims.RoiIterator(*args)
class soma.aims.MaskIterator(*args)