#!/usr/bin/env python """ Author: Flavio Codeco Coelho License: GPL Stripchart module for vpython Features: -user defined number of channels """ import psyco import time from visual import * from visual.text import * from RandomArray import random from psyco.classes import * psyco.full() class Strip: """ Stripchart object. """ def __init__(self, nch=1, xlabel='t(s)',ylabel='V'): self.scene = display(title="Stripchart Recorder",width=600,height=400, uniform=0, ambient=1,autoscale=1) #create the curves self.channels = self.addch(nch) self.gridon = True self.grid = frame() #collection of horizontal grid lines self.ticklabels=frame()#collection of labels self.xlabel = label(frame=self.grid,pos=(9,-9,0),text=xlabel,color=color.orange,box=0, line=0) self.ylabel = label(frame=self.grid,pos=(-9,9,0),text=ylabel,color=color.orange,box=0,line=0) self.drawGrid() self.drawTickLabels(range(-10,10),range(-10,10)) def addch(self, nch=1): """ Creates a channel object (curve) nch is the number of channels. """ col = [color.white,color.blue,color.red,color.green,color.yellow,color.cyan,color.magenta, color.orange] tplch = tuple([curve(radius=0, color=col[n%len(col)])for n in xrange(nch)]) return tplch def toggleGrid(self): """ Toggle visibility of gridlines """ r = len(self.grid.objects) if self.gridon: for i in range(r): self.grid.objects[0].visible = 0 self.gridon = False else: self.drawGrid() self.gridon = True pass def drawGrid(self): """ draw grid lines """ hrng = int(self.scene.range[1]) vrng = int(self.scene.range[0]) [curve(frame=self.grid,pos=[(-vrng,i),(vrng,i)],color=color.white) for i in xrange(-hrng, hrng, hrng*2/10)] [curve(frame=self.grid,pos=[(j,-hrng),(j,hrng)],color=color.white) for j in xrange(-vrng, vrng, vrng*2/10)] def drawTickLabels(self,xticks,yticks): """ Draw x and y tick labels """ xticks2 = array([round(i,2) for i in xticks]) yticks2 = array([round(i,2) for i in yticks]) labidx = range(0,len(xticks2),len(xticks2)/10) #indices to the labels to be plotted Pos = range(-10,10,2) #position of the ticklabels within the frame coordinates #List comprehensions to draw ticklabels. [(xticks,yticks) for i in xrange(len(Pos))] # Not as clear as a regular "for" but much faster... [label(frame=self.ticklabels,pos=(Pos[i],-8,0),text=str(xticks2[labidx[i]]),color=color.orange,box=0,line=0) for i in xrange(len(Pos))] #x ticklables [label(frame=self.ticklabels,pos=(-8,Pos[i],0),text=str(yticks2[labidx[i]]),color=color.orange,box=0,line=0) for i in xrange(len(Pos))] #y ticklabels def updateTicks(self,xticks,yticks): """ Update tick labels values """ xticks2 = array([round(i,2) for i in xticks]) yticks2 = array([round(i,2) for i in yticks]) labidx = range(0,len(xticks2),len(xticks2)/10) #indices to the labels to be plotted Pos = range(-10,10,2) #position of the ticklabels within the frame coordinates i = j = 0 for l in self.ticklabels.objects: if self.ticklabels.objects.index(l) < 10: #update x axis l.text = str(xticks2[labidx[i]]) i += 1 else: #update y axis l.text = str(yticks2[labidx[j]]) j += 1 def plot(self,ch,point): """ Appends a point to the channel(curve) object ch. Fills the scene and after it is full, shifts the curve one step left, for each new point. If its the first point it creates the plot. """ #Adjust the scene and frames vertically to folow data if point[1] > self.scene.range[1]: self.scene.center[1] = point[1]-9 self.grid.y = point[1]-9 self.ticklabels.y = point[1]-9 elif point[1] < -self.scene.range[1]: self.scene.center[1] = point[1]+9 self.grid.y = point[1]+9 self.ticklabels.y = point[1]+9 #========================================= if self.scene.kb.keys:#key trap s = self.scene.kb.getkey() # obtain keyboard information if s == 'g' or s == 'G': self.toggleGrid() # Scroll scene center right to follow data if len(ch.x) > 0 and ch.x[-1] > 10: # scroll center of the scene with x new_x_center = (ch.x[0]+ch.x[-1])/2. self.scene.center = (new_x_center,0,0) self.updateTicks(ch.x,ch.y) self.grid.x = new_x_center self.ticklabels.x = new_x_center # shift curve and append ch.pos[:-1] = ch.pos[1:] ch.pos[-1] = point else: ch.append(pos=point) if __name__=='__main__': st = Strip(2) ch1 = st.channels[0] ch2 = st.channels[1] start = time.clock() for i in arange(-10,200,.1): st.plot(ch1,(i,10*sin(i),0)) st.plot(ch2,(i,10*cos(i)+random(),0)) #rate(50)#set maximum frame rate print "frame rate: ", 1/((time.clock()-start)/210.)