使用 Python 的 matplotlib 3D API 的轮廓问题

我正在尝试做一些类似于文档中的 3D 示例的事情,但使用点云而不是光滑表面。该示例将 2D 轮廓投影到三个坐标平面中的每一个平面上。这表明我能够在xy平面上做到这一点。

https://img1.sycdn.imooc.com/65269ea70001cf9c04800371.jpg

当我尝试在其他两个平面上做同样的事情时,我得到一个奇怪的轮廓塌陷成一条细条,

https://img1.sycdn.imooc.com/65269eb00001234b05340410.jpg

或者是我在 matplotlib 内部无法企及的例外。


Traceback (most recent call last):

  File ".../matplotlib/backends/backend_qt5.py", line 519, in _draw_idle

    self.draw()

  File ".../matplotlib/backends/backend_agg.py", line 433, in draw

    self.figure.draw(self.renderer)

  File ".../matplotlib/artist.py", line 55, in draw_wrapper

    return draw(artist, renderer, *args, **kwargs)

  File ".../matplotlib/figure.py", line 1475, in draw

    renderer, self, artists, self.suppressComposite)

  File ".../matplotlib/image.py", line 141, in _draw_list_compositing_images

    a.draw(renderer)

  File ".../mpl_toolkits/mplot3d/axes3d.py", line 281, in draw

    reverse=True)):

  File ".../mpl_toolkits/mplot3d/axes3d.py", line 280, in <lambda>

    key=lambda col: col.do_3d_projection(renderer),

  File ".../mpl_toolkits/mplot3d/art3d.py", line 226, in do_3d_projection

    self._segments3d]

  File ".../mpl_toolkits/mplot3d/art3d.py", line 225, in <listcomp>

    proj3d.proj_trans_points(points, renderer.M) for points in

  File ".../mpl_toolkits/mplot3d/proj3d.py", line 188, in proj_trans_points

    xs, ys, zs = zip(*points)

ValueError: not enough values to unpack (expected 3, got 0)

下面是该问题的一个示例。此版本有效。取消注释函数中的一个或两个调用,以查看奇怪的轮廓,或者更有可能是异常。ax.contour()plot()

这是 matplotlib 2.2.2 和 3.1.1 的。感谢您提供的任何帮助,以获得所有三个平面上的轮廓,例如演示。


子衿沉夜
浏览 63回答 1
1回答

慕桂英4014372

