我希望能够看到线(和点),是在3D表面上的表面(第二个图像),而不是后面(第一个图像)。这是我的3D函数:
def f(x, y):
return np.sin(2*x) * np.cos(2*y)
3D曲面的X、Y、Z:
x = np.linspace(-2, 2, 100)
y = np.linspace(-2, 2, 100)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
我生成了一个x点(xx)和y点(yy)的向量,其中zz = f(xx,yy)
fig = plt.figure(figsize=(8,6))
ax = plt.axes(projection='3d')
ax.scatter(xx, yy, zz, c='r', marker='o')
#ax.plot(xx,yy,zz, c= 'r')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap='viridis', edgecolor='none')
正如你所看到的,点在图的后面,图覆盖了点。我想看点在图上。我该怎么办?
我希望能够看到像这样的点和线:
编辑:这是我生成积分的方法:
for i in range(1,2000):
[a, b] = np.random.rand(2,1)*np.sign(np.random.randn(2,1))*2
xx = np.append(xx, a)
yy = np.append(yy, b)
我注意到,如果我写zz = f(xx,yy) + epsilon
,我可以看到点。如果epsilon = 0
,那么这些点在数学上是在表面上的,我不能清楚地看到它们,就像第一张图一样。如果epsilon > 0.05
,我可以看到点,但这意味着要将点向上移动。我真的不喜欢这个解决方案。如果一个点在一个曲面上,则该曲面具有优先级,该曲面看起来在该点之上。我希望我的图形是相反的。
3条答案
按热度按时间w7t8yxp51#
首先,我想说你想要的东西有点不明确。你想在一个底层表面上精确地绘制点,以使它们总是显示在图中,即。即 * 刚好在表面上方 *,而不明确地将它们向上移动。这已经是一个问题了,因为
1.浮点运算意味着点和曲面的精确坐标可以随着机器精度的变化而变化,因此试图依赖精确等式是行不通的。
1.即使这些数字精确到无限精确,曲面也是用近似平面的集合绘制的。这意味着你的 * 精确 * 数据点将 * 在函数为凸的近似曲面下 *。
然而,最大的问题是,matplotlib中的3d绘图在图形中绘制多个或复杂对象时是不可靠的。特别是,渲染器本质上是2d的,并且在试图找出对象的相对明显位置时经常遇到问题。要克服这个问题,你可以尝试hacking around the problem,或者切换到
mayavi
这样的3d渲染器。不幸的是,
zorder
可选关键字参数通常被3d轴对象忽略。所以我在pyplot中唯一能想到的就是你几乎拥有的东西,注解了:使用ax.plot
而不是ax.scatter
。后者会生成第一张图中所示的图(无论视角如何,由于某种原因,每个散点都隐藏),前者会生成第二张图中所示的图(点可见)。通过从绘图样式中删除线条,我们几乎可以得到你想要的:但不完全是:很明显,在这种情况下,这些点总是可见的,即使它们应该隐藏在表面的一部分后面:
很容易看出,前面的凸起应该隐藏了背景中的一大块点,但这些点是可见的。这正是pyplot在复杂的3d可视化中遇到的问题。因此,我的底线是,你不能可靠地使用matplotlib做你想做的事情。无论如何,我不确定这样的情节有多容易理解。
为了更积极地结束,以下是如何使用
mayavi
(为此,您需要安装vtk
,最好通过包管理器完成):如您所见,结果是一个交互式3d图,其中表面上的数据点是适当的球体。人们可以尝试使用不透明度和球体比例设置,以获得令人满意的可视化效果。由于正确的3d渲染,您可以看到每个点的适当数量,而不管视角如何。
iklwldmw2#
Andras Deak给出了一个非常全面的answer,讨论了matplotlibs 3D绘图功能在手头任务方面的问题/限制。在他回答的最后--以肯定的语气结束--他给出了一个使用替代库的解决方案。
我开始尝试在matplotlib中找到一个黑客/专业的解决方案。让我先谈谈原因。我想在2D表面上绘制轨迹,我被设置使用matplotlib。我使用它为我所有的二维绘图,并希望找到一个解决方案,为这个特定的三维绘图应用程序。matplotlibs 3D绘图的好处是它们是矢量化的,因为它们基本上只是通过将3D元素投影到相机平面上并覆盖它们(根据它们到相机的距离按顺序绘制它们)生成的2D绘图。可以单独控制图中每个元素的栅格化,而不会影响轴、标签等。使用光线跟踪的“真实的”3D绘图库通常不具有生成完全矢量化绘图的能力。我认为
mayavi
就是一个例子,我知道Mathematica在这方面也非常有限。我的解决方案:我研究了
plot_surface
的代码,它最终基于Poly3DCollection
,以了解matplotlib如何决定首先绘制表面上的哪些多边形/元素。Poly3DCollection
的方法_do_3d_projection
按照(原始3D对象的)到相机的距离对投影到2d相机平面上的多边形进行排序。首先绘制远离相机的元素,然后绘制靠近相机的元素。对于大多数情节来说,这足以创建一个合适的视角(但这种方法有局限性,见E。例如,mplot3d FAQ。然而,这个顺序是我解决方案的关键。给定一组点 pts 和一个表面 surf(必须用show
或savefig
绘制以设置其相机/投影变量):1.计算 surf 中的所有3D多边形到相机平面中的2D投影 segments_2d,包括它们基于到相机的距离的排序(存储在 segments_idxs 中)。
1.所有点都与三维曲面上的元素/多边形相关联。
1.计算3D点到相机平面中的2D投影。
1.为了确定一个点是否可见,我们检查它是否被一个多边形覆盖,该多边形在它所关联的多边形之后绘制(从步骤2。)。为此,我们使用
matplotlib.path
中的contains_points
方法,另请参阅相关问题What's the fastest way of checking if a point is inside a polygon in python。1.我包含了一个动态更新(改编自How to obscure a line behind a surface plot in matplotlib?)。警告:编码/绘制具有大量多边形的曲面可能会非常慢。
这里的必要的代码/最小的工作示例与表面给定的OP一个样本点位于单位圆。
代码仍然有点混乱,它仍然不能完美地工作,但这里有一些结果,表面上有25*25=625个四边形,单位圆上有200个点。x1c 0d1xx 1c 1d 1xx 1c 2d 1x红色的点是可见的点,绿色的点是不可见的点(这里绘制用于说明目的,但为了最初的问题/问题,人们会从图中省略它们)。一些点应该清晰可见,但被检测为不可见。我还不确定那里出了什么问题,但对我来说,这种有限的错过检测不是太大的问题,因为我最终想绘制许多(任意密集)点的线/轨迹。如果错过不集群,我可以生活与一些失踪的。
另一个固有问题/限制是当前方法不具有点是在表面上方还是下方的真实的概念,这意味着当从表面下方观看时,表面上方/上的点是可见的。下面是这种行为的示例:
这与Andras Deak已经提出的观点相联系,即目前的问题在没有额外限制的情况下有些定义不清,或者至少是模棱两可的。例如,可以要求将所有点放置在指向相机的表面上。在本方法中实现这一点是困难的。在几何方面,当前的实现方式将有限大小的球放置在无限小的多边形上,使得它们从两侧可见(这在某些用例中实际上可能是可行的/期望的)。
代码仍在进行中,如果我发现重大改进,我可能会更新这个答案。欢迎对一般方法和/或执行情况提出意见。我绝不是一个pythonMaven(我几乎只使用它来绘图和相关的非常轻的数据处理),所以它们在代码性能和范围方面可能有很大的改进空间。
yhxst69z3#
从你的图中,看起来你愿意显示非线性优化器局部解的路径,所以我认为你应该考虑在等高线图上绘制一个线框:
...
ax.scatter(xx,yy,zz,c='r',marker='o')###这将只绘制点,而不是线
ax.plot_surface(X,Y,Z,rstride=1,cstride= 1,cmap='viridis',edgecolor='none')
ax.plot_wireframe(xx,yy,zz)###这将绘制线和可能的点。
...
were(xx,yy,zz)包含了到达局部最大值的路径,正如我所假设的,它是从非线性回归方法得到的。