pie
ExamplesDocs

Topics

  • Canvas
  • Reactivity
  • Broadcasting
  • Autodiff
  • Animation
  • Sorting
  • Line fit
  • Convex hull
  • Python
unitgridOpacitycanvasColororiginXoriginY

Fitting a line

The least-squares line is the line that makes the vertical gaps to the points as small as possible, measured by the total of their squares. Here those squares are drawn on the canvas. Every red point can be dragged, and everything refits as it moves.

np.polyfit(x, y, 1) returns the slope and intercept of the least-squares line. Each square's left side is the gap between a point and the line.

pie.clear()
import numpy as np
xs = [-5, -3.5, -2, -1, 0.5, 2, 3, 4.5]
ys = [-2.6, -1.2, -1.8, 0.4, 0.1, 1.6, 1.1, 2.9]
pts = [pie.point(x, y, fill='crimson') for x, y in zip(xs, ys)]

def best_slope(*ps):
    x, y = np.array(ps).T
    return np.polyfit(x, y, 1)[0]

def best_intercept(*ps):
    x, y = np.array(ps).T
    return np.polyfit(x, y, 1)[1]

def y_on(m, b, x):
    """The height of the line y = mx + b at x."""
    return m * x + b

def gap(p, m, b):
    """The vertical distance from point p to the line."""
    return abs(p[1] - y_on(m, b, p[0]))

def square_center(p, m, b):
    return p[0] + gap(p, m, b) / 2, (p[1] + y_on(m, b, p[0])) / 2

def describe(m, b, *ps):
    total = sum(gap(p, m, b) ** 2 for p in ps)
    return f'y = {m:.2f}x + {b:.2f}, squares: {total:.2f}'

line_y = pie.lift(y_on, pie.Scalar)
side = pie.lift(gap, pie.Scalar)
center = pie.lift(square_center, pie.Point)

m = pie.lift(best_slope, pie.Scalar)(*pts)
b = pie.lift(best_intercept, pie.Scalar)(*pts)
left = pie.point(-20, line_y(m, b, -20), hidden=True)
right = pie.point(20, line_y(m, b, 20), hidden=True)
pie.line(left, right, stroke='teal')
for p in pts:
    pie.square(center(p, m, b, hidden=True), side(p, m, b), fill='rgba(13, 148, 136, 0.15)', stroke='teal')
pie.text(pie.lift(describe, str)(m, b, *pts), 0, 4.5, 14, stroke='#1c1917')

Drag any red point. The line, the squares and the numbers follow it.

The gaps are squared, so a point twice as far from the line costs four times as much. Drag one point far away and see how hard it pulls the line: a single outlier can tilt the whole fit.