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. The ''normalized iteration count'' algorithm is used, which provides a smooth transition of colors between iterations (cf. Wikipedia: [https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Continuous_(smooth)_coloring ''Plotting algorithms for the Mandelbrot set: Continuous (smooth) coloring'']).
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, 10 # number of iterations and escape radius (r > 2)
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.4 + 0.6 * 1j) + 1.5 * G
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 # normalized iteration count for smooth coloring
N = abs(Z) >= r
T[N] = T[N] - np.log2(np.log(abs(Z[N])) / np.log(r))
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.twilight_shifted)
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.twilight_shifted, vmin=0)
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'']). Escape time compression is used as described by David Madore.
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, 1000 # number of iterations and escape radius (r > 2)
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.4105 + 0.6102 * 1j) + 1.5 * G
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
T[N] = T[N] - np.log2(np.log(abs(Z[N])) / np.log(r))


N = abs(Z) >= r
T = T - T.min() # shifting escape times towards zero before compression
T[N] = 2 * abs(Z[N]) * np.log(abs(Z[N])) / abs(dZ[N])
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.twilight_shifted)
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.twilight_shifted, vmin=0)
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.twilight_shifted, vmin=0)
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.twilight_shifted, vmin=0)
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.twilight_shifted, vmin=0)
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>