Chapter 15 · Part V · Color & computer fractals

Escape time & smooth color

Every color in a Mandelbrot picture is an answer to one question: how many steps did this point take to run away? This chapter shows what that count is, why it makes stripes, and the small piece of logarithm algebra that turns the stripes into silk.

2the escape radius: once an orbit of z² + c gets farther than 2 from zero, it is certain to run off to infinity
about 10more squarings after |z| passes 2 before the number overflows a 64-bit float (about 1.8 × 10³⁰⁸)
22%of full brightness from an sRGB pixel value of 128: half the code is not half the light

Common mix-up: the colors are not part of the Mandelbrot set. The set is only the black region. Every color outside it is a choice the programmer made about how to show one number per pixel: how quickly that point escaped.

The picture is a chart

What the colors encode

Take a pixel. It sits at some point in the complex plane, and that point is a number, c. Start with z = 0 and apply the rule z → z² + c over and over: z₁ = c, z₂ = c² + c, and so on (Chapter 8 walks through the rule itself). The sequence of z values is the point's orbit. Either it stays near zero forever, and c belongs to the Mandelbrot set, or it eventually grows without limit, and c does not.

A computer cannot wait forever, so it asks a cheaper question. It counts the steps until |z|, the distance from zero, passes a fixed radius. That count is the escape time, written n. If the orbit is still inside the radius after some maximum number of steps, the program gives up and calls the point "inside". This is the escape-time algorithm, and nearly every Mandelbrot picture you have ever seen was drawn with it.

So a fractal image is really a chart of one number per pixel. Points far from the set escape in one or two steps. Points close to its edge can circle for hundreds or thousands of steps before they break away. The color is a look-up: count in, color out. Change the look-up and the same numbers give a completely different picture, which is the subject of the next chapter.

The radius is called the bailout radius, R. The smallest safe choice is 2, for a reason worth seeing once: it is the point of no return.

n(c) = the first step k with |zₖ| > R, where z₀ = 0, zₖ₊₁ = zₖ² + c
The escape time of a pixel. Every colored pixel in an escape-time picture stores this one whole number; the black ones never reached R.
Go deeper: why 2 is the point of no return

Suppose at some step |z| > 2 and |z| ≥ |c|. The next value is z² + c, and the triangle inequality says its size is at least |z|² − |c|. Since |c| ≤ |z|, that is at least |z|² − |z| = |z|(|z| − 1). Because |z| > 2, the factor |z| − 1 is bigger than 1, so the next |z| is strictly larger than this one, and by a factor that itself keeps growing. The orbit can never come back.

The condition |z| ≥ |c| is always met here. Every point of the Mandelbrot set has |c| ≤ 2, so for points near the set, passing 2 means passing |c| too. And if |c| > 2, the very first step gives z₁ = c, which is already outside the circle; that point escapes at step 1. Either way, the first time |z| goes past 2, the answer is settled.

That makes 2 the smallest bailout that never gives a wrong answer. Any bigger radius is also correct; it just takes a few more steps to reach. Later in this chapter, that "few more steps" turns out to be a bargain.

Stored per pixelWhat it isUsed for
nThe escape step, a whole numberClassic banded coloring
|zₙ|How far past the radius the orbit landed on that stepThe fractional part that smooths the bands
inside?Whether the orbit was still bounded at the iteration limitPainting the set itself, usually black
orbit statisticsSmallest |z| reached, final |z|, average angle and so onInterior coloring and orbit traps (Chapter 17)
Stripes

Why whole-number counts make bands

Color each pixel by its count and the picture splits into rings. All the points that escape in exactly 5 steps form one ring, all the points that take 6 form the next one in, and so on toward the set. Each ring gets one color. Where two rings meet, the color jumps.

That is not a bug in the program. It is what whole numbers do. The count can only be 5 or 6, never 5.4, so neighboring pixels whose orbits were nearly identical, one escaping just before step 6 and one just after, are forced into different classes. The boundary between rings is a level set: a contour line, exactly like the lines on a hiking map, except that the map has only whole-number heights.

Far from the set the rings are wide, smooth curves. Near the set they crowd together, because a tiny move in c can change the orbit's fate by many steps. In the seahorse valleys and spirals the rings pile up so tightly that, with a palette that changes quickly, they shimmer into noise.

Banding is sometimes exactly what you want: the rings are honest, and the early printed pictures of the set used them to good effect. But they put fake edges into a picture whose real structure is smooth everywhere outside the set. The next few sections show how to recover that smoothness from information the program already had and threw away.

Go deeper: the rings are approximate equipotentials

Imagine the Mandelbrot set as a charged metal object. The electric potential around it is a smooth function, G(c), that is zero on the set and grows outward. Adrien Douady and John Hubbard used this potential, through a map named after Lucjan Böttcher, in their 1982 proof that the set is connected. Its level curves, the equipotentials, are smooth closed loops that wrap the set ever more tightly as G shrinks.

The band edges of an escape-time picture are rough copies of those loops. A band edge is where |zₙ| = R exactly for some n, and for large R that curve is very nearly the equipotential G = (ln R)/2ⁿ. As R grows, the match improves. With R = 2, the edges are visibly kinked near the set; with R = 1,000,000 they are almost exactly the equipotential lines. That fact is the whole reason the smoothing formula below works.

How far is far

The bailout radius

If 2 is enough to decide whether a point escapes, why would anyone use more? Because the program is not just deciding; it is measuring. The escape step n is a coarse measurement. How far past the radius the orbit landed is a fine one, and it is only trustworthy when the orbit is already far out, where the "+ c" in z² + c hardly matters.

Raising R costs surprisingly little. Out past the circle, each step roughly squares |z|. Squaring is fast: 2 becomes 4, then 16, then 256, then 65,536. To go from a radius of 2 to a radius of a million takes only about four more steps, whatever the point. Those four steps are added to every escaping pixel equally, so the picture's structure doesn't change; only the measurement gets better.

The same squaring sets a hard ceiling. After about ten squarings beyond 2, |z| is around 2¹⁰²⁴, which is past the largest number a 64-bit floating-point value can hold. Programs usually compare |z|² against R² to avoid a square root, so with R = 10⁶ they compare against 10¹², which is still nowhere near trouble. A bailout of 10¹⁰⁰ would also work; there is simply no visible gain beyond about 256.

extra steps ≈ log₂( ln R ⁄ ln 2 )
How many more iterations a bigger bailout costs compared with R = 2, once the orbit is far out. For R = 4 it is 1, for R = 256 it is 3, for R = 10⁶ it is about 4.3.
Bailout RTest (|z|² > R²)Extra steps vs R = 2What smooth coloring looks like
2|z|² > 40Correct escape, but faint seams remain at every band edge
4|z|² > 161Seams much weaker; visible in flat gradients
256|z|² > 65,5363Seams far below one palette step; the usual choice
10⁶|z|² > 10¹²about 4.3Indistinguishable from exact
Instrument 1

Banded versus smooth, same numbers

Both pictures come from one calculation. The left one is colored by the whole-number count n. The right one adds a fraction of the smooth correction; slide it from 0 to 1 and watch the bands melt. Change the bailout and the whole set is recomputed, so you can see the seams that R = 2 leaves behind. Click either picture to zoom in on that spot. Changing the palette, the cycle length or the slider only recolors; it never recomputes an orbit.

Whole-number count n
Smooth count ν
Centre–
View width–
Bailout–
Computed–

Try this: choose the grey ramp and R = 2, set the cycle length short, and look closely at the right-hand picture. Faint ridges sit exactly where the left picture's bands meet. Switch to R = 256 and they vanish. "Stretched" mapping uses (ν ⁄ limit)^γ instead of cycling, so raising the iteration limit changes the colors: one reason most renderers prefer cycling.

Four lines of algebra

Deriving the smooth count

The fix for banding is to add a fraction to n that says how far through its band each pixel is. The program already has what it needs: on the step where the orbit escaped, it knows |zₙ|, how far past the radius it landed. A pixel that only just escaped on step 6 lands barely past R. A pixel that very nearly escaped on step 5 lands far past it, at almost R². That spread, from R to R², is the band's width, measured from the inside. Here is how to turn it into a number between 0 and 1, one step at a time.

Step 1: far out, the "+ c" stops mattering

Once |z| is large, z² is enormous compared with c. If |z| is 1,000, z² has size 1,000,000, and adding a c of size 2 or less changes it by a fraction of a millionth. So, to excellent accuracy, each step simply squares the size.

|zₖ₊₁| ≈ |zₖ|²
Far from zero, iterating z² + c is just squaring. The approximation gets better the larger |z| is, which is why a larger bailout gives smoother results.

Step 2: take one logarithm, and squaring becomes doubling

A logarithm turns powers into multiples: ln(x²) = 2 ln x. So the natural log of the size doubles every step. It is still growing very fast, but now it grows in a simple, predictable way.

ln|zₖ₊₁| ≈ 2 · ln|zₖ|
The log of the size doubles each step. If ln|z| is 3 now, it will be about 6, then 12, then 24.

Step 3: take a second logarithm, and doubling becomes counting

Doubling is itself a power: something that doubles every step is 2 to the power of the step number. Take a base-2 logarithm of it and you get the step number back. So log₂ of ln|z| goes up by exactly 1 each step, like a clock ticking once per iteration. That is the whole reason for the "log of a log": the first log undoes the squaring, the second undoes the doubling, and what is left is linear in the step count.

log₂(ln|zₖ₊₁|) ≈ log₂(ln|zₖ|) + 1
After two logarithms, one more iteration simply adds 1. This quantity is a clock that counts steps continuously.

Step 4: subtract the clock from the count

Now compare two ways of describing the same orbit. Stop at step n and you have the pair (n, log₂ ln|zₙ|). Stop one step later and you have (n + 1, log₂ ln|zₙ| + 1). Both numbers went up by one. Their difference did not change. So n − log₂(ln|zₙ|) is the same no matter which step you happened to stop on. It depends on c alone, and it changes smoothly as c moves.

That is exactly what fixes the bands. At a band edge, one pixel stops on step 6 and its neighbor on step 5, but both report the same value of n − log₂(ln|zₙ|), so there is no jump. Adding 1 keeps the result close to n and positive, and gives the standard formula.

ν = n + 1 − log₂( ln|zₙ| )
The smooth, or normalized, iteration count. n is the escape step and |zₙ| is the size on that step. The natural log is inside, the base-2 log is outside. Use a bailout of at least 2; larger is smoother.

The correction 1 − log₂(ln|zₙ|) is the "fractional part" the instruments in this chapter show. With R = 2 it lies between about 0.16 and 1.53. With a bigger radius it turns negative, because n itself is bigger: every extra step the larger radius costs adds one to n and one to the clock, and the two cancel. That is a pleasant property. Apart from the small errors of step 1, ν comes out the same whatever bailout you choose, so a palette tuned at one radius still fits at another.

Go deeper: the normalized form, other powers, and the potential

A version that stays between n − 1 and n. Dividing by the bailout before the second log gives μ = n − log₂(ln|zₙ| ⁄ ln R). Because R < |zₙ| ≤ about R² (a little more, since c is added), the ratio ln|zₙ| ⁄ ln R lies between 1 and 2, so its log₂ lies between 0 and 1, and μ lies between n − 1 and n. ν − μ is the constant 1 − log₂(ln R), the same for every pixel, so either formula gives the same picture with the palette shifted. The trade: μ is tidy within each band, while ν stays put when you change R.

Other powers. For z^d + c, each step raises the size to the power d instead of 2, so the second logarithm has base d: ν = n + 1 − log_d(ln|zₙ|). The Multibrot pictures in Chapter 10 use this. For Burning Ship and Tricorn, which also square the size, the base stays 2.

Where it really comes from. The potential from the bands section can be computed as G(c) = lim 2⁻ⁿ ln|zₙ|. Take log₂ of the approximation G ≈ 2⁻ⁿ ln|zₙ| and you get log₂ G ≈ log₂(ln|zₙ|) − n. Rearranged, ν ≈ 1 − log₂ G(c). The smooth count is just the negative logarithm of the potential: its level curves are the equipotentials, and that is why the colors follow smooth loops around the set.

Why not just interpolate the count? You could blend each pixel's count with its neighbors', but that blurs real detail and depends on the image resolution. The log-log formula uses only that pixel's own orbit, so it is exact to the accuracy of step 1, at any zoom.

Instrument 2

One pixel's story

Click anywhere outside the black region. The program follows that point's orbit, draws it on the picture, and shows each step's size. The top chart is |z| on a log scale: watch it hover, then climb past the dashed bailout line. The bottom chart is log₂(ln|z|), the clock from step 3; once the orbit is far out, its dots line up on a staircase rising exactly one per step. The readouts then walk through the formula to the exact palette entry and color of that one pixel. The pale bars after escape are steps the renderer never needs; they are computed here only to show the clock keeps ticking.

Pixel c–
Escape step n–
|zₙ|–
ln|zₙ|–
log₂(ln|zₙ|)–
Fraction 1 − log₂(ln|zₙ|)–
Smooth count ν–
Palette position–
Color–

Palette position = (ν ⁄ 20) mod 1, times 256 entries. The picture uses that same rule for every pixel, so the swatch is exactly the color under the crosshair.

Step kzₖ|zₖ|ln|zₖ|log₂(ln|zₖ|)
The last seams

Why a bigger bailout is smoother

The derivation rested on one approximation: that far out, a step squares the size and the "+ c" doesn't matter. How far out is far enough? The error that c introduces at the escape step is at most about |c| ⁄ |zₙ|² as a fraction of the size. With R = 2, |zₙ| can be as small as 2 and |c| as large as 2, so the error can be a large fraction, and the clock in step 3 ticks unevenly on the first beat. That shows up as faint creases in the smooth picture, exactly where the old band edges were.

With R = 256 the same error is at most about 2 ⁄ 65,536, around three thousandths of a percent, and the creases fall far below anything a palette can show. That is why 256 is a common default, and why the seam readouts in the slice below collapse as you raise R. Four extra iterations per pixel to make a picture seamless is a trade any renderer will take.

There is a second, quieter benefit. Some coloring methods that come later, such as the distance estimate in Chapter 17, also rely on the orbit being far out when it stops. A large bailout makes all of them more accurate at once.

Instrument 3

A slice through the picture

This samples one straight line of points, one per screen pixel, and plots both counts along it. The grey staircase is n; the colored curve is ν. Every step of the staircase is a band edge in the pictures above. The program also computes every point a second time with a huge bailout, 10¹⁰, as an "exact" reference, and measures how far this bailout's ν is from it. Inside a band that error changes smoothly; where n jumps, any sudden change in the error is a seam you could see. A perfect formula would show none.

Band edges crossed–
Average seam in ν–
Worst seam in ν–
Worst error vs exact ν–

On the real axis right of the cusp at c = 0.25, the counts climb like π ⁄ √(c − 0.25) as you approach the set: that is the narrow neck where orbits linger longest. Compare the worst seam at R = 2, about a tenth of a count, with R = 256, around a millionth.

The black part

Coloring the inside

Points inside the set never escape, so they have no escape time. The traditional answer is to paint them black, and it is a good one: the set reads as a solid silhouette and all the attention goes to the edge. But the orbits inside are not idle. Most of them settle down onto a repeating cycle, and the program has watched them do it for the whole iteration limit. That gives several honest things to show.

  • Final |z|. Where the orbit happens to be when the limit runs out. Points in the main cardioid converge to a single fixed point, so this varies smoothly across the cardioid; it is the "final |z|" option in Instrument 1.
  • Smallest |z| reached. How close the orbit ever came to zero. This draws faint circular patterns inside the bulbs and is the simplest example of an orbit trap, the family of techniques in Chapter 17.
  • Period. How many points are in the cycle the orbit settles into. Each bulb has one period: 1 for the main cardioid, 2 for the big disk to its left, 3 for the two largest bulbs on top and bottom. Coloring by period paints each bulb a flat color.
  • How fast it converged. The interior analogue of escape time: the number of steps until the orbit is within some tiny distance of its cycle.

There is also a practical reason to care about the inside: it is where all the time goes. An outside pixel stops when it escapes; an inside pixel runs the full iteration limit. Renderers save most of that by skipping two regions that can be tested with a formula, the main cardioid and the period-2 disk, and by periodicity checking: remember z every so often, and if the orbit lands on the remembered value again, it is in a cycle and will never escape. The instruments on this page do both.

Go deeper: the two shortcut tests

The main cardioid is the set of c for which z² + c has an attracting fixed point. Writing q = (x − ¼)² + y² for c = x + iy, the point is inside the cardioid when q(q + x − ¼) ≤ ¼y². The period-2 disk is simply the disk of radius ¼ around −1: (x + 1)² + y² ≤ 1⁄16. Together these two regions cover most of the set's area in a whole-set view, so testing them first can make the first picture several times faster.

Neither test helps with the smaller bulbs, which is where periodicity checking takes over. The checking must use a tolerance a little smaller than the pixel size: too tight and nearly-periodic orbits are never caught; too loose and a slowly escaping point near the edge is wrongly declared inside.

Count in, color out

From ν to a palette index

A smooth count ν is a real number, typically somewhere from 1 to a few thousand. A palette is a strip of colors, usually stored as a table of 256 or 1,024 entries. The last step is to map one onto the other, and there are only a few sensible ways to do it.

Cycling. Divide ν by a cycle length P, keep the fractional part, and use it as a position along the palette: index = (ν ⁄ P + offset) mod 1. The palette repeats every P counts. Because it never runs off the end, it works at any zoom and for any iteration limit, and it is what most renderers do. A short P shows fine structure but turns to noise near the set, where ν changes by many counts from one pixel to the next. A long P is calm but can look flat. The offset slides every color along the palette at once; animate it and you have palette cycling, which the next chapter takes apart.

Stretching. Divide ν by the iteration limit to get a number from 0 to 1 and use the palette once. It sounds tidy, but almost every pixel has a small count compared with the limit, so the whole picture lands in the first sliver of the palette. Raising the limit to see more detail then shifts every color. Applying an exponent γ less than 1, (ν ⁄ limit)^γ, spreads out the small values; a logarithm does the same more strongly. The fully adaptive version of this idea is histogram coloring, also in the next chapter.

The same word, gamma, means something else in the next step, and both matter. Screens do not emit light in proportion to the number stored in a pixel. The sRGB standard that nearly every screen follows uses a curve that is close to a power of 2.2, so a pixel value of 128, half of 255, produces only about 22 percent of full brightness. This is display gamma. It matters whenever colors are mixed: blending two palette entries, or averaging several samples inside one pixel for antialiasing, should be done on the linear light values, not on the stored numbers.

index = ⌊ 256 · frac( ν ⁄ P + offset ) ⌋
Cyclic palette lookup. frac keeps only the fractional part, so the palette repeats every P counts. This is the rule Instrument 2 uses for its swatch, with P = 20.
Go deeper: antialiasing averages colors, not counts

The edge of the set is infinitely detailed, so a single sample per pixel aliases: thin filaments flicker in and out as you move. The fix is to take several samples inside each pixel and average. The order matters. Averaging the counts first and then looking up one color produces a color that none of the samples had, often from a different part of the palette entirely. Look up each sample's color first, convert to linear light, average, and convert back.

A small check of why linear light matters: a fine checkerboard of black and white pixels, seen from across the room, looks like a grey whose stored sRGB value is about 188, not 128. Average in stored values and antialiased edges come out too dark. JellyDazzle's fractal patterns take their colors from the app's live palette, and the next chapter shows how that palette is blended.

MappingRuleGood atWatch out for
Cyclicfrac(ν ⁄ P + offset)Any zoom, any limit; animatesNoise near the set when P is short
Linear stretchν ⁄ limitSimple to explainUses a sliver of the palette; colors move when the limit changes
Power stretch(ν ⁄ limit)^γSpreads the common small countsStill tied to the limit
Log stretchln(1 + ν) ⁄ ln(1 + limit)Deep zooms with a huge range of countsCompresses the outer bands
HistogramFraction of pixels with a smaller countUses the whole palette, alwaysColors change as the view changes (Chapter 16)
Cheat sheet

Terms from this chapter

Orbit
The sequence z₀ = 0, z₁, z₂, … produced by repeating z → z² + c for one pixel's c.
Escape time n
The first step at which |z| passes the bailout radius. A whole number.
Bailout radius R
The size at which an orbit is declared escaped. 2 is the smallest correct value; 256 or more gives smooth coloring.
Iteration limit
The step at which the program gives up and calls a point inside.
Banding
Visible rings caused by coloring with whole-number counts. Each ring is a level set.
Smooth count ν
n + 1 − log₂(ln|zₙ|): a real-valued escape time with no jumps at band edges.
Potential G(c)
The smooth "electric potential" of the set, lim 2⁻ⁿ ln|zₙ|. Its level curves are the shapes the smooth colors follow.
Interior coloring
Any rule for painting points that never escape: black, final |z|, smallest |z|, period.
Periodicity check
Detecting that an orbit has fallen into a cycle, so the program can stop early.
Cycle length P
How many counts one pass through a cyclic palette covers.
Display gamma
The non-linear curve between stored pixel values and emitted light; about a power of 2.2 for sRGB.
Where this comes from

Sources