Draw a curve connecting two points instead of a straight line

You are going to need some expression for the curve you want to plot, then you can make the curve out of many line segments.

Here's a parabola:

x = np.linspace(-1, 1, 100)
y = x*x
plt.plot(x, y)

parabola

Here's a sin curve:

x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = np.sin(x)
plt.plot(x, y)

sin

Each of these looks smooth, but is actually made up of many small line segments.

To get a collection of curves like you showed, you are going to need some expression for a curve you want to plot in terms of its two endpoints. The ones in your picture look like catenarys which are (approximately) the shape a hanging chain assumes under the force of gravity:

x = np.linspace(-2*np.pi, 2*np.pi, 100)
y = 2*np.cosh(x/2)
plt.plot(x, y)

catenary

You will have to find a way of parameterizing this curve in terms of its two endpoints, which will require you substituting your values of y and x into:

y = a*cosh(x/a) + b

and solving the resulting pair of equations for a and b.


For people interested in this question, I followed Matthew's suggestion and came up with this implementation:

def hanging_line(point1, point2):
    import numpy as np

    a = (point2[1] - point1[1])/(np.cosh(point2[0]) - np.cosh(point1[0]))
    b = point1[1] - a*np.cosh(point1[0])
    x = np.linspace(point1[0], point2[0], 100)
    y = a*np.cosh(x) + b

    return (x,y)

Here is what the result looks like:

import matplotlib.pyplot as plt

point1 = [0,1]
point2 = [1,2]
x,y = hanging_line(point1, point2)

plt.plot(point1[0], point1[1], 'o')
plt.plot(point2[0], point2[1], 'o')
plt.plot(x,y)

§1


There is a cool (at least for me) way to draw curve lines between two points, using Bezier curves. Just with some simple code you can create lists with dots connecting points and chart them with matplotlib, for example:

def recta(x1, y1, x2, y2):
    a = (y1 - y2) / (x1 - x2)
    b = y1 - a * x1
    return (a, b)

def curva_b(xa, ya, xb, yb, xc, yc):
    (x1, y1, x2, y2) = (xa, ya, xb, yb)
    (a1, b1) = recta(xa, ya, xb, yb)
    (a2, b2) = recta(xb, yb, xc, yc)
    puntos = []

    for i in range(0, 1000):
        if x1 == x2:
            continue
        else:
            (a, b) = recta(x1, y1, x2, y2)
        x = i*(x2 - x1)/1000 + x1
        y = a*x + b
        puntos.append((x,y))
        x1 += (xb - xa)/1000
        y1 = a1*x1 + b1
        x2 += (xc - xb)/1000
        y2 = a2*x2 + b2
    return puntos

Then, just run the function for some starting, mid and ending points, and use matplotlib:

lista1 = curva_b(1, 2, 2, 1, 3, 2.5)
lista2 = curva_b(1, 2, 2.5, 1.5, 3, 2.5)
lista3 = curva_b(1, 2, 2.5, 2, 3, 2.5)
lista4 = curva_b(1, 2, 1.5, 3, 3, 2.5)

fig, ax = plt.subplots()
ax.scatter(*zip(*lista1), s=1, c='b')
ax.scatter(*zip(*lista2), s=1, c='r')
ax.scatter(*zip(*lista3), s=1, c='g')
ax.scatter(*zip(*lista4), s=1, c='k')

This should be the results:

several Bezier quadratic curves

By extending the code a little more, you can get forms like this:

Bezier quartic curve