簡體   English   中英

計算曲線下面積

[英]Calculating area under the curves

我正在嘗試計算藍色區域的面積和黃色區域的面積:在此圖中:y=blue, peak_line=green, thresh=orange。

圖片1

我正在使用此代碼:

idx = np.argwhere(np.diff(np.sign(y - peak_line))).flatten()
bounds = [1077.912, 1078.26, 1078.336, 1078.468, 1078.612, 1078.78, 1078.828, 1078.88, 1079.856, 1079.86]
plt.plot(x, y, x, thresh, x, peak_line)
plt.fill_between(x, y, thresh, where=(y>=peak_line),interpolate=True, color='#fff8ba')
plt.fill_between(x, thresh, peak_line, where=(y<=peak_line),interpolate=True, color='#fff8ba')
plt.fill_between(x, y, peak_line, where=(y>=peak_line) & (x>=x[idx][0]) & (x<=bounds[-1]), interpolate=True, color='#CDEAFF')
plt.plot(x[idx], y[idx], 'ro')
plt.show()

estimated_y = interp1d(x, y, kind='cubic')
estimated_peak_line = interp1d(x, peak_line, kind='cubic')
estimated_thresh = interp1d(x, thresh, kind='cubic')

yellow_areas = []
blue_areas = []
for i in range(len(bounds) - 1):
    midpoint = (bounds[i] + bounds[i+1]) / 2
    if estimated_y(midpoint) < estimated_peak_line(midpoint):
        above_peak_line = abs(integrate.quad(estimated_peak_line, bounds[i], bounds[i+1])[0])
        above_thresh_line = abs(integrate.quad(estimated_thresh, bounds[i], bounds[i+1])[0])
        yellow_areas.append(above_peak_line - above_thresh_line)

    else:
        above_peak_line = abs(integrate.quad(estimated_peak_line, bounds[i], bounds[i+1])[0])
        above_y = abs(integrate.quad(estimated_y, bounds[i], bounds[i+1])[0])
        blue_areas.append(above_peak_line - above_y)

print(sum(yellow_areas))
print(sum(blue_areas))
4.900000000000318
2.999654602006661

我以為我計算了藍色區域的面積和黃色區域的面積是正確的,直到我計算出多邊形的面積:

bunch_of_xs = np.linspace(min(x), max(x), num=10000, endpoint=True)
final_curve = estimated_y(bunch_of_xs)
final_thresh = estimated_thresh(bunch_of_xs)
final_peak_line = estimated_peak_line(bunch_of_xs)

def PolygonArea(corners):
    n = len(corners) # of corners
    area = 0.0
    for i in range(n):
        j = (i + 1) % n
        area += corners[i][0] * corners[j][1]
        area -= corners[j][0] * corners[i][1]
    area = abs(area) / 2.0
    return area

vertex1 = (bunch_of_xs[0], final_thresh[0])
vertex2 = (bunch_of_xs[-1], final_thresh[-1])
vertex3 = (x[idx][-1], y[idx][-1])
vertex4 = (x[idx][0], y[idx][0])
coords = (vertex1,vertex2,vertex3,vertex4)
plt.plot(x, y, 'o', bunch_of_xs, final_curve, '--', bunch_of_xs, final_thresh, bunch_of_xs, final_peak_line)
x_val = [x[0] for x in coords]
y_val = [x[1] for x in coords]
plt.plot(x_val,y_val,'or')
print("Coordinates of total polygon:", coords)
print("Total polygon area:", PolygonArea(coords))
Coordinates of total polygon: ((1077.728, -41.30177170550451), (1079.96, -42.254314285935834), (1079.86, -49.207348695828706), (1077.912, -48.271572477115136))
Total polygon area: 14.509708069890621

圖片2

藍色區域的面積和黃色區域的面積之和應等於多邊形的總面積。

4.900000000000318 + 2.999654602006661 ≠ 14.509708069890621

我究竟做錯了什么?

編輯:此代碼將用於許多不同的圖表。 並非所有圖形看起來都一樣。 例如,此圖有 3 個藍色區域,因此我必須計算所有 3 個藍色區域的面積並將它們加在一起以獲得總藍色區域。 每個圖都有不同數量的藍色區域(有些只有 1 個區域)。 因此,我必須使代碼靈活,以考慮將具有多個藍色區域的圖形加在一起以獲得總藍色區域面積的可能性。

一般來說,兩條曲線f(x)g(x)之間的面積是integral(g(x) - f(x))

所以說我們有兩條曲線:

xvals = np.linspace(0, 1, 100)
yvals_1 = np.sin(xvals * 10)
yvals_2 = 0.5 - 0.5 * xvals

plt.plot(xvals, yvals_1, '-b')
plt.plot(xvals, yvals_2, '-g')

在此處輸入圖片說明

“轉換”曲線變為:

yvals_3 = yvals_1 - yvals_2
plt.plot(xvals, yvals_3, '--r')
plt.plot(xvals, np.zeros(xvals.shape), '--k')

既然我們想忽略綠線下的一切,

yvals_3[yvals_3 < 0] = 0
plt.plot(xvals, yvals_3, '-r')

在此處輸入圖片說明

由於您想施加額外的約束,例如“僅在第一個和最后一個交叉點之間的區域”,現在就這樣做。

# Cheating a little bit -- but you already know how to get the intersections.
first_intersection_x = xvals[4]
last_intersection_x = xvals[94]

cfilter = np.logical_and(xvals >= first_intersection_x, xvals <= last_intersection_x)
xvals_calc = xvals[cfilter]
yvals_calc = yvals_3[cfilter]

使用np.trapz可以輕松計算該曲線下的面積

area_under_curve = np.trapz(yvals_calc, xvals_calc)

當然,這個答案假設yvals_1yvals_2在同一個xvals中可用。 如果沒有, 插值很容易

由於我沒有您的所有數據,因此我將在偽代碼和實現之間提供一些信息。 假設我們有數組x (x 軸)、 y1 (數據)、 y2 (某條線,它限制了我們想要積分的部分)。

第一步:迭代你的邊界數組,看看我們想要整合哪些部分。 我假設你已經有了邊界數組,正如你的問題所暗示的那樣。

def get_pairs_of_idxs(x, y1, y2, bounds):
    lst_pairs = []
    for i in range(len(bounds)-1):
        x0, x1 = bounds[i], bounds[i+1]
        xc = 0.5 * (x0 + x1) # we want to see if the straight line y2 is above or below, so we take one x value and test it
        indx_xc = np.searchsorted(x, xc) # this returns us the index at which xc is located
        y1c, y2c = y1[indx_xc], y2[indx_xc]
        if y2c < y1c: # then the line is below the curve, so we want to integrate
            lst_pairs.append((x0, x1))

現在我們有一個索引對列表,我們希望在它們之間進行整合。

def solution(x, y1, y2, bounds):
     tot_area = 0
     lst_pairs = get_pairs_of_idxs(x, y1, y2, bounds)
     for x0, x1 in lst_pairs:
          mask = np.logical_and(x >= x0, x <= x1) # relevant places in x and y data
          xs = x[mask] # the x values along which we integrate
          ys = (y2 - y1)[mask] # we want to integrate the difference of the curves
          tot_area += np.trapz(ys, xs)
     return tot_area

這就是我所想的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM