diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 39727ca60614..bdb05754dbe2 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -84,7 +84,7 @@ def draw(self, renderer): [self._position3d, self._position3d + self._dir_vec], renderer.M) dx = proj[0][1] - proj[0][0] dy = proj[1][1] - proj[1][0] - if dx==0. and dy==0.: + if dx == 0. and dy == 0.: # atan2 raises ValueError: math domain error on 0,0 angle = 0. else: @@ -200,7 +200,8 @@ class Line3DCollection(LineCollection): def __init__(self, segments, *args, **kwargs): ''' - Keyword arguments are passed onto :func:`~matplotlib.collections.LineCollection`. + Keyword arguments are passed onto + :func:`~matplotlib.collections.LineCollection`. ''' LineCollection.__init__(self, segments, *args, **kwargs) @@ -309,7 +310,7 @@ def do_3d_projection(self, renderer): def get_patch_verts(patch): """Return a list of vertices for the path of a patch.""" trans = patch.get_patch_transform() - path = patch.get_path() + path = patch.get_path() polygons = path.to_polygons(trans) if len(polygons): return polygons[0] @@ -449,6 +450,52 @@ def set_3d_properties(self, zs, zdir): self._edgecolor3d = self.get_edgecolor() self.stale = True + def set_facecolor(self, colors): + ''' + Override setter for facecolor so that 3dfacecolor + will be updated as well. + In providing consitentcy in 2dcolor and 3dcolor setter. + Note: will also update edgecolor if it follows facecolor + ''' + + PathCollection.set_facecolor(self, colors) + self._facecolor3d = PathCollection.get_facecolor(self) + try: + # Will update edge color together if it follows facecolor + if (isinstance(self._edgecolors, six.string_types) and + self._edgecolors == str('face')): + self.set_edgecolor(colors) + except AttributeError: + pass + set_facecolors = set_facecolor + + def set_edgecolor(self, colors): + ''' + Override setter for edgecolor so that 3dedgecolor + will be updated as well. + In providing consitentcy in 2dcolor and 3dcolor setter. + ''' + + PathCollection.set_edgecolor(self, colors) + self._edgecolor3d = PathCollection.get_edgecolor(self) + set_edgecolors = set_edgecolor + + def _set_facecolor_on_projection(self, color): + ''' + A sepearted method that changes edgecolor in drawing + as in this case, we dont change 3d facecolor + ''' + + super().set_facecolor(color) + + def _set_edgecolor_on_projection(self, color): + ''' + A sepearted method that changes edgecolor in drawing + as in this case, we dont change 3d edgecolor + ''' + + super().set_edgecolor(color) + def do_3d_projection(self, renderer): xs, ys, zs = self._offsets3d vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) @@ -456,17 +503,17 @@ 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) + self._set_facecolor_on_projection(fcs) ecs = (zalpha(self._edgecolor3d, vzs) if self._depthshade else self._edgecolor3d) ecs = mcolors.to_rgba_array(ecs, self._alpha) - self.set_edgecolors(ecs) + self._set_edgecolor_on_projection(ecs) PathCollection.set_offsets(self, np.column_stack([vxs, vys])) - if vzs.size > 0 : + if vzs.size > 0: return min(vzs) - else : + else: return np.nan @@ -561,7 +608,7 @@ def get_vector(self, segments3d): if len(segments3d): xs, ys, zs = zip(*points) - else : + else: # We need this so that we can skip the bad unpacking from zip() xs, ys, zs = [], [], [] @@ -595,7 +642,7 @@ def set_3d_properties(self): self._alpha3d = PolyCollection.get_alpha(self) self.stale = True - def set_sort_zpos(self,val): + def set_sort_zpos(self, val): '''Set the position to use for z-sorting.''' self._sort_zpos = val self.stale = True @@ -652,12 +699,12 @@ def do_3d_projection(self, renderer): zvec = np.array([[0], [0], [self._sort_zpos], [1]]) ztrans = proj3d.proj_transform_vec(zvec, renderer.M) return ztrans[2][0] - elif tzs.size > 0 : + elif tzs.size > 0: # FIXME: Some results still don't look quite right. # In particular, examine contourf3d_demo2.py # with az = -54 and elev = -45. return np.min(tzs) - else : + else: return np.nan def set_facecolor(self, colors): diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_edgecolor_nochange.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_edgecolor_nochange.png new file mode 100644 index 000000000000..31e73a3d9dea Binary files /dev/null and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_edgecolor_nochange.png differ diff --git a/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_face_color_change.png b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_face_color_change.png new file mode 100644 index 000000000000..3de79ab4140e Binary files /dev/null and b/lib/mpl_toolkits/tests/baseline_images/test_mplot3d/scatter_face_color_change.png differ diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 31dc5a40ed79..3cbb2ed6be2b 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -175,6 +175,32 @@ def test_scatter3d_color(): color='b', marker='s') +@image_comparison(baseline_images=['scatter_face_color_change'], + remove_text=True, extensions=['png']) +def test_scatter_face_color_change(): + # Take the test data from above + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + scat = ax.scatter(np.arange(10), np.arange(10), np.arange(10), + facecolors="red") + # changes facecolor, it should also change edgecolor when displayed + scat.set_facecolors("green") + + +@image_comparison(baseline_images=['scatter_edgecolor_nochange'], + remove_text=True, extensions=['png']) +def test_scatter_edgecolor_nochange(): + # test to ensure edge color is not updated with facecolor if it + # is set at the beginning + # Take the test data from above + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + scat = ax.scatter(np.arange(10), np.arange(10), np.arange(10), + facecolors="red", edgecolors="blue") + # changes facecolor, it should not change edgecolor when displayed + scat.set_edgecolors("green") + + @image_comparison(baseline_images=['surface3d'], remove_text=True) def test_surface3d(): fig = plt.figure() @@ -305,10 +331,11 @@ def test_quiver3d(): u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * - np.sin(np.pi * z)) + np.sin(np.pi * z)) ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) + @image_comparison(baseline_images=['quiver3d_empty'], remove_text=True) def test_quiver3d_empty(): fig = plt.figure() @@ -319,10 +346,11 @@ def test_quiver3d_empty(): u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * - np.sin(np.pi * z)) + np.sin(np.pi * z)) ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) + @image_comparison(baseline_images=['quiver3d_masked'], remove_text=True) def test_quiver3d_masked(): fig = plt.figure() @@ -335,12 +363,13 @@ def test_quiver3d_masked(): u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * - np.sin(np.pi * z)) + np.sin(np.pi * z)) u = np.ma.masked_where((-0.4 < x) & (x < 0.1), u, copy=False) v = np.ma.masked_where((0.1 < y) & (y < 0.7), v, copy=False) ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tip', normalize=True) + @image_comparison(baseline_images=['quiver3d_pivot_middle'], remove_text=True, extensions=['png']) def test_quiver3d_pivot_middle(): @@ -352,10 +381,11 @@ def test_quiver3d_pivot_middle(): u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * - np.sin(np.pi * z)) + np.sin(np.pi * z)) ax.quiver(x, y, z, u, v, w, length=0.1, pivot='middle', normalize=True) + @image_comparison(baseline_images=['quiver3d_pivot_tail'], remove_text=True, extensions=['png']) def test_quiver3d_pivot_tail(): @@ -367,7 +397,7 @@ def test_quiver3d_pivot_tail(): u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z) v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z) w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * - np.sin(np.pi * z)) + np.sin(np.pi * z)) ax.quiver(x, y, z, u, v, w, length=0.1, pivot='tail', normalize=True) @@ -414,17 +444,18 @@ def test_axes3d_labelpad(): def test_axes3d_cla(): # fixed in pull request 4553 fig = plt.figure() - ax = fig.add_subplot(1,1,1, projection='3d') + ax = fig.add_subplot(1, 1, 1, projection='3d') ax.set_axis_off() ax.cla() # make sure the axis displayed is 3D (not 2D) + def test_plotsurface_1d_raises(): x = np.linspace(0.5, 10, num=100) y = np.linspace(0.5, 10, num=100) X, Y = np.meshgrid(x, y) z = np.random.randn(100) - fig = plt.figure(figsize=(14,6)) + fig = plt.figure(figsize=(14, 6)) ax = fig.add_subplot(1, 2, 1, projection='3d') with pytest.raises(ValueError): ax.plot_surface(X, Y, z) @@ -523,6 +554,7 @@ def test_proj_axes_cube_ortho(): ax.set_xlim(-200, 200) ax.set_ylim(-200, 200) + def test_rot(): V = [1, 0, 0, 1] rotated_V = proj3d.rot_x(V, np.pi / 6) @@ -663,9 +695,9 @@ def test_rgb_data(self): x, y, z = np.indices((10, 10, 10)) voxels = (x == y) | (y == z) colors = np.zeros((10, 10, 10, 3)) - colors[...,0] = x/9.0 - colors[...,1] = y/9.0 - colors[...,2] = z/9.0 + colors[..., 0] = x/9.0 + colors[..., 1] = y/9.0 + colors[..., 2] = z/9.0 ax.voxels(voxels, facecolors=colors) @image_comparison(