Search code examples
pythonpython-2.7numpymatplotlibfractals

How to improve poor visuals of Julia sets made using matplotlib?


If you run the code I've included below (python 2.7) you'll find that the resultant image is dark and blurry and almost seems to have lines running across it. I realize that using the scatter function to plot something like this is probably an abuse of the functionality.

I've looked through the documentation and got lost in it and was just hoping that someone could show me how to make my Julia sets look as nice as the pretty color plates you see in books and online.

import numpy as np
import matplotlib.pyplot as plt

# Plot ranges
r_min, r_max = -2.0, 2.0
c_min, c_max = -2.0, 2.0

# Even intervals for points to compute orbits of
r_range = np.arange(r_min, r_max, (r_max - r_min) / 200.0)
c_range = np.arange(c_min, c_max, (c_max - c_min) / 200.0)

c = complex(-0.624, 0.435)
xs = []
ys = []
colors = []

for comp in c_range:
    for real in r_range:
        z = complex(real, comp)

        escaped = False
        for i in range(0, 50):
            z = z*z + c

            if abs(z) > max(abs(c), 2):
                escaped = True

                # Colors correspond to escape speed
                if i < 7:
                    colors.append((1.0 - .055* i, 0.0, 0.0))

                if i >= 7 and i < 14:
                    colors.append((1.0 - .025*i, .6 - .025*i, 0))

                if i >= 14 and i < 21:
                    colors.append((1.0 - .0035*i, 1.0 - .0045*i, 0.0))

                if i >= 21 and i < 28:
                    colors.append((0.0, 1.0 - .0045*i, 0.0))

                if i >= 28 and i < 35:
                    colors.append((0.0, 0.0, 1.0 - .0055*i))

                if i >= 35 and i < 42:
                    colors.append((.435 - .0055*i, 0.0, 1.0 - .0055*i))    

                if i >= 42:
                    colors.append((0.62 - .005*i, 0, 1.0 - .005*i))
                break


        xs.append(real)
        ys.append(comp)

        # Points that don't escape are black
        if escaped == False:
            colors.append((0.0, 0.0, 0.0))

plt.axis([-2, 2, -2, 2])
plt.xlabel('x0')
plt.ylabel('c')
plt.scatter(xs, ys, c = colors, alpha = .2)
plt.show()

Edit: Here's a result of the above - https://i.sstatic.net/2LjQ2.jpg


Solution

  • There are three main ways to improve this plot:

    1 - Instead of a scatter plot, create an N by N matrix where the value of each point determines the color at that point. Then use plt.imshow(...)

    2 - Experiment with different colormaps (plt.imshow(...cmap="RdGy"))

    3 - Increase the number of points to improve sharpness. That is, increase the denominator in your statements defining c_range and r_range

    I have edited your code to implement these changes. Look for the # CHANGED comments. The new figure looks much nicer.

    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    # Plot ranges
    r_min, r_max = -2.0, 2.0
    c_min, c_max = -2.0, 2.0
    
    # Even intervals for points to compute orbits of
    # CHANGED
    r_range = np.arange(r_min, r_max, (r_max - r_min) / 500.0)
    c_range = np.arange(c_min, c_max, (c_max - c_min) / 500.0)
    
    c = complex(-0.624, 0.435)
    xs = []
    ys = []
    # CHANGED
    mat = np.zeros((len(c_range),len(r_range)))
    colors = []
    
    # CHANGED
    matComp = 0 # Index of the new mat values
    matReal = 0
    for comp in c_range:
        for real in r_range:
            z = complex(real, comp)
    
            escaped = False
            for i in range(0, 50):
                z = z*z + c
    
                if abs(z) > max(abs(c), 2):
                    escaped = True
                    # CHANGED
                    mat[matComp, matReal]=i
    
                    # Colors correspond to escape speed
                    if i < 7:
                        colors.append((1.0 - .055* i, 0.0, 0.0))
    
                    if i >= 7 and i < 14:
                        colors.append((1.0 - .025*i, .6 - .025*i, 0))
    
                    if i >= 14 and i < 21:
                        colors.append((1.0 - .0035*i, 1.0 - .0045*i, 0.0))
    
                    if i >= 21 and i < 28:
                        colors.append((0.0, 1.0 - .0045*i, 0.0))
    
                    if i >= 28 and i < 35:
                        colors.append((0.0, 0.0, 1.0 - .0055*i))
    
                    if i >= 35 and i < 42:
                        colors.append((.435 - .0055*i, 0.0, 1.0 - .0055*i))    
    
                    if i >= 42:
                        colors.append((0.62 - .005*i, 0, 1.0 - .005*i))
                    break
            # CHANGED
            matReal += 1
    
    
            xs.append(real)
            ys.append(comp)
    
            # Points that don't escape are black
            if escaped == False:
                colors.append((0.0, 0.0, 0.0))
        # CHANGED
        matComp+=1
        matReal=0
    
    #CHANGED
    fig = plt.figure(figsize=(15,15))
    plt.imshow(mat, cmap="RdGy", extent=[-2,2,-2,2])
    

    enter image description here