One file, no installation

Everything in this course runs from a single HTML file. Create a file called playground.html, paste this in, and open it in your browser.



ML playground





Open it. You should see an empty box and the word “ready” underneath. That is the whole setup.

Two helpers we will reuse

Canvas measures from the top left, with y increasing downwards. Our data will use ordinary maths coordinates, with y increasing upwards. Rather than getting confused about this every time, we write one function that converts between them.

const view = { xMin: 0, xMax: 10, yMin: 0, yMax: 10 };

function toScreen(x, y) {
  const sx = (x - view.xMin) / (view.xMax - view.xMin) * canvas.width;
  const sy = canvas.height - (y - view.yMin) / (view.yMax - view.yMin) * canvas.height;
  return [sx, sy];
}

function dot(x, y, color = "#c33", r = 4) {
  const [sx, sy] = toScreen(x, y);
  ctx.fillStyle = color;
  ctx.beginPath();
  ctx.arc(sx, sy, r, 0, Math.PI * 2);
  ctx.fill();
}

function line(x1, y1, x2, y2, color = "#333") {
  const [ax, ay] = toScreen(x1, y1);
  const [bx, by] = toScreen(x2, y2);
  ctx.strokeStyle = color;
  ctx.beginPath();
  ctx.moveTo(ax, ay);
  ctx.lineTo(bx, by);
  ctx.stroke();
}

toScreen does the conversion. dot and line use it so that the rest of our code can think entirely in data coordinates and never worry about pixels again.

0 3 6 9 20 60 100 x, in data units y, in data units (4, 60) y goes up px py origin (112, 103) y goes down toScreen does one job: flip y, and rescale
The only thing toScreen does is this flip, plus a rescale. Every plotting bug in this course is a point that went through it once too often, or not at all.

Check that it works

Add this at the bottom of the script and reload.

const data = [[1, 3], [2, 5], [3, 7], [4, 9]];
for (const [x, y] of data) dot(x, y);
line(0, 1, 10, 21);
log("plotted", data.length, "points");

You should see four red dots sitting exactly on a black line. The line is y = 2x + 1, which is the rule the data came from. Seeing the points land on it is your confirmation that the coordinate conversion is correct.

Keep this file

Every later lesson assumes this playground exists. Save a clean copy before you start editing, so you can always return to a working version. If a demo ever behaves strangely, start from the clean copy and add code back a piece at a time.

Try this before the next section

  1. Change view.xMax to 20 and reload. Explain what happened to the dots and why.
  2. Write a function grid() that draws faint lines at every whole number in both directions.
  3. Plot the points from y = 2x + 1, but move one of them off the line by hand. This is what noisy data looks like, and every dataset in the real world looks like this.