From 6a1a6e9c388ae91bb32f0a0b9d735218a41dbeb2 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 9 Feb 2015 15:36:32 -0500 Subject: [PATCH 1/7] FIX: Add get/set color methods for some 3d collections closes #3370 We need to do an extra step to propagate the color information back to the 3D projections --- lib/mpl_toolkits/mplot3d/art3d.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index e936f4f28577..54e9e2867299 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -403,6 +403,16 @@ def __init__(self, *args, zs=0, zdir='z', depthshade=True, **kwargs): super().__init__(*args, **kwargs) self.set_3d_properties(zs, zdir) + def set_facecolor(self, c): + # docstring inherited + super().set_facecolor(c) + self._facecolor3d = self.get_facecolor() + + def set_edgecolor(self, c): + # docstring inherited + super().set_edgecolor(c) + self._edgecolor3d = self.get_edgecolor() + def set_sort_zpos(self, val): """Set the position to use for z-sorting.""" self._sort_zpos = val @@ -491,6 +501,16 @@ def set_3d_properties(self, zs, zdir): self._linewidth3d = self.get_linewidth() self.stale = True + def set_facecolor(self, c): + # docstring inherited + super().set_facecolor(c) + self._facecolor3d = self.get_facecolor() + + def set_edgecolor(self, c): + # docstring inherited + super().set_edgecolor(c) + self._edgecolor3d = self.get_edgecolor() + def do_3d_projection(self, renderer): xs, ys, zs = self._offsets3d vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) @@ -722,10 +742,12 @@ def do_3d_projection(self, renderer): return np.nan def set_facecolor(self, colors): + # docstring inherited super().set_facecolor(colors) self._facecolors3d = PolyCollection.get_facecolor(self) def set_edgecolor(self, colors): + # docstring inherited super().set_edgecolor(colors) self._edgecolors3d = PolyCollection.get_edgecolor(self) From b1eb984dabc4ba5712d10f947c490399fc364b1e Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 16 Sep 2020 03:40:54 -0400 Subject: [PATCH 2/7] Correctly set depthshaded colours on 3D collections. --- lib/mpl_toolkits/mplot3d/art3d.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 54e9e2867299..2298f28ee5ad 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -440,13 +440,13 @@ def do_3d_projection(self, renderer): fcs = (_zalpha(self._facecolor3d, vzs) if self._depthshade else self._facecolor3d) fcs = mcolors.to_rgba_array(fcs, self._alpha) - self.set_facecolors(fcs) + super().set_facecolor(fcs) ecs = (_zalpha(self._edgecolor3d, vzs) if self._depthshade else self._edgecolor3d) ecs = mcolors.to_rgba_array(ecs, self._alpha) - self.set_edgecolors(ecs) - PatchCollection.set_offsets(self, np.column_stack([vxs, vys])) + super().set_edgecolor(ecs) + super().set_offsets(np.column_stack([vxs, vys])) if vzs.size > 0: return min(vzs) @@ -544,8 +544,8 @@ def do_3d_projection(self, renderer): fcs = mcolors.to_rgba_array(fcs, self._alpha) ecs = mcolors.to_rgba_array(ecs, self._alpha) - self.set_edgecolors(ecs) - self.set_facecolors(fcs) + super().set_edgecolor(ecs) + super().set_facecolor(fcs) self.set_sizes(sizes) self.set_linewidth(lws) From b0ac3f3aeb09a3cf3ba209f72860b83e3e356fa6 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 16 Sep 2020 23:51:42 -0400 Subject: [PATCH 3/7] Add tests for 3D collection colour setters. --- lib/mpl_toolkits/tests/test_mplot3d.py | 39 ++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index b68c250496ed..025f1d3d994f 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -243,6 +243,20 @@ def test_scatter3d_color(): color='b', marker='s') +@check_figures_equal(extensions=['png']) +def test_scatter3d_modification(fig_ref, fig_test): + # Changing Path3DCollection properties post-creation should work correctly. + ax_test = fig_test.add_subplot(projection='3d') + c = ax_test.scatter(np.arange(10), np.arange(10), np.arange(10), + marker='o') + c.set_facecolor('C1') + c.set_edgecolor('C2') + + ax_ref = fig_ref.add_subplot(projection='3d') + ax_ref.scatter(np.arange(10), np.arange(10), np.arange(10), marker='o', + facecolor='C1', edgecolor='C2') + + @pytest.mark.parametrize('depthshade', [True, False]) @check_figures_equal(extensions=['png']) def test_scatter3d_sorting(fig_ref, fig_test, depthshade): @@ -526,6 +540,25 @@ def test_quiver3d_masked(): ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) +@check_figures_equal(extensions=['png']) +def test_patch_collection_modification(fig_test, fig_ref): + # Test that modifying Patch3DCollection properties after creation works. + patch = Circle((0, 0), 0.05) + c = art3d.Patch3DCollection([patch], linewidths=3) + + ax_test = fig_test.add_subplot(projection='3d') + ax_test.add_collection3d(c) + c.set_edgecolor('C2') + c.set_facecolor('C3') + + patch = Circle((0, 0), 0.05) + c = art3d.Patch3DCollection([patch], linewidths=3, + edgecolor='C2', facecolor='C3') + + ax_ref = fig_ref.add_subplot(projection='3d') + ax_ref.add_collection3d(c) + + @mpl3d_image_comparison(['poly3dcollection_closed.png']) def test_poly3dcollection_closed(): fig = plt.figure() @@ -558,8 +591,10 @@ def test_poly3dcollection_alpha(): c1 = art3d.Poly3DCollection([poly1], linewidths=3, edgecolor='k', facecolor=(0.5, 0.5, 1), closed=True) c1.set_alpha(0.5) - c2 = art3d.Poly3DCollection([poly2], linewidths=3, edgecolor='k', - facecolor=(1, 0.5, 0.5), closed=False) + c2 = art3d.Poly3DCollection([poly2], linewidths=3, closed=False) + # Post-creation modification should work. + c2.set_facecolor((1, 0.5, 0.5)) + c2.set_edgecolor('k') c2.set_alpha(0.5) ax.add_collection3d(c1) ax.add_collection3d(c2) From e6d9cbb5a4b1fc14faea0a9474a61ca8556f7110 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 17 Sep 2020 02:12:04 -0400 Subject: [PATCH 4/7] Add setters for more overridden 3D collection properties. --- lib/mpl_toolkits/mplot3d/art3d.py | 14 ++++++++++++-- lib/mpl_toolkits/tests/test_mplot3d.py | 4 +++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 2298f28ee5ad..f5b661715e5f 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -511,6 +511,16 @@ def set_edgecolor(self, c): super().set_edgecolor(c) self._edgecolor3d = self.get_edgecolor() + def set_sizes(self, sizes, dpi=72.0): + # docstring inherited + super().set_sizes(sizes, dpi=dpi) + self._sizes3d = self.get_sizes() + + def set_linewidth(self, lw): + # docstring inherited + super().set_linewidth(lw) + self._linewidth3d = self.get_linewidth() + def do_3d_projection(self, renderer): xs, ys, zs = self._offsets3d vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) @@ -546,8 +556,8 @@ def do_3d_projection(self, renderer): super().set_edgecolor(ecs) super().set_facecolor(fcs) - self.set_sizes(sizes) - self.set_linewidth(lws) + super().set_sizes(sizes) + super().set_linewidth(lws) PathCollection.set_offsets(self, vps) diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 025f1d3d994f..c26a8a96a4b0 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -251,10 +251,12 @@ def test_scatter3d_modification(fig_ref, fig_test): marker='o') c.set_facecolor('C1') c.set_edgecolor('C2') + c.set_sizes(np.full(10, 75)) + c.set_linewidths(3) ax_ref = fig_ref.add_subplot(projection='3d') ax_ref.scatter(np.arange(10), np.arange(10), np.arange(10), marker='o', - facecolor='C1', edgecolor='C2') + facecolor='C1', edgecolor='C2', s=75, linewidths=3) @pytest.mark.parametrize('depthshade', [True, False]) From 264f5c91e5ecc6362085d07f1c2ccf3f144a6773 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 17 Sep 2020 03:05:04 -0400 Subject: [PATCH 5/7] Add accessors for 3D collection's depth shading. --- lib/mpl_toolkits/mplot3d/art3d.py | 32 ++++++++++++++++++++++++++ lib/mpl_toolkits/tests/test_mplot3d.py | 10 ++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index f5b661715e5f..d930b52966c9 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -403,6 +403,22 @@ def __init__(self, *args, zs=0, zdir='z', depthshade=True, **kwargs): super().__init__(*args, **kwargs) self.set_3d_properties(zs, zdir) + def get_depthshade(self): + return self._depthshade + + def set_depthshade(self, depthshade): + """ + Set whether depth shading is performed on collection members. + + Parameters + ---------- + depthshade : bool + Whether to shade the patches in order to give the appearance of + depth. + """ + self._depthshade = depthshade + self.stale = True + def set_facecolor(self, c): # docstring inherited super().set_facecolor(c) @@ -501,6 +517,22 @@ def set_3d_properties(self, zs, zdir): self._linewidth3d = self.get_linewidth() self.stale = True + def get_depthshade(self): + return self._depthshade + + def set_depthshade(self, depthshade): + """ + Set whether depth shading is performed on collection members. + + Parameters + ---------- + depthshade : bool + Whether to shade the patches in order to give the appearance of + depth. + """ + self._depthshade = depthshade + self.stale = True + def set_facecolor(self, c): # docstring inherited super().set_facecolor(c) diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index c26a8a96a4b0..fbe6b61e63a6 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -251,12 +251,15 @@ def test_scatter3d_modification(fig_ref, fig_test): marker='o') c.set_facecolor('C1') c.set_edgecolor('C2') + c.set_alpha([0.3, 0.7] * 5) + c.set_depthshade(False) c.set_sizes(np.full(10, 75)) c.set_linewidths(3) ax_ref = fig_ref.add_subplot(projection='3d') ax_ref.scatter(np.arange(10), np.arange(10), np.arange(10), marker='o', - facecolor='C1', edgecolor='C2', s=75, linewidths=3) + facecolor='C1', edgecolor='C2', alpha=[0.3, 0.7] * 5, + depthshade=False, s=75, linewidths=3) @pytest.mark.parametrize('depthshade', [True, False]) @@ -552,10 +555,13 @@ def test_patch_collection_modification(fig_test, fig_ref): ax_test.add_collection3d(c) c.set_edgecolor('C2') c.set_facecolor('C3') + c.set_alpha(0.7) + c.set_depthshade(False) patch = Circle((0, 0), 0.05) c = art3d.Patch3DCollection([patch], linewidths=3, - edgecolor='C2', facecolor='C3') + edgecolor='C2', facecolor='C3', alpha=0.7, + depthshade=False) ax_ref = fig_ref.add_subplot(projection='3d') ax_ref.add_collection3d(c) From 7cc0b869b65b7ada754b5b6074bba80d8f85802a Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 17 Sep 2020 03:10:34 -0400 Subject: [PATCH 6/7] Add a what's new entry for 3D collection modification. --- doc/users/next_whats_new/mplot3d_modification.rst | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 doc/users/next_whats_new/mplot3d_modification.rst diff --git a/doc/users/next_whats_new/mplot3d_modification.rst b/doc/users/next_whats_new/mplot3d_modification.rst new file mode 100644 index 000000000000..0ed3735a0e3b --- /dev/null +++ b/doc/users/next_whats_new/mplot3d_modification.rst @@ -0,0 +1,8 @@ +3D Collection properties are now modifiable +------------------------------------------- + +Previously, properties of a 3D Collection that were used for 3D effects (e.g., +colors were modified to produce depth shading) could not be changed after it +was created. + +Now it is possible to modify all properties of 3D Collections at any time. From 021dd9bb5153d820106a915d47baea8c5797522c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 23 Sep 2020 15:28:58 -0400 Subject: [PATCH 7/7] TST: exercise get_depthshade --- lib/mpl_toolkits/tests/test_mplot3d.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index fbe6b61e63a6..8a6e5228296f 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -252,7 +252,9 @@ def test_scatter3d_modification(fig_ref, fig_test): c.set_facecolor('C1') c.set_edgecolor('C2') c.set_alpha([0.3, 0.7] * 5) + assert c.get_depthshade() c.set_depthshade(False) + assert not c.get_depthshade() c.set_sizes(np.full(10, 75)) c.set_linewidths(3) @@ -556,7 +558,9 @@ def test_patch_collection_modification(fig_test, fig_ref): c.set_edgecolor('C2') c.set_facecolor('C3') c.set_alpha(0.7) + assert c.get_depthshade() c.set_depthshade(False) + assert not c.get_depthshade() patch = Circle((0, 0), 0.05) c = art3d.Patch3DCollection([patch], linewidths=3,