|
19 | 19 | import matplotlib.collections as mcoll |
20 | 20 | from matplotlib import docstring |
21 | 21 | import matplotlib.scale as mscale |
| 22 | +from matplotlib.tri.triangulation import Triangulation |
22 | 23 | import numpy as np |
23 | 24 | from matplotlib.colors import Normalize, colorConverter, LightSource |
24 | 25 |
|
@@ -1570,6 +1571,94 @@ def plot_wireframe(self, X, Y, Z, *args, **kwargs): |
1570 | 1571 |
|
1571 | 1572 | return linec |
1572 | 1573 |
|
| 1574 | + def plot_trisurf(self, X, Y, Z, *args, **kwargs): |
| 1575 | + ''' |
| 1576 | + ============= ================================================ |
| 1577 | + Argument Description |
| 1578 | + ============= ================================================ |
| 1579 | + *X*, *Y*, *Z* Data values as 1D arrays |
| 1580 | + *color* Color of the surface patches |
| 1581 | + *cmap* A colormap for the surface patches. |
| 1582 | + *norm* An instance of Normalize to map values to colors |
| 1583 | + *vmin* Minimum value to map |
| 1584 | + *vmax* Maximum value to map |
| 1585 | + *shade* Whether to shade the facecolors |
| 1586 | + ============= ================================================ |
| 1587 | +
|
| 1588 | + Other arguments are passed on to |
| 1589 | + :class:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection` |
| 1590 | + ''' |
| 1591 | + |
| 1592 | + had_data = self.has_data() |
| 1593 | + |
| 1594 | + # TODO: Support custom face colours |
| 1595 | + color = np.array(colorConverter.to_rgba(kwargs.pop('color', 'b'))) |
| 1596 | + |
| 1597 | + cmap = kwargs.get('cmap', None) |
| 1598 | + norm = kwargs.pop('norm', None) |
| 1599 | + vmin = kwargs.pop('vmin', None) |
| 1600 | + vmax = kwargs.pop('vmax', None) |
| 1601 | + linewidth = kwargs.get('linewidth', None) |
| 1602 | + shade = kwargs.pop('shade', cmap is None) |
| 1603 | + lightsource = kwargs.pop('lightsource', None) |
| 1604 | + |
| 1605 | + # TODO: Support masked triangulations |
| 1606 | + tri = Triangulation(X, Y) |
| 1607 | + x = tri.x |
| 1608 | + y = tri.y |
| 1609 | + triangles = tri.triangles |
| 1610 | + |
| 1611 | + xt = x[triangles][...,np.newaxis] |
| 1612 | + yt = y[triangles][...,np.newaxis] |
| 1613 | + zt = np.array(Z)[triangles][...,np.newaxis] |
| 1614 | + |
| 1615 | + verts = np.concatenate((xt, yt, zt), axis=2) |
| 1616 | + |
| 1617 | + # Only need these vectors to shade if there is no cmap |
| 1618 | + if cmap is None and shade: |
| 1619 | + totpts = len(verts) |
| 1620 | + v1 = np.empty((totpts, 3)) |
| 1621 | + v2 = np.empty((totpts, 3)) |
| 1622 | + # This indexes the vertex points |
| 1623 | + which_pt = 0 |
| 1624 | + |
| 1625 | + colset = [] |
| 1626 | + for i in xrange(len(verts)): |
| 1627 | + avgzsum = verts[i,0,2] + verts[i,1,2] + verts[i,2,2] |
| 1628 | + colset.append(avgzsum / 3.0) |
| 1629 | + |
| 1630 | + # Only need vectors to shade if no cmap |
| 1631 | + if cmap is None and shade: |
| 1632 | + v1[which_pt] = np.array(verts[i,0]) - np.array(verts[i,1]) |
| 1633 | + v2[which_pt] = np.array(verts[i,1]) - np.array(verts[i,2]) |
| 1634 | + which_pt += 1 |
| 1635 | + |
| 1636 | + if cmap is None and shade: |
| 1637 | + normals = np.cross(v1, v2) |
| 1638 | + else: |
| 1639 | + normals = [] |
| 1640 | + |
| 1641 | + polyc = art3d.Poly3DCollection(verts, *args, **kwargs) |
| 1642 | + |
| 1643 | + if cmap: |
| 1644 | + colset = np.array(colset) |
| 1645 | + polyc.set_array(colset) |
| 1646 | + if vmin is not None or vmax is not None: |
| 1647 | + polyc.set_clim(vmin, vmax) |
| 1648 | + if norm is not None: |
| 1649 | + polyc.set_norm(norm) |
| 1650 | + else: |
| 1651 | + if shade: |
| 1652 | + colset = self._shade_colors(color, normals) |
| 1653 | + else: |
| 1654 | + colset = color |
| 1655 | + polyc.set_facecolors(colset) |
| 1656 | + |
| 1657 | + self.add_collection(polyc) |
| 1658 | + self.auto_scale_xyz(X, Y, Z, had_data) |
| 1659 | + |
| 1660 | + return polyc |
| 1661 | + |
1573 | 1662 | def _3d_extend_contour(self, cset, stride=5): |
1574 | 1663 | ''' |
1575 | 1664 | Extend a contour in 3D by creating |
|
0 commit comments