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