@@ -71,27 +71,18 @@ class Surface(object):
7171 Which hemisphere to load
7272 surf : string
7373 Name of the surface to load (eg. inflated, orig ...)
74- data_path : string
75- Path where to look for data
76- x: 1d array
77- x coordinates of vertices
78- y: 1d array
79- y coordinates of vertices
80- z: 1d array
81- z coordinates of vertices
82- coords : 2d array of shape [n_vertices, 3]
83- The vertices coordinates
84- faces : 2d array
85- The faces ie. the triangles
86- nn : 2d array
87- Normalized surface normals for vertices.
8874 subjects_dir : str | None
8975 If not None, this directory will be used as the subjects directory
9076 instead of the value set using the SUBJECTS_DIR environment variable.
77+ offset : float | None
78+ If float, align inside edge of each hemisphere to center + offset.
79+ If None, do not change coordinates (default).
80+ units : str
81+ Can be 'm' or 'mm' (default).
9182 """
9283
9384 def __init__ (self , subject_id , hemi , surf , subjects_dir = None ,
94- offset = None ):
85+ offset = None , units = 'mm' ):
9586 """Surface
9687
9788 Parameters
@@ -116,6 +107,7 @@ def __init__(self, subject_id, hemi, surf, subjects_dir=None,
116107 self .coords = None
117108 self .faces = None
118109 self .nn = None
110+ self .units = _check_units (units )
119111
120112 subjects_dir = _get_subjects_dir (subjects_dir )
121113 self .data_path = op .join (subjects_dir , subject_id )
@@ -124,6 +116,8 @@ def load_geometry(self):
124116 surf_path = op .join (self .data_path , "surf" ,
125117 "%s.%s" % (self .hemi , self .surf ))
126118 coords , faces = nib .freesurfer .read_geometry (surf_path )
119+ if self .units == 'm' :
120+ coords /= 1000.
127121 if self .offset is not None :
128122 if self .hemi == 'lh' :
129123 coords [:, 0 ] -= (np .max (coords [:, 0 ]) + self .offset )
@@ -140,11 +134,6 @@ def load_geometry(self):
140134 self .faces [:] = faces
141135 self .nn [:] = nn
142136
143- def save_geometry (self ):
144- surf_path = op .join (self .data_path , "surf" ,
145- "%s.%s" % (self .hemi , self .surf ))
146- nib .freesurfer .write_geometry (surf_path , self .coords , self .faces )
147-
148137 @property
149138 def x (self ):
150139 return self .coords [:, 0 ]
@@ -392,6 +381,12 @@ def dec(*args, **kwargs):
392381###############################################################################
393382# USEFUL FUNCTIONS
394383
384+ def _check_units (units ):
385+ if units not in ('m' , 'mm' ):
386+ raise ValueError ('Units must be "m" or "mm", got %r' % (units ,))
387+ return units
388+
389+
395390def find_closest_vertices (surface_coords , point_coords ):
396391 """Return the vertices on a surface mesh closest to some given coordinates.
397392
@@ -414,25 +409,29 @@ def find_closest_vertices(surface_coords, point_coords):
414409 return np .argmin (cdist (surface_coords , point_coords ), axis = 0 )
415410
416411
417- def tal_to_mni (coords ):
412+ def tal_to_mni (coords , units = 'mm' ):
418413 """Convert Talairach coords to MNI using the Lancaster transform.
419414
420415 Parameters
421416 ----------
422417 coords : n x 3 numpy array
423418 Array of Talairach coordinates
419+ units : str
420+ Can be 'm' or 'mm' (default).
424421
425422 Returns
426423 -------
427424 mni_coords : n x 3 numpy array
428- Array of coordinates converted to MNI space
429-
425+ Array of coordinates converted to MNI space.
430426 """
431427 coords = np .atleast_2d (coords )
432428 xfm = np .array ([[1.06860 , - 0.00396 , 0.00826 , 1.07816 ],
433429 [0.00640 , 1.05741 , 0.08566 , 1.16824 ],
434430 [- 0.01281 , - 0.08863 , 1.10792 , - 4.17805 ],
435431 [0.00000 , 0.00000 , 0.00000 , 1.00000 ]])
432+ units = _check_units (units )
433+ if units == 'm' :
434+ xfm [:3 , 3 ] /= 1000.
436435 mni_coords = np .dot (np .c_ [coords , np .ones (coords .shape [0 ])], xfm .T )[:, :3 ]
437436 return mni_coords
438437
@@ -597,7 +596,8 @@ def smoothing_matrix(vertices, adj_mat, smoothing_steps=20, verbose=None):
597596
598597@verbose
599598def coord_to_label (subject_id , coord , label , hemi = 'lh' , n_steps = 30 ,
600- map_surface = 'white' , coord_as_vert = False , verbose = None ):
599+ map_surface = 'white' , coord_as_vert = False , units = 'mm' ,
600+ verbose = None ):
601601 """Create label from MNI coordinate
602602
603603 Parameters
@@ -616,18 +616,24 @@ def coord_to_label(subject_id, coord, label, hemi='lh', n_steps=30,
616616 The surface name used to find the closest point
617617 coord_as_vert : bool
618618 whether the coords parameter should be interpreted as vertex ids
619+ units : str
620+ Can be 'm' or 'mm' (default).
619621 verbose : bool, str, int, or None
620622 If not None, override default verbose level (see surfer.verbose).
621623 """
622- geo = Surface (subject_id , hemi , map_surface )
624+ geo = Surface (subject_id , hemi , map_surface , units = units )
623625 geo .load_geometry ()
624626
627+ coords = geo .coords
628+ # work in mm from here on
629+ if geo .units == 'm' :
630+ coords = coords * 1000
625631 if coord_as_vert :
626- coord = geo . coords [coord ]
632+ coord = coords [coord ]
627633
628- n_vertices = len (geo . coords )
634+ n_vertices = len (coords )
629635 adj_mat = mesh_edges (geo .faces )
630- foci_vtxs = find_closest_vertices (geo . coords , [coord ])
636+ foci_vtxs = find_closest_vertices (coords , [coord ])
631637 data = np .zeros (n_vertices )
632638 data [foci_vtxs ] = 1.
633639 smooth_mat = smoothing_matrix (np .arange (n_vertices ), adj_mat , 1 )
@@ -641,7 +647,7 @@ def coord_to_label(subject_id, coord, label, hemi='lh', n_steps=30,
641647 f .write ('#label at %s from subject %s\n ' % (coord , subject_id ))
642648 f .write ('%d\n ' % len (idx ))
643649 for i in idx :
644- x , y , z = geo . coords [i ]
650+ x , y , z = coords [i ]
645651 f .write ('%d %f %f %f 0.000000\n ' % (i , x , y , z ))
646652
647653
@@ -696,7 +702,7 @@ def has_fsaverage(subjects_dir=None, raise_error=True, return_why=False):
696702
697703def has_imageio ():
698704 try :
699- import imageio # NOQA
705+ import imageio # noqa, analysis:ignore
700706 except ImportError :
701707 return False
702708 else :
0 commit comments