```python
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad # numerical integration
import matplotlib.cm as cm # for colormaps 
def involute(f, df, x0, l0, dxs):

   """
   f: the function that produces the curve
   df: the derivative. That is, df(x) = f'(x)
   x0: the origin point
   l0: the string length at origin point
   dxs: the differential points at which to plot the involute. 
       Assumed to be sorted in increasing order
   returns f_xs, f_ys, inv_xs, inv_ys
   """
   f_xs = x0 + dxs
   f_ys = f(f_xs)
   
   inv_xs = np.zeros(len(dxs))
   inv_ys = np.zeros(len(dxs))
   arclength_integrand = lambda x: np.sqrt(1 + df(x)**2)
   for i in range(len(dxs)):
       x = x0 + dxs[i]
       arclength = quad(arclength_integrand, x0, x)[0]
       string_length = l0 - arclength
       string_angle = np.arctan(df(x))
       inv_xs[i] = f_xs[i] + string_length * np.cos(string_angle)
       inv_ys[i] = f_ys[i] + string_length * np.sin(string_angle)
       
   return f_xs, f_ys, inv_xs, inv_ys

def plot_line(x, y, slope, dxmin, dxmax, **kwargs):

   plt.plot([x+dxmin, x+dxmax], [y+dxmin*slope, y+dxmax*slope], 
            **kwargs)

f = lambda x: x**3
df = lambda x: 3 * x**2
f_xs, f_ys, inv_xs, inv_ys = involute(f, df, 0, l0=0.8, dxs=np.arange(200) / 100 - 1)
y_x_ratio = 1
plt.figure(figsize=(16, int(16*y_x_ratio)))
plt.plot(f_xs, f_ys)
for l0 in np.arange(20)/10-1:

   f_xs, f_ys, inv_xs, inv_ys = involute(f, df, 0, l0=l0, dxs=np.arange(200) / 100 - 0.5)
   plt.plot(inv_xs, inv_ys, color='green', linewidth=0.2)

for x in np.linspace(-0.5, 0.5, 15):

   y = f(x)
   slope = df(x)
   plot_line(x, y, slope, -1, +2, color=cm.viridis(x), marker='o',markersize=5, linewidth=1)

xlim_low = -0.5
xlim_width = 2
ylim_low = -0.5
plt.xlim(xlim_low, xlim_low + xlim_width) 
plt.ylim(ylim_low, ylim_low + xlim_width * y_x_ratio)
plt.savefig("involutes of a cubic curve.svg")
plt.show()

```
Own work
Cosmia Nebula