annotate CADrawer.py @ 47:2b0e229e163c

Chapter 7, exercise 2. R-Pentomino game of life.
author Brian Neal <bgneal@gmail.com>
date Thu, 25 Jul 2013 21:53:44 -0500
parents d83a72eec954
children
rev   line source
bgneal@46 1 """ Code example from Complexity and Computation, a book about
bgneal@46 2 exploring complexity science with Python. Available free from
bgneal@46 3
bgneal@46 4 http://greenteapress.com/complexity
bgneal@46 5
bgneal@46 6 Copyright 2011 Allen B. Downey.
bgneal@46 7 Distributed under the GNU General Public License at gnu.org/licenses/gpl.html.
bgneal@46 8 """
bgneal@46 9
bgneal@46 10 import numpy
bgneal@46 11
bgneal@46 12
bgneal@46 13 class UnimplementedMethodException(Exception):
bgneal@46 14 """Used to indicate that a child class has not implemented an
bgneal@46 15 abstract method."""
bgneal@46 16
bgneal@46 17
bgneal@46 18 class Drawer(object):
bgneal@46 19 """Drawer is an abstract class that should not be instantiated.
bgneal@46 20 It defines the interface for a CA drawer; child classes of Drawer
bgneal@46 21 should implement draw, show and save.
bgneal@46 22
bgneal@46 23 If draw_array is not overridden, the child class should provide
bgneal@46 24 draw_cell.
bgneal@46 25 """
bgneal@46 26 def __init__(self):
bgneal@46 27 msg = 'CADrawer is an abstract type and should not be instantiated.'
bgneal@46 28 raise UnimplementedMethodException, msg
bgneal@46 29
bgneal@46 30 def draw(self, ca):
bgneal@46 31 """Draws a representation of cellular automaton (CA).
bgneal@46 32 This function generally has no visible effect."""
bgneal@46 33 raise UnimplementedMethodException
bgneal@46 34
bgneal@46 35 def draw_array(self, a):
bgneal@46 36 """Iterate through array (a) and draws any non-zero cells."""
bgneal@46 37 for i in xrange(self.rows):
bgneal@46 38 for j in xrange(self.cols):
bgneal@46 39 if a[i,j]:
bgneal@46 40 self.draw_cell(j, self.rows-i-1)
bgneal@46 41
bgneal@46 42 def draw_cell(self, ca):
bgneal@46 43 """Draws a single cell.
bgneal@46 44 Not required for all implementations."""
bgneal@46 45 raise UnimplementedMethodException
bgneal@46 46
bgneal@46 47 def show(self):
bgneal@46 48 """Displays the representation on the screen, if possible."""
bgneal@46 49 raise UnimplementedMethodException
bgneal@46 50
bgneal@46 51 def save(self, filename):
bgneal@46 52 """Saves the representation of the CA in filename."""
bgneal@46 53 raise UnimplementedMethodException
bgneal@46 54
bgneal@46 55
bgneal@46 56 class PyplotDrawer(Drawer):
bgneal@46 57 """Implementation of Drawer using matplotlib."""
bgneal@46 58
bgneal@46 59 def __init__(self):
bgneal@46 60 # we only need to import pyplot if a PyplotDrawer
bgneal@46 61 # gets instantiated
bgneal@46 62 global pyplot
bgneal@46 63 import matplotlib.pyplot as pyplot
bgneal@46 64
bgneal@46 65 def draw(self, ca, start=0, end=None):
bgneal@46 66 """Draws the CA using pyplot.pcolor."""
bgneal@46 67 pyplot.gray()
bgneal@46 68 a = ca.get_array(start, end)
bgneal@46 69 rows, cols = a.shape
bgneal@46 70
bgneal@46 71 # flipud puts the first row at the top;
bgneal@46 72 # negating it makes the non-zero cells black.
bgneal@46 73 pyplot.pcolor(-numpy.flipud(a))
bgneal@46 74 pyplot.axis([0, cols, 0, rows])
bgneal@46 75
bgneal@46 76 # empty lists draw no ticks
bgneal@46 77 pyplot.xticks([])
bgneal@46 78 pyplot.yticks([])
bgneal@46 79
bgneal@46 80 def show(self):
bgneal@46 81 """display the pseudocolor representation of the CA"""
bgneal@46 82 pyplot.show()
bgneal@46 83
bgneal@46 84 def save(self, filename='ca.png'):
bgneal@46 85 """save the pseudocolor representation of the CA in (filename)."""
bgneal@46 86 pyplot.savefig(filename)
bgneal@46 87
bgneal@46 88
bgneal@46 89 class PILDrawer(Drawer):
bgneal@46 90 """Implementation of Drawer using PIL and Swampy."""
bgneal@46 91
bgneal@46 92 def __init__(self, csize=4, color='black'):
bgneal@46 93 # we only need to import these modules if a PILDrawer
bgneal@46 94 # gets instantiated
bgneal@46 95 global Image, ImageDraw, ImageTk, Gui
bgneal@46 96 import Image
bgneal@46 97 import ImageDraw
bgneal@46 98 import ImageTk
bgneal@46 99 try:
bgneal@46 100 import Gui
bgneal@46 101 except ImportError:
bgneal@46 102 import swampy.Gui
bgneal@46 103 self.csize = csize
bgneal@46 104 self.color = color
bgneal@46 105
bgneal@46 106 def draw(self, ca, start=0, end=None):
bgneal@46 107 a = ca.get_array(start, end)
bgneal@46 108 self.rows, self.cols = a.shape
bgneal@46 109 size = [self.cols * self.csize, self.rows * self.csize]
bgneal@46 110
bgneal@46 111 self.gui = Gui.Gui()
bgneal@46 112 self.button = self.gui.bu(command=self.gui.quit)
bgneal@46 113
bgneal@46 114 self.image = Image.new(mode='1', size=size, color='white')
bgneal@46 115 self.drawable = ImageDraw.Draw(self.image)
bgneal@46 116 self.draw_array(numpy.flipud(a))
bgneal@46 117
bgneal@46 118 def draw_cell(self, i, j):
bgneal@46 119 size = self.csize
bgneal@46 120 x, y = i*size, j*size
bgneal@46 121 self.drawable.rectangle([x, y, x+size, y+size], fill=self.color)
bgneal@46 122
bgneal@46 123 def show(self):
bgneal@46 124 self.tkpi = ImageTk.PhotoImage(self.image)
bgneal@46 125 self.button.config(image=self.tkpi)
bgneal@46 126 self.gui.mainloop()
bgneal@46 127
bgneal@46 128 def save(self, filename='ca.gif'):
bgneal@46 129 self.image.save(filename)
bgneal@46 130
bgneal@46 131
bgneal@46 132 class EPSDrawer(Drawer):
bgneal@46 133 """Implementation of Drawer using encapsulated Postscript (EPS)."""
bgneal@46 134
bgneal@46 135 def __init__(self):
bgneal@46 136 self.cells = []
bgneal@46 137
bgneal@46 138 def draw(self, ca, start=0, end=None):
bgneal@46 139 a = ca.get_array(start, end)
bgneal@46 140 self.rows, self.cols = a.shape
bgneal@46 141 self.draw_array(a)
bgneal@46 142
bgneal@46 143 def draw_cell(self, i, j):
bgneal@46 144 self.cells.append((i,j))
bgneal@46 145
bgneal@46 146 def show(self):
bgneal@46 147 raise UnimplementedMethodException
bgneal@46 148
bgneal@46 149 def save(self, filename='ca.eps'):
bgneal@46 150 fp = open(filename, 'w')
bgneal@46 151 self.print_header(fp)
bgneal@46 152 self.print_outline(fp)
bgneal@46 153 self.print_cells(fp)
bgneal@46 154 self.print_footer(fp)
bgneal@46 155
bgneal@46 156 def print_cells(self, fp):
bgneal@46 157 for i, j in self.cells:
bgneal@46 158 fp.write('%s %s c\n' % (i, j))
bgneal@46 159
bgneal@46 160 def print_header(self, fp, size=0.9):
bgneal@46 161 fp.write('%!PS-Adobe-3.0 EPSF-3.0\n')
bgneal@46 162 fp.write('%%%%BoundingBox: -2 -2 %s %s\n' % (self.cols+2, self.rows+2))
bgneal@46 163
bgneal@46 164 fp.write('/c {\n')
bgneal@46 165 fp.write(' newpath moveto\n')
bgneal@46 166 fp.write(' 0 %g rlineto\n' % size)
bgneal@46 167 fp.write(' %g 0 rlineto\n' % size)
bgneal@46 168 fp.write(' 0 -%g rlineto\n' % size)
bgneal@46 169 fp.write(' closepath fill\n')
bgneal@46 170 fp.write('} def\n')
bgneal@46 171
bgneal@46 172 def print_outline(self, fp):
bgneal@46 173 fp.write('newpath 0.1 setlinewidth 0 0 moveto\n')
bgneal@46 174 fp.write('0 %s rlineto\n' % self.rows)
bgneal@46 175 fp.write('%s 0 rlineto\n' % self.cols)
bgneal@46 176 fp.write('0 -%s rlineto\n' % self.rows)
bgneal@46 177 fp.write('closepath stroke\n')
bgneal@46 178
bgneal@46 179 def print_footer(self, fp):
bgneal@46 180 fp.write('%%EOF\n')
bgneal@46 181