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,6 +22,7 @@ import logging | ||
22 | from serialselect import selectserial | 22 | from serialselect import selectserial |
23 | from colours import * | 23 | from colours import * |
24 | from series import Series | 24 | from series import Series |
25 | +from plot import Plot | ||
25 | 26 | ||
26 | logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) | 27 | logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) |
27 | logging.info("Logging system active") | 28 | logging.info("Logging system active") |
@@ -39,128 +40,6 @@ else: | @@ -39,128 +40,6 @@ else: | ||
39 | os='Other' | 40 | os='Other' |
40 | logging.info('OS = ' + os) | 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 | testseries = Series() | 43 | testseries = Series() |
165 | logging.info("Series created") | 44 | logging.info("Series created") |
166 | plots = [] | 45 | plots = [] |
robots/little_john/telemetry/code/monitor/version1/plot.py
0 โ 100644
@@ -0,0 +1,130 @@ | @@ -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() |