找到在 matplotlib 中绘制的两条曲线之间的区域(fill_between area) [英] Find the area between two curves plotted in matplotlib (fill_between area)

查看:31
本文介绍了找到在 matplotlib 中绘制的两条曲线之间的区域(fill_between area)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两条曲线的 x 和 y 值列表,它们都具有奇怪的形状,但我没有任何函数.我需要做两件事:(1)绘制它并对曲线之间的区域进行阴影处理,如下图;(2) 求曲线之间阴影区域的总面积.

I have a list of x and y values for two curves, both having weird shapes, and I don't have a function for any of them. I need to do two things: (1) plot it and shade the area between the curves like the image below; (2) find the total area of this shaded region between the curves.

我可以在 matplotlib 中用 fill_between 和 fill_betweenx 绘制和阴影这些曲线之间的区域,但我不知道如何计算它们之间的确切面积,特别是因为我没有任何函数那些曲线.

I'm able to plot and shade the area between those curves with fill_between and fill_betweenx in matplotlib, but I have no idea on how to calculate the exact area between them, specially because I don't have a function for any of those curves.

有什么想法吗?

我到处找,找不到简单的解决方案.我很绝望,所以非常感谢任何帮助.

I looked everywhere and can't find a simple solution for this. I'm quite desperate, so any help is much appreciated.

非常感谢!

为了将来参考(以防有人遇到同样的问题),这是我解决这个问题的方法:将每条曲线的第一个和最后一个节点/点连接在一起,导致一个奇怪的大多边形,然后使用 shapely 自动计算多边形的面积,这是曲线之间的精确区域,无论它们走哪条路或它们有多非线性.奇迹般有效!:)

For future reference (in case anyone runs into the same problem), here is how I've solved this: connected the first and last node/point of each curve together, resulting in a big weird-shaped polygon, then used shapely to calculate the polygon's area automatically, which is the exact area between the curves, no matter which way they go or how nonlinear they are. Works like a charm! :)

这是我的代码:

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)

编辑 2:感谢您的回答,就像凯尔解释的那样,这仅适用于正值.如果您的曲线低于 0(这不是我的情况,如示例图表所示),那么您将不得不使用绝对数字.

EDIT 2: Thank you for the answers, like Kyle explained, this only works for positive values. If your curves go below 0 (which is not my case, as showed in the example chart), then you would have to work with absolute numbers.

推荐答案

在两条曲线不相交的块中,面积计算很简单:这就是上面指出的梯形.如果它们相交,则在 x[i] 和 x[i+1] 之间创建两个三角形,然后将两者的面积相加.如果你想直接做,你应该分开处理这两种情况.这是解决您的问题的基本工作示例.首先,我将从一些假数据开始:

The area calculation is straightforward in blocks where the two curves don't intersect: thats the trapezium as has been pointed out above. If they intersect, then you create two triangles between x[i] and x[i+1], and you should add the area of the two. If you want to do it directly, you should handle the two cases separately. Here's a basic working example to solve your problem. First, I will start with some fake data:

#!/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.然后我们定义,

Now, the main code. Based on your plot, looks like you have y1 and y2 defined at the same X points. Then we define,

z = y1-y2
dx = x[1:] - x[:-1]
cross_test = np.sign(z[:-1] * z[1:])

cross_test 将在两个图形交叉时为负.在这些点上,我们要计算交叉点的 x 坐标.为简单起见,我将计算 y 的所有段的交点的 x 坐标.对于两条曲线不相交的地方,它们将是无用的值,我们不会在任何地方使用它们.这只是让代码更容易理解.

cross_test will be negative whenever the two graphs cross. At these points, we want to calculate the x coordinate of the crossover. For simplicity, I will calculate x coordinates of the intersection of all segments of y. For places where the two curves don't intersect, they will be useless values, and we won't use them anywhere. This just keeps the code easier to understand.

假设您在 x1 和 x2 处有 z1 和 z2,那么我们正在求解 x0,使得 z = 0:

Suppose you have z1 and z2 at x1 and x2, then we are solving for x0 such that 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]

曲线不相交的地方,面积由下式给出:

Where the curves don't intersect, area is simply given by:

areas_pos = abs(z[:-1] + z[1:]) * 0.5 * dx # signs of both z are same

在它们相交的地方,我们添加两个三角形的面积:

Where they intersect, we add areas of both triangles:

areas_neg = 0.5 * dx_intersect * abs(z[:-1]) + 0.5 * (dx - dx_intersect) * abs(z[1:])

现在,要选择每个块 x[i] 到 x[i+1] 中的区域,为此我使用 np.where:

Now, the area in each block x[i] to x[i+1] is to be selected, for which I use np.where:

areas = np.where(cross_test < 0, areas_neg, areas_pos)
total_area = np.sum(areas)

这就是您想要的答案.如上所述,如果两个 y 图都定义在不同的 x 点,这将变得更加复杂.如果你想测试这个,你可以简单地绘制它(在我的测试用例中,y 范围是 -20 到 20)

That is your desired answer. As has been pointed out above, this will get more complicated if the both the y graphs were defined at different x points. If you want to test this, you can simply plot it (in my test case, y range will be -20 to 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)

这篇关于找到在 matplotlib 中绘制的两条曲线之间的区域(fill_between area)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