Mandelbrot set: Difference between revisions
Content added Content deleted
(→Python with and without NumPy (no optimizations): Heading changed: Escape time and normalized iteration count (Basic)) |
(→Mercator zooms of the Mandelbrot set using NumPy: Changed the heading and the algorithm to exterior distance estimation) |
||
Line 7,212: | Line 7,212: | ||
plt.savefig("Mandelbrot.png", dpi=250)</lang> |
plt.savefig("Mandelbrot.png", dpi=250)</lang> |
||
===Advanced: Distance estimation and Mercator zoom=== |
|||
===Mercator zooms of the Mandelbrot set using NumPy=== |
|||
It is possible to print the Mandelbrot set with a scatter plot. |
It is possible to print the Mandelbrot set with a scatter plot. Exterior distance estimation is used, which provides a smooth transition of colors (cf. Wikipedia: [https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Exterior_distance_estimation ''Advanced plotting algorithms: Exterior distance estimation'']). |
||
<lang python>import numpy as np |
<lang python>import numpy as np |
||
import matplotlib.pyplot as plt |
import matplotlib.pyplot as plt |
||
d, h = 60, 40 # pixel density and image height |
d, h = 60, 40 # pixel density and image height |
||
n, r = 50, |
n, r = 50, 1e8 # number of iterations and escape radius (r >> 2) |
||
x = np.linspace(0, 2, d, endpoint=False) |
x = np.linspace(0, 2, d, endpoint=False) |
||
Line 7,226: | Line 7,226: | ||
G = (X - 1) + (Y - h / d) * 1j # rectangular grid around zero |
G = (X - 1) + (Y - h / d) * 1j # rectangular grid around zero |
||
C = (-0. |
C = (-0.8 + 0.2 * 1j) + 1.5 * G |
||
A, B = C.real, C.imag |
A, B = C.real, C.imag |
||
Z = np.zeros_like(C) |
Z, dZ = np.zeros_like(C), np.zeros_like(C) |
||
T = np.zeros(C.shape) |
T = np.zeros(C.shape) |
||
for k in range(n): |
for k in range(n): |
||
M = abs(Z) < r |
M = abs(Z) < r |
||
Z[M] = Z[M] ** 2 + C[M] |
Z[M], dZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1 |
||
T[M] = k + 1 |
|||
N = abs(Z) >= r |
N = abs(Z) >= r |
||
T[N] = |
T[N] = 2 * abs(Z[N]) * np.log(abs(Z[N])) / abs(dZ[N]) |
||
T = T - T.min() # shifting escape times towards zero before compression |
|||
T = T ** 0.5 # compression of the escape times with a concave function |
|||
fig, ax = plt.subplots(figsize=(4, 3)) |
fig, ax = plt.subplots(figsize=(4, 3)) |
||
ax.imshow(T, cmap=plt.cm. |
ax.imshow(T ** 0.2, cmap=plt.cm.nipy_spectral) |
||
plt.savefig("Mandelbrot_set.png", dpi=100) |
plt.savefig("Mandelbrot_set.png", dpi=100) |
||
Line 7,251: | Line 7,247: | ||
fig, ax = plt.subplots(figsize=(6, 4)) |
fig, ax = plt.subplots(figsize=(6, 4)) |
||
ax.scatter(A, B, s=S, c=T, cmap=plt.cm. |
ax.scatter(A, B, s=S, c=T ** 0.4, cmap=plt.cm.nipy_spectral) |
||
plt.savefig("Mandelbrot_plot.png", dpi=100)</lang> |
plt.savefig("Mandelbrot_plot.png", dpi=100)</lang> |
||
A small change in the code above allows Mercator zooms of the Mandelbrot set (cf. David Madore: [http://www.madore.org/~david/math/mandelbrot.html ''Mandelbrot set images and videos'']). |
A small change in the code above allows Mercator zooms of the Mandelbrot set (cf. David Madore: [http://www.madore.org/~david/math/mandelbrot.html ''Mandelbrot set images and videos'']). Compression is used as described by David Madore. |
||
<lang python>import numpy as np |
<lang python>import numpy as np |
||
import matplotlib.pyplot as plt |
import matplotlib.pyplot as plt |
||
d, h = 400, 1200 # pixel density and zoom depth |
d, h = 400, 1200 # pixel density and zoom depth |
||
n, r = 250, |
n, r = 250, 1e8 # number of iterations and escape radius (r >> 2) |
||
x = np.linspace(0, 2 * np.pi, d, endpoint=False) |
x = np.linspace(0, 2 * np.pi, d, endpoint=False) |
||
Line 7,266: | Line 7,262: | ||
G = np.exp(X * 1j - Y) # circular grid around zero |
G = np.exp(X * 1j - Y) # circular grid around zero |
||
C = (-0. |
C = (-0.7894 + 0.1631 * 1j) + 1.5 * G |
||
A, B = C.real, C.imag |
A, B = C.real, C.imag |
||
Z = np.zeros_like(C) |
Z, dZ = np.zeros_like(C), np.zeros_like(C) |
||
T = np.zeros(C.shape) |
T = np.zeros(C.shape) |
||
for k in range(n): |
for k in range(n): |
||
M = abs(Z) < r |
M = abs(Z) < r |
||
Z[M] = Z[M] ** 2 + C[M] |
Z[M], dZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1 |
||
T[M] = k + 1 |
|||
N = abs(Z) >= r # normalized iteration count for smooth coloring |
|||
⚫ | |||
N = abs(Z) >= r |
|||
T = T - T.min() # shifting escape times towards zero before compression |
|||
⚫ | |||
T = T ** 0.5 # compression of the escape times with a concave function |
|||
fig, ax = plt.subplots(figsize=(4, 12)) |
fig, ax = plt.subplots(figsize=(4, 12)) |
||
ax.imshow(T, cmap=plt.cm. |
ax.imshow(T ** 0.1, cmap=plt.cm.nipy_spectral) |
||
plt.savefig("Mercator_map.png", dpi=100) |
plt.savefig("Mercator_map.png", dpi=100) |
||
Line 7,291: | Line 7,283: | ||
fig, ax = plt.subplots(2, 2, figsize=(12, 12)) |
fig, ax = plt.subplots(2, 2, figsize=(12, 12)) |
||
ax[0, 0].scatter(A[0:300], B[0:300], s=S[0:300], c=T[0:300], cmap=plt.cm. |
ax[0, 0].scatter(A[0:300], B[0:300], s=S[0:300], c=T[0:300] ** 0.1, cmap=plt.cm.nipy_spectral) |
||
ax[0, 1].scatter(A[100:400], B[100:400], s=S[0:300], c=T[100:400], cmap=plt.cm. |
ax[0, 1].scatter(A[100:400], B[100:400], s=S[0:300], c=T[100:400] ** 0.2, cmap=plt.cm.nipy_spectral) |
||
ax[1, 0].scatter(A[200:500], B[200:500], s=S[0:300], c=T[200:500], cmap=plt.cm. |
ax[1, 0].scatter(A[200:500], B[200:500], s=S[0:300], c=T[200:500] ** 0.3, cmap=plt.cm.nipy_spectral) |
||
ax[1, 1].scatter(A[300:600], B[300:600], s=S[0:300], c=T[300:600], cmap=plt.cm. |
ax[1, 1].scatter(A[300:600], B[300:600], s=S[0:300], c=T[300:600] ** 0.4, cmap=plt.cm.nipy_spectral) |
||
plt.savefig("Mercator_zoom.png", dpi=100)</lang> |
plt.savefig("Mercator_zoom.png", dpi=100)</lang> |
||