bgneal@46: """ Code example from Complexity and Computation, a book about bgneal@46: exploring complexity science with Python. Available free from bgneal@46: bgneal@46: http://greenteapress.com/complexity bgneal@46: bgneal@46: Copyright 2011 Allen B. Downey. bgneal@46: Distributed under the GNU General Public License at gnu.org/licenses/gpl.html. bgneal@46: """ bgneal@46: bgneal@46: import numpy bgneal@46: bgneal@46: bgneal@46: class UnimplementedMethodException(Exception): bgneal@46: """Used to indicate that a child class has not implemented an bgneal@46: abstract method.""" bgneal@46: bgneal@46: bgneal@46: class Drawer(object): bgneal@46: """Drawer is an abstract class that should not be instantiated. bgneal@46: It defines the interface for a CA drawer; child classes of Drawer bgneal@46: should implement draw, show and save. bgneal@46: bgneal@46: If draw_array is not overridden, the child class should provide bgneal@46: draw_cell. bgneal@46: """ bgneal@46: def __init__(self): bgneal@46: msg = 'CADrawer is an abstract type and should not be instantiated.' bgneal@46: raise UnimplementedMethodException, msg bgneal@46: bgneal@46: def draw(self, ca): bgneal@46: """Draws a representation of cellular automaton (CA). bgneal@46: This function generally has no visible effect.""" bgneal@46: raise UnimplementedMethodException bgneal@46: bgneal@46: def draw_array(self, a): bgneal@46: """Iterate through array (a) and draws any non-zero cells.""" bgneal@46: for i in xrange(self.rows): bgneal@46: for j in xrange(self.cols): bgneal@46: if a[i,j]: bgneal@46: self.draw_cell(j, self.rows-i-1) bgneal@46: bgneal@46: def draw_cell(self, ca): bgneal@46: """Draws a single cell. bgneal@46: Not required for all implementations.""" bgneal@46: raise UnimplementedMethodException bgneal@46: bgneal@46: def show(self): bgneal@46: """Displays the representation on the screen, if possible.""" bgneal@46: raise UnimplementedMethodException bgneal@46: bgneal@46: def save(self, filename): bgneal@46: """Saves the representation of the CA in filename.""" bgneal@46: raise UnimplementedMethodException bgneal@46: bgneal@46: bgneal@46: class PyplotDrawer(Drawer): bgneal@46: """Implementation of Drawer using matplotlib.""" bgneal@46: bgneal@46: def __init__(self): bgneal@46: # we only need to import pyplot if a PyplotDrawer bgneal@46: # gets instantiated bgneal@46: global pyplot bgneal@46: import matplotlib.pyplot as pyplot bgneal@46: bgneal@46: def draw(self, ca, start=0, end=None): bgneal@46: """Draws the CA using pyplot.pcolor.""" bgneal@46: pyplot.gray() bgneal@46: a = ca.get_array(start, end) bgneal@46: rows, cols = a.shape bgneal@46: bgneal@46: # flipud puts the first row at the top; bgneal@46: # negating it makes the non-zero cells black. bgneal@46: pyplot.pcolor(-numpy.flipud(a)) bgneal@46: pyplot.axis([0, cols, 0, rows]) bgneal@46: bgneal@46: # empty lists draw no ticks bgneal@46: pyplot.xticks([]) bgneal@46: pyplot.yticks([]) bgneal@46: bgneal@46: def show(self): bgneal@46: """display the pseudocolor representation of the CA""" bgneal@46: pyplot.show() bgneal@46: bgneal@46: def save(self, filename='ca.png'): bgneal@46: """save the pseudocolor representation of the CA in (filename).""" bgneal@46: pyplot.savefig(filename) bgneal@46: bgneal@46: bgneal@46: class PILDrawer(Drawer): bgneal@46: """Implementation of Drawer using PIL and Swampy.""" bgneal@46: bgneal@46: def __init__(self, csize=4, color='black'): bgneal@46: # we only need to import these modules if a PILDrawer bgneal@46: # gets instantiated bgneal@46: global Image, ImageDraw, ImageTk, Gui bgneal@46: import Image bgneal@46: import ImageDraw bgneal@46: import ImageTk bgneal@46: try: bgneal@46: import Gui bgneal@46: except ImportError: bgneal@46: import swampy.Gui bgneal@46: self.csize = csize bgneal@46: self.color = color bgneal@46: bgneal@46: def draw(self, ca, start=0, end=None): bgneal@46: a = ca.get_array(start, end) bgneal@46: self.rows, self.cols = a.shape bgneal@46: size = [self.cols * self.csize, self.rows * self.csize] bgneal@46: bgneal@46: self.gui = Gui.Gui() bgneal@46: self.button = self.gui.bu(command=self.gui.quit) bgneal@46: bgneal@46: self.image = Image.new(mode='1', size=size, color='white') bgneal@46: self.drawable = ImageDraw.Draw(self.image) bgneal@46: self.draw_array(numpy.flipud(a)) bgneal@46: bgneal@46: def draw_cell(self, i, j): bgneal@46: size = self.csize bgneal@46: x, y = i*size, j*size bgneal@46: self.drawable.rectangle([x, y, x+size, y+size], fill=self.color) bgneal@46: bgneal@46: def show(self): bgneal@46: self.tkpi = ImageTk.PhotoImage(self.image) bgneal@46: self.button.config(image=self.tkpi) bgneal@46: self.gui.mainloop() bgneal@46: bgneal@46: def save(self, filename='ca.gif'): bgneal@46: self.image.save(filename) bgneal@46: bgneal@46: bgneal@46: class EPSDrawer(Drawer): bgneal@46: """Implementation of Drawer using encapsulated Postscript (EPS).""" bgneal@46: bgneal@46: def __init__(self): bgneal@46: self.cells = [] bgneal@46: bgneal@46: def draw(self, ca, start=0, end=None): bgneal@46: a = ca.get_array(start, end) bgneal@46: self.rows, self.cols = a.shape bgneal@46: self.draw_array(a) bgneal@46: bgneal@46: def draw_cell(self, i, j): bgneal@46: self.cells.append((i,j)) bgneal@46: bgneal@46: def show(self): bgneal@46: raise UnimplementedMethodException bgneal@46: bgneal@46: def save(self, filename='ca.eps'): bgneal@46: fp = open(filename, 'w') bgneal@46: self.print_header(fp) bgneal@46: self.print_outline(fp) bgneal@46: self.print_cells(fp) bgneal@46: self.print_footer(fp) bgneal@46: bgneal@46: def print_cells(self, fp): bgneal@46: for i, j in self.cells: bgneal@46: fp.write('%s %s c\n' % (i, j)) bgneal@46: bgneal@46: def print_header(self, fp, size=0.9): bgneal@46: fp.write('%!PS-Adobe-3.0 EPSF-3.0\n') bgneal@46: fp.write('%%%%BoundingBox: -2 -2 %s %s\n' % (self.cols+2, self.rows+2)) bgneal@46: bgneal@46: fp.write('/c {\n') bgneal@46: fp.write(' newpath moveto\n') bgneal@46: fp.write(' 0 %g rlineto\n' % size) bgneal@46: fp.write(' %g 0 rlineto\n' % size) bgneal@46: fp.write(' 0 -%g rlineto\n' % size) bgneal@46: fp.write(' closepath fill\n') bgneal@46: fp.write('} def\n') bgneal@46: bgneal@46: def print_outline(self, fp): bgneal@46: fp.write('newpath 0.1 setlinewidth 0 0 moveto\n') bgneal@46: fp.write('0 %s rlineto\n' % self.rows) bgneal@46: fp.write('%s 0 rlineto\n' % self.cols) bgneal@46: fp.write('0 -%s rlineto\n' % self.rows) bgneal@46: fp.write('closepath stroke\n') bgneal@46: bgneal@46: def print_footer(self, fp): bgneal@46: fp.write('%%EOF\n') bgneal@46: