@@ -110,22 +110,55 @@ def _round(i, round=True):
110110 else :
111111 return i
112112
113- def x2i (self , x , round = True ):
114- return self ._round ((x - self .x0 ) / self .dx , round = round )
115-
116- def y2i (self , y , round = True ):
117- return self ._round ((y - self .y0 ) / self .dy , round = round )
118-
119- def z2i (self , z , round = True ):
120- return self ._round ((z - self .z0 ) / self .dz , round = round )
113+ def x2i (self , x , round = True , mode = 'raise' ):
114+ i = np .asarray (self ._round ((x - self .x0 ) / self .dx , round = round ))
115+ if np .any (i < 0 ) or np .any (i >= self .nx ):
116+ if mode == 'clip' :
117+ i [i < 0 ] = 0
118+ i [i >= self .nx ] = self .nx - 1
119+ elif mode == 'raise' :
120+ raise ValueError ("At least one x value lies outside of the atlas volume." )
121+ elif mode == 'wrap' :
122+ pass
123+ return i
124+
125+ def y2i (self , y , round = True , mode = 'raise' ):
126+ i = np .asarray (self ._round ((y - self .y0 ) / self .dy , round = round ))
127+ if np .any (i < 0 ) or np .any (i >= self .ny ):
128+ if mode == 'clip' :
129+ i [i < 0 ] = 0
130+ i [i >= self .ny ] = self .ny - 1
131+ elif mode == 'raise' :
132+ raise ValueError ("At least one y value lies outside of the atlas volume." )
133+ elif mode == 'wrap' :
134+ pass
135+ return i
136+
137+ def z2i (self , z , round = True , mode = 'raise' ):
138+ i = np .asarray (self ._round ((z - self .z0 ) / self .dz , round = round ))
139+ if np .any (i < 0 ) or np .any (i >= self .nz ):
140+ if mode == 'clip' :
141+ i [i < 0 ] = 0
142+ i [i >= self .nz ] = self .nz - 1
143+ elif mode == 'raise' :
144+ raise ValueError ("At least one z value lies outside of the atlas volume." )
145+ elif mode == 'wrap' :
146+ pass
147+ return i
121148
122- def xyz2i (self , xyz , round = True ):
149+ def xyz2i (self , xyz , round = True , mode = 'raise' ):
150+ """
151+ :param mode: {‘raise’, 'clip', 'wrap'} determines what to do when determined index lies outside the atlas volume
152+ 'raise' will raise a ValueError
153+ 'clip' will replace the index with the closest index inside the volume
154+ 'wrap' will wrap around to the other side of the volume. This is only here for legacy reasons
155+ """
123156 xyz = np .array (xyz )
124157 dt = int if round else float
125158 out = np .zeros_like (xyz , dtype = dt )
126- out [..., 0 ] = self .x2i (xyz [..., 0 ], round = round )
127- out [..., 1 ] = self .y2i (xyz [..., 1 ], round = round )
128- out [..., 2 ] = self .z2i (xyz [..., 2 ], round = round )
159+ out [..., 0 ] = self .x2i (xyz [..., 0 ], round = round , mode = mode )
160+ out [..., 1 ] = self .y2i (xyz [..., 1 ], round = round , mode = mode )
161+ out [..., 2 ] = self .z2i (xyz [..., 2 ], round = round , mode = mode )
129162 return out
130163
131164 """Methods indices to distance"""
@@ -227,7 +260,10 @@ def _get_cache_dir():
227260 def compute_surface (self ):
228261 """
229262 Get the volume top, bottom, left and right surfaces, and from these the outer surface of
230- the image volume. This is needed to compute probe insertions intersections
263+ the image volume. This is needed to compute probe insertions intersections.
264+
265+ NOTE: In places where the top or bottom surface touch the top or bottom of the atlas volume, the surface
266+ will be set to np.nan. If you encounter issues working with these surfaces check if this might be the cause.
231267 """
232268 if self .surface is None : # only compute if it hasn't already been computed
233269 axz = self .xyz2dims [2 ] # this is the dv axis
@@ -439,7 +475,12 @@ def slice(self, coordinate, axis, volume='image', mode='raise', region_values=No
439475 :param mapping: mapping to use. Options can be found using ba.regions.mappings.keys()
440476 :return: 2d array or 3d RGB numpy int8 array
441477 """
442- index = self .bc .xyz2i (np .array ([coordinate ] * 3 ))[axis ]
478+ if axis == 0 :
479+ index = self .bc .x2i (np .array (coordinate ), mode = mode )
480+ elif axis == 1 :
481+ index = self .bc .y2i (np .array (coordinate ), mode = mode )
482+ elif axis == 2 :
483+ index = self .bc .z2i (np .array (coordinate ), mode = mode )
443484
444485 # np.take is 50 thousand times slower than straight slicing !
445486 def _take (vol , ind , axis ):
@@ -765,7 +806,10 @@ def from_dict(d, brain_atlas=None):
765806 if brain_atlas :
766807 iy = brain_atlas .bc .y2i (d ['y' ] / 1e6 )
767808 ix = brain_atlas .bc .x2i (d ['x' ] / 1e6 )
768- z = brain_atlas .top [iy , ix ]
809+ # Only use the brain surface value as z if it isn't NaN (this happens when the surface touches the edges
810+ # of the atlas volume
811+ if not np .isnan (brain_atlas .top [iy , ix ]):
812+ z = brain_atlas .top [iy , ix ]
769813 return Insertion (x = d ['x' ] / 1e6 , y = d ['y' ] / 1e6 , z = z ,
770814 phi = d ['phi' ], theta = d ['theta' ], depth = d ['depth' ] / 1e6 ,
771815 beta = d .get ('beta' , 0 ), label = d .get ('label' , '' ))
0 commit comments