In [41]:
from __future__ import division
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
import numpy as np

class ComplexFractal():
    "Abstract complex fractal"
    maxit = 128
    def __init__(self,minz,maxz,**kwargs):
        self.__dict__.update(kwargs)
        self.at(minz, maxz)

    def at(self,minz,maxz): 
        self.minz = minz; self.maxz = maxz
        self.d = self.maxz-self.minz
        self.x = int(self.scale * self.d.real); self.y = int(self.scale * self.d.imag)

    def z(self,i,j):
        return complex(self.minz.real + i * self.d.real / self.x,
                       self.minz.imag + (self.y-j) * self.d.imag / self.y)

    def render(self):
        self.im = np.empty((self.x, self.y), dtype=np.uint32)
        self.view = self.im.view(dtype=np.uint8).reshape((self.x, self.y, 4))
        for i in range(self.x):
            for j in range(self.y):
                m = self.fractal(self.z(j,i))
                self.view[i,j,0]=m
                self.view[i,j,1]=m*self.y/255
                self.view[i,j,2]=m*self.x/255
                self.view[i,j,3]=255

    def draw(self):
        self.render()
        p = figure(x_range=[0,self.x], y_range=[0,self.y])
        p.image_rgba(image=[self.im],x=[0],y=[0],dw=[self.x],dh=[self.y])
        show(p)
                        
class Mandelbrot(ComplexFractal):
    "Mandelbrot fractal"
    julia = None

    def __init__(self,minz,maxz,**kwargs):
        ComplexFractal.__init__(self,minz,maxz,**kwargs)

    def fractal(self,c):
        i = 0; z = self.julia and c or 0
        while i<self.maxit:
            z=z*z+(self.julia or c)
            if abs(z)>=2: 
                return self.maxit-i
            i+=1
        return 0

In [ ]:
mandel = Mandelbrot(-2-1.5j,1+1.5j,title='Mandelbrot',scale=10).draw()

In [ ]: