An ordinary graph maps a number to a number, so a curve fits on a flat screen. A complex function maps a plane to a plane — two inputs, two outputs, four dimensions — and there's no curve to draw.
So we do what mathematicians do on paper: we paint the plane. Here's how domain coloring works, the small evaluator behind it, and how it stays interactive in a browser tab without WebGL. Everything below is live in the free LK Forge graphing calculator — press f(z) and follow along.
Two numbers, two channels of colour
Every output f(z) is a complex number, and a complex number has exactly two visible parts: an angle (its argument) and a size (its modulus). Domain coloring spends one visual channel on each:
-
Hue = the argument of
f(z)— red one way, cyan the opposite way, a full colour wheel for a full turn. -
Brightness = the modulus — dark where
f(z)is near zero, bright where it grows large.
That one rule makes the features that matter jump out. A zero is a dark spot with the whole colour wheel wrapped around it. A pole (where the function runs to infinity) is a bright spot, also ringed by every hue. Faint contour rings mark each doubling of the modulus, so you read growth like a topographic map reads elevation.
The evaluator: the same parser, a different number
The 2D graph and the complex plane share one expression parser — a shunting-yard compiler with no eval() anywhere. The only thing that changes is what sits on the evaluation stack:
- Real graph → the stack holds ordinary numbers.
-
f(z)→ the stack holds{re, im}pairs, and each operator does complex arithmetic.
The imaginary unit i is just the constant {re: 0, im: 1}, and every function gets its principal-branch definition, so the identities you'd check by hand come out exactly right:
i² = -1
√(-1) = i
ln(-1) = πi
e^(iπ) = -1
Each of those is what the live evaluator returns, to six decimals.
Speed matters, because the picture is built one pixel at a time. Timed in the browser, the complex evaluator runs about 3.4 million evaluations per second (200,000 evaluations of a rational function in 58 ms) on a single thread — enough to colour a full board and still respond to a drag.
Interactive speed without WebGL
There's no 3D here and no shader — the whole plane is drawn on a plain 2D canvas. The trick is resolution:
- The plane is sampled into a half-resolution offscreen canvas (one sample per 2×2 block, ~77,000 for a full board) and scaled up with smoothing — close enough that the eye can't tell.
- While dragging or zooming it drops to quarter resolution for a fluid feel, then repaints once at higher resolution 140 ms after you stop.
- No animation loop runs when the image is still, so an idle plane costs nothing.
Because it's all arithmetic through a safe parser, a shared link can only ever draw a picture — ?cx= in the URL loads any f(z) straight onto the plane.
A field guide: reading functions by their fingerprint
Once you know the rule, each function has a signature you can read at a glance. Count how many times the colour wheel wraps a spot and you have the order of that zero or pole.
-
z²— a double zero. One dark point at the origin, but the hue wheel wraps it twice: squaring doubles every angle. Open it → -
1/z— a single pole. A bright point instead of a dark one, hue running the opposite way. Poles are zeros turned inside out. Open it → -
(z² − 1)/(z² + 1)— zeros meet poles. Two dark zeros at ±1, two bright poles at ±i. Open it → -
z³ − 1— three roots of unity. Three dark zeros evenly spaced on the unit circle. Open it → -
sin(z)— a row of zeros. Dark spots at every multiple of π, brightness climbing fast off the real axis. Open it → -
eᶻ— no zeros, no poles. Horizontal bands of hue: the argument depends only on the imaginary part, brightness only on the real part. Open it → -
ln(z)— a branch cut. One zero at z = 1 and a sharp seam along the negative real axis where the colour jumps. Domain coloring makes branch cuts visible. Open it →
Try it on your own function
Domain coloring turns "what does this function do near its zeros?" from a paragraph of algebra into a picture you read in a second. Open the graphing calculator, press f(z), and type something of your own — conj(z), z + 1/z, (z − i)/(z + i) — then hover to read z and f(z). A Colour intensity slider runs from pastel to vivid.
Full write-up with the maths: Domain Coloring: How We Plot Complex Functions in the Browser. Free, no sign-up, everything runs client-side.
Top comments (0)