@@ -1668,15 +1668,13 @@ def plot_surface(self, X, Y, Z, *, norm=None, vmin=None,
16681668
16691669 # note that the striding causes some polygons to have more coordinates
16701670 # than others
1671- polyc = art3d .Poly3DCollection (polys , ** kwargs )
16721671
16731672 if fcolors is not None :
1674- if shade :
1675- colset = self ._shade_colors (
1676- colset , self ._generate_normals (polys ), lightsource )
1677- polyc .set_facecolors (colset )
1678- polyc .set_edgecolors (colset )
1673+ polyc = art3d .Poly3DCollection (
1674+ polys , edgecolors = colset , facecolors = colset , shade = shade ,
1675+ lightsource = lightsource , ** kwargs )
16791676 elif cmap :
1677+ polyc = art3d .Poly3DCollection (polys , ** kwargs )
16801678 # can't always vectorize, because polys might be jagged
16811679 if isinstance (polys , np .ndarray ):
16821680 avg_z = polys [..., 2 ].mean (axis = - 1 )
@@ -1688,97 +1686,15 @@ def plot_surface(self, X, Y, Z, *, norm=None, vmin=None,
16881686 if norm is not None :
16891687 polyc .set_norm (norm )
16901688 else :
1691- if shade :
1692- colset = self ._shade_colors (
1693- color , self ._generate_normals (polys ), lightsource )
1694- else :
1695- colset = color
1696- polyc .set_facecolors (colset )
1689+ polyc = art3d .Poly3DCollection (
1690+ polys , facecolors = color , shade = shade ,
1691+ lightsource = lightsource , ** kwargs )
16971692
16981693 self .add_collection (polyc )
16991694 self .auto_scale_xyz (X , Y , Z , had_data )
17001695
17011696 return polyc
17021697
1703- def _generate_normals (self , polygons ):
1704- """
1705- Compute the normals of a list of polygons.
1706-
1707- Normals point towards the viewer for a face with its vertices in
1708- counterclockwise order, following the right hand rule.
1709-
1710- Uses three points equally spaced around the polygon.
1711- This normal of course might not make sense for polygons with more than
1712- three points not lying in a plane, but it's a plausible and fast
1713- approximation.
1714-
1715- Parameters
1716- ----------
1717- polygons : list of (M_i, 3) array-like, or (..., M, 3) array-like
1718- A sequence of polygons to compute normals for, which can have
1719- varying numbers of vertices. If the polygons all have the same
1720- number of vertices and array is passed, then the operation will
1721- be vectorized.
1722-
1723- Returns
1724- -------
1725- normals : (..., 3) array
1726- A normal vector estimated for the polygon.
1727- """
1728- if isinstance (polygons , np .ndarray ):
1729- # optimization: polygons all have the same number of points, so can
1730- # vectorize
1731- n = polygons .shape [- 2 ]
1732- i1 , i2 , i3 = 0 , n // 3 , 2 * n // 3
1733- v1 = polygons [..., i1 , :] - polygons [..., i2 , :]
1734- v2 = polygons [..., i2 , :] - polygons [..., i3 , :]
1735- else :
1736- # The subtraction doesn't vectorize because polygons is jagged.
1737- v1 = np .empty ((len (polygons ), 3 ))
1738- v2 = np .empty ((len (polygons ), 3 ))
1739- for poly_i , ps in enumerate (polygons ):
1740- n = len (ps )
1741- i1 , i2 , i3 = 0 , n // 3 , 2 * n // 3
1742- v1 [poly_i , :] = ps [i1 , :] - ps [i2 , :]
1743- v2 [poly_i , :] = ps [i2 , :] - ps [i3 , :]
1744- return np .cross (v1 , v2 )
1745-
1746- def _shade_colors (self , color , normals , lightsource = None ):
1747- """
1748- Shade *color* using normal vectors given by *normals*.
1749- *color* can also be an array of the same length as *normals*.
1750- """
1751- if lightsource is None :
1752- # chosen for backwards-compatibility
1753- lightsource = mcolors .LightSource (azdeg = 225 , altdeg = 19.4712 )
1754-
1755- with np .errstate (invalid = "ignore" ):
1756- shade = ((normals / np .linalg .norm (normals , axis = 1 , keepdims = True ))
1757- @ lightsource .direction )
1758- mask = ~ np .isnan (shade )
1759-
1760- if mask .any ():
1761- # convert dot product to allowed shading fractions
1762- in_norm = mcolors .Normalize (- 1 , 1 )
1763- out_norm = mcolors .Normalize (0.3 , 1 ).inverse
1764-
1765- def norm (x ):
1766- return out_norm (in_norm (x ))
1767-
1768- shade [~ mask ] = 0
1769-
1770- color = mcolors .to_rgba_array (color )
1771- # shape of color should be (M, 4) (where M is number of faces)
1772- # shape of shade should be (M,)
1773- # colors should have final shape of (M, 4)
1774- alpha = color [:, 3 ]
1775- colors = norm (shade )[:, np .newaxis ] * color
1776- colors [:, 3 ] = alpha
1777- else :
1778- colors = np .asanyarray (color ).copy ()
1779-
1780- return colors
1781-
17821698 def plot_wireframe (self , X , Y , Z , ** kwargs ):
17831699 """
17841700 Plot a 3D wireframe.
@@ -1975,9 +1891,8 @@ def plot_trisurf(self, *args, color=None, norm=None, vmin=None, vmax=None,
19751891 zt = z [triangles ]
19761892 verts = np .stack ((xt , yt , zt ), axis = - 1 )
19771893
1978- polyc = art3d .Poly3DCollection (verts , * args , ** kwargs )
1979-
19801894 if cmap :
1895+ polyc = art3d .Poly3DCollection (verts , * args , ** kwargs )
19811896 # average over the three points of each triangle
19821897 avg_z = verts [:, :, 2 ].mean (axis = 1 )
19831898 polyc .set_array (avg_z )
@@ -1986,12 +1901,9 @@ def plot_trisurf(self, *args, color=None, norm=None, vmin=None, vmax=None,
19861901 if norm is not None :
19871902 polyc .set_norm (norm )
19881903 else :
1989- if shade :
1990- normals = self ._generate_normals (verts )
1991- colset = self ._shade_colors (color , normals , lightsource )
1992- else :
1993- colset = color
1994- polyc .set_facecolors (colset )
1904+ polyc = art3d .Poly3DCollection (
1905+ verts , * args , shade = shade , lightsource = lightsource ,
1906+ facecolors = color , ** kwargs )
19951907
19961908 self .add_collection (polyc )
19971909 self .auto_scale_xyz (tri .x , tri .y , z , had_data )
@@ -2036,13 +1948,10 @@ def _3d_extend_contour(self, cset, stride=5):
20361948
20371949 # all polygons have 4 vertices, so vectorize
20381950 polyverts = np .array (polyverts )
2039- normals = self ._generate_normals (polyverts )
2040-
2041- colors = self ._shade_colors (color , normals )
2042- colors2 = self ._shade_colors (color , normals )
20431951 polycol = art3d .Poly3DCollection (polyverts ,
2044- facecolors = colors ,
2045- edgecolors = colors2 )
1952+ facecolors = color ,
1953+ edgecolors = color ,
1954+ shade = True )
20461955 polycol .set_sort_zpos (z )
20471956 self .add_collection3d (polycol )
20481957
@@ -2587,15 +2496,11 @@ def bar3d(self, x, y, z, dx, dy, dz, color=None,
25872496 if len (facecolors ) < len (x ):
25882497 facecolors *= (6 * len (x ))
25892498
2590- if shade :
2591- normals = self ._generate_normals (polys )
2592- sfacecolors = self ._shade_colors (facecolors , normals , lightsource )
2593- else :
2594- sfacecolors = facecolors
2595-
25962499 col = art3d .Poly3DCollection (polys ,
25972500 zsort = zsort ,
2598- facecolor = sfacecolors ,
2501+ facecolors = facecolors ,
2502+ shade = shade ,
2503+ lightsource = lightsource ,
25992504 * args , ** kwargs )
26002505 self .add_collection (col )
26012506
@@ -2964,16 +2869,10 @@ def permutation_matrices(n):
29642869 # shade the faces
29652870 facecolor = facecolors [coord ]
29662871 edgecolor = edgecolors [coord ]
2967- if shade :
2968- normals = self ._generate_normals (faces )
2969- facecolor = self ._shade_colors (facecolor , normals , lightsource )
2970- if edgecolor is not None :
2971- edgecolor = self ._shade_colors (
2972- edgecolor , normals , lightsource
2973- )
29742872
29752873 poly = art3d .Poly3DCollection (
2976- faces , facecolors = facecolor , edgecolors = edgecolor , ** kwargs )
2874+ faces , facecolors = facecolor , edgecolors = edgecolor ,
2875+ shade = shade , lightsource = lightsource , ** kwargs )
29772876 self .add_collection3d (poly )
29782877 polygons [coord ] = poly
29792878
0 commit comments