@@ -598,16 +598,28 @@ def set_zsort(self, zsort):
598598 self .stale = True
599599
600600 def get_vector (self , segments3d ):
601- """Optimize points for projection."""
602- if len (segments3d ):
603- xs , ys , zs = np .row_stack (segments3d ).T
604- else : # row_stack can't stack zero arrays.
605- xs , ys , zs = [], [], []
606- ones = np .ones (len (xs ))
607- self ._vec = np .array ([xs , ys , zs , ones ])
601+ """
602+ Optimize points for projection.
608603
609- indices = [0 , * np .cumsum ([len (segment ) for segment in segments3d ])]
610- self ._segslices = [* map (slice , indices [:- 1 ], indices [1 :])]
604+ Parameters
605+ ----------
606+ segments3d : NumPy array or list of NumPy arrays
607+ List of vertices of the boundary of every segment. If all paths are
608+ of equal length and this argument is a NumPy arrray, then it should
609+ be of shape (num_faces, num_vertices, 3).
610+ """
611+ if isinstance (segments3d , np .ndarray ):
612+ if segments3d .ndim != 3 or segments3d .shape [- 1 ] != 3 :
613+ raise ValueError ("segments3d must be a MxNx3 array, but got " +
614+ "shape {}" .format (segments3d .shape ))
615+ self ._segments = segments3d
616+ else :
617+ num_faces = len (segments3d )
618+ max_verts = max ((len (face ) for face in segments3d ), default = 0 )
619+ padded = np .full ((num_faces , max_verts , 3 ), np .nan )
620+ for i , face in enumerate (segments3d ):
621+ padded [i , :len (face )] = face
622+ self ._segments = np .ma .masked_invalid (padded )
611623
612624 def set_verts (self , verts , closed = True ):
613625 """Set 3D vertices."""
@@ -649,37 +661,39 @@ def do_3d_projection(self, renderer):
649661 self .update_scalarmappable ()
650662 self ._facecolors3d = self ._facecolors
651663
652- txs , tys , tzs = proj3d ._proj_transform_vec (self ._vec , renderer .M )
653- xyzlist = [( txs [ sl ], tys [ sl ], tzs [ sl ]) for sl in self . _segslices ]
664+ psegments = proj3d ._proj_transform_vectors (self ._segments , renderer .M )
665+ num_faces = len ( psegments )
654666
655667 # This extra fuss is to re-order face / edge colors
656668 cface = self ._facecolors3d
657669 cedge = self ._edgecolors3d
658- if len (cface ) != len ( xyzlist ) :
659- cface = cface .repeat (len ( xyzlist ) , axis = 0 )
660- if len (cedge ) != len ( xyzlist ) :
670+ if len (cface ) != num_faces :
671+ cface = cface .repeat (num_faces , axis = 0 )
672+ if len (cedge ) != num_faces :
661673 if len (cedge ) == 0 :
662674 cedge = cface
663675 else :
664- cedge = cedge .repeat (len ( xyzlist ) , axis = 0 )
676+ cedge = cedge .repeat (num_faces , axis = 0 )
665677
666- # sort by depth (furthest drawn first )
667- z_segments_2d = sorted (
668- (( self . _zsortfunc ( zs ), np . column_stack ([ xs , ys ]), fc , ec , idx )
669- for idx , (( xs , ys , zs ), fc , ec )
670- in enumerate ( zip ( xyzlist , cface , cedge ))),
671- key = lambda x : x [ 0 ], reverse = True )
678+ face_z = self . _zsortfunc ( psegments [..., 2 ], axis = - 1 )
679+ if isinstance ( face_z , np . ma . MaskedArray ):
680+ # NOTE: Unpacking .data is safe here, because every face has to
681+ # contain a valid vertex.
682+ face_z = face_z . data
683+ face_order = np . argsort ( face_z , axis = - 1 )[:: - 1 ]
672684
673- segments_2d = [s for z , s , fc , ec , idx in z_segments_2d ]
674685 if self ._codes3d is not None :
675- codes = [self ._codes3d [idx ] for z , s , fc , ec , idx in z_segments_2d ]
686+ segments_2d = [s .compressed ().reshape (- 1 , 2 )
687+ for s in psegments [face_order , :, :2 ]]
688+ codes = [self ._codes3d [idx ] for idx in face_order ]
676689 PolyCollection .set_verts_and_codes (self , segments_2d , codes )
677690 else :
691+ segments_2d = psegments [face_order , :, :2 ]
678692 PolyCollection .set_verts (self , segments_2d , self ._closed )
679693
680- self ._facecolors2d = [ fc for z , s , fc , ec , idx in z_segments_2d ]
694+ self ._facecolors2d = cface [ face_order ]
681695 if len (self ._edgecolors3d ) == len (cface ):
682- self ._edgecolors2d = [ ec for z , s , fc , ec , idx in z_segments_2d ]
696+ self ._edgecolors2d = cedge [ face_order ]
683697 else :
684698 self ._edgecolors2d = self ._edgecolors3d
685699
@@ -688,11 +702,11 @@ def do_3d_projection(self, renderer):
688702 zvec = np .array ([[0 ], [0 ], [self ._sort_zpos ], [1 ]])
689703 ztrans = proj3d ._proj_transform_vec (zvec , renderer .M )
690704 return ztrans [2 ][0 ]
691- elif tzs .size > 0 :
705+ elif psegments .size > 0 :
692706 # FIXME: Some results still don't look quite right.
693707 # In particular, examine contourf3d_demo2.py
694708 # with az = -54 and elev = -45.
695- return np .min (tzs )
709+ return np .min (psegments [..., 2 ] )
696710 else :
697711 return np .nan
698712
0 commit comments