我有两条曲线的x和y值列表,两条曲线都有奇怪的形状,我没有任何一个函数。我需要做两件事:(1)绘制它并遮蔽曲线之间的区域,如下图所示; (2)找出曲线之间阴影区域的总面积。
我能够在matplotlib中用fill_between和fill_betweenx绘制和遮蔽这些曲线之间的区域,但我不知道如何计算它们之间的确切区域,特别是因为我没有任何函数那些曲线。
有什么想法吗?
我到处寻找,找不到一个简单的解决方案。我非常绝望,所以非常感谢任何帮助。
非常感谢!
编辑:为了将来的参考(如果有人遇到同样的问题),这就是我解决这个问题的方法(几个月后):将每条曲线的第一个和最后一个节点/点连接在一起,产生一个巨大的奇怪形状的多边形,然后使用shapely自动计算多边形的面积,这是曲线之间的确切区域,无论它们走向何方或它们是多么非线性。像魅力一样,已经成千上万的曲线。 :)
这是我的代码:
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)
答案 0 :(得分:5)
将两条曲线定义为按分段线性的函数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建议的“空中总结”。
答案 1 :(得分:3)
在两条曲线不相交的区块中,区域计算很简单:就像上面指出的梯形一样。如果它们相交,则在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
现在,主要代码。根据您的情节,看起来您在相同的X点定义了y1和y2。然后我们定义,
z = y1-y2
dx = x[1:] - x[:-1]
cross_test = np.sign(z[:-1] * z[1:])
每当两个图交叉时,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]
曲线不相交的地方,区域简单地由下式给出:
areas_pos = abs(z[:-1] + z[1:]) * 0.5 * dx # signs of both z are same
在它们相交的地方,我们添加了两个三角形的区域:
areas_neg = 0.5 * dx_intersect * abs(z[:-1]) + 0.5 * (dx - dx_intersect) * abs(z[1:])
现在,要选择每个块x [i]到x [i + 1]的区域,我使用np.where:
areas = np.where(cross_test < 0, areas_neg, areas_pos)
total_area = np.sum(areas)
这是你想要的答案。如上所述,如果两个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)
答案 2 :(得分:2)
在两组数据共享同一组x坐标的意义上,您的数据集非常“漂亮”。因此,您可以使用一系列梯形来计算面积。
e.g。将两个函数定义为f(x)和g(x),然后,在x中的任意两个连续点之间,您有四个数据点:
(x1, f(x1))-->(x2, f(x2))
(x1, g(x1))-->(x2, g(x2))
然后,梯形的区域是
A(x1-->x2) = ( f(x1)-g(x1) + f(x2)-g(x2) ) * (x2-x1)/2 (1)
出现了一个复杂因素,即等式(1)仅适用于简单连接的区域,即在该区域内不得有交叉:
|\ |\/|
|_| vs |/\|
交叉路口两侧的区域必须单独评估。您需要浏览数据以查找所有交叉点,然后将其坐标插入坐标列表中。必须保持x的正确顺序。然后,您可以遍历简单连接区域列表并获得梯形区域的总和。
修改强>
为了好奇,如果两个列表的x坐标不同,你可以改为构造三角形。 e.g。
.____.
| / \
| / \
| / \
|/ \
._________.
必须避免三角形之间的重叠,因此您需要再次找到交叉点并将它们插入到有序列表中。可以使用毕达哥拉斯公式计算三角形每边的长度,并使用Heron公式计算三角形的面积。
答案 3 :(得分:0)
我遇到了同样的问题。以下答案基于问题作者的尝试。但是,shape不会直接以紫色给出多边形的面积。您需要编辑代码以将其分解为组件多边形,然后获取每个组件的面积。之后,您只需将它们加起来即可。
请考虑以下几行:
Sample Two lines 如果您在下面运行代码,则面积为零,因为它采用顺时针方向并减去逆时针面积:
from shapely.geometry import Polygon
x_y_curve1 = [(1,1),(2,1),(3,3),(4,3)] #these are your points for curve 1
x_y_curve2 = [(1,3),(2,3),(3,1),(4,1)] #these are your points for curve 2
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)
因此,解决方案是根据直线相交的位置将多边形分成较小的部分。然后使用for循环将它们加起来:
from shapely.geometry import Polygon
x_y_curve1 = [(1,1),(2,1),(3,3),(4,3)] #these are your points for curve 1
x_y_curve2 = [(1,3),(2,3),(3,1),(4,1)] #these are your points for curve 2
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
x,y = polygon.exterior.xy
# original data
ls = LineString(np.c_[x, y])
# closed, non-simple
lr = LineString(ls.coords[:] + ls.coords[0:1])
lr.is_simple # False
mls = unary_union(lr)
mls.geom_type # MultiLineString'
Area_cal =[]
for polygon in polygonize(mls):
Area_cal.append(polygon.area)
Area_poly = (np.asarray(Area_cal).sum())
print(Area_poly)
答案 4 :(得分:0)
pypi库similaritymeasures(于2018年发布)中的area_between_two_curves
函数可能会为您提供所需的内容。我尝试了一个简单的示例,比较了函数和常量值之间的面积,并非常接近Excel(在2%以内)。不知道为什么它不能给我100%的回扣,也许我做错了。值得考虑。