F4R*_*F4R 14 python matplotlib area scipy
我有一个两条曲线的x和y值列表,两者都有奇怪的形状,我没有任何一个函数.我需要做两件事:(1)绘制它并遮蔽曲线之间的区域,如下图所示; (2)找出曲线之间阴影区域的总面积.
我能够在matplotlib中用fill_between和fill_betweenx绘制和遮蔽这些曲线之间的区域,但我不知道如何计算它们之间的确切区域,特别是因为我没有任何这些曲线的函数.
有任何想法吗?
我到处寻找,找不到一个简单的解决方案.我非常绝望,所以任何帮助都非常感激.
非常感谢你!

编辑:为了将来的参考(如果有人遇到同样的问题),这就是我解决这个问题的方法(几个月后):将每条曲线的第一个和最后一个节点/点连接在一起,产生一个巨大的奇怪形状的多边形,然后用形状自然地计算多边形的面积,这是曲线之间的确切区域,无论它们走向哪个方向或它们的非线性.像魅力一样,已经成千上万的曲线.:)
这是我的代码:
from shapely.geometry import Polygon
x_y_curve1 = [(0.121,0.232),(2.898,4.554),(7.865,9.987)] #these are your points for curve 1 (I just put some random numbers)
x_y_curve2 = [(1.221,1.232),(3.898,5.554),(8.865,7.987)] #these are your points for curve 2 (I just put some random numbers)
polygon_points = [] #creates a empty list where we will append the points to create the polygon
for xyvalue in x_y_curve1:
polygon_points.append([xyvalue[0],xyvalue[1]]) #append all xy points for curve 1
for xyvalue in x_y_curve2[::-1]:
polygon_points.append([xyvalue[0],xyvalue[1]]) #append all xy points for curve 2 in the reverse order (from last point to first point)
for xyvalue in x_y_curve1[0:1]:
polygon_points.append([xyvalue[0],xyvalue[1]]) #append the first point in curve 1 again, to it "closes" the polygon
polygon = Polygon(polygon_points)
area = polygon.area
print(area)
Run Code Online (Sandbox Code Playgroud)
定义两条曲线作为功能f和g由段之间,例如线性的x1和x2,f(x) = f(x1) + ((x-x1)/(x2-x1))*(f(x2)-f(x1)).定义h(x)=abs(g(x)-f(x)).然后scipy.integrate.quad用来整合h.
这样你就不需要为交叉点烦恼了.它将自动执行ch41rmn建议的"空中总结".
在两条曲线不相交的块中,面积计算很简单:这就是上面指出的梯形。如果它们相交,则在 x[i] 和 x[i+1] 之间创建两个三角形,然后将两者的面积相加。如果你想直接做,你应该分开处理这两种情况。这是解决您的问题的基本工作示例。首先,我将从一些假数据开始:
#!/usr/bin/python
import numpy as np
# let us generate fake test data
x = np.arange(10)
y1 = np.random.rand(10) * 20
y2 = np.random.rand(10) * 20
Run Code Online (Sandbox Code Playgroud)
现在,主要代码。根据您的情节,您似乎在相同的 X 点处定义了 y1 和 y2。然后我们定义,
z = y1-y2
dx = x[1:] - x[:-1]
cross_test = np.sign(z[:-1] * z[1:])
Run Code Online (Sandbox Code Playgroud)
每当两个图交叉时,cross_test 将为负数。在这些点上,我们要计算交叉点的 x 坐标。为简单起见,我将计算 y 的所有段的交点的 x 坐标。对于两条曲线不相交的地方,它们将是无用的值,我们不会在任何地方使用它们。这只是让代码更容易理解。
假设您在 x1 和 x2 处有 z1 和 z2,那么我们正在求解 x0,使得 z = 0:
# (z2 - z1)/(x2 - x1) = (z0 - z1) / (x0 - x1) = -z1/(x0 - x1)
# x0 = x1 - (x2 - x1) / (z2 - z1) * z1
x_intersect = x[:-1] - dx / (z[1:] - z[:-1]) * z[:-1]
dx_intersect = - dx / (z[1:] - z[:-1]) * z[:-1]
Run Code Online (Sandbox Code Playgroud)
在曲线不相交的地方,面积简单地由下式给出:
areas_pos = abs(z[:-1] + z[1:]) * 0.5 * dx # signs of both z are same
Run Code Online (Sandbox Code Playgroud)
在它们相交的地方,我们添加两个三角形的面积:
areas_neg = 0.5 * dx_intersect * abs(z[:-1]) + 0.5 * (dx - dx_intersect) * abs(z[1:])
Run Code Online (Sandbox Code Playgroud)
现在,要选择每个块 x[i] 到 x[i+1] 中的区域,为此我使用 np.where:
areas = np.where(cross_test < 0, areas_neg, areas_pos)
total_area = np.sum(areas)
Run Code Online (Sandbox Code Playgroud)
这就是你想要的答案。如上所述,如果两个 y 图都定义在不同的 x 点,这将变得更加复杂。如果你想测试这个,你可以简单地绘制它(在我的测试用例中,y 范围是 -20 到 20)
negatives = np.where(cross_test < 0)
positives = np.where(cross_test >= 0)
plot(x, y1)
plot(x, y2)
plot(x, z)
plt.vlines(x_intersect[negatives], -20, 20)
Run Code Online (Sandbox Code Playgroud)