Dragon curve

Download this notebook from GitHub (right-click to download).


Dragon curve example from the L-systems topic notebook in examples/topics/geometry.

Most examples work across multiple plotting backends, this example is also available for:

In [1]:
import holoviews as hv
from holoviews import opts
import numpy as np
hv.extension('bokeh')

L-system definition

The following class is a simplified version of the approach used in the L-systems notebook, made specifically for plotting the Dragon Curve.

In [2]:
class DragonCurve(object):
    "L-system agent that follows rules to generate the Dragon Curve"
    
    initial ='FX'
    productions = {'X':'X+YF+', 'Y':'-FX-Y'}
    dragon_rules = {'F': lambda t,d,a: t.forward(d),
                    'B': lambda t,d,a: t.back(d),
                    '+': lambda t,d,a: t.rotate(-a),
                    '-': lambda t,d,a: t.rotate(a),
                    'X':lambda t,d,a: None,
                    'Y':lambda t,d,a: None }
    
    def __init__(self, x=0,y=0, iterations=1):
        self.heading = 0
        self.distance = 5
        self.angle = 90
        self.x, self.y = x,y
        self.trace = [(self.x, self.y)]
        self.process(self.expand(iterations), self.distance, self.angle)
        
    def process(self, instructions, distance, angle):
        for i in instructions:          
            self.dragon_rules[i](self, distance, angle)
        
    def expand(self, iterations):
        "Expand an initial symbol with the given production rules"
        expansion = self.initial
        
        for i in range(iterations):
            intermediate = ""
            for ch in expansion:
                intermediate = intermediate + self.productions.get(ch,ch)
            expansion = intermediate
        return expansion

    def forward(self, distance):
        self.x += np.cos(2*np.pi * self.heading/360.0)
        self.y += np.sin(2*np.pi * self.heading/360.0)
        self.trace.append((self.x,self.y))
    
    def rotate(self, angle):
        self.heading += angle
        
    def back(self, distance):
        self.heading += 180
        self.forward(distance)
        self.heading += 180
        
    @property
    def path(self):
        return hv.Path([self.trace])

Plot

In [3]:
hmap = hv.HoloMap(kdims='Iteration')
for i in range(7,17):
    hmap[i] = DragonCurve(-200, 0, i).path

hmap.opts(
    opts.Path(axiswise=False, color='black', line_width=1, 
              title='', xaxis=None, yaxis=None, framewise=True))
Out[3]:

Download this notebook from GitHub (right-click to download).