pythonmatplotlibplotintegralsimpsons-rule

Finding the integral between two horizontally overlapping curves


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!


Solution

  • 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