20
20
Collection , LineCollection , PolyCollection , PatchCollection , PathCollection )
21
21
from matplotlib .colors import Normalize
22
22
from matplotlib .patches import Patch
23
- from . import proj3d
24
23
25
24
26
25
def _norm_angle (a ):
@@ -148,12 +147,11 @@ def set_3d_properties(self, z=0, zdir='z'):
148
147
@artist .allow_rasterization
149
148
def draw (self , renderer ):
150
149
position3d = np .array ((self ._x , self ._y , self ._z ))
151
- proj = proj3d ._proj_trans_points (
152
- [position3d , position3d + self ._dir_vec ], self .axes .M )
153
- dx = proj [0 ][1 ] - proj [0 ][0 ]
154
- dy = proj [1 ][1 ] - proj [1 ][0 ]
150
+ proj = self .axes .M .transform ([position3d , position3d + self ._dir_vec ])
151
+ dx = proj [1 ][0 ] - proj [0 ][0 ]
152
+ dy = proj [1 ][1 ] - proj [0 ][1 ]
155
153
angle = math .degrees (math .atan2 (dy , dx ))
156
- with cbook ._setattr_cm (self , _x = proj [0 ][0 ], _y = proj [1 ][ 0 ],
154
+ with cbook ._setattr_cm (self , _x = proj [0 ][0 ], _y = proj [0 ][ 1 ],
157
155
_rotation = _norm_text_angle (angle )):
158
156
mtext .Text .draw (self , renderer )
159
157
self .stale = False
@@ -267,8 +265,8 @@ def get_data_3d(self):
267
265
@artist .allow_rasterization
268
266
def draw (self , renderer ):
269
267
xs3d , ys3d , zs3d = self ._verts3d
270
- xs , ys , zs = proj3d . proj_transform ( xs3d , ys3d , zs3d , self . axes . M )
271
- self .set_data (xs , ys )
268
+ points = self . axes . M . transform ( np . column_stack (( xs3d , ys3d , zs3d )) )
269
+ self .set_data (points [:, 0 ], points [:, 1 ] )
272
270
super ().draw (renderer )
273
271
self .stale = False
274
272
@@ -349,11 +347,11 @@ class Collection3D(Collection):
349
347
350
348
def do_3d_projection (self ):
351
349
"""Project the points according to renderer matrix."""
352
- xyzs_list = [proj3d . proj_transform ( * vs . T , self .axes . M )
353
- for vs , _ in self . _3dverts_codes ]
354
- self . _paths = [ mpath . Path ( np . column_stack ([ xs , ys ]), cs )
355
- for ( xs , ys , _ ), ( _ , cs ) in zip (xyzs_list , self ._3dverts_codes )]
356
- zs = np .concatenate ([ zs for _ , _ , zs in xyzs_list ])
350
+ path_vertices = [self . axes . M . transform ( vs ) for vs , _ in self ._3dverts_codes ]
351
+ self . _paths = [ mpath . Path ( vertices [:, : 2 ], codes )
352
+ for ( vertices , ( _ , codes ) )
353
+ in zip (path_vertices , self ._3dverts_codes )]
354
+ zs = np .concatenate (path_vertices )[:, 2 ]
357
355
return zs .min () if len (zs ) else 1e9
358
356
359
357
@@ -390,15 +388,14 @@ def do_3d_projection(self):
390
388
"""
391
389
Project the points according to renderer matrix.
392
390
"""
393
- xyslist = [proj3d ._proj_trans_points (points , self .axes .M )
394
- for points in self ._segments3d ]
395
- segments_2d = [np .column_stack ([xs , ys ]) for xs , ys , zs in xyslist ]
391
+ segments_3d = [self .axes .M .transform (segment ) for segment in self ._segments3d ]
392
+ segments_2d = [segment [:, :2 ] for segment in segments_3d ]
396
393
LineCollection .set_segments (self , segments_2d )
397
394
398
395
# FIXME
399
396
minz = 1e9
400
- for xs , ys , zs in xyslist :
401
- minz = min (minz , min ( zs ) )
397
+ for segment in segments_3d :
398
+ minz = min (minz , segment [ 0 ][ 2 ], segment [ 1 ][ 2 ] )
402
399
return minz
403
400
404
401
@@ -456,12 +453,10 @@ def get_path(self):
456
453
return self ._path2d
457
454
458
455
def do_3d_projection (self ):
459
- s = self ._segment3d
460
- xs , ys , zs = zip (* s )
461
- vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
462
- self .axes .M )
463
- self ._path2d = mpath .Path (np .column_stack ([vxs , vys ]))
464
- return min (vzs )
456
+ segments = self .axes .M .transform (self ._segment3d )
457
+ self ._path2d = mpath .Path (segments [:, :2 ])
458
+
459
+ return min (segments [:, 2 ])
465
460
466
461
467
462
class PathPatch3D (Patch3D ):
@@ -503,12 +498,10 @@ def set_3d_properties(self, path, zs=0, zdir='z'):
503
498
self ._code3d = path .codes
504
499
505
500
def do_3d_projection (self ):
506
- s = self ._segment3d
507
- xs , ys , zs = zip (* s )
508
- vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
509
- self .axes .M )
510
- self ._path2d = mpath .Path (np .column_stack ([vxs , vys ]), self ._code3d )
511
- return min (vzs )
501
+ segments = self .axes .M .transform (self ._segment3d )
502
+ self ._path2d = mpath .Path (segments [:, :2 ], self ._code3d )
503
+
504
+ return min (segments [:, 2 ])
512
505
513
506
514
507
def _get_patch_verts (patch ):
@@ -610,14 +603,13 @@ def set_3d_properties(self, zs, zdir):
610
603
self .stale = True
611
604
612
605
def do_3d_projection (self ):
613
- xs , ys , zs = self ._offsets3d
614
- vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
615
- self .axes .M )
616
- self ._vzs = vzs
617
- super ().set_offsets (np .column_stack ([vxs , vys ]))
606
+ points = self .axes .M .transform (np .column_stack (self ._offsets3d ))
607
+ super ().set_offsets (points [:, :2 ])
618
608
619
- if vzs .size > 0 :
620
- return min (vzs )
609
+ self ._vzs = points [:, 2 ]
610
+
611
+ if self ._vzs .size > 0 :
612
+ return min (self ._vzs )
621
613
else :
622
614
return np .nan
623
615
@@ -751,37 +743,31 @@ def set_depthshade(self, depthshade):
751
743
self .stale = True
752
744
753
745
def do_3d_projection (self ):
754
- xs , ys , zs = self ._offsets3d
755
- vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
756
- self .axes .M )
757
746
# Sort the points based on z coordinates
758
747
# Performance optimization: Create a sorted index array and reorder
759
748
# points and point properties according to the index array
760
- z_markers_idx = self ._z_markers_idx = np .argsort (vzs )[::- 1 ]
761
- self ._vzs = vzs
749
+ points = self .axes .M .transform (np .column_stack (self ._offsets3d ))
750
+ z_markers_idx = self ._z_markers_idx = np .argsort (points [:, 2 ])[::- 1 ]
751
+ self ._vzs = points [:, 2 ]
762
752
763
753
# we have to special case the sizes because of code in collections.py
764
754
# as the draw method does
765
755
# self.set_sizes(self._sizes, self.figure.dpi)
766
756
# so we cannot rely on doing the sorting on the way out via get_*
767
-
768
757
if len (self ._sizes3d ) > 1 :
769
758
self ._sizes = self ._sizes3d [z_markers_idx ]
770
759
771
760
if len (self ._linewidths3d ) > 1 :
772
761
self ._linewidths = self ._linewidths3d [z_markers_idx ]
773
762
774
- PathCollection .set_offsets (self , np . column_stack (( vxs , vys )) )
763
+ PathCollection .set_offsets (self , points [:, : 2 ] )
775
764
776
765
# Re-order items
777
- vzs = vzs [z_markers_idx ]
778
- vxs = vxs [z_markers_idx ]
779
- vys = vys [z_markers_idx ]
766
+ points = points [z_markers_idx ]
780
767
781
768
# Store ordered offset for drawing purpose
782
- self ._offset_zordered = np .column_stack ((vxs , vys ))
783
-
784
- return np .min (vzs ) if vzs .size else np .nan
769
+ self ._offset_zordered = points [:, :2 ]
770
+ return np .min (self ._vzs ) if self ._vzs .size else np .nan
785
771
786
772
@contextmanager
787
773
def _use_zordered_offset (self ):
@@ -954,8 +940,7 @@ def get_vector(self, segments3d):
954
940
xs , ys , zs = np .vstack (segments3d ).T
955
941
else : # vstack can't stack zero arrays.
956
942
xs , ys , zs = [], [], []
957
- ones = np .ones (len (xs ))
958
- self ._vec = np .array ([xs , ys , zs , ones ])
943
+ self ._vec = np .array ([xs , ys , zs ])
959
944
960
945
indices = [0 , * np .cumsum ([len (segment ) for segment in segments3d ])]
961
946
self ._segslices = [* map (slice , indices [:- 1 ], indices [1 :])]
@@ -1020,27 +1005,28 @@ def do_3d_projection(self):
1020
1005
self ._facecolor3d = self ._facecolors
1021
1006
if self ._edge_is_mapped :
1022
1007
self ._edgecolor3d = self ._edgecolors
1023
- txs , tys , tzs = proj3d ._proj_transform_vec (self ._vec , self .axes .M )
1024
- xyzlist = [(txs [sl ], tys [sl ], tzs [sl ]) for sl in self ._segslices ]
1008
+
1009
+ verts = self .axes .M .transform (np .column_stack (self ._vec ))
1010
+ verts_slices = [verts [sl ] for sl in self ._segslices ]
1025
1011
1026
1012
# This extra fuss is to re-order face / edge colors
1027
1013
cface = self ._facecolor3d
1028
1014
cedge = self ._edgecolor3d
1029
- if len (cface ) != len (xyzlist ):
1030
- cface = cface .repeat (len (xyzlist ), axis = 0 )
1031
- if len (cedge ) != len (xyzlist ):
1015
+
1016
+ if len (cface ) != len (verts_slices ):
1017
+ cface = cface .repeat (len (verts_slices ), axis = 0 )
1018
+ if len (cedge ) != len (verts_slices ):
1032
1019
if len (cedge ) == 0 :
1033
1020
cedge = cface
1034
1021
else :
1035
- cedge = cedge .repeat (len (xyzlist ), axis = 0 )
1022
+ cedge = cedge .repeat (len (verts_slices ), axis = 0 )
1036
1023
1037
- if xyzlist :
1038
- # sort by depth (furthest drawn first)
1024
+ if verts_slices :
1039
1025
z_segments_2d = sorted (
1040
- ((self ._zsortfunc (zs ), np . column_stack ([ xs , ys ]) , fc , ec , idx )
1041
- for idx , (( xs , ys , zs ) , fc , ec )
1042
- in enumerate (zip (xyzlist , cface , cedge ))),
1043
- key = lambda x : x [0 ], reverse = True )
1026
+ ((self ._zsortfunc (verts [:, 2 ] ), verts [:, : 2 ] , fc , ec , idx )
1027
+ for idx , (verts , fc , ec )
1028
+ in enumerate (zip (verts_slices , cface , cedge ))),
1029
+ key = lambda x : x [0 ], reverse = True )
1044
1030
1045
1031
_ , segments_2d , self ._facecolors2d , self ._edgecolors2d , idxs = \
1046
1032
zip (* z_segments_2d )
@@ -1061,14 +1047,12 @@ def do_3d_projection(self):
1061
1047
1062
1048
# Return zorder value
1063
1049
if self ._sort_zpos is not None :
1064
- zvec = np .array ([[0 ], [0 ], [self ._sort_zpos ], [1 ]])
1065
- ztrans = proj3d ._proj_transform_vec (zvec , self .axes .M )
1066
- return ztrans [2 ][0 ]
1067
- elif tzs .size > 0 :
1050
+ return self .axes .M .transform ([0 , 0 , self ._sort_zpos ])[2 ]
1051
+ elif len (verts ) > 0 :
1068
1052
# FIXME: Some results still don't look quite right.
1069
1053
# In particular, examine contourf3d_demo2.py
1070
1054
# with az = -54 and elev = -45.
1071
- return np .min (tzs )
1055
+ return np .min (verts [:, 2 ] )
1072
1056
else :
1073
1057
return np .nan
1074
1058
0 commit comments