Commit 58501ed77f5937cac4036858ce0c7bcce62b9c13
1 parent
8ffbc4ad
Exists in
master
Split class plot into separate module, as part of attempt to declutter main
Showing
2 changed files
with
131 additions
and
122 deletions
Show diff stats
robots/little_john/telemetry/code/monitor/version1/main.py
... | ... | @@ -22,6 +22,7 @@ import logging |
22 | 22 | from serialselect import selectserial |
23 | 23 | from colours import * |
24 | 24 | from series import Series |
25 | +from plot import Plot | |
25 | 26 | |
26 | 27 | logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) |
27 | 28 | logging.info("Logging system active") |
... | ... | @@ -39,128 +40,6 @@ else: |
39 | 40 | os='Other' |
40 | 41 | logging.info('OS = ' + os) |
41 | 42 | |
42 | -class Plot(pyglet.window.Window): | |
43 | - def __init__(self, series): | |
44 | - """Setup a the details of a plot, and create a corresponding window""" | |
45 | - pyglet.window.Window.__init__(self, resizable=True) | |
46 | - self.set_icon(pyglet.image.load('32x32.png')) | |
47 | - self.set_minimum_size(320,320) | |
48 | - self.series = series | |
49 | - self.font = 'Arkhip' | |
50 | - self.margins = (0.09, 0.08) # Fractions of window size | |
51 | - self.lines = (10, 8) | |
52 | - #self.resizable = True | |
53 | - self.set_caption(self.series.title) | |
54 | - | |
55 | - def on_resize(self, width, height): | |
56 | - """Handle a resize event from the pyglet event loop""" | |
57 | - try: | |
58 | - self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), | |
59 | - (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) | |
60 | - except Exception as e: | |
61 | - logging.critical(str(e)) | |
62 | - self.close() | |
63 | - logging.critical('Instance closed') | |
64 | - sys.exit() | |
65 | - self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) | |
66 | - # This sometimes seems to throw an error ('AttributeError: 'Plot' object has no attribute 'margins') when started for a second time from the same instance. Interesting. Causes the plot windows to freeze | |
67 | - pyglet.window.Window.on_resize(self, width, height) | |
68 | - | |
69 | - def on_draw(self): | |
70 | - """Draw all the components of the graph""" | |
71 | - self.drawBackground() | |
72 | - self.drawHeading() | |
73 | - self.drawAxis(0) | |
74 | - self.drawAxis(1) | |
75 | - self.drawLine(self.series) | |
76 | - | |
77 | - def drawBackground(self): | |
78 | - """Draw the graph background, currently a plain colour""" | |
79 | - pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) | |
80 | - | |
81 | - def drawHeading(self): | |
82 | - """Draw a title for the graph (duplicated in the window titlebar, if present""" | |
83 | - heading = pyglet.text.Label(self.series.title, color=BLACK, | |
84 | - font_name=self.font, font_size=self.height*self.margins[0]*0.5, | |
85 | - x=self.width/2, y=self.height-(self.margins[1]), | |
86 | - anchor_x='center', anchor_y='top') | |
87 | - heading.draw() | |
88 | - | |
89 | - def drawLine(self, series): | |
90 | - xscale = float(self.series.xlimits[1]-self.series.xlimits[0])/(self.bounds[0][1]-self.bounds[0][0]) | |
91 | - yscale = float(self.series.ylimits[1]-self.series.ylimits[0])/(self.bounds[1][1]-self.bounds[1][0]) | |
92 | - logging.debug("xscale = " + str(xscale) + ", yscale = " + str(yscale)) | |
93 | - lmar = int(self.width * self.margins[0]) | |
94 | - rmar = int(self.width * self.margins[1]) | |
95 | - tmar = int(self.height * self.margins[0]) | |
96 | - bmar = int(self.height * self.margins[1]) | |
97 | - | |
98 | - pyglet.gl.glLineWidth(2) | |
99 | - | |
100 | - for n in range(len(series.data) - 1): | |
101 | - x1, y1 = series.data[n][0]-series.xlimits[0], series.data[n][1]-series.ylimits[0] | |
102 | - x2, y2 = series.data[n+1][0]-series.xlimits[0], series.data[n+1][1]-series.ylimits[0] | |
103 | - x1 = int((x1/xscale)+lmar) | |
104 | - y1 = int((y1/yscale)+bmar) | |
105 | - x2 = int((x2/xscale)+lmar) | |
106 | - y2 = int((y2/yscale)+bmar) | |
107 | - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, | |
108 | - ('v2i', (x1, y1, x2, y2)), | |
109 | - ('c3B', (255, 0, 0, 255, 0, 0))) | |
110 | - pyglet.gl.glLineWidth(1) | |
111 | - | |
112 | - | |
113 | - | |
114 | - def drawAxis(self, axis): # axis=0 is x, 1 is y | |
115 | - """Draw the gridlines and labels for one axis, specified in the last argument""" | |
116 | - limita = self.bounds[1-axis][1] | |
117 | - limitb = self.bounds[1-axis][0] | |
118 | - start = self.bounds[axis][0] | |
119 | - stop = self.bounds[axis][1] | |
120 | - increment = float(stop-start)/self.lines[axis] | |
121 | - for pos in numpy.arange(start, stop+1, increment): | |
122 | - # Using fp arithmetic to avoid intermittent fencepost errors | |
123 | - pos = int(pos) | |
124 | - if axis==0: # x axis, vertical lines | |
125 | - scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) | |
126 | - tagvalue = ((pos-start) * scale) + self.series.xlimits[0] | |
127 | - tagtext = str(int(tagvalue)) | |
128 | - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), | |
129 | - ('c3B', (0, 0, 0, 0, 0, 0))) | |
130 | - tag = pyglet.text.Label(tagtext, color=BLACK, | |
131 | - font_name=self.font, font_size=self.tag_size, | |
132 | - x=pos, y=self.height*self.margins[1], | |
133 | - anchor_x='left', anchor_y='top') | |
134 | - axistitle = pyglet.text.Label(self.series.xname, color=BLACK, | |
135 | - font_name=self.font, font_size=self.tag_size, | |
136 | - x=self.width/2, y=0, | |
137 | - anchor_x='center', anchor_y='bottom') | |
138 | - axistitle.draw() | |
139 | - if axis==1: # y axis, horizontal lines | |
140 | - scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) | |
141 | - tagvalue = ((pos-start) * scale) + self.series.ylimits[0] | |
142 | - tagtext = str(int(tagvalue)) | |
143 | - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), | |
144 | - ('c3B', (0, 0, 0, 0, 0, 0))) | |
145 | - tag = pyglet.text.Label(tagtext, color=BLACK, | |
146 | - font_name=self.font, font_size=self.tag_size, | |
147 | - x=self.width*self.margins[0]*0.9, y=pos, | |
148 | - anchor_x='right', anchor_y='center') | |
149 | - axistitle = pyglet.text.Label(self.series.yname, color=BLACK, | |
150 | - font_name=self.font, font_size=self.tag_size, | |
151 | - x=0, y=self.height/2, | |
152 | - anchor_x='center', anchor_y='top') | |
153 | - pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one | |
154 | - # Tranformation to rotate label, and ensure it ends up in the right place | |
155 | - pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) | |
156 | - pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) | |
157 | - # Draw the axis title using the rotated coordinate system | |
158 | - axistitle.draw() | |
159 | - # Return everything to its previous state | |
160 | - pyglet.gl.glPopMatrix() | |
161 | - | |
162 | - tag.draw() | |
163 | - | |
164 | 43 | testseries = Series() |
165 | 44 | logging.info("Series created") |
166 | 45 | plots = [] | ... | ... |
robots/little_john/telemetry/code/monitor/version1/plot.py
0 โ 100644
... | ... | @@ -0,0 +1,130 @@ |
1 | +# Class representing a single 2D plot window and its properties | |
2 | +# Written as a telemetry tool by: | |
3 | +# The UoN Robot Wars Project, 2018 | |
4 | + | |
5 | +import pyglet | |
6 | +import numpy | |
7 | +import logging | |
8 | +from colours import * | |
9 | + | |
10 | +class Plot(pyglet.window.Window): | |
11 | + def __init__(self, series): | |
12 | + """Setup a the details of a plot, and create a corresponding window""" | |
13 | + pyglet.window.Window.__init__(self, resizable=True) | |
14 | + self.set_icon(pyglet.image.load('32x32.png')) | |
15 | + self.set_minimum_size(320,320) | |
16 | + self.series = series | |
17 | + self.font = 'Arkhip' | |
18 | + self.margins = (0.09, 0.08) # Fractions of window size | |
19 | + self.lines = (10, 8) | |
20 | + #self.resizable = True | |
21 | + self.set_caption(self.series.title) | |
22 | + | |
23 | + def on_resize(self, width, height): | |
24 | + """Handle a resize event from the pyglet event loop""" | |
25 | + try: | |
26 | + self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), | |
27 | + (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) | |
28 | + except Exception as e: | |
29 | + logging.critical(str(e)) | |
30 | + self.close() | |
31 | + logging.critical('Instance closed') | |
32 | + sys.exit() | |
33 | + self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) | |
34 | + # This sometimes seems to throw an error ('AttributeError: 'Plot' object has no attribute 'margins') when started for a second time from the same instance. Interesting. Causes the plot windows to freeze | |
35 | + pyglet.window.Window.on_resize(self, width, height) | |
36 | + | |
37 | + def on_draw(self): | |
38 | + """Draw all the components of the graph""" | |
39 | + self.drawBackground() | |
40 | + self.drawHeading() | |
41 | + self.drawAxis(0) | |
42 | + self.drawAxis(1) | |
43 | + self.drawLine(self.series) | |
44 | + | |
45 | + def drawBackground(self): | |
46 | + """Draw the graph background, currently a plain colour""" | |
47 | + pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) | |
48 | + | |
49 | + def drawHeading(self): | |
50 | + """Draw a title for the graph (duplicated in the window titlebar, if present""" | |
51 | + heading = pyglet.text.Label(self.series.title, color=BLACK, | |
52 | + font_name=self.font, font_size=self.height*self.margins[0]*0.5, | |
53 | + x=self.width/2, y=self.height-(self.margins[1]), | |
54 | + anchor_x='center', anchor_y='top') | |
55 | + heading.draw() | |
56 | + | |
57 | + def drawLine(self, series): | |
58 | + xscale = float(self.series.xlimits[1]-self.series.xlimits[0])/(self.bounds[0][1]-self.bounds[0][0]) | |
59 | + yscale = float(self.series.ylimits[1]-self.series.ylimits[0])/(self.bounds[1][1]-self.bounds[1][0]) | |
60 | + logging.debug("xscale = " + str(xscale) + ", yscale = " + str(yscale)) | |
61 | + lmar = int(self.width * self.margins[0]) | |
62 | + rmar = int(self.width * self.margins[1]) | |
63 | + tmar = int(self.height * self.margins[0]) | |
64 | + bmar = int(self.height * self.margins[1]) | |
65 | + | |
66 | + pyglet.gl.glLineWidth(2) | |
67 | + | |
68 | + for n in range(len(series.data) - 1): | |
69 | + x1, y1 = series.data[n][0]-series.xlimits[0], series.data[n][1]-series.ylimits[0] | |
70 | + x2, y2 = series.data[n+1][0]-series.xlimits[0], series.data[n+1][1]-series.ylimits[0] | |
71 | + x1 = int((x1/xscale)+lmar) | |
72 | + y1 = int((y1/yscale)+bmar) | |
73 | + x2 = int((x2/xscale)+lmar) | |
74 | + y2 = int((y2/yscale)+bmar) | |
75 | + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, | |
76 | + ('v2i', (x1, y1, x2, y2)), | |
77 | + ('c3B', (255, 0, 0, 255, 0, 0))) | |
78 | + pyglet.gl.glLineWidth(1) | |
79 | + | |
80 | + | |
81 | + | |
82 | + def drawAxis(self, axis): # axis=0 is x, 1 is y | |
83 | + """Draw the gridlines and labels for one axis, specified in the last argument""" | |
84 | + limita = self.bounds[1-axis][1] | |
85 | + limitb = self.bounds[1-axis][0] | |
86 | + start = self.bounds[axis][0] | |
87 | + stop = self.bounds[axis][1] | |
88 | + increment = float(stop-start)/self.lines[axis] | |
89 | + for pos in numpy.arange(start, stop+1, increment): | |
90 | + # Using fp arithmetic to avoid intermittent fencepost errors | |
91 | + pos = int(pos) | |
92 | + if axis==0: # x axis, vertical lines | |
93 | + scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) | |
94 | + tagvalue = ((pos-start) * scale) + self.series.xlimits[0] | |
95 | + tagtext = str(int(tagvalue)) | |
96 | + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), | |
97 | + ('c3B', (0, 0, 0, 0, 0, 0))) | |
98 | + tag = pyglet.text.Label(tagtext, color=BLACK, | |
99 | + font_name=self.font, font_size=self.tag_size, | |
100 | + x=pos, y=self.height*self.margins[1], | |
101 | + anchor_x='left', anchor_y='top') | |
102 | + axistitle = pyglet.text.Label(self.series.xname, color=BLACK, | |
103 | + font_name=self.font, font_size=self.tag_size, | |
104 | + x=self.width/2, y=0, | |
105 | + anchor_x='center', anchor_y='bottom') | |
106 | + axistitle.draw() | |
107 | + if axis==1: # y axis, horizontal lines | |
108 | + scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) | |
109 | + tagvalue = ((pos-start) * scale) + self.series.ylimits[0] | |
110 | + tagtext = str(int(tagvalue)) | |
111 | + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), | |
112 | + ('c3B', (0, 0, 0, 0, 0, 0))) | |
113 | + tag = pyglet.text.Label(tagtext, color=BLACK, | |
114 | + font_name=self.font, font_size=self.tag_size, | |
115 | + x=self.width*self.margins[0]*0.9, y=pos, | |
116 | + anchor_x='right', anchor_y='center') | |
117 | + axistitle = pyglet.text.Label(self.series.yname, color=BLACK, | |
118 | + font_name=self.font, font_size=self.tag_size, | |
119 | + x=0, y=self.height/2, | |
120 | + anchor_x='center', anchor_y='top') | |
121 | + pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one | |
122 | + # Tranformation to rotate label, and ensure it ends up in the right place | |
123 | + pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) | |
124 | + pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) | |
125 | + # Draw the axis title using the rotated coordinate system | |
126 | + axistitle.draw() | |
127 | + # Return everything to its previous state | |
128 | + pyglet.gl.glPopMatrix() | |
129 | + | |
130 | + tag.draw() | ... | ... |