Real-time graphs

SeeBelow at SeeBelow.Nut SeeBelow at SeeBelow.Nut
Wed May 12 22:53:58 EDT 2004


snrkiwi-lists at yahoo.com wrote:
> 
> I've trolled the lists, FAQs, and Net as a whole, but
> can't find anything definitive to answer this.
> 
> We're looking for real-time graph capability (bar,
> line, etc), so that we can display telemetry from a
> robot system.  There are a bunch of packages out
> there, but many seem to provide only static graphs
> (e.g. for scientific, financial data, etc). Does
> anyone currently display real-time telemetry using
> Python? Can anyone provide any suggestions?

Here is something I wrote a few years ago that simulates a strip chart
recorder.  Execute plotter.py; it will import from model.py.

Mitchell Timin

-- 
"Many are stubborn in pursuit of the path they have chosen, few in
pursuit of the goal." - Friedrich Nietzsche

http://annevolve.sourceforge.net is what I'm into nowadays.
-------------- next part --------------
# model.py - components for dynamic models
# by Mitchell Timin, 1999

from random import gauss

class delay:
    "Pure time delay of a time sequence, like a tape loop"
    def __init__(self, steps):
        "initialize a new delaying object - argument is number of steps"  
        self.hist = []
        for i in range(steps):  
            self.hist.append(0.0)   
    def lag(self, input):
        " Object.lag(input) returns an earlier value of input."
        self.hist.append(input)
        return(self.hist.pop(0))

class generate:
    def __init__(self):
        self.X = 10.0   
        self.Y = 10.0   
        self.A = -0.2
        self.B = -0.15
        self.C = +0.12

    def next(self):
        dX = self.A*self.X + self.B*self.Y + gauss(0.0, .05)
        dY = .4*self.X + self.C*self.Y
        self.X = self.X + dX
        self.Y = self.Y + dY
        return(self.X, self.Y)
        
    def modA(self, cont, oldcont):
        self.A = self.A * (100 + cont - oldcont)/98.0
    def modB(self, cont, oldcont):
        self.B = self.B * (100 + cont - oldcont)/98.0
    def modC(self, cont, oldcont):
        self.C = self.C * (100 + cont - oldcont)/98.0
-------------- next part --------------
# Continuous plotting & control of a dynamic model
# by Mitchell Timin, 1999

# These are Python standard items:
from Tkinter import *
from time import sleep
from thread import start_new_thread, exit

# This is the dynamic model:
from model import generate
model = generate()

# This section sets up the graphics display and controls:
wide = 810  ;   high = 560   # pixel dimensions of canvas
Halt = 0
def halt():
    "used by PAUSE button to toggle Halt variable"
    global Halt
    if(Halt):
        Halt = 0
    else:
        Halt = 1        
root=Tk()
root.protocol("WM_DELETE_WINDOW", root.destroy)
frame = Frame(root)
frame.pack()    
button = Button(frame, text="QUIT", fg="red", command=frame.quit)
button.pack(side=LEFT)
butt = Button(frame, text="PAUSE", fg="blue", command=halt)
butt.pack(side=LEFT)
but = Button(frame, text="RESTART", fg="green", command=model.__init__)
but.pack(side=LEFT)
scale = Scale(root)
scale.pack(side=LEFT)
scal = Scale(root)
scal.pack(side=LEFT)
sca = Scale(root)
sca.pack(side=LEFT)
canvas=Canvas(root,width=wide,height=high)
canvas.pack()

# A sequence of short line segments will be drawn on the canvas.
# This code gets ready for that:
offset = 5          # just a few pixels away from the edge
dx = 20             # stepsize in horizontal direction
stime = .15         # real time delay between segments (seconds)

# Y and Z are the model's dependent variables, unscaled.
# ypix and zpix are the scale values in pixels.
# xpix represents time, in pixels horizontally.
yscale = zscale = 10.0


def nexpix(x):
    "returns a tuple of the pixel values representing the models output"
    Y, Z = model.next()
    ypix = int((high/2)-Y*yscale)
    zpix = int((high/2)-Z*zscale)
    return x+dx, ypix, zpix

# compute the starting points:    
xs, ys, zs = nexpix(offset-dx) 
    
def draw(stime):
    "Repeatedly draws line segments, calling the model for values:"
    global xs,ys,zs,dx
    # get the user control values:
    pc1, pc2, pc3 = scale.get(), scal.get(), sca.get()
    while 1:
        sleep(stime)
        while(Halt):
            sleep(.1)
        # get the user control values:
        c1, c2, c3 = scale.get(), scal.get(), sca.get()
        if(c1 != pc1):
            model.modA(c1, pc1)
            pc1 = c1
        if(c2 != pc2):
            model.modB(c2, pc2)
            pc2 = c2
        if(c3 != pc3):
            model.modC(c3, pc3)
            pc3= c3
        #update the model, then draw a line segment for each variable:    
        xf, yf, zf = nexpix(xs)
        l1 = canvas.create_line(xs, ys, xf, yf, width=2,fill="blue")
        l2 = canvas.create_line(xs, zs, xf, zf, width=2,fill="green")
        # save the endpoints; they will become the starting points:
        xs,ys,zs = xf, yf, zf
        # This is to delete the older, offscreen, line segments:
        if l1 > 100 and l2 > 100:
            canvas.delete(l1-100);canvas.delete(l2-100)
        if xs >= wide:
            canvas.move(ALL,-dx,0)
            xs = xs - dx
    
start_new_thread(draw,(stime,))

root.mainloop()


More information about the Python-list mailing list