一位matplotlib开发人员指出,重新采样是错误的。修复后,这是更正后的情节。对于边上看到数据的坐标平面,例如本例中的 yz 平面,等高线看起来可能有点不稳定。这是意料之中的,因为数据可以接近多值。xz平面轮廓看起来也很粗糙。我怀疑这两个问题都可以通过单独三角化和轮廓化每个平面来改善,而不是像这里所做的那样偏爱 xy 平面。下面是固定的测试脚本。唯一重要的更改是 和 。plot()resample()import mathimport sysimport matplotlib as mplimport matplotlib.pyplot as pltimport mpl_toolkits.mplot3dimport numpy as npimport scipy.spatial#np.random.seed(4)numPts = 1000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# number of points in cloudnumGrid = 120&nbsp; &nbsp; &nbsp; # number of points in meshgrid used in resample for contoursscatter = False&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# adds scatter plot to show point clouddef main():&nbsp; &nbsp; (pts, f) = mkData()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # create the point cloud&nbsp; &nbsp; tris = mkTris(pts)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# triangulate it&nbsp; &nbsp; plot(pts, tris, f)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # plot itdef plot(pts, tris, f):&nbsp; &nbsp; fig = plt.figure()&nbsp; &nbsp; ax = fig.add_subplot(111, projection="3d")&nbsp; &nbsp; cmap = plt.get_cmap("coolwarm")&nbsp; &nbsp; collec = ax.plot_trisurf(tris, pts[:, 2], cmap=cmap)&nbsp; &nbsp; colors = np.mean(f[tris.triangles], axis=1)&nbsp; &nbsp; collec.set_array(colors)&nbsp; &nbsp; collec.autoscale()&nbsp; &nbsp; (xr, yr, zr, fr, xMin, xMax, yMin, yMax, zMin, zMax) = resample(ax, tris,&nbsp; &nbsp; &nbsp; &nbsp;pts, f)&nbsp; &nbsp; ax.set_xlim(xMin, xMax)&nbsp; &nbsp; &nbsp; # default always includes zero for some reason&nbsp; &nbsp; ax.set_ylim(yMin, yMax)&nbsp; &nbsp; ax.set_zlim(zMin, zMax)&nbsp; &nbsp; ax.contour(xr, yr, fr, 10, zdir="z", cmap=cmap, offset=zMin)&nbsp; &nbsp; ax.contour(fr, yr, zr, 10, zdir="x", cmap=cmap, offset=xMin)&nbsp; &nbsp; ax.contour(xr, fr, zr, 10, zdir="y", cmap=cmap, offset=yMax)&nbsp; &nbsp; if scatter:&nbsp; &nbsp; &nbsp; &nbsp;ax.scatter(pts[:, 0], pts[:, 1], pts[:, 2], alpha=0.1)&nbsp; &nbsp; ax.set_xlabel("x")&nbsp; &nbsp; ax.set_ylabel("y")&nbsp; &nbsp; ax.set_zlabel("z")&nbsp; &nbsp; fig.colorbar(collec, shrink=0.5, aspect=5)&nbsp; &nbsp; plt.show()def mkData():&nbsp; &nbsp; """&nbsp; &nbsp; Create a random point cloud near a random plane, and define a function on&nbsp; &nbsp; the plane for colors and contours.&nbsp; &nbsp; """&nbsp; &nbsp; offset = 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# generate points near a unit square, xy-plane&nbsp; &nbsp; pts = 2 * np.random.rand(numPts, 3) - 1&nbsp; &nbsp; pts[:, 2] = offset * (2 * np.random.rand(numPts) - 1)&nbsp; &nbsp; x = 2 * np.ravel(pts[:, 0])&nbsp; &nbsp; y = 2 * np.ravel(pts[:, 1])&nbsp; &nbsp; f = x * np.exp(-x**2 - y**2)&nbsp; &nbsp; &nbsp; # just some function for colors, contours&nbsp; &nbsp; width = 100&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# scale unit square to a larger rectangle&nbsp; &nbsp; height = 20&nbsp; &nbsp; pts[:, 0] *= width&nbsp; &nbsp; pts[:, 1] *= height&nbsp; &nbsp; (e1, e2, e3) =[2 * np.pi * np.random.rand() for _ in range(3)]&nbsp; &nbsp; (c1, s1) = (math.cos(e1), math.sin(e1))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# rotate scaled rectangle&nbsp; &nbsp; (c2, s2) = (math.cos(e2), math.sin(e2))&nbsp; &nbsp; (c3, s3) = (math.cos(e3), math.sin(e3))&nbsp; &nbsp; Ta2b = np.array((&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# do not have scipy.spatial.transform&nbsp; &nbsp; &nbsp; &nbsp; [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;c1&nbsp; *c2,&nbsp; &nbsp; &nbsp; &nbsp;s2,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -s1 * c2],&nbsp; &nbsp; &nbsp; &nbsp; [s1 * s3 - c1 * s2 * c3,&nbsp; c2 * c3, c1 *s3 + s1 * s2 * c3],&nbsp; &nbsp; &nbsp; &nbsp; [s1 * c3 + c1 * s2 * s3, -c2 * s3, c1 *c3 - s1 * s2 * s3]))&nbsp; &nbsp; pts = (Ta2b @ pts.T).T&nbsp; &nbsp; dist = 500&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# translate away from the origin&nbsp; &nbsp; Ra2bNb = dist * (2 * np.random.rand(3, 1) - 1)&nbsp; &nbsp; pts += Ra2bNb.T&nbsp; &nbsp; return (pts, f)def mkTris(pts):&nbsp; &nbsp; "Triangulate the point cloud."&nbsp; &nbsp; u = np.ravel(pts[:, 0])&nbsp; &nbsp; v = np.ravel(pts[:, 1])&nbsp; &nbsp; try:&nbsp; &nbsp; &nbsp; &nbsp; return mpl.tri.Triangulation(u, v)&nbsp; &nbsp; except (ValueError, RuntimeError) as ex:&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(f"Unable to compute triangulation: {ex}.")def resample(ax, tris, pts, f):&nbsp; &nbsp; "Resample the triangulation onto a regular grid for contours."&nbsp; &nbsp; (xMin, xMax) = ax.get_xlim()&nbsp; &nbsp; (yMin, yMax) = ax.get_ylim()&nbsp; &nbsp; (zMin, zMax) = ax.get_zlim()&nbsp; &nbsp; x = np.linspace(xMin, xMax, numGrid)&nbsp; &nbsp; y = np.linspace(yMin, yMax, numGrid)&nbsp; &nbsp; (xm, ym)=np.meshgrid(x, y)&nbsp; &nbsp; fInterp = mpl.tri.CubicTriInterpolator(tris, f)&nbsp; &nbsp; fm = fInterp(xm, ym)&nbsp; &nbsp; zInterp = mpl.tri.CubicTriInterpolator(tris, pts[:,2])&nbsp; &nbsp; zm = zInterp(xm, ym)&nbsp; &nbsp; return (xm, ym, zm, fm, xMin, xMax, yMin, yMax, zMin, zMax)if __name__ == "__main__":&nbsp; &nbsp; main()
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python