1

I have a code that plots data from a text file. I have been able to get the integrals under each data curve (although I do not know the functions for any of them, so I just used integral = s = simps(y, x)). Two of the curves overlap horizontally, and I would like to find the area between where they overlap. I am having some trouble with this since they overlap horizontally rather than vertically. The area I would like to find is between the red and blue lines on this graph. The data are in numpy arrays, for example bx and by for the blue lines x and y, and rx and ry for the red lines x and y. I have no function to represent them but they are in those arrays. It is hard to know how to proceed because they overlap horizontally rather than vertically.

I'm pretty stuck on this, any help would be greatly appreciated!

Update: The code provided by JohanC has worked in one case but not another. The non-working plot initially looks like this (I want the area only of that middle overlapping area), but when that did not work either, I had tried limiting the x range to hopefully help the code narrow in on the area where I would like the overlapping integral to be calculated (that is where that plot with the smaller range came from). The code I am currently using is the one JohanC provided and looks like this:

def get_overlap_integral(bx, by, rx, ry):
    fig, ax = plt.subplots()
    ax.plot(bx, by, color='b')
    ax.plot(rx, ry, color='r')

    # create a common x range
    gx = np.linspace(min(bx.min(), rx.min()), max(bx.max(), rx.max()), 1000)
    gby = np.interp(gx, bx, by)  # set bx,by onto the common x range
    gry = np.interp(gx, rx, ry)  # set rx,ry onto the common x range
    gy = np.minimum(gby, gry)  # let gx,gy be the intersection of the two curves
    ax.fill_between(gx, gy, color='g', alpha=0.3)

    area = np.trapz(gy, gx)  # calculate the green area
    ax.text(0.05, 0.95, f'Overlap: {area:.3f}', color='g', ha='left', va='top', transform=ax.transAxes)
    plt.show()
    return area

The text bx, by, rx, and ry are values such as these:

BX: [999.5 999.  998.5 ... 201.  200.5 200. ]
BY: [-3.786867e-05 -4.366451e-05 -4.745308e-05 ...  1.068685e-05  1.555391e-05
 -8.949840e-06]
RX: [999.5 999.  998.5 ... 201.  200.5 200. ]
RY: [-5.865443e-05 -7.808241e-05 -5.887286e-05 ... -1.556630e-06 -3.473830e-06
 -6.367470e-06]

I am not sure why this function will not work for one case but will work perfectly for another. Any help would be greatly appreciated!

  • Could you create a reproducible example? Maybe you can add the values (as text) of the arrays? – JohanC Jul 19 '21 at 09:44
  • Your arrays seem to be in reversed order, which gives problems both for the logic of `min(bx.min(), rx.min())` and for `np.interp`. You could try to call your function with all arrays reversed, e.g. `get_overlap_integral(bx[::-1], by[::-1], rx[::-1], ry[::-1])` – JohanC Jul 22 '21 at 21:14

1 Answers1

0

np.interp(new_x, old_x, old_y) can calculate a curve for a new x range. When set on a common x range, np.minimum finds the common area of two positive-valued curves. np.trapz calculates the area.

Here is some example code, starting with the creation of test data:

from matplotlib import pyplot as plt
import numpy as np

# create some test data
Nb = 300
bx = np.linspace(320, 750, Nb)
by = np.random.randn(Nb).cumsum()
by -= by[0]  # start at zero
by -= np.linspace(0, 1, Nb) * by[-1]  # let end in zero
by = (by ** 2) ** .3  # positive curve starting and ending with zero
Nr = 200
rx = np.linspace(610, 1080, Nr)
ry = np.random.randn(Nr).cumsum()
ry -= ry[0]  # start at zero
ry -= np.linspace(0, 1, Nr) * ry[-1]  # let end in zero
ry = (ry ** 2) ** .3  # positive curve starting and ending with zero

fig, ax = plt.subplots()
ax.plot(bx, by, color='b')
ax.plot(rx, ry, color='r')

# create a common x range
gx = np.linspace(min(bx.min(), rx.min()), max(bx.max(), rx.max()), 1000)
gby = np.interp(gx, bx, by)  # set bx,by onto the common x range
gry = np.interp(gx, rx, ry)  # set rx,ry onto the common x range
gy = np.minimum(gby, gry)  # let gx,gy be the intersection of the two curves
ax.fill_between(gx, gy, color='g', alpha=0.3)

area = np.trapz(gy, gx)  # calculate the green area
ax.text(0.05, 0.95, f'Overlap: {area:.3f}', color='g', ha='left', va='top', transform=ax.transAxes)
plt.show()

finding the common area of two curves with different x ranges

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Thank you very much for the help, it has worked for one of the cases! In another case, it is not though. I am not sure why it does not work in that case, I have looked at the code and cannot find where it is going wrong. Would you be able to provide some insight? I will attach images to my initial question and describe the issue there. – Python n Physics Jul 19 '21 at 00:30
  • Are bx, by, rx and ry 1D numpy arrays? – JohanC Jul 20 '21 at 10:34
  • Yes they are, for example the first few values in some of them: BX: [325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. ... ] BY: [3.87054116e-05 1.75771984e-04 6.49485416e-04 1.96690820e-03 5.01083084e-03 1.09458069e-02 2.07035425e-02 3.46967871e-02 5.25319303e-02 7.35388438e-02 9.60352312e-02 ... ] RX: [ 610. 611. 612. 613. 614. 615. 616. 617. 618. 619. 620. 621. ... ] RY: [1.06681221e-04 1.49827932e-04 2.16489151e-04 3.10012201e-04 4.59318092e-04 7.05041053e-04 1.08825407e-03 1.75652781e-03 2.96747712e-03 5.11095889e-03 8.95907309e-03 ... ] – Python n Physics Jul 22 '21 at 20:25