From 6e8ccbef733afe7458f9b8eba640efcb2ef48585 Mon Sep 17 00:00:00 2001 From: Benjamin Root Date: Mon, 4 Dec 2017 12:53:57 -0500 Subject: [PATCH] First try at allowing an option for all faces of a voxel to be drawn. Can only get 5 of the 6 faces, though... --- lib/mpl_toolkits/mplot3d/axes3d.py | 13 +++++++++-- lib/mpl_toolkits/tests/test_mplot3d.py | 31 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index cb5e7dbfede2..79a47e905062 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2753,6 +2753,12 @@ def voxels(self, *args, **kwargs): - A 4D ndarray of rgb/rgba data, with the components along the last axis. + internal_faces : boolean + By default, only exposed faces of a voxel are rendered, + but you can force the rendering of all faces of the voxels + by setting this keyword argument to True. + .. versionadded:: 2.1 + **kwargs Additional keyword arguments to pass onto :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` @@ -2823,6 +2829,9 @@ def _broadcast_color_arg(color, name): edgecolors = kwargs.pop('edgecolors', None) edgecolors = _broadcast_color_arg(edgecolors, 'edgecolors') + # include possibly occluded internal faces or not + internal_faces = kwargs.pop('internal_faces', False) + # always scale to the full array, even if the data is only in the center self.auto_scale_xyz(x, y, z) @@ -2875,9 +2884,9 @@ def permutation_matrices(n): i1 = tuple(p1) i2 = tuple(p2) - if filled[i1] and not filled[i2]: + if filled[i1] and (internal_faces or not filled[i2]): voxel_faces[i1].append(p2 + square_rot) - elif not filled[i1] and filled[i2]: + elif (internal_faces or not filled[i1]) and filled[i2]: voxel_faces[i2].append(p2 + square_rot) # draw upper faces diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index c157433c752a..0aee5b14eeb2 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -655,6 +655,37 @@ def test_alpha(self): assert voxels[coord], "faces returned for absent voxel" assert isinstance(poly, art3d.Poly3DCollection) + @image_comparison( + baseline_images=['voxels-internal-faces'], + extensions=['png'], + remove_text=True + ) + def test_internal_faces(self): + # Create 3 voxels (with one of them nearly invisible) + # and adjust the view so that we can see if the adjacent + # voxels are drawn or not. + fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) + + test_data = np.array( + [[[ 0., 1], + [ 0., 2]], + + [[ 0., 0.], + [ 0., 1]]]) + alphas = np.divide(test_data, np.max(test_data))/2.0 + colors = np.empty(test_data.shape + (4,)) + colors[:, :, :] = [1, 0, 0, 1.0] + colors[:, :, :, 3] = alphas + + v = ax.voxels(test_data, facecolors=colors, internal_faces=True) + ax.view_init(azim=45, elev=45) + + assert type(v) is dict + assert len(v) == 3 + for coord, poly in v.items(): + assert isinstance(poly, art3d.Poly3DCollection) + assert len(poly.get_paths()) == 6, "voxel %s is wrong" % (coord,) + @image_comparison( baseline_images=['voxels-xyz'], extensions=['png'],