diff --git a/doc/api/next_api_changes/2019-02-EW.rst b/doc/api/next_api_changes/2019-02-EW.rst new file mode 100644 index 000000000000..14c7d933f384 --- /dev/null +++ b/doc/api/next_api_changes/2019-02-EW.rst @@ -0,0 +1,5 @@ +``Axes3D.voxels`` now shades the resulting voxels +------------------------------------------------- + +See Whats new for details. The previous behavior can be achieved by passing +``shade=False``. diff --git a/doc/users/next_whats_new/2019-01-06-shaded-voxels.rst b/doc/users/next_whats_new/2019-01-06-shaded-voxels.rst new file mode 100644 index 000000000000..6a12b673007d --- /dev/null +++ b/doc/users/next_whats_new/2019-01-06-shaded-voxels.rst @@ -0,0 +1,42 @@ +``Axes3D.voxels`` now shades the resulting voxels +------------------------------------------------- + +The :meth:`~mpl_toolkits.mplot3d.Axes3D.voxels` method now takes a ``shade`` +parameter that defaults to ``True``. This shades faces based on their +orientation, behaving just like the matching parameters to +:meth:`~mpl_toolkits.mplot3d.Axes3D.trisurf` and +:meth:`~mpl_toolkits.mplot3d.Axes3D.bar3d`. +The plot below shows how this affects the output. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + from mpl_toolkits.mplot3d import Axes3D # noqa: F401 unused import + + # prepare some coordinates + x, y, z = np.indices((8, 8, 8)) + + # draw cuboids in the top left and bottom right corners, and a link between them + cube1 = (x < 3) & (y < 3) & (z < 3) + cube2 = (x >= 5) & (y >= 5) & (z >= 5) + link = abs(x - y) + abs(y - z) + abs(z - x) <= 2 + + # combine the objects into a single boolean array + voxels = cube1 | cube2 | link + + # set the colors of each object + colors = np.empty(voxels.shape, dtype=object) + colors[link] = 'red' + colors[cube1] = 'blue' + colors[cube2] = 'green' + + # and plot everything + fig = plt.figure(figsize=plt.figaspect(0.5)) + ax, ax_shaded = fig.subplots(1, 2, subplot_kw=dict(projection='3d')) + ax.voxels(voxels, facecolors=colors, edgecolor='k', shade=False) + ax.set_title("Unshaded") + ax_shaded.voxels(voxels, facecolors=colors, edgecolor='k', shade=True) + ax_shaded.set_title("Shaded (default)") + + plt.show() diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 43b5897b4229..763e44c50220 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2729,7 +2729,8 @@ def calc_arrow(uvw, angle=15): quiver3D = quiver - def voxels(self, *args, facecolors=None, edgecolors=None, **kwargs): + def voxels(self, *args, facecolors=None, edgecolors=None, shade=True, + lightsource=None, **kwargs): """ ax.voxels([x, y, z,] /, filled, **kwargs) @@ -2776,6 +2777,17 @@ def voxels(self, *args, facecolors=None, edgecolors=None, **kwargs): - A 4D ndarray of rgb/rgba data, with the components along the last axis. + shade : bool + Whether to shade the facecolors. Defaults to True. Shading is + always disabled when *cmap* is specified. + + .. versionadded:: 3.1 + + lightsource : `~matplotlib.colors.LightSource` + The lightsource to use when *shade* is True. + + .. versionadded:: 3.1 + **kwargs Additional keyword arguments to pass onto :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` @@ -2849,9 +2861,9 @@ def _broadcast_color_arg(color, name): # points lying on corners of a square square = np.array([ [0, 0, 0], - [0, 1, 0], + [1, 0, 0], [1, 1, 0], - [1, 0, 0] + [0, 1, 0], ], dtype=np.intp) voxel_faces = defaultdict(list) @@ -2872,7 +2884,8 @@ def permutation_matrices(n): qinds = np.arange(qc) rinds = np.arange(rc) - square_rot = square.dot(permute.T) + square_rot_pos = square.dot(permute.T) + square_rot_neg = square_rot_pos[::-1] # iterate within the current plane for p in pinds: @@ -2885,7 +2898,7 @@ def permutation_matrices(n): p0 = permute.dot([p, q, 0]) i0 = tuple(p0) if filled[i0]: - voxel_faces[i0].append(p0 + square_rot) + voxel_faces[i0].append(p0 + square_rot_neg) # draw middle faces for r1, r2 in zip(rinds[:-1], rinds[1:]): @@ -2896,16 +2909,16 @@ def permutation_matrices(n): i2 = tuple(p2) if filled[i1] and not filled[i2]: - voxel_faces[i1].append(p2 + square_rot) + voxel_faces[i1].append(p2 + square_rot_pos) elif not filled[i1] and filled[i2]: - voxel_faces[i2].append(p2 + square_rot) + voxel_faces[i2].append(p2 + square_rot_neg) # draw upper faces pk = permute.dot([p, q, rc-1]) pk2 = permute.dot([p, q, rc]) ik = tuple(pk) if filled[ik]: - voxel_faces[ik].append(pk2 + square_rot) + voxel_faces[ik].append(pk2 + square_rot_pos) # iterate over the faces, and generate a Poly3DCollection for each # voxel @@ -2924,9 +2937,20 @@ def permutation_matrices(n): face[:, 2] = z[ind] faces.append(face) + # shade the faces + facecolor = facecolors[coord] + edgecolor = edgecolors[coord] + if shade: + normals = self._generate_normals(faces) + facecolor = self._shade_colors(facecolor, normals, lightsource) + if edgecolor is not None: + edgecolor = self._shade_colors( + edgecolor, normals, lightsource + ) + poly = art3d.Poly3DCollection(faces, - facecolors=facecolors[coord], - edgecolors=edgecolors[coord], + facecolors=facecolor, + edgecolors=edgecolor, **kwargs ) self.add_collection3d(poly) diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-alpha.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-alpha.png index ed84237b5450..1b1348d0ab40 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-alpha.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-alpha.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-edge-style.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-edge-style.png index c4dc28a988de..fddbf5fe7353 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-edge-style.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-edge-style.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-named-colors.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-named-colors.png index 6a139acc5e2d..16758aae1428 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-named-colors.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-named-colors.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-rgb-data.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-rgb-data.png index ab8308cead26..2fa5ceb28398 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-rgb-data.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-rgb-data.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-simple.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-simple.png index 9889a775bfed..b23da1a36784 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-simple.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-simple.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-xyz.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-xyz.png index 4e2ecc61462e..c69443628aaa 100644 Binary files a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-xyz.png and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/voxels-xyz.png differ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy