[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky]
[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Draw a smoothly shaded Mandelbrot set fractal in Python and tkinter

[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
[Smoothly shaded Mandelbrot set fractal]
The example Draw the Mandelbrot set and zoom in on areas in Python and tkinter explains how to draw a Mandelbrot set by iterating the following equation.

Z(n) = Z(n-1)2 + C

Where Z(n) and C are complex numbers. The program iterates this equation until the magnitude of Z(n) is at least 2 or the program performs a maximum number of iterations.

It then uses the number of iterations to determine a color for the pixel. For example, if the program is using K colors and it performed I iterations, then it assigns the point color number I mod K.

This example modifies the coloring algorithm to produce smoothly varying colors. First note that the following value mu approximates the fractional number of iterations that would be needed before the magnitude of Z(n) is at least 2.

mu = iteration + 1 - math.log(math.log(abs(z))) / log_escape

Here iteration is the number of iterations actually performed, abs(z) is the magnitude of z right after the magnitude is greater than 2, and log_escape is the logarithm of the escape radius 2.

This value only approximates the actual expected fractional number of iterations and there is a noticeable error where the colors don't blend smoothly. Fortunately it's easy to reduce the error by using a later value of Z(n). For example, if you use Z(n + 3), then the error isn't noticeable. The following shows the code used by the program to calculate mu.

# Reduce the error in mu. for i in range(3): z = z * z + c iteration += 1 mu = iteration + 1 - math.log(math.log(abs(z))) / log_escape

This program also provides one other smooth color model. If you uncheck the Parameters menu's Repeat Colors item, the program scales the resulting value of mu so it varies only once over the available colors as the number of iterations varies from 0 to the maximum number of iterations. That means the colors do not repeat and you get a very gradual smoothing.

if not self.repeat_colors.get(): mu = mu / self.max_iterations * len(colors)

Finally after calculating mu with whichever method, the code calls the following get_color method to return an appropriate color for the pixel.

def get_color(self, colors, mu): '''Get a color for this pixel.''' clr1 = int(mu) t2 = mu - clr1 t1 = 1 - t2 clr1 = clr1 % len(colors) clr2 = (clr1 + 1) % len(colors) r = int(colors[clr1][0] * t1 + colors[clr2][0] * t2) g = int(colors[clr1][1] * t1 + colors[clr2][1] * t2) b = int(colors[clr1][2] * t1 + colors[clr2][2] * t2) return (r, g, b)

The get_color method truncates mu to find an integer color index value and a fractional value. It then returns a color that uses the weighted average of the integer color and the following color.

Download the example to experiment with it and to see additional details.

© 2024 Rocky Mountain Computer Consulting, Inc. All rights reserved.