Skip to content

Commit f580423

Browse files
Apply suggestions from code review
Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com> Docstrings and typos Code review updates varname varname
1 parent e353a99 commit f580423

File tree

3 files changed

+80
-94
lines changed

3 files changed

+80
-94
lines changed

doc/users/next_whats_new/depthshading_improvement.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@ items could lead to sudden and unexpected changes in transparency as the plot
66
orientation changed.
77

88
Now, the behavior has been made smooth and predictable. A new parameter
9-
``depthshade_minalpha`` has also been added to allow users to set the minimum
9+
*depthshade_minalpha* has also been added to allow users to set the minimum
1010
transparency level. Depth-shading is an option for Patch3DCollections and
1111
Path3DCollections, including 3D scatter plots.
1212

13-
The default values for ``depthshade`` and ``depthshade_minalpha`` are now also
13+
The default values for *depthshade* and *depthshade_minalpha* are now also
1414
controlled via rcParams, with values of ``True`` and ``0.3`` respectively.
1515

1616
A simple example:
1717

1818
.. plot::
19+
:include-source: true
20+
:alt: 3D scatter plot with depth shading
21+
1922
import matplotlib.pyplot as plt
2023

2124
fig = plt.figure()

lib/mpl_toolkits/mplot3d/art3d.py

Lines changed: 68 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from matplotlib import (
1717
_api, artist, cbook, colors as mcolors, lines, text as mtext,
18-
path as mpath, rcParams)
18+
path as mpath, _val_or_rc)
1919
from matplotlib.collections import (
2020
Collection, LineCollection, PolyCollection, PatchCollection, PathCollection)
2121
from matplotlib.patches import Patch
@@ -646,31 +646,36 @@ def __init__(
646646
:class:`~matplotlib.collections.PatchCollection`. In addition,
647647
keywords *zs=0* and *zdir='z'* are available.
648648
649-
The keyword argument *depthshade* is available to
650-
indicate whether or not to shade the patches in order to
651-
give the appearance of depth (default is *True*).
652-
This is typically desired in scatter plots.
653-
654-
*depthshade_minalpha* sets the minimum alpha value applied by
655-
depth-shading.
649+
Parameters
650+
----------
651+
zs : float or array of floats
652+
The location or locations to place the patches in the collection
653+
along the *zdir* axis.
654+
zdir : {'x', 'y', 'z'}
655+
Plane to plot patches orthogonal to.
656+
All patches must have the same direction.
657+
See `.get_dir_vector` for a description of the values.
658+
depthshade : bool, default: :rc:`axes3d.depthshade`
659+
Whether to shade the patches in order to give the appearance of
660+
depth.
661+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
662+
Sets the minimum alpha value used by depth-shading.
663+
axlim_clip : bool, default: False
664+
Whether to hide patches with a vertex outside the axes view limits.
665+
kwargs :
666+
Additional keyword arguments are the same as for
667+
:class:`~matplotlib.collections.PatchCollection`.
656668
"""
657-
if depthshade is None:
658-
depthshade = rcParams['axes3d.depthshade']
659-
if depthshade_minalpha is None:
660-
depthshade_minalpha = rcParams['axes3d.depthshade_minalpha']
661-
self._depthshade = depthshade
662-
self._depthshade_minalpha = depthshade_minalpha
669+
self._depthshade = _val_or_rc(depthshade, 'axes3d.depthshade')
670+
self._depthshade_minalpha = _val_or_rc(depthshade_minalpha,
671+
'axes3d.depthshade_minalpha')
663672
super().__init__(*args, **kwargs)
664673
self.set_3d_properties(zs, zdir, axlim_clip)
665674

666675
def get_depthshade(self):
667676
return self._depthshade
668677

669-
def set_depthshade(
670-
self,
671-
depthshade,
672-
depthshade_minalpha=None,
673-
):
678+
def set_depthshade(self, depthshade, depthshade_minalpha=None):
674679
"""
675680
Set whether depth shading is performed on collection members.
676681
@@ -679,14 +684,12 @@ def set_depthshade(
679684
depthshade : bool
680685
Whether to shade the patches in order to give the appearance of
681686
depth.
682-
depthshade_minalpha : float, default: None
687+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
683688
Sets the minimum alpha value used by depth-shading.
684-
If None, use the value from rcParams['axes3d.depthshade_minalpha'].
685689
"""
686-
if depthshade_minalpha is None:
687-
depthshade_minalpha = rcParams['axes3d.depthshade_minalpha']
688690
self._depthshade = depthshade
689-
self._depthshade_minalpha = depthshade_minalpha
691+
self._depthshade_minalpha = _val_or_rc(depthshade_minalpha,
692+
'axes3d.depthshade_minalpha')
690693
self.stale = True
691694

692695
def set_sort_zpos(self, val):
@@ -743,11 +746,7 @@ def do_3d_projection(self):
743746

744747
def _maybe_depth_shade_and_sort_colors(self, color_array):
745748
color_array = (
746-
_zalpha(
747-
color_array,
748-
self._vzs,
749-
min_alpha=self._depthshade_minalpha,
750-
)
749+
_zalpha(color_array, self._vzs, min_alpha=self._depthshade_minalpha)
751750
if self._vzs is not None and self._depthshade
752751
else color_array
753752
)
@@ -776,18 +775,12 @@ def _get_data_scale(X, Y, Z):
776775
X, Y, Z : masked arrays
777776
The data to estimate the scale of.
778777
"""
779-
# Account for empty datasets. Assume that X Y and Z have the same number
780-
# of elements.
781-
if not np.ma.count(X):
778+
# Account for empty datasets.
779+
if not np.ma.count(X) or not np.ma.count(Y) or not np.ma.count(Z):
782780
return 0
783781

784782
# Estimate the scale using the RSS of the ranges of the dimensions
785-
# Note that we don't use np.ma.ptp() because we otherwise get a build
786-
# warning about handing empty arrays.
787-
ptp_x = X.max() - X.min()
788-
ptp_y = Y.max() - Y.min()
789-
ptp_z = Z.max() - Z.min()
790-
return np.sqrt(ptp_x ** 2 + ptp_y ** 2 + ptp_z ** 2)
783+
return np.sqrt(np.ma.ptp(X) ** 2 + np.ma.ptp(Y) ** 2 + np.ma.ptp(Z) ** 2)
791784

792785

793786
class Path3DCollection(PathCollection):
@@ -815,20 +808,29 @@ def __init__(
815808
:class:`~matplotlib.collections.PathCollection`. In addition,
816809
keywords *zs=0* and *zdir='z'* are available.
817810
818-
Also, the keyword argument *depthshade* is available to
819-
indicate whether or not to shade the patches in order to
820-
give the appearance of depth (default is *True*).
821-
This is typically desired in scatter plots.
822-
823-
*depthshade_minalpha* sets the minimum alpha value applied by
824-
depth-shading.
811+
Parameters
812+
----------
813+
zs : float or array of floats
814+
The location or locations to place the paths in the collection
815+
along the *zdir* axis.
816+
zdir : {'x', 'y', 'z'}
817+
Vector to plot paths orthogonal to.
818+
All paths must have the same direction.
819+
See `.get_dir_vector` for a description of the values.
820+
depthshade : bool, default: :rc:`axes3d.depthshade`
821+
Whether to shade the paths in order to give the appearance of
822+
depth.
823+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
824+
Sets the minimum alpha value used by depth-shading.
825+
axlim_clip : bool, default: False
826+
Whether to hide paths with a vertex outside the axes view limits.
827+
kwargs :
828+
Additional keyword arguments are the same as for
829+
:class:`~matplotlib.collections.PathCollection`.
825830
"""
826-
if depthshade is None:
827-
depthshade = rcParams['axes3d.depthshade']
828-
if depthshade_minalpha is None:
829-
depthshade_minalpha = rcParams['axes3d.depthshade_minalpha']
830-
self._depthshade = depthshade
831-
self._depthshade_minalpha = depthshade_minalpha
831+
self._depthshade = _val_or_rc(depthshade, 'axes3d.depthshade')
832+
self._depthshade_minalpha = _val_or_rc(depthshade_minalpha,
833+
'axes3d.depthshade_minalpha')
832834
self._in_draw = False
833835
super().__init__(*args, **kwargs)
834836
self.set_3d_properties(zs, zdir, axlim_clip)
@@ -854,7 +856,7 @@ def set_3d_properties(self, zs, zdir, axlim_clip=False):
854856
The location or locations to place the paths in the collection
855857
along the *zdir* axis.
856858
zdir : {'x', 'y', 'z'}
857-
Plane to plot paths orthogonal to.
859+
Vector to plot paths orthogonal to.
858860
All paths must have the same direction.
859861
See `.get_dir_vector` for a description of the values.
860862
axlim_clip : bool, default: False
@@ -907,11 +909,7 @@ def set_linewidth(self, lw):
907909
def get_depthshade(self):
908910
return self._depthshade
909911

910-
def set_depthshade(
911-
self,
912-
depthshade,
913-
depthshade_minalpha=None,
914-
):
912+
def set_depthshade(self, depthshade, depthshade_minalpha=None):
915913
"""
916914
Set whether depth shading is performed on collection members.
917915
@@ -920,13 +918,12 @@ def set_depthshade(
920918
depthshade : bool
921919
Whether to shade the patches in order to give the appearance of
922920
depth.
923-
depthshade_minalpha : float
921+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
924922
Sets the minimum alpha value used by depth-shading.
925923
"""
926-
if depthshade_minalpha is None:
927-
depthshade_minalpha = rcParams['axes3d.depthshade_minalpha']
928924
self._depthshade = depthshade
929-
self._depthshade_minalpha = depthshade_minalpha
925+
self._depthshade_minalpha = _val_or_rc(depthshade_minalpha,
926+
'axes3d.depthshade_minalpha')
930927
self.stale = True
931928

932929
def do_3d_projection(self):
@@ -989,15 +986,15 @@ def _maybe_depth_shade_and_sort_colors(self, color_array):
989986
color_array,
990987
self._vzs,
991988
min_alpha=self._depthshade_minalpha,
992-
_data_scale=self._data_scale,
989+
data_scale=self._data_scale,
993990
)
994991

995992
# Adjust the order of the color_array using the _z_markers_idx,
996993
# which has been sorted by z-depth
997994
if len(color_array) > 1:
998995
color_array = color_array[self._z_markers_idx]
999996

1000-
return mcolors.to_rgba_array(color_array)
997+
return mcolors.to_rgba_array(color_array, self._alpha)
1001998

1002999
def get_facecolor(self):
10031000
return self._maybe_depth_shade_and_sort_colors(super().get_facecolor())
@@ -1017,7 +1014,7 @@ def patch_collection_2d_to_3d(
10171014
zdir="z",
10181015
depthshade=None,
10191016
axlim_clip=False,
1020-
*args,
1017+
*,
10211018
depthshade_minalpha=None,
10221019
):
10231020
"""
@@ -1035,12 +1032,10 @@ def patch_collection_2d_to_3d(
10351032
zdir : {'x', 'y', 'z'}
10361033
The axis in which to place the patches. Default: "z".
10371034
See `.get_dir_vector` for a description of the values.
1038-
depthshade : bool, default: None
1035+
depthshade : bool, default: :rc:`axes3d.depthshade`
10391036
Whether to shade the patches to give a sense of depth.
1040-
If None, use the value from rcParams['axes3d.depthshade'].
1041-
depthshade_minalpha : float, default: None
1037+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
10421038
Sets the minimum alpha value used by depth-shading.
1043-
If None, use the value from rcParams['axes3d.depthshade_minalpha'].
10441039
axlim_clip : bool, default: False
10451040
Whether to hide patches with a vertex outside the axes view limits.
10461041
"""
@@ -1049,12 +1044,9 @@ def patch_collection_2d_to_3d(
10491044
col._offset_zordered = None
10501045
elif isinstance(col, PatchCollection):
10511046
col.__class__ = Patch3DCollection
1052-
if depthshade is None:
1053-
depthshade = rcParams['axes3d.depthshade']
1054-
if depthshade_minalpha is None:
1055-
depthshade_minalpha = rcParams['axes3d.depthshade_minalpha']
10561047
col._depthshade = depthshade
1057-
col._depthshade_minalpha = depthshade_minalpha
1048+
col._depthshade_minalpha = _val_or_rc(depthshade_minalpha,
1049+
'axes3d.depthshade_minalpha')
10581050
col._in_draw = False
10591051
col.set_3d_properties(zs, zdir, axlim_clip)
10601052

@@ -1395,12 +1387,7 @@ def rotate_axes(xs, ys, zs, zdir):
13951387
return xs, ys, zs
13961388

13971389

1398-
def _zalpha(
1399-
colors,
1400-
zs,
1401-
min_alpha=0.3,
1402-
_data_scale=None,
1403-
):
1390+
def _zalpha(colors, zs, min_alpha=0.3, data_scale=None):
14041391
"""Modify the alphas of the color list according to depth."""
14051392

14061393
if len(colors) == 0 or len(zs) == 0:
@@ -1409,13 +1396,13 @@ def _zalpha(
14091396
# Alpha values beyond the range 0-1 inclusive make no sense, so clip them
14101397
min_alpha = np.clip(min_alpha, 0, 1)
14111398

1412-
if _data_scale is None or _data_scale == 0:
1399+
if data_scale is None or data_scale == 0:
14131400
# Don't scale the alpha values since we have no valid data scale for reference
14141401
sats = np.ones_like(zs)
14151402

14161403
else:
14171404
# Deeper points have an increasingly transparent appearance
1418-
sats = np.clip(1 - (zs - min(zs)) / _data_scale, min_alpha, 1)
1405+
sats = np.clip(1 - (zs - min(zs)) / data_scale, min_alpha, 1)
14191406

14201407
rgba = np.broadcast_to(mcolors.to_rgba_array(colors), (len(zs), 4))
14211408

lib/mpl_toolkits/mplot3d/axes3d.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import numpy as np
2020

2121
import matplotlib as mpl
22-
from matplotlib import _api, cbook, _docstring, _preprocess_data
22+
from matplotlib import _api, cbook, _docstring, _preprocess_data, _val_or_rc
2323
import matplotlib.artist as martist
2424
import matplotlib.collections as mcoll
2525
import matplotlib.colors as mcolors
@@ -2940,15 +2940,12 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=None,
29402940
- A 2D array in which the rows are RGB or RGBA.
29412941
29422942
For more details see the *c* argument of `~.axes.Axes.scatter`.
2943-
depthshade : bool, default: None
2943+
depthshade : bool, default: :rc:`axes3d.depthshade`
29442944
Whether to shade the scatter markers to give the appearance of
29452945
depth. Each call to ``scatter()`` will perform its depthshading
29462946
independently.
2947-
If None, use the value from rcParams['axes3d.depthshade'].
2948-
2949-
depthshade_minalpha : float, default: None
2947+
depthshade_minalpha : float, default: :rc:`axes3d.depthshade_minalpha`
29502948
The lowest alpha value applied by depth-shading.
2951-
If None, use the value from rcParams['axes3d.depthshade_minalpha'].
29522949
axlim_clip : bool, default: False
29532950
Whether to hide the scatter points outside the axes view limits.
29542951
@@ -2976,10 +2973,9 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=None,
29762973
)
29772974
if kwargs.get("color") is not None:
29782975
kwargs['color'] = color
2979-
if depthshade is None:
2980-
depthshade = mpl.rcParams['axes3d.depthshade']
2981-
if depthshade_minalpha is None:
2982-
depthshade_minalpha = mpl.rcParams['axes3d.depthshade_minalpha']
2976+
depthshade = _val_or_rc(depthshade, 'axes3d.depthshade')
2977+
depthshade_minalpha = _val_or_rc(depthshade_minalpha,
2978+
'axes3d.depthshade_minalpha')
29832979

29842980
# For xs and ys, 2D scatter() will do the copying.
29852981
if np.may_share_memory(zs_orig, zs): # Avoid unnecessary copies.
@@ -4033,7 +4029,7 @@ def stem(self, x, y, z, *, linefmt='C0-', markerfmt='C0o', basefmt='C3-',
40334029

40344030
# Determine style for stem lines.
40354031
linestyle, linemarker, linecolor = _process_plot_format(linefmt)
4036-
linestyle = mpl._val_or_rc(linestyle, 'lines.linestyle')
4032+
linestyle = _val_or_rc(linestyle, 'lines.linestyle')
40374033

40384034
# Plot everything in required order.
40394035
baseline, = self.plot(basex, basey, basefmt, zs=bottom,

0 commit comments

Comments
 (0)