diff --git a/doc/users/next_whats_new/depthshading_improvement.rst b/doc/users/next_whats_new/depthshading_improvement.rst new file mode 100644 index 000000000000..d22d9624731a --- /dev/null +++ b/doc/users/next_whats_new/depthshading_improvement.rst @@ -0,0 +1,41 @@ +3D depth-shading fix +-------------------- + +Previously, a slightly buggy method of estimating the visual "depth" of 3D +items could lead to sudden and unexpected changes in transparency as the plot +orientation changed. + +Now, the behavior has been made smooth and predictable. A new parameter +``depthshade_minalpha`` has also been added to allow users to set the minimum +transparency level. Depth-shading is an option for Patch3DCollections and +Path3DCollections, including 3D scatter plots. + +The default values for ``depthshade`` and ``depthshade_minalpha`` are now also +controlled via rcParams, with values of ``True`` and ``0.3`` respectively. + +A simple example: + +.. plot:: + :include-source: true + :alt: A 3D scatter plot with depth-shading enabled. + + import matplotlib.pyplot as plt + + fig = plt.figure() + ax = fig.add_subplot(projection="3d") + + X = [i for i in range(10)] + Y = [i for i in range(10)] + Z = [i for i in range(10)] + S = [(i + 1) * 400 for i in range(10)] + + ax.scatter( + xs=X, + ys=Y, + zs=Z, + s=S, + depthshade=True, + depthshade_minalpha=0.3, + ) + + plt.show() diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc index cc498dc69a9c..ab412302f3b2 100644 --- a/lib/matplotlib/mpl-data/matplotlibrc +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -439,6 +439,9 @@ #axes3d.yaxis.panecolor: (0.90, 0.90, 0.90, 0.5) # background pane on 3D axes #axes3d.zaxis.panecolor: (0.925, 0.925, 0.925, 0.5) # background pane on 3D axes +#axes3d.depthshade: True # depth shade for 3D scatter plots +#axes3d.depthshade_minalpha: 0.3 # minimum alpha value for depth shading + #axes3d.mouserotationstyle: arcball # {azel, trackball, sphere, arcball} # See also https://matplotlib.org/stable/api/toolkits/mplot3d/view_angles.html#rotation-with-mouse #axes3d.trackballsize: 0.667 # trackball diameter, in units of the Axes bbox diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle index 50516d831ae4..6cba66076ac7 100644 --- a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle @@ -225,6 +225,8 @@ axes.spines.top : True polaraxes.grid : True # display grid on polar axes axes3d.grid : True # display grid on 3D axes axes3d.automargin : False # automatically add margin when manually setting 3D axis limits +axes3d.depthshade : False # depth shade for 3D scatter plots +axes3d.depthshade_minalpha : 0.3 # minimum alpha value for depth shading date.autoformatter.year : %Y date.autoformatter.month : %b %Y diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index e35517b07d19..d927e93fae8b 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1133,6 +1133,9 @@ def _convert_validator_spec(key, conv): "axes3d.yaxis.panecolor": validate_color, # 3d background pane "axes3d.zaxis.panecolor": validate_color, # 3d background pane + "axes3d.depthshade": validate_bool, # depth shade for 3D scatter plots + "axes3d.depthshade_minalpha": validate_float, # min alpha value for depth shading + "axes3d.mouserotationstyle": ["azel", "trackball", "sphere", "arcball"], "axes3d.trackballsize": validate_float, "axes3d.trackballborder": validate_float, diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 39ca835c7687..2571e6447f5c 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -15,10 +15,9 @@ from matplotlib import ( _api, artist, cbook, colors as mcolors, lines, text as mtext, - path as mpath) + path as mpath, rcParams) from matplotlib.collections import ( Collection, LineCollection, PolyCollection, PatchCollection, PathCollection) -from matplotlib.colors import Normalize from matplotlib.patches import Patch from . import proj3d @@ -114,6 +113,8 @@ class Text3D(mtext.Text): axlim_clip : bool, default: False Whether to hide text outside the axes view limits. + .. versionadded:: 3.10 + Other Parameters ---------------- **kwargs @@ -170,6 +171,8 @@ def set_3d_properties(self, z=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide text outside the axes view limits. + + .. versionadded:: 3.10 """ self._z = z self._dir_vec = get_dir_vector(zdir) @@ -213,6 +216,8 @@ def text_2d_to_3d(obj, z=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide text outside the axes view limits. + + .. versionadded:: 3.10 """ obj.__class__ = Text3D obj.set_3d_properties(z, zdir, axlim_clip) @@ -261,6 +266,8 @@ def set_3d_properties(self, zs=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide lines with an endpoint outside the axes view limits. + + .. versionadded:: 3.10 """ xs = self.get_xdata() ys = self.get_ydata() @@ -338,6 +345,8 @@ def line_2d_to_3d(line, zs=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide lines with an endpoint outside the axes view limits. + + .. versionadded:: 3.10 """ line.__class__ = Line3D @@ -507,6 +516,8 @@ def __init__(self, *args, zs=(), zdir='z', axlim_clip=False, **kwargs): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide patches with a vertex outside the axes view limits. + + .. versionadded:: 3.10 """ super().__init__(*args, **kwargs) self.set_3d_properties(zs, zdir, axlim_clip) @@ -526,6 +537,8 @@ def set_3d_properties(self, verts, zs=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide patches with a vertex outside the axes view limits. + + .. versionadded:: 3.10 """ zs = np.broadcast_to(zs, len(verts)) self._segment3d = [juggle_axes(x, y, z, zdir) @@ -573,6 +586,8 @@ def __init__(self, path, *, zs=(), zdir='z', axlim_clip=False, **kwargs): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide path patches with a point outside the axes view limits. + + .. versionadded:: 3.10 """ # Not super().__init__! Patch.__init__(self, **kwargs) @@ -593,6 +608,8 @@ def set_3d_properties(self, path, zs=0, zdir='z', axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide path patches with a point outside the axes view limits. + + .. versionadded:: 3.10 """ Patch3D.set_3d_properties(self, path.vertices, zs=zs, zdir=zdir, axlim_clip=axlim_clip) @@ -643,8 +660,16 @@ class Patch3DCollection(PatchCollection): A collection of 3D patches. """ - def __init__(self, *args, - zs=0, zdir='z', depthshade=True, axlim_clip=False, **kwargs): + def __init__( + self, + *args, + zs=0, + zdir="z", + depthshade=None, + depthshade_minalpha=None, + axlim_clip=False, + **kwargs + ): """ Create a collection of flat 3D patches with its normal vector pointed in *zdir* direction, and located at *zs* on the *zdir* @@ -655,18 +680,31 @@ def __init__(self, *args, :class:`~matplotlib.collections.PatchCollection`. In addition, keywords *zs=0* and *zdir='z'* are available. - Also, the keyword argument *depthshade* is available to indicate - whether to shade the patches in order to give the appearance of depth - (default is *True*). This is typically desired in scatter plots. + The keyword argument *depthshade* is available to + indicate whether or not to shade the patches in order to + give the appearance of depth (default is *True*). + This is typically desired in scatter plots. + + *depthshade_minalpha* sets the minimum alpha value applied by + depth-shading. """ + if depthshade is None: + depthshade = rcParams['axes3d.depthshade'] + if depthshade_minalpha is None: + depthshade_minalpha = rcParams['axes3d.depthshade_minalpha'] self._depthshade = depthshade + self._depthshade_minalpha = depthshade_minalpha super().__init__(*args, **kwargs) self.set_3d_properties(zs, zdir, axlim_clip) def get_depthshade(self): return self._depthshade - def set_depthshade(self, depthshade): + def set_depthshade( + self, + depthshade, + depthshade_minalpha=None, + ): """ Set whether depth shading is performed on collection members. @@ -675,8 +713,16 @@ def set_depthshade(self, depthshade): depthshade : bool Whether to shade the patches in order to give the appearance of depth. + depthshade_minalpha : float, default: None + Sets the minimum alpha value used by depth-shading. + If None, use the value from rcParams['axes3d.depthshade_minalpha']. + + .. versionadded:: 3.11 """ + if depthshade_minalpha is None: + depthshade_minalpha = rcParams['axes3d.depthshade_minalpha'] self._depthshade = depthshade + self._depthshade_minalpha = depthshade_minalpha self.stale = True def set_sort_zpos(self, val): @@ -699,6 +745,8 @@ def set_3d_properties(self, zs, zdir, axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide patches with a vertex outside the axes view limits. + + .. versionadded:: 3.10 """ # Force the collection to initialize the face and edgecolors # just in case it is a scalarmappable with a colormap. @@ -737,7 +785,11 @@ def do_3d_projection(self): def _maybe_depth_shade_and_sort_colors(self, color_array): color_array = ( - _zalpha(color_array, self._vzs) + _zalpha( + color_array, + self._vzs, + min_alpha=self._depthshade_minalpha, + ) if self._vzs is not None and self._depthshade else color_array ) @@ -757,13 +809,44 @@ def get_edgecolor(self): return self._maybe_depth_shade_and_sort_colors(super().get_edgecolor()) +def _get_data_scale(X, Y, Z): + """ + Estimate the scale of the 3D data for use in depth shading + + Parameters + ---------- + X, Y, Z : masked arrays + The data to estimate the scale of. + """ + # Account for empty datasets. Assume that X Y and Z have the same number + # of elements. + if not np.ma.count(X): + return 0 + + # Estimate the scale using the RSS of the ranges of the dimensions + # Note that we don't use np.ma.ptp() because we otherwise get a build + # warning about handing empty arrays. + ptp_x = X.max() - X.min() + ptp_y = Y.max() - Y.min() + ptp_z = Z.max() - Z.min() + return np.sqrt(ptp_x ** 2 + ptp_y ** 2 + ptp_z ** 2) + + class Path3DCollection(PathCollection): """ A collection of 3D paths. """ - def __init__(self, *args, - zs=0, zdir='z', depthshade=True, axlim_clip=False, **kwargs): + def __init__( + self, + *args, + zs=0, + zdir="z", + depthshade=None, + depthshade_minalpha=None, + axlim_clip=False, + **kwargs + ): """ Create a collection of flat 3D paths with its normal vector pointed in *zdir* direction, and located at *zs* on the *zdir* @@ -774,11 +857,20 @@ def __init__(self, *args, :class:`~matplotlib.collections.PathCollection`. In addition, keywords *zs=0* and *zdir='z'* are available. - Also, the keyword argument *depthshade* is available to indicate - whether to shade the patches in order to give the appearance of depth - (default is *True*). This is typically desired in scatter plots. + Also, the keyword argument *depthshade* is available to + indicate whether or not to shade the patches in order to + give the appearance of depth (default is *True*). + This is typically desired in scatter plots. + + *depthshade_minalpha* sets the minimum alpha value applied by + depth-shading. """ + if depthshade is None: + depthshade = rcParams['axes3d.depthshade'] + if depthshade_minalpha is None: + depthshade_minalpha = rcParams['axes3d.depthshade_minalpha'] self._depthshade = depthshade + self._depthshade_minalpha = depthshade_minalpha self._in_draw = False super().__init__(*args, **kwargs) self.set_3d_properties(zs, zdir, axlim_clip) @@ -809,6 +901,8 @@ def set_3d_properties(self, zs, zdir, axlim_clip=False): See `.get_dir_vector` for a description of the values. axlim_clip : bool, default: False Whether to hide paths with a vertex outside the axes view limits. + + .. versionadded:: 3.10 """ # Force the collection to initialize the face and edgecolors # just in case it is a scalarmappable with a colormap. @@ -857,7 +951,11 @@ def set_linewidth(self, lw): def get_depthshade(self): return self._depthshade - def set_depthshade(self, depthshade): + def set_depthshade( + self, + depthshade, + depthshade_minalpha=None, + ): """ Set whether depth shading is performed on collection members. @@ -866,8 +964,15 @@ def set_depthshade(self, depthshade): depthshade : bool Whether to shade the patches in order to give the appearance of depth. + depthshade_minalpha : float + Sets the minimum alpha value used by depth-shading. + + .. versionadded:: 3.11 """ + if depthshade_minalpha is None: + depthshade_minalpha = rcParams['axes3d.depthshade_minalpha'] self._depthshade = depthshade + self._depthshade_minalpha = depthshade_minalpha self.stale = True def do_3d_projection(self): @@ -885,6 +990,7 @@ def do_3d_projection(self): vxs, vys, vzs, vis = proj3d._proj_transform_clip(*xyzs, self.axes.M, self.axes._focal_length) + self._data_scale = _get_data_scale(vxs, vys, vzs) # Sort the points based on z coordinates # Performance optimization: Create a sorted index array and reorder # points and point properties according to the index array @@ -929,14 +1035,22 @@ def _use_zordered_offset(self): self._offsets = old_offset def _maybe_depth_shade_and_sort_colors(self, color_array): - color_array = ( - _zalpha(color_array, self._vzs) - if self._vzs is not None and self._depthshade - else color_array - ) + # Adjust the color_array alpha values if point depths are defined + # and depth shading is active + if self._vzs is not None and self._depthshade: + color_array = _zalpha( + color_array, + self._vzs, + min_alpha=self._depthshade_minalpha, + _data_scale=self._data_scale, + ) + + # Adjust the order of the color_array using the _z_markers_idx, + # which has been sorted by z-depth if len(color_array) > 1: color_array = color_array[self._z_markers_idx] - return mcolors.to_rgba_array(color_array, self._alpha) + + return mcolors.to_rgba_array(color_array) def get_facecolor(self): return self._maybe_depth_shade_and_sort_colors(super().get_facecolor()) @@ -950,7 +1064,15 @@ def get_edgecolor(self): return self._maybe_depth_shade_and_sort_colors(super().get_edgecolor()) -def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True, axlim_clip=False): +def patch_collection_2d_to_3d( + col, + zs=0, + zdir="z", + depthshade=None, + axlim_clip=False, + *args, + depthshade_minalpha=None, +): """ Convert a `.PatchCollection` into a `.Patch3DCollection` object (or a `.PathCollection` into a `.Path3DCollection` object). @@ -966,17 +1088,31 @@ def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True, axlim_clip=F zdir : {'x', 'y', 'z'} The axis in which to place the patches. Default: "z". See `.get_dir_vector` for a description of the values. - depthshade : bool, default: True + depthshade : bool, default: None Whether to shade the patches to give a sense of depth. + If None, use the value from rcParams['axes3d.depthshade']. axlim_clip : bool, default: False Whether to hide patches with a vertex outside the axes view limits. + + .. versionadded:: 3.10 + + depthshade_minalpha : float, default: None + Sets the minimum alpha value used by depth-shading. + If None, use the value from rcParams['axes3d.depthshade_minalpha']. + + .. versionadded:: 3.11 """ if isinstance(col, PathCollection): col.__class__ = Path3DCollection col._offset_zordered = None elif isinstance(col, PatchCollection): col.__class__ = Patch3DCollection + if depthshade is None: + depthshade = rcParams['axes3d.depthshade'] + if depthshade_minalpha is None: + depthshade_minalpha = rcParams['axes3d.depthshade_minalpha'] col._depthshade = depthshade + col._depthshade_minalpha = depthshade_minalpha col._in_draw = False col.set_3d_properties(zs, zdir, axlim_clip) @@ -1028,6 +1164,8 @@ def __init__(self, verts, *args, zsort='average', shade=False, axlim_clip : bool, default: False Whether to hide polygons with a vertex outside the view limits. + .. versionadded:: 3.10 + *args, **kwargs All other parameters are forwarded to `.PolyCollection`. @@ -1357,17 +1495,31 @@ def rotate_axes(xs, ys, zs, zdir): return xs, ys, zs -def _zalpha(colors, zs): - """Modify the alphas of the color list according to depth.""" - # FIXME: This only works well if the points for *zs* are well-spaced - # in all three dimensions. Otherwise, at certain orientations, - # the min and max zs are very close together. - # Should really normalize against the viewing depth. +def _zalpha( + colors, + zs, + min_alpha=0.3, + _data_scale=None, +): + """Modify the alpha values of the color list according to z-depth.""" + if len(colors) == 0 or len(zs) == 0: return np.zeros((0, 4)) - norm = Normalize(np.min(zs), np.max(zs)) - sats = 1 - norm(zs) * 0.7 + + # Alpha values beyond the range 0-1 inclusive make no sense, so clip them + min_alpha = np.clip(min_alpha, 0, 1) + + if _data_scale is None or _data_scale == 0: + # Don't scale the alpha values since we have no valid data scale for reference + sats = np.ones_like(zs) + + else: + # Deeper points have an increasingly transparent appearance + sats = np.clip(1 - (zs - np.min(zs)) / _data_scale, min_alpha, 1) + rgba = np.broadcast_to(mcolors.to_rgba_array(colors), (len(zs), 4)) + + # Change the alpha values of the colors using the generated alpha multipliers return np.column_stack([rgba[:, :3], rgba[:, 3] * sats]) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 8ec63aba3349..55b204022fb9 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -2907,9 +2907,11 @@ def add_collection3d(self, col, zs=0, zdir='z', autolim=True, *, @_preprocess_data(replace_names=["xs", "ys", "zs", "s", "edgecolors", "c", "facecolor", "facecolors", "color"]) - def scatter(self, xs, ys, - zs=0, zdir='z', s=20, c=None, depthshade=True, *args, - axlim_clip=False, **kwargs): + def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=None, + *args, + depthshade_minalpha=None, + axlim_clip=False, + **kwargs): """ Create a scatter plot. @@ -2941,16 +2943,26 @@ def scatter(self, xs, ys, - A 2D array in which the rows are RGB or RGBA. For more details see the *c* argument of `~.axes.Axes.scatter`. - depthshade : bool, default: True + depthshade : bool, default: None Whether to shade the scatter markers to give the appearance of depth. Each call to ``scatter()`` will perform its depthshading independently. + If None, use the value from rcParams['axes3d.depthshade']. + + depthshade_minalpha : float, default: None + The lowest alpha value applied by depth-shading. + If None, use the value from rcParams['axes3d.depthshade_minalpha']. + + .. versionadded:: 3.11 + axlim_clip : bool, default: False Whether to hide the scatter points outside the axes view limits. .. versionadded:: 3.10 + data : indexable object, optional DATA_PARAMETER_PLACEHOLDER + **kwargs All other keyword arguments are passed on to `~.axes.Axes.scatter`. @@ -2970,16 +2982,24 @@ def scatter(self, xs, ys, ) if kwargs.get("color") is not None: kwargs['color'] = color + if depthshade is None: + depthshade = mpl.rcParams['axes3d.depthshade'] + if depthshade_minalpha is None: + depthshade_minalpha = mpl.rcParams['axes3d.depthshade_minalpha'] # For xs and ys, 2D scatter() will do the copying. if np.may_share_memory(zs_orig, zs): # Avoid unnecessary copies. zs = zs.copy() patches = super().scatter(xs, ys, s=s, c=c, *args, **kwargs) - art3d.patch_collection_2d_to_3d(patches, zs=zs, zdir=zdir, - depthshade=depthshade, - axlim_clip=axlim_clip) - + art3d.patch_collection_2d_to_3d( + patches, + zs=zs, + zdir=zdir, + depthshade=depthshade, + depthshade_minalpha=depthshade_minalpha, + axlim_clip=axlim_clip, + ) if self._zmargin < 0.05 and xs.size > 0: self.set_zmargin(0.05) diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/quiver3d.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/quiver3d.png index 5d58cea8bccf..af8cc16b14cc 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/quiver3d.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/quiver3d.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d.png index ed8b3831726e..aa15bb95168c 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_color.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_color.png index 2d35d95e68bd..f295ec7132ba 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_color.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_color.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_linewidth.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_linewidth.png index 15cc2d77a2ac..676ee10370f6 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_linewidth.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter3d_linewidth.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter_spiral.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter_spiral.png index 8e8df221d640..ee562e27242b 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter_spiral.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_axes3d/scatter_spiral.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_legend3d/fancy.png b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_legend3d/fancy.png index b9b0fb6ef094..62e7dbc6cdae 100644 Binary files a/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_legend3d/fancy.png and b/lib/mpl_toolkits/mplot3d/tests/baseline_images/test_legend3d/fancy.png differ diff --git a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py index 243f04be61df..065652f47b54 100644 --- a/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py +++ b/lib/mpl_toolkits/mplot3d/tests/test_axes3d.py @@ -409,7 +409,6 @@ def test_tight_layout_text(fig_test, fig_ref): @mpl3d_image_comparison(['scatter3d.png'], style='mpl20') def test_scatter3d(): - plt.rcParams['axes3d.automargin'] = True # Remove when image is regenerated fig = plt.figure() ax = fig.add_subplot(projection='3d') ax.scatter(np.arange(10), np.arange(10), np.arange(10), @@ -423,7 +422,6 @@ def test_scatter3d(): @mpl3d_image_comparison(['scatter3d_color.png'], style='mpl20') def test_scatter3d_color(): - plt.rcParams['axes3d.automargin'] = True # Remove when image is regenerated fig = plt.figure() ax = fig.add_subplot(projection='3d') @@ -467,7 +465,7 @@ 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') + marker='o', depthshade=True) c.set_facecolor('C1') c.set_edgecolor('C2') c.set_alpha([0.3, 0.7] * 5) @@ -483,13 +481,13 @@ def test_scatter3d_modification(fig_ref, fig_test): depthshade=False, s=75, linewidths=3) -@pytest.mark.parametrize('depthshade', [True, False]) @check_figures_equal(extensions=['png']) -def test_scatter3d_sorting(fig_ref, fig_test, depthshade): +def test_scatter3d_sorting(fig_ref, fig_test): """Test that marker properties are correctly sorted.""" y, x = np.mgrid[:10, :10] z = np.arange(x.size).reshape(x.shape) + depthshade = False sizes = np.full(z.shape, 25) sizes[0::2, 0::2] = 100 @@ -890,7 +888,6 @@ def test_mixedsamplesraises(): # remove tolerance when regenerating the test image @mpl3d_image_comparison(['quiver3d.png'], style='mpl20', tol=0.003) def test_quiver3d(): - plt.rcParams['axes3d.automargin'] = True # Remove when image is regenerated fig = plt.figure() ax = fig.add_subplot(projection='3d') pivots = ['tip', 'middle', 'tail'] @@ -968,7 +965,7 @@ def test_patch_collection_modification(fig_test, fig_ref): patch1 = Circle((0, 0), 0.05) patch2 = Circle((0.1, 0.1), 0.03) facecolors = np.array([[0., 0.5, 0., 1.], [0.5, 0., 0., 0.5]]) - c = art3d.Patch3DCollection([patch1, patch2], linewidths=3) + c = art3d.Patch3DCollection([patch1, patch2], linewidths=3, depthshade=True) ax_test = fig_test.add_subplot(projection='3d') ax_test.add_collection3d(c)