-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscreen.py
More file actions
114 lines (91 loc) · 3.84 KB
/
screen.py
File metadata and controls
114 lines (91 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import wx
from automata.organism import Organism
from layout import spring_layout
import itertools
import support
WIN_WIDTH = 800 # Main window width
WIN_HEIGHT = 800 # Main window height
FORCE_FQ = 100 # The frequency of a force-directed algorithm updates in ms
ITERATION_FQ = 1000 # The frequency of organism's iterations in ms
LAYOUT_ITERATIONS = 10 # The number of iterations in a force-directed algorithm per update
FRAME_WIDTH = 600 # Graph frame width
FRAME_HEIGHT = 600 # Graph frame height
class GraphVisualizerFrame(wx.Frame):
def __init__(self, parent, title, organism):
self.organism = organism
super(GraphVisualizerFrame, self).__init__(parent, title=title, size=(WIN_WIDTH, WIN_HEIGHT))
self.InitUI()
self.Show(True)
def InitUI(self):
"""
Initializes main UI elements: panel, toolbar, bitmap buffer.
"""
self.panel = wx.Panel(self)
self.SetMenuBar(wx.MenuBar())
toolbar = self.CreateToolBar()
toolbar.Realize()
self.buffer = wx.EmptyBitmap(WIN_WIDTH, WIN_HEIGHT)
self.draw(None)
def draw(self, event):
"""
Initializes timers related to displaying the organism.
"""
self.force_timer = wx.Timer(self)
self.force_timer.Start(FORCE_FQ)
self.iterate_timer = wx.Timer(self)
self.iterate_timer.Start(ITERATION_FQ)
self.Bind(wx.EVT_TIMER, self.update_layout, self.force_timer)
self.Bind(wx.EVT_TIMER, self.update_organism, self.iterate_timer)
dc = wx.BufferedDC(wx.ClientDC(self.panel), self.buffer)
spring_layout(self.organism.graph, width=FRAME_WIDTH, height=FRAME_HEIGHT, iterations=LAYOUT_ITERATIONS, c=0.2)
# Generate a color for each state
states = self.organism.genome.states()
self.colors = dict(zip(states, support.distinct_colors(len(states))))
self.draw_graph(dc)
def update_layout(self, event):
"""
Updates layout by calling force-directed algorithm.
"""
if not spring_layout(self.organism.graph, width=FRAME_WIDTH, height=FRAME_HEIGHT, iterations=LAYOUT_ITERATIONS, c=0.2):
self.force_timer.Destroy()
self.update(event)
def update_organism(self, event):
"""
Updates organism by performing one iteration.
"""
if not self.organism.iterate():
self.iterate_timer.Destroy()
def update(self, event):
"""
Updates bitmap buffer.
"""
if self.force_timer.IsRunning() or self.iterate_timer.IsRunning():
dc = wx.BufferedDC(wx.ClientDC(self.panel), self.buffer)
self.draw_graph(dc)
def draw_graph(self, dc):
"""
Draws graph in bitmap buffer, called by update()
"""
dc.Clear()
dc.SetBrush(wx.Brush('#000000'))
dc.DrawRectangle(0, 0, WIN_WIDTH, WIN_HEIGHT)
for pair in itertools.combinations(self.organism.graph.keys(), 2):
edge_state = None
if pair[0] in self.organism.graph[pair[1]]:
if pair[0] in pair[1].imediate_parents:
edge_state = pair[0].state
elif pair[1] in pair[0].imediate_parents:
edge_state = pair[1].state
dc.SetPen(wx.Pen(self.colors[edge_state]))
x1 = int(pair[0].pos['x']) + FRAME_WIDTH/2 + (WIN_WIDTH - FRAME_WIDTH)/2
y1 = int(pair[0].pos['y']) + FRAME_HEIGHT/2 + (WIN_HEIGHT - FRAME_HEIGHT)/2
x2 = int(pair[1].pos['x']) + FRAME_WIDTH/2 + (WIN_WIDTH - FRAME_WIDTH)/2
y2 = int(pair[1].pos['y']) + FRAME_HEIGHT/2 + (WIN_HEIGHT - FRAME_HEIGHT)/2
dc.DrawLine(x1, y1, x2, y2)
app = wx.App()
code = 'A|2|3|++|A'
organism = Organism(code)
frame = GraphVisualizerFrame(None, 'Organism', organism)
frame.Show()
app.MainLoop()
app.Destroy()