[Nipy-devel] Axis and friends

Jonathan Taylor jonathan.taylor at stanford.edu
Tue Jul 11 13:40:07 CDT 2006


I have no objection -- sorry didn't reply this weekend...

-- Jonathan

Tim Leslie wrote:
> On 7/11/06, Karl Young <Karl.Young at ucsf.edu> wrote:
>   
>> At the level of class definitions in the basic infrastructure I'm more
>> of a user than a developer but these changes look good to me (unless
>> Jonathan or anyone else had specific reasons for the bottom up version),
>> and they are easy to parse.
>>     
>
> Well, I've got one reply in support and none against, so I'll check
> these in tonight. We can always revert if we decide to stick with the
> old design.
>
> The other significant change I'd like to make to the reference package
> is to add a separate mni.py module to handle the MNI specific stuff
> (MNI, MNI_voxel, MNI_world, etc). These had been scattered through
> various other modules and I think they deserve a home of their own.
> When looking through the various reference modules, these particular
> instances would be tacked on at the end, and IMHO looked a little out
> of place. Only when you realise that they all come together as a
> single collection of references do they begin to make sense. By having
> a separate MNI module, these instances are all grouped together, so
> it's easy to see how the MNI reference world is constructed, without
> polluting the modules which actually do the hard work.
>
> Since the axis changes and the mni changes are all kinda squished
> together in my svn tree, I'd like to check them all in at once. I'll
> do this at the end of the night unless anyone raises an object and of
> course Jonathon, if you don't like some of these changes we can always
> change them back.
>
> Cheers,
>
> Tim
>
>   
>>> Hi All,
>>>
>>> I was looking at reference/axis.py today and thinking about the class
>>> structure. At present, we have Axis, which just has a name, then we
>>> derive from the VoxelAxis, which also has a length and a set of
>>> values(), we then derive RegularAxis which adds a start and step
>>> parameter. In essence, we are creating subclasses to _extend_ the base
>>> class. We start off with the bare bones Axis class and add on the new
>>> features at each level.
>>>
>>> The other way to approach this design is to have the base class (Axis)
>>> provide the full interface (values, length, name) and then have each
>>> of the base classes _specialise_ this class. So an Axis can have any
>>> set of values it wants, a RegularAxis has values which are regularly
>>> spaced  with a given start and step, and a VoxelAxis is a RegularAxis
>>> where start = 0 and step = 1.
>>>
>>> The advantages to this kind of arrangement is that there is a single
>>> interface which the external users have to know about, and the
>>> implementation of each of these classes becomes easier.
>>>
>>> I've implemented this different arrangement to show what I mean. I was
>>> hoping to hear other peoples thoughts on this design choice. My new
>>> version of axis.py passes all the tests, so we don't have to worry
>>> about breaking existing. The new version cuts the line count from 114
>>> down to 81 and IMHO is a lot easier to read.
>>>
>>> What do other people think?
>>>
>>> Cheers,
>>>
>>> Tim
>>>
>>> ------------------------------------------------------------------------
>>>
>>> import numpy as N
>>>       
>> >from attributes import readonly
>>     
>>> valid = ['xspace', 'yspace', 'zspace', 'time', 'vector_dimension', 'concat']
>>> space = ['zspace', 'yspace', 'xspace']
>>> spacetime = ['time', 'zspace', 'yspace', 'xspace']
>>>
>>>
>>> class Axis (object):
>>>    """
>>>    This class represents a generic axis. Axes are used in the definition
>>>    of CoordinateSystem.
>>>    """
>>>    class name (readonly): "dimension name"; implements=str
>>>
>>>    def __init__(self, name, values=None):
>>>        self.name = name
>>>        if self.name not in valid:
>>>            raise ValueError, 'recognized dimension names are ' + `valid`
>>>        if values is None:
>>>            self._values = []
>>>        else:
>>>            self._values = values
>>>        self.length = len(self._values)
>>>
>>>    def values(self):
>>>        return self._values
>>>
>>>    def __eq__(self, axis):
>>>        "Equality is defined by name and values."
>>>        return hasattr(axis,"name") and self.name == axis.name and self.length == axis.length and N.all(N.equal(self.values(), axis.values()))
>>>
>>>    def __len__(self):
>>>        return self.length
>>>
>>> class RegularAxis (Axis):
>>>    """
>>>    This class represents a regularly spaced axis. Axes are used in the
>>>    definition Coordinate system. The attributes step and start are usually
>>>    ignored if a valid transformation matrix is provided -- otherwise they
>>>    can be used to create an orthogonal transformation matrix.
>>>
>>>    >>> from neuroimaging.reference.axis import RegularAxis
>>>    >>> from numpy import allclose, array
>>>    >>> r = RegularAxis(name='xspace',length=10, start=0.25, step=0.3)
>>>    >>> allclose(r.values(), array([ 0.25,  0.55,  0.85,  1.15,  1.45,  1.75,  2.05,  2.35,  2.65,  2.95]))
>>>    True
>>>    >>>
>>>    """
>>>
>>>    def __init__(self, name, length=0, start=0, step=0):
>>>        _values = N.linspace(start, start + step*length, length, False)
>>>        Axis.__init__(self, name, _values)
>>>        self.start = start
>>>        self.step = step
>>>
>>>
>>>
>>> class VoxelAxis (RegularAxis):
>>>    "An axis with a length as well."
>>>
>>>    def __init__(self, name, length=0):
>>>        RegularAxis.__init__(self, name, length, start=0, step=1)
>>>
>>>
>>> # Default axes
>>> generic = (
>>>  Axis(name='zspace'),
>>>  Axis(name='yspace'),
>>>  Axis(name='xspace'))
>>>
>>> # MNI template axes
>>> MNI = (
>>>  RegularAxis(name='zspace', length=109, start=-72., step=2.0),
>>>  RegularAxis(name='yspace', length=109, start=-126., step=2.0),
>>>  RegularAxis(name='xspace', length=91, start=-90., step=2.0))
>>>
>>>
>>> if __name__ == "__main__":
>>>    import doctest
>>>    doctest.testmod()
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> _______________________________________________
>>> Nipy-devel mailing list
>>> Nipy-devel at scipy.org
>>> http://projects.scipy.org/mailman/listinfo/nipy-devel
>>>
>>>
>>>       
>> --
>>
>> Karl Young
>> Center for Imaging of Neurodegenerative Diseases, UCSF
>> VA Medical Center (114M)              Phone:  (415) 221-4810 x3114  lab
>> 4150 Clement Street                   FAX:    (415) 668-2864
>> San Francisco, CA 94121               Email:  karl young at ucsf edu
>>
>>     
> _______________________________________________
> Nipy-devel mailing list
> Nipy-devel at scipy.org
> http://projects.scipy.org/mailman/listinfo/nipy-devel
>   

-- 

------------------------------------------------------------------------
Jonathan Taylor                           Tel:   650.723.9230
Dept. of Statistics                       Fax:   650.725.8977
Sequoia Hall, 137                         www-stat.stanford.edu/~jtaylo
390 Serra Mall
Stanford, CA 94305

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://projects.scipy.org/pipermail/nipy-devel/attachments/20060711/e2f30c02/attachment.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: jonathan.taylor.vcf
Type: text/x-vcard
Size: 329 bytes
Desc: not available
Url : http://projects.scipy.org/pipermail/nipy-devel/attachments/20060711/e2f30c02/attachment.vcf 


More information about the Nipy-devel mailing list