Search code examples
pythonmatplotlibplotgraphdraw

How can I stop pyplot lines on another line?


Plot of lines not crossing over the AB line

Hello! Does anyone know to achieve something similar to what the graph shows, using matpltolib? I need to draw some lines, such as CC' and DD', that do not cross over a given line AB. Is there any way to achieve this?


Solution

  • To draw a line from a point C, perpendicular to a line AB and stopping at AB, a projection point P can be calculated. P should be on AB, so P = t*A + (1-t)*B. This equation on points means it should hold both for the x and for the y coordinates: xp = t * xa + (1 - t) * xb and yp = t * ya + (1 - t) * yb) for some t. P should also be on a line containing C, and having the perpendicular vector as its direction. The perpendicular vector is yb - ya, - (xb - xa). So, P = C + u * Perp for some u.

    Sympy, Python's symbolic math library can be used to solve these equations:

    
    from sympy import symbols, Eq, solve
    
    t, u, xa, ya, xb, yb, xc, yc = symbols('t u xa ya xb yb xc yc ')
    
    eqpx = Eq(xc + u * (yb - ya), t * xa + (1 - t) * xb)
    eqpy = Eq(yc + u * (xa - xb), t * ya + (1 - t) * yb)
    
    solution = solve([eqpx, eqpy])
    

    This finds:

    {t: -(xa*xb - xa*xc - xb**2 + xb*xc + ya*yb - ya*yc - yb**2 + yb*yc)/(xa**2 - 2*xa*xb + xb**2 + ya**2 - 2*ya*yb + yb**2),
      u: (xa*yb - xa*yc - xb*ya + xb*yc + xc*ya - xc*yb)/(xa**2 - 2*xa*xb + xb**2 + ya**2 - 2*ya*yb + yb**2)}
    

    The solution can be used to define a function to project a point C onto a line AB. Here is an example:

    from matplotlib import pyplot as plt
    
    def project_on_line(xc, yc, xa, ya, xb, yb):
        t = -(xa * xb - xa * xc - xb ** 2 + xb * xc + ya * yb - ya * yc - yb ** 2 + yb * yc) / (
                    xa ** 2 - 2 * xa * xb + xb ** 2 + ya ** 2 - 2 * ya * yb + yb ** 2)
        return t * xa + (1 - t) * xb, t * ya + (1 - t) * yb
    
    def show_point(x, y, name):
        plt.text(x, y, f' {name}', ha='left', va='top')
    
    xa, ya = 0, 2
    xb, yb = 6, 5
    xc, yc = 5, 1
    xd, yd = 7, 0
    xcp, ycp = project_on_line(xc, yc, xa, ya, xb, yb)
    xdp, ydp = project_on_line(xd, yd, xa, ya, xb, yb)
    show_point(xa, ya, "A")
    show_point(xb, yb, "B")
    show_point(xc, yc, "C")
    show_point(xcp, ycp, "C'")
    show_point(xd, yd, "D")
    show_point(xdp, ydp, "D'")
    
    plt.plot([xa, xb], [ya, yb], color='dodgerblue')
    plt.plot([xc, xcp], [yc, ycp], color='dodgerblue')
    plt.plot([xd, xdp], [yd, ydp], color='dodgerblue')
    plt.axis('equal')
    
    plt.show()
    

    example plot