[python] style fixes for real_time_plot

This commit is contained in:
Felix Ruess
2015-12-21 13:08:36 +01:00
parent 72564f4dc1
commit 67505034a1
3 changed files with 141 additions and 142 deletions
@@ -32,7 +32,7 @@ class Aircraft(object):
class MessagePicker(wx.Frame):
def __init__(self, parent, callback, initIvy = True):
def __init__(self, parent, callback, initIvy=True):
wx.Frame.__init__(self, parent, name="MessagePicker", title=u'Message Picker', size=wx.Size(320,640))
self.aircrafts = {}
@@ -42,7 +42,7 @@ class MessagePicker(wx.Frame):
self.root = self.tree.AddRoot("Telemetry")
self.tree.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick)
self.tree.Bind(wx.EVT_CHAR, self.OnKeyChar)
self.Bind( wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.message_interface = IvyMessagesInterface(self.msg_recv, initIvy)
def OnClose(self, event):
@@ -8,15 +8,19 @@ from textdroptarget import *
import math
import random
import sys
import os
from os import getenv, path
import messagepicker
sys.path.append(os.getenv("PAPARAZZI_SRC") + "/sw/lib/python")
# if PAPARAZZI_SRC not set, then assume the tree containing this
# file is a reasonable substitute
PPRZ_SRC = getenv("PAPARAZZI_SRC", path.normpath(path.join(path.dirname(path.abspath(__file__)), '../../../../')))
sys.path.append(PPRZ_SRC + "/sw/lib/python")
from pprz_msg import messages_xml_map
class plot_data:
def __init__(self, ivy_msg_id, title, width, color = None):
class PlotData:
def __init__(self, ivy_msg_id, title, width, color=None):
self.id = ivy_msg_id
self.title = title
self.SetPlotSize(width)
@@ -30,11 +34,11 @@ class plot_data:
self.scale = 1.0
self.offset = 0.0
if (color != None):
if color is not None:
self.color = color
else:
r,g,b = random.randint(0,255),random.randint(0,255),random.randint(0,255)
self.color = wx.Color(r,g,b)
r, g, b = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
self.color = wx.Color(r, g, b)
def SetRealTime(self, value):
self.real_time = value
@@ -47,8 +51,8 @@ class plot_data:
def SetPlotSize(self, size):
self.size = size
self.index = size-1 # holds the index of the next point to add and the first point to draw
self.data = [] # holds the list of points to plot
self.index = size - 1 # holds the index of the next point to add and the first point to draw
self.data = [] # holds the list of points to plot
for i in range(size):
self.data.append(None)
@@ -58,19 +62,18 @@ class plot_data:
def AddPoint(self, point, x_axis):
self.data[self.index] = point
if self.real_time or (x_axis != None):
self.index = (self.index + 1) % self.size # increment index to next point
if self.real_time or (x_axis is not None):
self.index = (self.index + 1) % self.size # increment index to next point
self.data[self.index] = None
def DrawTitle(self, dc, margin, width, height):
text ='avg:%.2f std:%.2f %s' % (self.avg, self.std_dev, self.title)
text = 'avg:%.2f std:%.2f %s' % (self.avg, self.std_dev, self.title)
(w,h) = dc.GetTextExtent(text)
(w, h) = dc.GetTextExtent(text)
dc.SetBrush(wx.Brush(self.color))
dc.DrawRectangle( width-h-margin, height, h, h)
dc.DrawText(text, width-2*margin-w-h, height)
dc.DrawRectangle(width - h - margin, height, h, h)
dc.DrawText(text, width - 2 * margin - w - h, height)
return h
def DrawCurve(self, dc, width, height, margin, _max_, _min_, x_axis):
@@ -78,20 +81,20 @@ class plot_data:
self.SetPlotSize(width)
return
if (not self.real_time) and (x_axis == None):
self.index = (self.index + 1) % self.size # increment index to next point
if (not self.real_time) and (x_axis is None):
self.index = (self.index + 1) % self.size # increment index to next point
self.data[self.index] = None
if x_axis != None:
if x_axis is not None:
(x_min, x_max) = x_axis.GetXMinMax()
dc.SetPen(wx.Pen(self.color,1))
dc.SetPen(wx.Pen(self.color, 1))
if _max_ < _min_:
(_min_, _max_) = (-1,1) #prevent divide by zero or inversion
(_min_, _max_) = (-1, 1) # prevent divide by zero or inversion
if _max_ == _min_:
(_min_, _max_) = (_max_-0.5, _max_+0.5)
delta = _max_-_min_
dy = (height - margin*2) / delta
(_min_, _max_) = (_max_ - 0.5, _max_ + 0.5)
delta = _max_ - _min_
dy = (height - margin * 2) / delta
n = 0
sums = 0.0
@@ -99,31 +102,31 @@ class plot_data:
lines = []
point_1 = None
for i in range(self.size):
ix = (i+self.index) % self.size
ix = (i + self.index) % self.size
point = self.data[ix]
if point == None:
if point is None:
continue
n += 1
sums = sums + point
sum_squares = sum_squares + (point*point)
sum_squares = sum_squares + (point * point)
if x_axis != None:
if x_axis is not None:
x = x_axis.data[ix]
if x == None:
if x is None:
continue
dx = (width-1) / (x_max-x_min)
x = int((x-x_min) * dx)
dx = (width - 1) / (x_max - x_min)
x = int((x - x_min) * dx)
else:
x = i * width / self.size
scaled_point = (point + self.offset) * self.scale
y = height - margin - int((scaled_point - _min_)*dy)
y = height - margin - int((scaled_point - _min_) * dy)
if point_1 != None:
if point_1 is not None:
line = (point_1[0], point_1[1], x, y)
lines.append( line)
point_1 = (x,y)
lines.append(line)
point_1 = (x, y)
dc.DrawLineList(lines)
if n > 0:
@@ -136,41 +139,43 @@ class plot_data:
for i in range(self.size):
point = self.data[i]
if point == None: continue
x_min = min( x_min, point)
x_max = max( x_max, point)
if point is None:
continue
x_min = min(x_min, point)
x_max = max(x_max, point)
if x_max < x_min:
(x_min, x_max) = (-1,1) #prevent divide by zero or inversion
(x_min, x_max) = (-1, 1) # prevent divide by zero or inversion
if x_max == x_min:
(x_min, x_max) = (x_max-0.5, x_max+0.5)
(x_min, x_max) = (x_max - 0.5, x_max + 0.5)
self.x_max = x_max
self.x_min = x_min
return (x_min, x_max)
_IVY_APPNAME='JobyPlot'
_IVY_APPNAME = 'RealtimePlot'
_IVY_STRING = '(%s %s .*$)'
#_IVY_STRING = '^([^ ]*) +(%s( .*|$))' ## <-- from original ocaml (doesn't work here, just returns Sender field...)
# _IVY_STRING = '^([^ ]*) +(%s( .*|$))' ## <-- from original ocaml (doesn't work here, just returns Sender field...)
def create(parent, frame):
return PlotPanel(parent, frame)
class PlotPanel():
class PlotPanel(object):
def __init__(self, parent, frame):
self.parent = parent # we are drawing on our parent, so dc comes from this
self.frame = frame # the frame owns any controls we might need to update
self.parent = parent # we are drawing on our parent, so dc comes from this
self.frame = frame # the frame owns any controls we might need to update
parent.SetDropTarget( TextDropTarget(self)) # calls self.OnDropText when drag and drop complete
parent.SetDropTarget(TextDropTarget(self)) # calls self.OnDropText when drag and drop complete
self.InitIvy()
self.width = 800
self.height = 200
self.margin = min(self.height / 10, 20)
self.font = wx.Font(self.margin/2, wx.DEFAULT, wx.FONTFLAG_DEFAULT, wx.FONTWEIGHT_NORMAL)
self.font = wx.Font(self.margin / 2, wx.DEFAULT, wx.FONTFLAG_DEFAULT, wx.FONTWEIGHT_NORMAL)
self.pixmap = wx.EmptyBitmap(self.width, self.height)
self.plot_size = self.width
self.max = -1e32
@@ -185,12 +190,12 @@ class PlotPanel():
messages_xml_map.parse_messages()
# start the timer
self.timer = wx.FutureCall( self.plot_interval, self.OnTimer)
self.timer = wx.FutureCall(self.plot_interval, self.OnTimer)
def SetPlotInterval(self, value):
self.plot_interval = value
self.timer.Restart(self.plot_interval)
self.timer = wx.FutureCall( self.plot_interval, self.OnTimer)
self.timer = wx.FutureCall(self.plot_interval, self.OnTimer)
def SetAutoScale(self, value):
self.auto_scale = value
@@ -205,7 +210,7 @@ class PlotPanel():
if pause:
self.timer.Stop()
else:
self.timer = wx.FutureCall( self.plot_interval, self.OnTimer)
self.timer = wx.FutureCall(self.plot_interval, self.OnTimer)
def ResetScale(self):
self.max = -1e32
@@ -227,11 +232,11 @@ class PlotPanel():
def InitIvy(self):
# initialising the bus
IvyInit(_IVY_APPNAME, # application name for Ivy
"",#"[%s is ready]" % IVYAPPNAME, # ready message
0, # main loop is local (ie. using IvyMainloop)
lambda x,y: y, # handler called on connection/deconnection
lambda x,y: y # handler called when a diemessage is received
IvyInit(_IVY_APPNAME, # application name for Ivy
"", # "[%s is ready]" % IVYAPPNAME, # ready message
0, # main loop is local (ie. using IvyMainloop)
lambda x, y: y, # handler called on connection/deconnection
lambda x, y: y # handler called when a diemessage is received
)
# starting the bus
@@ -241,7 +246,7 @@ class PlotPanel():
logging.getLogger('Ivy').setLevel(logging.WARN)
IvyStart("")
# binding to every message
#IvyBindMsg(self.OnIvyMsg, "(.*)")
# IvyBindMsg(self.OnIvyMsg, "(.*)")
except:
IvyStop()
@@ -250,7 +255,7 @@ class PlotPanel():
self.BindCurve(int(ac_id), message, field)
def OnIvyMsg(self, agent, *larg):
#print(larg[0])
# print(larg[0])
data = larg[0].split(' ')
ac_id = int(data[0])
message = data[1]
@@ -264,22 +269,22 @@ class PlotPanel():
for field in self.plots[ac_id][message]:
plot = self.plots[ac_id][message][field]
ix = messages_xml_map.message_dictionary["telemetry"][message].index(field)
point = float(data[ix+2])
point = float(data[ix + 2])
if self.x_axis == None or self.x_axis.id != plot.id:
if self.x_axis is None or self.x_axis.id != plot.id:
if self.auto_scale:
scaled_point = (point + plot.offset) * plot.scale
self.max = max( self.max, scaled_point)
self.min = min( self.min, scaled_point)
self.max = max(self.max, scaled_point)
self.min = min(self.min, scaled_point)
if self.x_axis != None:
if self.x_axis is not None:
plot.index = self.x_axis.index
plot.AddPoint(point, self.x_axis)
def BindCurve(self, ac_id, message, field, color = None, use_as_x = False):
def BindCurve(self, ac_id, message, field, color=None, use_as_x=False):
# -- add this telemetry to our list of things to plot ...
message_string = _IVY_STRING % (ac_id, message)
#print('Binding to %s' % message_string)
# print('Binding to %s' % message_string)
if ac_id not in self.plots:
self.plots[ac_id] = {}
@@ -288,14 +293,15 @@ class PlotPanel():
self.plots[ac_id][message] = {}
if field in self.plots[ac_id][message]:
self.plots[ac_id][message][field].color = wx.Color(random.randint(0,255),random.randint(0,255),random.randint(0,255))
self.plots[ac_id][message][field].color = wx.Color(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255))
return
ivy_id = IvyBindMsg(self.OnIvyMsg, str(message_string))
title = '%i:%s:%s' % (ac_id, message, field)
self.plots[ac_id][message][field] = plot_data( ivy_id, title, self.plot_size, color)
self.frame.AddCurve( ivy_id, title, use_as_x)
if (use_as_x):
title = '%i:%s:%s' % (ac_id, message, field)
self.plots[ac_id][message][field] = PlotData(ivy_id, title, self.plot_size, color)
self.frame.AddCurve(ivy_id, title, use_as_x)
if use_as_x:
self.x_axis = self.plots[ac_id][message][field]
def CalcMinMax(self, plot):
@@ -314,62 +320,62 @@ class PlotPanel():
return (None, None, None)
def FindPlot(self, ivy_id):
(ac_id, msg, field) = self.FindPlotName( ivy_id)
if (ac_id == None):
(ac_id, msg, field) = self.FindPlotName(ivy_id)
if ac_id is None:
return None
return self.plots[ac_id][msg][field]
def RemovePlot(self, ivy_id):
(ac_id, msg, field) = self.FindPlotName( ivy_id)
if ac_id == None:
return
(ac_id, msg, field) = self.FindPlotName(ivy_id)
if ac_id is None:
return
if (self.x_axis != None) and (self.x_axis.id == ivy_id):
self.x_axis = None
if (self.x_axis is not None) and (self.x_axis.id == ivy_id):
self.x_axis = None
IvyUnBindMsg( ivy_id)
del self.plots[ac_id][msg][field]
if len(self.plots[ac_id][msg]) == 0:
del self.plots[ac_id][msg]
IvyUnBindMsg(ivy_id)
del self.plots[ac_id][msg][field]
if len(self.plots[ac_id][msg]) == 0:
del self.plots[ac_id][msg]
def OffsetPlot(self, ivy_id, offset):
plot = self.FindPlot( ivy_id)
if plot == None:
return
plot = self.FindPlot(ivy_id)
if plot is None:
return
plot.SetOffset(offset)
print('panel value: %.2f' % value)
CalcMinMax(plot)
plot.SetOffset(offset)
print('panel value: %.2f' % value)
CalcMinMax(plot)
def ScalePlot(self, ivy_id, offset):
plot = self.FindPlot( ivy_id)
if plot == None:
return
plot = self.FindPlot(ivy_id)
if plot is None:
return
plot.SetScale(offset)
CalcMinMax(plot)
plot.SetScale(offset)
CalcMinMax(plot)
def SetRealTime(self, ivy_id, value):
plot = self.FindPlot( ivy_id)
if plot == None:
return
plot = self.FindPlot(ivy_id)
if plot is None:
return
plot.SetRealTime(value)
plot.SetRealTime(value)
def SetXAxis(self, ivy_id):
plot = self.FindPlot( ivy_id)
if plot == None:
return
plot = self.FindPlot(ivy_id)
if plot is None:
return
self.x_axis = plot
self.x_axis = plot
def ClearXAxis(self):
self.x_axis = None
self.x_axis = None
def OnSize(self, size):
(width, height) = size
if( self.width == width and self.height == height):
if self.width == width and self.height == height:
return
self.pixmap = wx.EmptyBitmap(width, height)
@@ -377,7 +383,7 @@ class PlotPanel():
self.height = height
self.plot_size = width
self.margin = min(self.height / 10, 20)
self.font = wx.Font(self.margin/2, wx.DEFAULT, wx.FONTFLAG_DEFAULT, wx.FONTWEIGHT_NORMAL)
self.font = wx.Font(self.margin / 2, wx.DEFAULT, wx.FONTFLAG_DEFAULT, wx.FONTWEIGHT_NORMAL)
def OnTimer(self):
self.timer.Restart(self.plot_interval)
@@ -386,8 +392,8 @@ class PlotPanel():
def DrawFrame(self):
dc = wx.ClientDC(self.parent)
bdc = wx.BufferedDC( dc, self.pixmap)
bdc.SetBackground( wx.Brush( "White"))
bdc = wx.BufferedDC(dc, self.pixmap)
bdc.SetBackground(wx.Brush("White"))
bdc.Clear()
self.DrawBackground(bdc, self.width, self.height)
@@ -397,61 +403,60 @@ class PlotPanel():
for message in self.plots[ac_id]:
for field in self.plots[ac_id][message]:
plot = self.plots[ac_id][message][field]
if (self.x_axis != None) and (self.x_axis.id == plot.id):
if (self.x_axis is not None) and (self.x_axis.id == plot.id):
continue
title_height = plot.DrawTitle(bdc, 2, self.width, title_y)
plot.DrawCurve(bdc, self.width, self.height, self.margin, self.max, self.min, self.x_axis)
title_y += title_height + 2
def DrawBackground(self, dc, width, height):
# Time Graduations
dc.SetFont(self.font)
if self.x_axis == None:
if self.x_axis is None:
t = self.plot_interval * width
t1 = "0.0s"
t2 = "-%.1fs" % (t/2000.0)
t3 = "-%.1fs" % (t/1000.0)
t2 = "-%.1fs" % (t / 2000.0)
t3 = "-%.1fs" % (t / 1000.0)
else:
x_max = self.x_axis.x_max
x_min = self.x_axis.x_min
t1 = "%.2f" % x_max
t2 = "%.2f" % (x_min + (x_max-x_min)/2.0)
t2 = "%.2f" % (x_min + (x_max - x_min) / 2.0)
t3 = "%.2f" % x_min
(w,h) = dc.GetTextExtent(t1)
dc.DrawText(t1, width-w, height-h)
#(w,h) = dc.GetTextExtent(t2) #save time since h will be the same
dc.DrawText(t2, width/2, height-h)
#(w,h) = dc.GetTextExtent(t3) #save time since h will be the same
dc.DrawText(t3, 0, height-h)
(w, h) = dc.GetTextExtent(t1)
dc.DrawText(t1, width - w, height - h)
# (w,h) = dc.GetTextExtent(t2) #save time since h will be the same
dc.DrawText(t2, width / 2, height - h)
# (w,h) = dc.GetTextExtent(t3) #save time since h will be the same
dc.DrawText(t3, 0, height - h)
# Y graduations
if self.max == -1e32:
return
(_min_, _max_) = (self.min, self.max)
if _max_ < _min_: #prevent divide by zero or inversion
if _max_ < _min_: # prevent divide by zero or inversion
(_min_, _max_) = (-1, 1)
if _max_ == _min_:
(_min_, _max_) = (_max_-0.5, _max_+0.5)
(_min_, _max_) = (_max_ - 0.5, _max_ + 0.5)
delta = _max_-_min_
dy = (height - self.margin*2) / delta
scale = math.log10( delta)
delta = _max_ - _min_
dy = (height - self.margin * 2) / delta
scale = math.log10(delta)
d = math.pow(10.0, math.floor(scale))
u = d
if delta < 2*d:
u=d/5
elif delta < 5*d:
u=d/2
tick_min =_min_ - math.fmod(_min_, u)
for i in range( int(delta/u) + 1):
tick = tick_min + float(i)*u
if delta < 2 * d:
u = d / 5
elif delta < 5 * d:
u = d / 2
tick_min = _min_ - math.fmod(_min_, u)
for i in range(int(delta / u) + 1):
tick = tick_min + float(i) * u
s = str(tick)
(w,h) = dc.GetTextExtent(s)
y = height-self.margin-int((tick-_min_)*dy)-h/2
(w, h) = dc.GetTextExtent(s)
y = height - self.margin - int((tick - _min_) * dy) - h / 2
dc.DrawText(s, 0, y)
@@ -1,30 +1,24 @@
#!/usr/bin/env python
#Boa:App:BoaApp
import wx
import getopt
import sys
import plotframe
modules ={u'PlotFrame': [1, 'Main frame of Application', u'plotframe.py'],
u'messages_xml_map': [0, '', u'messages_xml_map.py'],
u'plotpanel': [0, '', u'plotpanel.py'],
u'realtimeplotapp': [0, '', u'realtimeplotapp.py'],
u'textdroptarget': [0, '', u'textdroptarget.py']}
class RealTimePlotApp(wx.App):
def OnInit(self):
self.main = plotframe.create(None)
self.main.Show()
self.SetTopWindow(self.main)
opts, args = getopt.getopt(sys.argv[1:], "p:",
["plot"])
for o,a in opts:
opts, args = getopt.getopt(sys.argv[1:], "p:", ["plot"])
for o, a in opts:
if o in ("-p", "--plot"):
[ac_id, message, field, color, use_x] = a.split(':')
self.main.AddPlot(int(ac_id), message, field, color, bool(int(use_x)))
return True
def main():
application = RealTimePlotApp(0)
application.MainLoop()