@@ -598,19 +598,20 @@ def set_3d_properties(self, zs, zdir):
598
598
# Force the collection to initialize the face and edgecolors
599
599
# just in case it is a scalarmappable with a colormap.
600
600
self .update_scalarmappable ()
601
- offsets = self .get_offsets ()
601
+ offsets = super () .get_offsets ()
602
602
if len (offsets ) > 0 :
603
603
xs , ys = offsets .T
604
604
else :
605
605
xs = []
606
606
ys = []
607
- self ._offsets3d = juggle_axes (xs , ys , np .atleast_1d (zs ), zdir )
607
+ self ._zdir = zdir
608
+ self .set_offsets3d (np .ma .column_stack ((xs , ys , np .atleast_1d (zs ))), zdir )
608
609
self ._z_markers_idx = slice (- 1 )
609
610
self ._vzs = None
610
611
self .stale = True
611
612
612
613
def do_3d_projection (self ):
613
- xs , ys , zs = self ._offsets3d
614
+ xs , ys , zs = self .get_offsets3d ()
614
615
vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
615
616
self .axes .M )
616
617
self ._vzs = vzs
@@ -642,6 +643,30 @@ def get_edgecolor(self):
642
643
return self .get_facecolor ()
643
644
return self ._maybe_depth_shade_and_sort_colors (super ().get_edgecolor ())
644
645
646
+ def set_offsets3d (self , offsets , zdir = 'z' ):
647
+ """
648
+ Set the 3d offsets for the collection.
649
+
650
+ Parameters
651
+ ----------
652
+ offsets : (N, 3) or (3,) array-like
653
+ The offsets to be set.
654
+ zdir : {'x', 'y', 'z'}
655
+ The axis in which to place the offsets. Default: 'z'.
656
+ See `.get_dir_vector` for a description of the values.
657
+ """
658
+ return _set_offsets3d (self , offsets , zdir )
659
+
660
+ def get_offsets3d (self ):
661
+ """Return the 3d offsets for the collection.
662
+
663
+ Returns
664
+ -------
665
+ offsets : (N, 3) array
666
+ The offsets for the collection.
667
+ """
668
+ return _get_offsets3d (self )
669
+
645
670
646
671
class Path3DCollection (PathCollection ):
647
672
"""
@@ -696,13 +721,13 @@ def set_3d_properties(self, zs, zdir):
696
721
# Force the collection to initialize the face and edgecolors
697
722
# just in case it is a scalarmappable with a colormap.
698
723
self .update_scalarmappable ()
699
- offsets = self .get_offsets ()
724
+ offsets = super () .get_offsets ()
700
725
if len (offsets ) > 0 :
701
726
xs , ys = offsets .T
702
727
else :
703
728
xs = []
704
729
ys = []
705
- self ._offsets3d = juggle_axes ( xs , ys , np .atleast_1d (zs ), zdir )
730
+ self .set_offsets3d ( np . ma . column_stack (( xs , ys , np .atleast_1d (zs )) ), zdir )
706
731
# In the base draw methods we access the attributes directly which
707
732
# means we cannot resolve the shuffling in the getter methods like
708
733
# we do for the edge and face colors.
@@ -715,7 +740,6 @@ def set_3d_properties(self, zs, zdir):
715
740
# Grab the current sizes and linewidths to preserve them.
716
741
self ._sizes3d = self ._sizes
717
742
self ._linewidths3d = np .array (self ._linewidths )
718
- xs , ys , zs = self ._offsets3d
719
743
720
744
# Sort the points based on z coordinates
721
745
# Performance optimization: Create a sorted index array and reorder
@@ -751,7 +775,7 @@ def set_depthshade(self, depthshade):
751
775
self .stale = True
752
776
753
777
def do_3d_projection (self ):
754
- xs , ys , zs = self ._offsets3d
778
+ xs , ys , zs = self .get_offsets3d ()
755
779
vxs , vys , vzs , vis = proj3d .proj_transform_clip (xs , ys , zs ,
756
780
self .axes .M )
757
781
# Sort the points based on z coordinates
@@ -818,6 +842,30 @@ def get_edgecolor(self):
818
842
return self .get_facecolor ()
819
843
return self ._maybe_depth_shade_and_sort_colors (super ().get_edgecolor ())
820
844
845
+ def set_offsets3d (self , offsets , zdir = 'z' ):
846
+ """
847
+ Set the 3d offsets for the collection.
848
+
849
+ Parameters
850
+ ----------
851
+ offsets : (N, 3) or (3,) array-like
852
+ The offsets to be set.
853
+ zdir : {'x', 'y', 'z'}
854
+ The axis in which to place the offsets. Default: 'z'.
855
+ See `.get_dir_vector` for a description of the values.
856
+ """
857
+ return _set_offsets3d (self , offsets , zdir )
858
+
859
+ def get_offsets3d (self ):
860
+ """Return the 3d offsets for the collection.
861
+
862
+ Returns
863
+ -------
864
+ offsets : (N, 3) array
865
+ The offsets for the collection.
866
+ """
867
+ return _get_offsets3d (self )
868
+
821
869
822
870
def patch_collection_2d_to_3d (col , zs = 0 , zdir = 'z' , depthshade = True ):
823
871
"""
@@ -1113,6 +1161,30 @@ def get_edgecolor(self):
1113
1161
self .do_3d_projection ()
1114
1162
return np .asarray (self ._edgecolors2d )
1115
1163
1164
+ def set_offsets3d (self , offsets , zdir = 'z' ):
1165
+ """
1166
+ Set the 3d offsets for the collection.
1167
+
1168
+ Parameters
1169
+ ----------
1170
+ offsets : (N, 3) or (3,) array-like
1171
+ The offsets to be set.
1172
+ zdir : {'x', 'y', 'z'}
1173
+ The axis in which to place the offsets. Default: 'z'.
1174
+ See `.get_dir_vector` for a description of the values.
1175
+ """
1176
+ return _set_offsets3d (self , offsets , zdir )
1177
+
1178
+ def get_offsets3d (self ):
1179
+ """Return the 3d offsets for the collection.
1180
+
1181
+ Returns
1182
+ -------
1183
+ offsets : (N, 3) array
1184
+ The offsets for the collection.
1185
+ """
1186
+ return _get_offsets3d (self )
1187
+
1116
1188
1117
1189
def poly_collection_2d_to_3d (col , zs = 0 , zdir = 'z' ):
1118
1190
"""
@@ -1167,6 +1239,34 @@ def rotate_axes(xs, ys, zs, zdir):
1167
1239
return xs , ys , zs
1168
1240
1169
1241
1242
+ def _set_offsets3d (col_3d , offsets , zdir = 'z' ):
1243
+ """
1244
+ Set the 3d offsets for the collection.
1245
+
1246
+ Parameters
1247
+ ----------
1248
+ offsets : (N, 3) or (3,) array-like
1249
+ The offsets to be set.
1250
+ zdir : {'x', 'y', 'z'}
1251
+ The axis in which to place the offsets. Default: 'z'.
1252
+ See `.get_dir_vector` for a description of the values.
1253
+ """
1254
+ offsets = np .asanyarray (offsets )
1255
+ if offsets .shape == (3 ,): # Broadcast (3,) -> (1, 3) but nothing else.
1256
+ offsets = offsets [None , :]
1257
+ xs = np .asanyarray (col_3d .convert_xunits (offsets [:, 0 ]), float )
1258
+ ys = np .asanyarray (col_3d .convert_yunits (offsets [:, 1 ]), float )
1259
+ zs = np .asanyarray (col_3d .convert_yunits (offsets [:, 2 ]), float )
1260
+ col_3d ._offsets3d = juggle_axes (xs , ys , np .atleast_1d (zs ), zdir )
1261
+ col_3d .stale = True
1262
+
1263
+
1264
+ def _get_offsets3d (col3d ):
1265
+ """Return the offsets for the collection."""
1266
+ # Default to zeros in the no-offset (None) case
1267
+ return np .zeros ((1 , 3 )) if col3d ._offsets3d is None else col3d ._offsets3d
1268
+
1269
+
1170
1270
def _zalpha (colors , zs ):
1171
1271
"""Modify the alphas of the color list according to depth."""
1172
1272
# FIXME: This only works well if the points for *zs* are well-spaced
0 commit comments