Skip to content

Commit bbd244b

Browse files
get_offsets3d and set_offsets3d
1 parent 8f296db commit bbd244b

File tree

2 files changed

+114
-7
lines changed

2 files changed

+114
-7
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
3D Collections have `set_offset3d` and `get_offset3d` methods
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
All 3D Collections (`Patch3DCollection`, `Path3DCollection`,
5+
`Poly3DCollection`) now have `set_offset3d` and `get_offset3d` methods
6+
which allow you to set and get the offset of the collection in data
7+
coordinates. In other words, this allows you to set and get the position of the
8+
of the collection points.

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -598,19 +598,20 @@ def set_3d_properties(self, zs, zdir):
598598
# Force the collection to initialize the face and edgecolors
599599
# just in case it is a scalarmappable with a colormap.
600600
self.update_scalarmappable()
601-
offsets = self.get_offsets()
601+
offsets = super().get_offsets()
602602
if len(offsets) > 0:
603603
xs, ys = offsets.T
604604
else:
605605
xs = []
606606
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)
608609
self._z_markers_idx = slice(-1)
609610
self._vzs = None
610611
self.stale = True
611612

612613
def do_3d_projection(self):
613-
xs, ys, zs = self._offsets3d
614+
xs, ys, zs = self.get_offsets3d()
614615
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
615616
self.axes.M)
616617
self._vzs = vzs
@@ -642,6 +643,29 @@ def get_edgecolor(self):
642643
return self.get_facecolor()
643644
return self._maybe_depth_shade_and_sort_colors(super().get_edgecolor())
644645

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)
645669

646670
class Path3DCollection(PathCollection):
647671
"""
@@ -696,13 +720,13 @@ def set_3d_properties(self, zs, zdir):
696720
# Force the collection to initialize the face and edgecolors
697721
# just in case it is a scalarmappable with a colormap.
698722
self.update_scalarmappable()
699-
offsets = self.get_offsets()
723+
offsets = super().get_offsets()
700724
if len(offsets) > 0:
701725
xs, ys = offsets.T
702726
else:
703727
xs = []
704728
ys = []
705-
self._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir)
729+
self.set_offsets3d(np.ma.column_stack((xs, ys, np.atleast_1d(zs))), zdir)
706730
# In the base draw methods we access the attributes directly which
707731
# means we cannot resolve the shuffling in the getter methods like
708732
# we do for the edge and face colors.
@@ -715,7 +739,6 @@ def set_3d_properties(self, zs, zdir):
715739
# Grab the current sizes and linewidths to preserve them.
716740
self._sizes3d = self._sizes
717741
self._linewidths3d = np.array(self._linewidths)
718-
xs, ys, zs = self._offsets3d
719742

720743
# Sort the points based on z coordinates
721744
# Performance optimization: Create a sorted index array and reorder
@@ -751,7 +774,7 @@ def set_depthshade(self, depthshade):
751774
self.stale = True
752775

753776
def do_3d_projection(self):
754-
xs, ys, zs = self._offsets3d
777+
xs, ys, zs = self.get_offsets3d()
755778
vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs,
756779
self.axes.M)
757780
# Sort the points based on z coordinates
@@ -818,6 +841,30 @@ def get_edgecolor(self):
818841
return self.get_facecolor()
819842
return self._maybe_depth_shade_and_sort_colors(super().get_edgecolor())
820843

844+
def set_offsets3d(self, offsets, zdir='z'):
845+
"""
846+
Set the 3d offsets for the collection.
847+
848+
Parameters
849+
----------
850+
offsets : (N, 3) or (3,) array-like
851+
The offsets to be set.
852+
zdir : {'x', 'y', 'z'}
853+
The axis in which to place the offsets. Default: 'z'.
854+
See `.get_dir_vector` for a description of the values.
855+
"""
856+
return _set_offsets3d(self, offsets, zdir)
857+
858+
def get_offsets3d(self):
859+
"""Return the 3d offsets for the collection.
860+
861+
Returns
862+
-------
863+
offsets : (N, 3) array
864+
The offsets for the collection.
865+
"""
866+
return _get_offsets3d(self)
867+
821868

822869
def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True):
823870
"""
@@ -1113,6 +1160,30 @@ def get_edgecolor(self):
11131160
self.do_3d_projection()
11141161
return np.asarray(self._edgecolors2d)
11151162

1163+
def set_offsets3d(self, offsets, zdir='z'):
1164+
"""
1165+
Set the 3d offsets for the collection.
1166+
1167+
Parameters
1168+
----------
1169+
offsets : (N, 3) or (3,) array-like
1170+
The offsets to be set.
1171+
zdir : {'x', 'y', 'z'}
1172+
The axis in which to place the offsets. Default: 'z'.
1173+
See `.get_dir_vector` for a description of the values.
1174+
"""
1175+
return _set_offsets3d(self, offsets, zdir)
1176+
1177+
def get_offsets3d(self):
1178+
"""Return the 3d offsets for the collection.
1179+
1180+
Returns
1181+
-------
1182+
offsets : (N, 3) array
1183+
The offsets for the collection.
1184+
"""
1185+
return _get_offsets3d(self)
1186+
11161187

11171188
def poly_collection_2d_to_3d(col, zs=0, zdir='z'):
11181189
"""
@@ -1167,6 +1238,34 @@ def rotate_axes(xs, ys, zs, zdir):
11671238
return xs, ys, zs
11681239

11691240

1241+
def _set_offsets3d(col_3d, offsets, zdir='z'):
1242+
"""
1243+
Set the 3d offsets for the collection.
1244+
1245+
Parameters
1246+
----------
1247+
offsets : (N, 3) or (3,) array-like
1248+
The offsets to be set.
1249+
zdir : {'x', 'y', 'z'}
1250+
The axis in which to place the offsets. Default: 'z'.
1251+
See `.get_dir_vector` for a description of the values.
1252+
"""
1253+
offsets = np.asanyarray(offsets)
1254+
if offsets.shape == (3,): # Broadcast (3,) -> (1, 3) but nothing else.
1255+
offsets = offsets[None, :]
1256+
xs = np.asanyarray(col_3d.convert_xunits(offsets[:, 0]), float)
1257+
ys = np.asanyarray(col_3d.convert_yunits(offsets[:, 1]), float)
1258+
zs = np.asanyarray(col_3d.convert_yunits(offsets[:, 2]), float)
1259+
col_3d._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir)
1260+
col_3d.stale = True
1261+
1262+
1263+
def _get_offsets3d(col3d):
1264+
"""Return the offsets for the collection."""
1265+
# Default to zeros in the no-offset (None) case
1266+
return np.zeros((1, 3)) if col3d._offsets3d is None else col3d._offsets3d
1267+
1268+
11701269
def _zalpha(colors, zs):
11711270
"""Modify the alphas of the color list according to depth."""
11721271
# FIXME: This only works well if the points for *zs* are well-spaced

0 commit comments

Comments
 (0)