From 58501ed77f5937cac4036858ce0c7bcce62b9c13 Mon Sep 17 00:00:00 2001 From: Christopher Stone Date: Fri, 9 Mar 2018 19:58:18 +0000 Subject: [PATCH] Split class plot into separate module, as part of attempt to declutter main --- robots/little_john/telemetry/code/monitor/version1/main.py | 123 +-------------------------------------------------------------------------------------------------------------------------- robots/little_john/telemetry/code/monitor/version1/plot.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 122 deletions(-) create mode 100644 robots/little_john/telemetry/code/monitor/version1/plot.py diff --git a/robots/little_john/telemetry/code/monitor/version1/main.py b/robots/little_john/telemetry/code/monitor/version1/main.py index b544933..7ed6615 100755 --- a/robots/little_john/telemetry/code/monitor/version1/main.py +++ b/robots/little_john/telemetry/code/monitor/version1/main.py @@ -22,6 +22,7 @@ import logging from serialselect import selectserial from colours import * from series import Series +from plot import Plot logging.basicConfig(format='%(levelname)s:\t%(message)s', level=logging.DEBUG) logging.info("Logging system active") @@ -39,128 +40,6 @@ else: os='Other' logging.info('OS = ' + os) -class Plot(pyglet.window.Window): - def __init__(self, series): - """Setup a the details of a plot, and create a corresponding window""" - pyglet.window.Window.__init__(self, resizable=True) - self.set_icon(pyglet.image.load('32x32.png')) - self.set_minimum_size(320,320) - self.series = series - self.font = 'Arkhip' - self.margins = (0.09, 0.08) # Fractions of window size - self.lines = (10, 8) - #self.resizable = True - self.set_caption(self.series.title) - - def on_resize(self, width, height): - """Handle a resize event from the pyglet event loop""" - try: - self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), - (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) - except Exception as e: - logging.critical(str(e)) - self.close() - logging.critical('Instance closed') - sys.exit() - self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) - # 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 - pyglet.window.Window.on_resize(self, width, height) - - def on_draw(self): - """Draw all the components of the graph""" - self.drawBackground() - self.drawHeading() - self.drawAxis(0) - self.drawAxis(1) - self.drawLine(self.series) - - def drawBackground(self): - """Draw the graph background, currently a plain colour""" - pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) - - def drawHeading(self): - """Draw a title for the graph (duplicated in the window titlebar, if present""" - heading = pyglet.text.Label(self.series.title, color=BLACK, - font_name=self.font, font_size=self.height*self.margins[0]*0.5, - x=self.width/2, y=self.height-(self.margins[1]), - anchor_x='center', anchor_y='top') - heading.draw() - - def drawLine(self, series): - xscale = float(self.series.xlimits[1]-self.series.xlimits[0])/(self.bounds[0][1]-self.bounds[0][0]) - yscale = float(self.series.ylimits[1]-self.series.ylimits[0])/(self.bounds[1][1]-self.bounds[1][0]) - logging.debug("xscale = " + str(xscale) + ", yscale = " + str(yscale)) - lmar = int(self.width * self.margins[0]) - rmar = int(self.width * self.margins[1]) - tmar = int(self.height * self.margins[0]) - bmar = int(self.height * self.margins[1]) - - pyglet.gl.glLineWidth(2) - - for n in range(len(series.data) - 1): - x1, y1 = series.data[n][0]-series.xlimits[0], series.data[n][1]-series.ylimits[0] - x2, y2 = series.data[n+1][0]-series.xlimits[0], series.data[n+1][1]-series.ylimits[0] - x1 = int((x1/xscale)+lmar) - y1 = int((y1/yscale)+bmar) - x2 = int((x2/xscale)+lmar) - y2 = int((y2/yscale)+bmar) - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, - ('v2i', (x1, y1, x2, y2)), - ('c3B', (255, 0, 0, 255, 0, 0))) - pyglet.gl.glLineWidth(1) - - - - def drawAxis(self, axis): # axis=0 is x, 1 is y - """Draw the gridlines and labels for one axis, specified in the last argument""" - limita = self.bounds[1-axis][1] - limitb = self.bounds[1-axis][0] - start = self.bounds[axis][0] - stop = self.bounds[axis][1] - increment = float(stop-start)/self.lines[axis] - for pos in numpy.arange(start, stop+1, increment): - # Using fp arithmetic to avoid intermittent fencepost errors - pos = int(pos) - if axis==0: # x axis, vertical lines - scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) - tagvalue = ((pos-start) * scale) + self.series.xlimits[0] - tagtext = str(int(tagvalue)) - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), - ('c3B', (0, 0, 0, 0, 0, 0))) - tag = pyglet.text.Label(tagtext, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=pos, y=self.height*self.margins[1], - anchor_x='left', anchor_y='top') - axistitle = pyglet.text.Label(self.series.xname, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=self.width/2, y=0, - anchor_x='center', anchor_y='bottom') - axistitle.draw() - if axis==1: # y axis, horizontal lines - scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) - tagvalue = ((pos-start) * scale) + self.series.ylimits[0] - tagtext = str(int(tagvalue)) - pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), - ('c3B', (0, 0, 0, 0, 0, 0))) - tag = pyglet.text.Label(tagtext, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=self.width*self.margins[0]*0.9, y=pos, - anchor_x='right', anchor_y='center') - axistitle = pyglet.text.Label(self.series.yname, color=BLACK, - font_name=self.font, font_size=self.tag_size, - x=0, y=self.height/2, - anchor_x='center', anchor_y='top') - pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one - # Tranformation to rotate label, and ensure it ends up in the right place - pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) - pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) - # Draw the axis title using the rotated coordinate system - axistitle.draw() - # Return everything to its previous state - pyglet.gl.glPopMatrix() - - tag.draw() - testseries = Series() logging.info("Series created") plots = [] diff --git a/robots/little_john/telemetry/code/monitor/version1/plot.py b/robots/little_john/telemetry/code/monitor/version1/plot.py new file mode 100644 index 0000000..4154b91 --- /dev/null +++ b/robots/little_john/telemetry/code/monitor/version1/plot.py @@ -0,0 +1,130 @@ +# Class representing a single 2D plot window and its properties +# Written as a telemetry tool by: +# The UoN Robot Wars Project, 2018 + +import pyglet +import numpy +import logging +from colours import * + +class Plot(pyglet.window.Window): + def __init__(self, series): + """Setup a the details of a plot, and create a corresponding window""" + pyglet.window.Window.__init__(self, resizable=True) + self.set_icon(pyglet.image.load('32x32.png')) + self.set_minimum_size(320,320) + self.series = series + self.font = 'Arkhip' + self.margins = (0.09, 0.08) # Fractions of window size + self.lines = (10, 8) + #self.resizable = True + self.set_caption(self.series.title) + + def on_resize(self, width, height): + """Handle a resize event from the pyglet event loop""" + try: + self.bounds = ((int(self.width * self.margins[0]), int(self.width * (1 - self.margins[0]))), + (int(self.height * self.margins[1]), int(self.height * (1 - self.margins[1])))) + except Exception as e: + logging.critical(str(e)) + self.close() + logging.critical('Instance closed') + sys.exit() + self.tag_size = min(self.height*self.margins[1]*0.3,self.width*self.margins[0]*0.3) + # 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 + pyglet.window.Window.on_resize(self, width, height) + + def on_draw(self): + """Draw all the components of the graph""" + self.drawBackground() + self.drawHeading() + self.drawAxis(0) + self.drawAxis(1) + self.drawLine(self.series) + + def drawBackground(self): + """Draw the graph background, currently a plain colour""" + pyglet.image.SolidColorImagePattern(WHITE).create_image(self.width, self.height).blit(0, 0) + + def drawHeading(self): + """Draw a title for the graph (duplicated in the window titlebar, if present""" + heading = pyglet.text.Label(self.series.title, color=BLACK, + font_name=self.font, font_size=self.height*self.margins[0]*0.5, + x=self.width/2, y=self.height-(self.margins[1]), + anchor_x='center', anchor_y='top') + heading.draw() + + def drawLine(self, series): + xscale = float(self.series.xlimits[1]-self.series.xlimits[0])/(self.bounds[0][1]-self.bounds[0][0]) + yscale = float(self.series.ylimits[1]-self.series.ylimits[0])/(self.bounds[1][1]-self.bounds[1][0]) + logging.debug("xscale = " + str(xscale) + ", yscale = " + str(yscale)) + lmar = int(self.width * self.margins[0]) + rmar = int(self.width * self.margins[1]) + tmar = int(self.height * self.margins[0]) + bmar = int(self.height * self.margins[1]) + + pyglet.gl.glLineWidth(2) + + for n in range(len(series.data) - 1): + x1, y1 = series.data[n][0]-series.xlimits[0], series.data[n][1]-series.ylimits[0] + x2, y2 = series.data[n+1][0]-series.xlimits[0], series.data[n+1][1]-series.ylimits[0] + x1 = int((x1/xscale)+lmar) + y1 = int((y1/yscale)+bmar) + x2 = int((x2/xscale)+lmar) + y2 = int((y2/yscale)+bmar) + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, + ('v2i', (x1, y1, x2, y2)), + ('c3B', (255, 0, 0, 255, 0, 0))) + pyglet.gl.glLineWidth(1) + + + + def drawAxis(self, axis): # axis=0 is x, 1 is y + """Draw the gridlines and labels for one axis, specified in the last argument""" + limita = self.bounds[1-axis][1] + limitb = self.bounds[1-axis][0] + start = self.bounds[axis][0] + stop = self.bounds[axis][1] + increment = float(stop-start)/self.lines[axis] + for pos in numpy.arange(start, stop+1, increment): + # Using fp arithmetic to avoid intermittent fencepost errors + pos = int(pos) + if axis==0: # x axis, vertical lines + scale = float(self.series.xlimits[1]-self.series.xlimits[0])/(stop-start) + tagvalue = ((pos-start) * scale) + self.series.xlimits[0] + tagtext = str(int(tagvalue)) + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (pos, limita, pos, limitb)), + ('c3B', (0, 0, 0, 0, 0, 0))) + tag = pyglet.text.Label(tagtext, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=pos, y=self.height*self.margins[1], + anchor_x='left', anchor_y='top') + axistitle = pyglet.text.Label(self.series.xname, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=self.width/2, y=0, + anchor_x='center', anchor_y='bottom') + axistitle.draw() + if axis==1: # y axis, horizontal lines + scale = float(self.series.ylimits[1]-self.series.ylimits[0])/(stop-start) + tagvalue = ((pos-start) * scale) + self.series.ylimits[0] + tagtext = str(int(tagvalue)) + pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2i', (limita, pos, limitb, pos)), + ('c3B', (0, 0, 0, 0, 0, 0))) + tag = pyglet.text.Label(tagtext, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=self.width*self.margins[0]*0.9, y=pos, + anchor_x='right', anchor_y='center') + axistitle = pyglet.text.Label(self.series.yname, color=BLACK, + font_name=self.font, font_size=self.tag_size, + x=0, y=self.height/2, + anchor_x='center', anchor_y='top') + pyglet.gl.glPushMatrix() # Set up a new context to avoid confusing the main one + # Tranformation to rotate label, and ensure it ends up in the right place + pyglet.gl.glTranslatef(self.height//2, self.height//2, 0.0) + pyglet.gl.glRotatef(90.0, 0.0, 0.0, 1.0) + # Draw the axis title using the rotated coordinate system + axistitle.draw() + # Return everything to its previous state + pyglet.gl.glPopMatrix() + + tag.draw() -- libgit2 0.21.2