[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky] [Facebook]
[Build Your Own Python Action Arcade!]

[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 escape time polynomial fractals in Python

[This program draws escape time polynomial fractals in Python]

Earlier I made two posts that explain how to draw Mandelbrot set and Julia set fractals.

This example generalizes the approach used by those two sets to produce a new family of fractals.

Approach

Here's the basic approach used to draw the Mandelbrot and Julia sets.
  1. For each pixel location (x, y) in the image:
    1. Initialize Z0 to some value
    2. Iterate the equation Zn+1 = F(Zn) for some function F until either:
      1. The magnitude of Zn diverges toward infinity
      2. A certain number of iterations have passed
    3. Use the number of iterations that were performed to set the pixel's color.
To draw the Mandelbrot and Julia sets, you use specific values for Z0 and the function F. To get a Mandelbrot set:
  • Z0 = 0
  • F is Zn+12 + (x + y * j)

To get a Julia set:

  • Z0 = (x + y * j)
  • F is Zn+12 + 1

This example lets you enter your own values for those two parameters at run time.

Parsing Functions

Here's the code that parses the equations that you enter into the Entry widgets.

# Get the Z0 and Zn+1 functions. function_def = \ f'''def func_z0(x, y): try: return {self.z0_var.get()} except: return 1000''' exec(function_def, globals()) if SHOW_FUNCTIONS: print(function_def, '\n') function_def = \ f'''def func_zn_plus_1(zn, x, y): try: return {self.zn_plus_1_var.get()} except: return 1000''' exec(function_def, globals()) if SHOW_FUNCTIONS: print(function_def, '\n')

This code sets variable function_def to a string that defines a function that incorporates the text you entered. It then calls exec(function_def, globals()) to execute the string as Python code. The second parameter to exec stores the resulting function in the global namespace so the program's code can use it.
Note: In general, executing code entered by the user is not safe because the user could enter code that deletes files, executes other programs, or does other evil things to your computer.

Only use exec if you trust your users and know they won't enter anything naughty.

If the SHOW_FUNCTIONS variable is True, the program prints out the strings that define the functions. Here's one example.

def func_z0(x, y): try: return 0 + 0j except: return 1000 def func_zn_plus_1(zn, x, y): try: return zn ** 2 + x + y * 1j except: return 1000

These are just simple functions that return numeric results. The func_z0 function uses a pixel's coordinates (x, y) to set Z0 for the fractal algorithm. The function func_zn_plus_1 calculates Zn+1 from Zn and the pixel's coordinates.

Calling the Functions

The code that builds the fractal is similar to the previous Mandelbrot and Julia set code except it calls functions func_z0 and func_zn_plus_1 instead of using hard-wired functions. Here's that code with the new function calls highlighted in blue.

# Loop over the pixels. for pix_x in range(image_wid): for pix_y in range(image_hgt): # Calculate this point's color. x, y = self.d_to_w(pix_x, pix_y) z0 = func_z0(x, y) # analysis:ignore z = z0 iteration = 0 while ((iteration < max_iterations) and (abs(z) < escape_radius)): # Calculate Z(clr). z = func_zn_plus_1(z, x, y) # analysis:ignore iteration += 1 # Set the pixel's color. if (iteration >= max_iterations): color = black else: if self.use_smooth_colors.get(): # Reduce the error in mu. for i in range(3): z = func_zn_plus_1(z, x, y) # analysis:ignore iteration += 1 try: # cmath.log provides a more interesting picture # because it is defined for negative numbers # while math.log is not. mu = abs(iteration + 1 - cmath.log(cmath.log(abs(z))) / log_escape) except: mu = 0 if not self.repeat_colors.get(): mu = mu / max_iterations * len(colors) color = self.get_color(colors, mu) else: color = colors[iteration % len(colors)] self.pixels[pix_x, pix_y] = color

Notice that the calls to the new functions are followed by the comment # analysis:ignore. Because the functions are not defined within the code, Spyder (or whatever Python environment you're using) can't see them so it won't understand what they are and it will display a warning. The comment tells Spyder to ignore this issue and not display the warning.

Meanwhile, the Python interpreter treats this is a normal comment and ignores it. Note that this is not a standard Python language thing, so some environments may not know how to use it. the console

Conclusion

This version of the program lets you enter equations to set Z0 and determine how to calculate Zn+1. The program's Presets sub-menus contain several examples that you can use to generate the pictures below. You can also use them as starting points for your own experiments.

Be sure to enter the two equations correctly. In particular, you cannot say something like yj or y * j, you must use y * 1j instead. If you have any mistakes in the equations, the program will print a syntax error in the console and the user interface won't do anything.

Download the example to experiment with it and to see additional details. If you generate any interesting pictures, post them (or links to them) in the comments. Be sure to include your equations so others can reproduce your results.

A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal
A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal
A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal A escape time polynomial fractal
© 2025 Rocky Mountain Computer Consulting, Inc. All rights reserved.