Last year I wrote a Drawbot tutorial on Medium.

If you want to jump directly into the code, here's the source:

```
##############################
# Draw Wiggles using Drawbot #
##############################
"""
Script by Roberto Arista, you can find the related tutorial here: https://medium.com/@roberto_arista/how-to-draw-a-wiggle-between-two-points-with-python-and-drawbot-788006c18fb0
You can find drawbot here: http://www.drawbot.com/
Code distributed with no guarantee, use at your own risk
"""
### Modules
from math import radians, atan2, sqrt, sin, cos
from collections import namedtuple
### Constants
BLACK = (0, 0, 0)
Point = namedtuple('Point', ['x', 'y'])
### Function & procedures
def calcAngle(pt1, pt2):
return atan2((pt2.y - pt1.y), (pt2.x - pt1.x))
def calcDistance(pt1, pt2):
return sqrt((pt1.x - pt2.x)**2 + (pt1.y - pt2.y)**2)
def calcWiggle(pt1, pt2, waveLength, waveHeight, curveSquaring=.57):
assert 0 <= curveSquaring <= 1, 'curveSquaring should be a value between 0 and 1: {}'.format(curveSquaring)
assert waveLength > 0, 'waveLength smaller or equal to zero: {}'.format(waveLength)
diagonal = calcDistance(pt1, pt2)
angleRad = calcAngle(pt1, pt2)
howManyWaves = diagonal//int(waveLength)
waveInterval = diagonal/float(howManyWaves)
maxBcpLength = sqrt((waveInterval/4.)**2+(waveHeight/2.)**2)
bcpLength = maxBcpLength*curveSquaring
bcpInclination = calcAngle(Point(0,0), Point(waveInterval/4., waveHeight/2.))
wigglePoints = [pt1]
prevFlexPt = pt1
polarity = 1
for waveIndex in range(0, int(howManyWaves*2)):
bcpOutAngle = angleRad+bcpInclination*polarity
bcpOut = Point(prevFlexPt.x+cos(bcpOutAngle)*bcpLength, prevFlexPt.y+sin(bcpOutAngle)*bcpLength)
flexPt = Point(prevFlexPt.x+cos(angleRad)*waveInterval/2., prevFlexPt.y+sin(angleRad)*waveInterval/2.)
bcpInAngle = angleRad+(radians(180)-bcpInclination)*polarity
bcpIn = Point(flexPt.x+cos(bcpInAngle)*bcpLength, flexPt.y+sin(bcpInAngle)*bcpLength)
wigglePoints.append((bcpOut, bcpIn, flexPt))
polarity *= -1
prevFlexPt = flexPt
return wigglePoints
def drawCurvesSequence(wigglePoints):
myBez = BezierPath()
myBez.moveTo(wigglePoints[0])
for eachBcpOut, eachBcpIn, eachAnchor in wigglePoints[1:]:
myBez.curveTo(eachBcpOut, eachBcpIn, eachAnchor)
myBez.endPath()
drawPath(myBez)
### Variables
pt1 = Point(50, 50)
pt2 = Point(150, 60)
### Instructions
size(400, 400)
oval(pt1.x-1, pt1.y-1, 2, 2)
oval(pt2.x-1, pt2.y-1, 2, 2)
stroke(*BLACK)
strokeWidth(.5)
fill(None)
wigglePoints = calcWiggle(pt1, pt2, 16, 36, .7)
drawCurvesSequence(wigglePoints)
```