Change in line slope affecting fill_between

47 views Asked by At

I currently have a curve defined by (x_orig, y_orig), and I want to plot the shaded region between two new curves defined by (x_orig - c, y_orig) and (x_orig + c, y_orig). When using matplotlib's fill_betweenx(), it does most of what I want, except when the two curves have opposite signs of their slope, they cross each other and there is nothing filled between them. I actually want the full space between the two filled. Imagine you grab the line (x_orig - c, y_orig) and drag it to the right to (x_orig + c, y_orig), I want to shade all of that area. I want to find the points that define the upper and lower shaded region so that I can additionally mask scatter points that happen to be in there.

I originally wrote an overcomplicated function that mostly does what I want, but it doesn't correctly handle the areas where the lines switch slope. Is there a more "pythonic" way of doing something that I want that isn't needlessly complicated?

def shaded_region(x_left, x_right, y_left, y_right):
    y_upper = []
    y_lower = []
    y_lower.append(y_left[0])
    y_upper.append(y_left[0])
    #
    s = np.sign((y_left[1] - y_left[0]))
    #
    x_new = []
    x_new.append(x_left[0])
    #
    for i in range(0, len(x_left)-1):
        m = (y_left[i+1] - y_left[i])
        s_new = np.sign(m)
        #
        if s_new == s:
            if m < 0:
                y_upper.append(y_left[i])
                y_lower.append(y_left[i+1])
            if m > 0:
                y_upper.append(y_left[i+1])
                y_lower.append(y_left[i])
            x_new.append((x_left[i+1]+x_right[i])/2)
        else:
            p1 = np.array([x_left[i+1], y_left[i+1]])
            p2 = np.array([x_left[i], y_left[i]])
            p3 = np.array([x_right[i], y_right[i]])
            p4 = np.array([x_right[i-1], y_right[i-1]])
            #
            # print(i)
            # print(p1,p2,p3,p4)
            intersection = seg_intersect(p1, p2, p3, p4)
            x_new.append(intersection[0])
            #
            if (s_new > 0) and (s < 0):
                y_upper.append(intersection[1])
                y_lower.append(np.min((y_right[i], y_right[i-1])))
                dx = (intersection[0]-x_left[i])
                x_new.append(intersection[0]+dx)
                y_upper.append(y_left[i+1])
                y_lower.append(y_left[i])
            if (s_new < 0) and (s > 0):
                y_upper.append(np.max((y_right[i+1], y_right[i])))
                y_lower.append(intersection[1])
                dx = (intersection[0]-x_left[i])
                x_new.append(intersection[0]+dx)
                y_upper.append(y_right[i])
                y_lower.append(y_right[i+1])
        #
        s = s_new
    y_upper.append(y_left[-1])
    y_lower.append(y_left[-1])
    x_new.append(x_right[-1])
    #
    return x_new, y_lower, y_upper

I'm attaching a figure that shows the results from fill_betweenx() to show the additional area I want to shade.

enter image description here

0

There are 0 answers