@@ -124,6 +124,30 @@ def _viewlim_mask(xs, ys, zs, axes):
124124 return mask
125125
126126
127+ def _apply_viewlim_mask_with_copy (xs , ys , zs , axes ):
128+ """
129+ Mask points outside view limits by setting to nan. Allocates new arrays.
130+
131+ Parameters
132+ ----------
133+ xs, ys, zs : array-like
134+ The points to mask. These should be in data coordinates.
135+ axes : Axes3D
136+ The axes to use for the view limits.
137+
138+ Returns
139+ -------
140+ xs, ys, zs : array-like
141+ The coordinates with out-of-bounds points set to nan.
142+ """
143+ mask = _viewlim_mask (xs , ys , zs , axes )
144+ if np .any (mask ):
145+ xs = np .where (mask , np .nan , xs )
146+ ys = np .where (mask , np .nan , ys )
147+ zs = np .where (mask , np .nan , zs )
148+ return xs , ys , zs
149+
150+
127151class Text3D (mtext .Text ):
128152 """
129153 Text object with 3D position and direction.
@@ -222,7 +246,7 @@ def draw(self, renderer):
222246 if self ._axlim_clip :
223247 mask = _viewlim_mask (self ._x , self ._y , self ._z , self .axes )
224248 if np .any (mask ):
225- pos3d = np .where ( mask , np . nan , pos3d )
249+ pos3d [ mask ] = np .nan
226250
227251 # Apply scale transforms before projection
228252 pos3d_scaled = np .array (_apply_scale_transforms (
@@ -362,11 +386,7 @@ def get_data_3d(self):
362386 def draw (self , renderer ):
363387 xs3d , ys3d , zs3d = self ._verts3d
364388 if self ._axlim_clip :
365- mask = _viewlim_mask (xs3d , ys3d , zs3d , self .axes )
366- if np .any (mask ):
367- xs3d = np .where (mask , np .nan , xs3d )
368- ys3d = np .where (mask , np .nan , ys3d )
369- zs3d = np .where (mask , np .nan , zs3d )
389+ xs3d , ys3d , zs3d = _apply_viewlim_mask_with_copy (xs3d , ys3d , zs3d , self .axes )
370390 # Apply scale transforms before projection
371391 xs3d , ys3d , zs3d = _apply_scale_transforms (xs3d , ys3d , zs3d , self .axes )
372392 xs , ys , zs , tis = proj3d ._proj_transform_clip (xs3d , ys3d , zs3d ,
@@ -650,23 +670,16 @@ def get_path(self):
650670
651671 def do_3d_projection (self ):
652672 s = self ._segment3d
653- mask = False
654673 xs , ys , zs = zip (* s )
655674 if self ._axlim_clip :
656- mask = _viewlim_mask (xs , ys , zs , self .axes )
657- if np .any (mask ):
658- xs = np .where (mask , np .nan , xs )
659- ys = np .where (mask , np .nan , ys )
660- zs = np .where (mask , np .nan , zs )
675+ xs , ys , zs = _apply_viewlim_mask_with_copy (xs , ys , zs , self .axes )
661676 # Apply scale transforms before projection
662677 xs , ys , zs = _apply_scale_transforms (xs , ys , zs , self .axes )
663678 vxs , vys , vzs , vis = proj3d ._proj_transform_clip (xs , ys , zs ,
664679 self .axes .M ,
665680 self .axes ._focal_length )
666681 self ._path2d = mpath .Path (np .column_stack ([vxs , vys ]))
667- if mask is False :
668- return np .min (vzs )
669- return np .min (vzs [~ mask ])
682+ return np .nanmin (vzs )
670683
671684
672685class PathPatch3D (Patch3D ):
@@ -718,24 +731,16 @@ def set_3d_properties(self, path, zs=0, zdir='z', axlim_clip=False):
718731
719732 def do_3d_projection (self ):
720733 s = self ._segment3d
721- mask = False
722734 xs , ys , zs = zip (* s )
723735 if self ._axlim_clip :
724- mask = _viewlim_mask (xs , ys , zs , self .axes )
725- if np .any (mask ):
726- xs = np .where (mask , np .nan , xs )
727- ys = np .where (mask , np .nan , ys )
728- zs = np .where (mask , np .nan , zs )
736+ xs , ys , zs = _apply_viewlim_mask_with_copy (xs , ys , zs , self .axes )
729737 # Apply scale transforms before projection
730738 xs , ys , zs = _apply_scale_transforms (xs , ys , zs , self .axes )
731739 vxs , vys , vzs , vis = proj3d ._proj_transform_clip (xs , ys , zs ,
732740 self .axes .M ,
733741 self .axes ._focal_length )
734742 self ._path2d = mpath .Path (np .column_stack ([vxs , vys ]), self ._code3d )
735-
736- if mask is False :
737- return np .min (vzs )
738- return np .min (vzs [~ mask ])
743+ return np .nanmin (vzs )
739744
740745
741746def _get_patch_verts (patch ):
@@ -872,13 +877,8 @@ def set_3d_properties(self, zs, zdir, axlim_clip=False):
872877
873878 def do_3d_projection (self ):
874879 xs , ys , zs = self ._offsets3d
875- mask = False
876880 if self ._axlim_clip :
877- mask = _viewlim_mask (xs , ys , zs , self .axes )
878- if np .any (mask ):
879- xs = np .where (mask , np .nan , xs )
880- ys = np .where (mask , np .nan , ys )
881- zs = np .where (mask , np .nan , zs )
881+ xs , ys , zs = _apply_viewlim_mask_with_copy (xs , ys , zs , self .axes )
882882 # Apply scale transforms before projection
883883 xs , ys , zs = _apply_scale_transforms (xs , ys , zs , self .axes )
884884 vxs , vys , vzs , vis = proj3d ._proj_transform_clip (xs , ys , zs ,
@@ -887,12 +887,7 @@ def do_3d_projection(self):
887887 self ._vzs = vzs
888888 super ().set_offsets (np .column_stack ([vxs , vys ]))
889889
890- if vzs .size > 0 :
891- if mask is False :
892- return np .min (vzs )
893- return np .min (vzs [~ mask ])
894- else :
895- return np .nan
890+ return np .nanmin (vzs ) if vzs .size > 0 else np .nan
896891
897892 def _maybe_depth_shade_and_sort_colors (self , color_array ):
898893 color_array = (
0 commit comments