5
10
15
20
25
30
35
40
45
50
55
60
65
70
75
80
85
90
95
100
105
110
115
120
125
130
135
140
145
150
155
160
165
170
175
180
185
190
195
200
205
210
215
220
225
230
235
240
245
250
255
260
265
270
275
280
285
290
295
300
305
310
315
320
325
330
335
340
345
350
355
360
365
370
375
380
385
390
395
400
405
410
415
420
425
430
435
440
445
450
455
460
465
470
475
480
485
490
|
#!/usr/bin/python
#was:
## Author: Jesper Skov <jskov@cygnus.co.uk>
## A rewite of the C canvas example in the GNOME Developer's Information
import GDK
from gtk import *
from gnome.ui import *
from _gnomeuimodule import *
import gnome.affine
import GdkImlib
import sys, string, socket
server = "127.0.0.1"
port = 1928
initial_time_scale = 5.0
initial_weight_scale = 5.0
GTK_CAULDRON_TOPLEVEL = 1
GTK_CAULDRON_IGNOREENTER = 1 << 8
GTK_CAULDRON_GRAB = 1 << 9
class timer:
def __init__ (self, func, freq = 1.0, *args):
if type (freq) == type (1):
freq = float (freq)
if type (freq) != type (1.0):
raise TypeError, "frequency must be a float"
if type (func) != type (self.__init__):
raise TypeError, "second arg must be a function"
self.func = func
self.args = args
self.time = 0.0
self.freq = freq
self.timer = timeout_add (int (1000.0 / self.freq), self)
def __call__ (self, *args):
self.time = self.time + 1.0 / self.freq;
return apply (self.func, (self.time,) + self.args)
def stop (self):
if not self.timer:
return
timeout_remove (self.timer)
self.timer = None
def start (self):
if self.timer:
return
self.timer = timeout_add (int (1000.0 / self.freq), self)
def reset (self):
self.time = 0.0
def __del__ (self):
timeout_remove (self.timer)
class CanvasExample:
def __init__(self, channel):
self.width = 400
self.height = 400
self.channel = []
self.numlines = len (channel)
for i in xrange (0, self.numlines):
self.channel.append (string.atoi (str (channel[i])))
def configure (self, widget, event):
if event.type == GDK.CONFIGURE:
self.grid.affine_relative (gnome.affine.scale (float (event.width) / float (self.width), \
float (event.height) / float (self.height)))
self.height = event.height
self.width = event.width
self.canvas.set_scroll_region (0, 0, self.width, self.height)
self.line_redraw ()
return FALSE
def get_y_pos (self, line, y):
if y < 0.0:
y = 0.0
shift = (int (line) / 2) * (int (self.height) / 10)
return float (self.height) - 1.0 - (y * (float (self.height) / self.weight_scale) + shift)
def get_weight (self, i, voltage):
return self.channel_gradient[i] * voltage + self.channel_offset[i]
def save_line (self, line):
win = GtkFileSelection ("Save Graph")
def delete_event (win, event = None):
win.destroy ()
win.connect ("delete_event", delete_event)
def file_selection_ok(_button, fs, line):
try:
f = open (fs.get_filename (), "w+")
for x, y in line:
f.write ("%.2f\t%.3f\n" % (x, y))
f.close ()
except:
gtk_dialog_cauldron ("Error", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
" ( [[(Error writing to file)xf]xf]xf )f / ( [%L]xf )f / ( %Bgxfrq | )f ", \
(str (sys.exc_value), "Button_Cancel"))
fs.destroy ()
win.ok_button.connect ("clicked", file_selection_ok, win, line)
win.cancel_button.connect ("clicked", win.hide)
win.show ()
def line_clicked (self, line):
x = gtk_dialog_cauldron ("Select", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
" %Bgxfrq // %Bgxfrq ", ("Save", "Button_Cancel"))
if x == "Save":
self.save_line (line)
return TRUE
def bold_event (self, widget, event):
if event.type == GDK.ENTER_NOTIFY:
widget.set (font = '-adobe-helvetica-bold-r-normal--14-140-75-75-p-77-iso8859-1')
return TRUE
elif event.type == GDK.LEAVE_NOTIFY:
widget.set (font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1')
return TRUE
return FALSE
def reset (self):
try:
self.timer.reset ()
except:
pass
self.last_redraw = 0.0
self.time_scale = initial_time_scale
self.weight_scale = initial_weight_scale
self.lines = []
for i in xrange (0, self.numlines):
self.lines.append ([(0.0, 0.0)])
self.channel_socket[i].send ("reset");
self.weight_division = 2
self.time_division = 2
self.line_redraw ()
def reset_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
self.reset ()
return self.bold_event (widget, event)
def start_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
for i in xrange (0, self.numlines):
self.channel_socket[i].send ("reset");
try:
self.timer.start ()
except:
self.timer = timer (self.next_line, self.freq)
self.line_redraw ()
return TRUE
return self.bold_event (widget, event)
def freq_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
x = gtk_dialog_cauldron ("Set Frequency", GTK_CAULDRON_TOPLEVEL,
" ( [(Enter the new sampling frequency:)]xf )f / ( %Ngxf )f / ( %Bgxfrq | %Bgxfq )f ", \
(str (self.freq), "datarecord-freq", "Frequency", "Button_Ok", "Button_Cancel"))
if not x:
return TRUE
if x[0] != "Button_Ok" and x[0] != "GTK_CAULDRON_ENTER":
return TRUE
self.freq = float (x[1])
try:
self.timer.stop ()
except:
pass
self.timer = None
self.reset ()
self.line_redraw ()
return TRUE
return self.bold_event (widget, event)
def quit_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
self.win.destroy ()
return TRUE
return self.bold_event (widget, event)
def stop_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
try:
self.timer.stop ()
except:
pass
self.line_redraw ()
return TRUE
return self.bold_event (widget, event)
# saves all channels
def save_event (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
win = GtkFileSelection ("Save All Graphs")
def delete_event (win, event = None):
win.destroy ()
win.connect ("delete_event", delete_event)
def file_selection_ok(_button, fs, lines):
try:
f = open (fs.get_filename (), "w+")
for i in xrange (0, len (lines[0])):
for j in xrange (0, len (lines)):
f.write ("%.2f\t%.3f\t\t" % lines[j][i])
f.write ("\n")
f.close ()
except:
gtk_dialog_cauldron ("Error", GTK_CAULDRON_TOPLEVEL | GTK_CAULDRON_GRAB,
" ( [[(Error writing to file)xf]xf]xf )f / ( [%L]xf )f / ( %Bgxfrq | )f ", \
(str (sys.exc_value), "Button_Cancel"))
fs.destroy ()
win.ok_button.connect ("clicked", file_selection_ok, win, self.lines)
win.cancel_button.connect ("clicked", win.hide)
win.show ()
self.line_redraw ()
return TRUE
return self.bold_event (widget, event)
def line_event (self, widget, event, line):
if event.type == GDK.BUTTON_PRESS:
self.line_clicked (line)
return TRUE
elif event.type == GDK.ENTER_NOTIFY:
widget.set (width_units = 3)
return TRUE
elif event.type == GDK.LEAVE_NOTIFY:
widget.set (width_units = 1)
return TRUE
return FALSE
def line_redraw (self):
i = 0
for line in self.lines:
p = []
# do not draw every point to reduce CPU load
step = 1 + len (line) / 100
j = 0
for k in xrange (0, len (line) - step + 1, step):
y = 0.0
for xt, yt in line[k:k + step]:
x = xt
y = y + yt
y = y / float (step)
p.append (x * float (self.width / 2) / self.time_scale + float ((self.width / 2) * (i % 2)))
p.append (self.get_y_pos (i, y))
j = j + 1
if len (p) == 2:
p = p + p
xs = p[-2]
# FIXME: 80 thumb suck value -->
if xs < 80:
xs = 80
if self.channel_gradient[i] == 1.0:
unit = "V"
else:
unit = "g"
if self.canvas_lines[i]:
self.canvas_text[i].set (text="%d(%.2f, %.3f%s)" % (i + 1, line[-1][0], \
line[-1][1], unit), x = xs, y = p[-1])
self.canvas_lines[i].set (points = tuple (p))
else:
self.canvas_text[i] = self.canvas.root ().add ('text', text="%d(%.2f, %.3f%s)" \
% (i + 1, line[-1][0], line[-1][1], unit),
x = xs, y = p[-1],
font = '-adobe-helvetica-bold-r-normal--10-100-75-75-p-60-iso8859-1',
anchor = ANCHOR_SOUTH_EAST,
fill_color = 'black')
self.canvas_lines[i] = self.canvas.root ().add ('line', points=p, \
width_pixels=1.0, fill_color=self.color[i])
self.canvas_lines[i].connect ("event", self.line_event, line)
i = i + 1
def read_channel (self, i):
self.channel_socket[i].send ("%d, 20" % (self.channel[i],));
x = string.split (self.channel_socket[i].recv (1024), ",");
return (string.atof (x[0]), 5.0 * string.atof (x[1]) / 2048.0)
def read_channel_weight (self, i):
t, y = self.read_channel (i)
return (t, y * self.channel_gradient[i] + self.channel_offset[i])
def calibrate (self, widget, event):
if event.type == GDK.BUTTON_PRESS:
import time
Sxx = 0.0
Sxy = 0.0
Sx = 0.0
Sy = 0.0
n = 0
v = gtk_dialog_cauldron ("Calibrate", GTK_CAULDRON_TOPLEVEL,
" ( [[(Enter line to calibrate 1 to " + str(self.numlines) + \
":)xf]xf]xf )f / ( %Nxf )f / ( %Bgxfrq || %Bgxfq )f ", ("1", "Button_Ok", "Button_Cancel"))
if not v:
return TRUE
if v[0] != "Button_Ok" and v[0] != "GTK_CAULDRON_ENTER":
return TRUE
try:
line = int (v[1]) - 1
except:
return TRUE
if line < 0 or line >= self.numlines:
return TRUE
while 1:
v = gtk_dialog_cauldron ("Calibrate", GTK_CAULDRON_TOPLEVEL,
" ( [[(Apply weight " + str (n) + ", enter its value in grams, and wait for 1 " \
"second:)xf]xf]xf )f / ( %Ngxf )f / ( %Bxfrq || %Bxfrq || %Bgxfq )f ", \
("0.0", "datarecord-cal", "Weight", "Done", "Enter Value", "Button_Cancel"))
if not v:
break
if v[0] != "Done" and v[0] != "GTK_CAULDRON_ENTER" and v[0] != "Enter Value":
break
if n > 1 and v[0] == "Done":
break
x = 0.0
for i in xrange (10):
time.sleep (0.1)
x = x + self.read_channel (line)[1]
x = x / 10.0
y = float (v[1])
Sxx = Sxx + x * x
Sx = Sx + x
Sy = Sy + y
Sxy = Sxy + x * y
n = n + 1
m = (float (n) * Sxy - Sx * Sy) / (float (n) * Sxx - Sx * Sx)
c = (Sy - m * Sx) / float (n)
self.channel_gradient[line] = m
self.channel_offset[line] = c
return TRUE
return self.bold_event (widget, event)
def next_line (self, time, *args):
i = 0
for line in self.lines:
x = self.read_channel_weight (i)
time = x[0]
line.append (x)
if time > self.time_scale:
if self.time_division == 5:
self.time_scale = self.time_scale * 5.0
self.time_division = 2
else:
self.time_scale = self.time_scale * 2.0
self.time_division = 5
if self.get_y_pos (i, line[-1][1]) < 0:
if self.weight_division == 5:
self.weight_scale = self.weight_scale * 5.0
self.weight_division = 2
else:
self.weight_scale = self.weight_scale * 2.0
self.weight_division = 5
i = i + 1
# if five seconds have past, or five pixels have advanced, then redraw:
# we don't want to redraw too often, 'cos it slows the machine down with long lines.
if time * float (self.width / 2) / self.time_scale > \
self.last_redraw * float (self.width / 2) / self.time_scale + 5.0 \
or time > self.last_redraw + 5.0:
self.last_redraw = time
self.line_redraw ()
return TRUE
def main (self):
# Open window to hold canvas.
self.win = GtkWindow ()
self.win.connect ('destroy', mainquit)
self.win.set_title ('Canvas Example')
# Create VBox to hold canvas and buttons.
vbox = GtkVBox ()
self.win.add (vbox)
vbox.show ()
# Create canvas.
self.canvas = GnomeCanvas ()
self.canvas.set_usize (self.width, self.height)
self.canvas.set_scroll_region (0,0, self.width, self.height)
vbox.pack_start (self.canvas, expand=TRUE, fill=TRUE)
self.canvas.show ()
self.color = ('blue', 'blue', 'red', 'red', 'yellow', 'yellow', 'cyan', 'cyan', 'blue', 'blue', \
'red', 'red', 'yellow', 'yellow', 'cyan', 'cyan', 'blue', 'blue', 'red', 'red', 'yellow', \
'yellow', 'cyan', 'cyan', 'blue', 'blue', 'red', 'red', 'yellow', 'yellow', 'cyan', 'cyan', )
self.grid = self.canvas.root ().add ('group')
for i in xrange (0, 50):
if not i % 5:
continue
self.grid.add ('line', points = (i * self.width / 50, 0, i * self.width / 50, self.height),
fill_color='gray',
width_pixels = 1)
self.grid.add ('line', points = (0, i * self.height / 50, self.width, i * self.height / 50),
fill_color='gray',
width_pixels = 1)
for i in xrange (0, 10):
self.grid.add ('line', points = (i * self.width / 10, 0, i * self.width / 10, self.height),
fill_color='black',
width_pixels = 1)
self.grid.add ('line', points = (0, i * self.height / 10, self.width, i * self.height / 10),
fill_color='black',
width_pixels = 1)
self.button_start = self.canvas.root ().add ('text', text="Start",
x = 5, y = 5,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_start.connect ("event", self.start_event)
self.button_stop = self.canvas.root ().add ('text', text="Stop",
x = 5, y = 25,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_stop.connect ("event", self.stop_event)
self.button_reset = self.canvas.root ().add ('text', text="Reset",
x = 5, y = 45,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_reset.connect ("event", self.reset_event)
self.button_save = self.canvas.root ().add ('text', text="Save All",
x = 5, y = 65,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_save.connect ("event", self.save_event)
self.button_save = self.canvas.root ().add ('text', text="Set Frequency",
x = 5, y = 85,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_save.connect ("event", self.freq_event)
self.button_reset = self.canvas.root ().add ('text', text="Calibrate",
x = 5, y = 105,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_reset.connect ("event", self.calibrate)
self.button_save = self.canvas.root ().add ('text', text="Quit",
x = 5, y = 125,
font = '-adobe-helvetica-medium-r-normal--14-140-75-75-p-77-iso8859-1',
anchor = ANCHOR_NORTH_WEST,
fill_color = 'red')
self.button_save.connect ("event", self.quit_event)
self.last_redraw = 0.0
self.time_scale = initial_time_scale
self.weight_scale = initial_weight_scale
self.lines = []
self.canvas_lines = []
self.canvas_text = []
self.freq = 10.0
self.channel_socket = []
self.channel_offset = []
self.channel_gradient = []
for i in xrange (0, self.numlines):
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect ((server, port))
self.channel_socket.append (s)
self.lines.append ([(0.0, 0.0)])
self.canvas_lines.append (0)
self.canvas_text.append (0)
self.channel_offset.append (0.0)
self.channel_gradient.append (1.0)
self.weight_division = 2
self.time_division = 2
self.win.show ()
self.win.connect ("event", self.configure)
if __name__ == '__main__':
c = CanvasExample (sys.argv[1:])
c.main ()
mainloop ()
|