[Assorted-commits] SF.net SVN: assorted:[1528] real-time-plotter
Brought to you by:
yangzhang
From: <yan...@us...> - 2009-12-18 00:37:20
|
Revision: 1528 http://assorted.svn.sourceforge.net/assorted/?rev=1528&view=rev Author: yangzhang Date: 2009-12-18 00:37:04 +0000 (Fri, 18 Dec 2009) Log Message: ----------- added real-time plotter Added Paths: ----------- real-time-plotter/ real-time-plotter/trunk/ real-time-plotter/trunk/src/ real-time-plotter/trunk/src/rtp.html real-time-plotter/trunk/src/server.py Added: real-time-plotter/trunk/src/rtp.html =================================================================== --- real-time-plotter/trunk/src/rtp.html (rev 0) +++ real-time-plotter/trunk/src/rtp.html 2009-12-18 00:37:04 UTC (rev 1528) @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>Real Time Plotter</title> + <meta charset="UTF-8"> + <script src="http://people.iola.dk/olau/flot/jquery.js"></script> + <script src="http://people.iola.dk/olau/flot/jquery.flot.js"></script> + <script> + window.onload = function() { + var s = new WebSocket("ws://hammer.csail.mit.edu:9877/"); + var data = {}; + s.onmessage = function(e) { + //alert('got ' + e.data); + var lines = e.data.split('\n'); + for (var i = 0; i < lines.length - 1; i++) { + var parts = lines[i].split(' '); + var d = parts[0], x = parseFloat(parts[1]), y = parseFloat(parts[2]); + if (!(d in data)) data[d] = []; + data[d].push([x,y]); + } + + var plots = []; + for (var d in data) plots.push( { data: data[d].slice(data[d].length - 200) } ); + $.plot( $("#holder"), plots, + { + series: { + lines: { show: true, fill: true }, + //points: { show: true }, + }, + //xaxis: { min: 0, max: 10 }, + //yaxis: { min: 0, max: 10 }, + xaxis: { min: 0 }, + yaxis: { min: 0 }, + } ); + + s.send(''); + }; + }; + </script> + </head> + <body> + <div id="holder" style="width:600px;height:300px"></div> + </body> +</html> Added: real-time-plotter/trunk/src/server.py =================================================================== --- real-time-plotter/trunk/src/server.py (rev 0) +++ real-time-plotter/trunk/src/server.py 2009-12-18 00:37:04 UTC (rev 1528) @@ -0,0 +1,120 @@ +#!/usr/bin/env python + +# I group the x values by the 1000s and only keep one distinct point from each +# such unique value. This is because I was written expecting millisecond +# timestamps for x values, and I only need to plot second granularity. This is +# easy to adjust/remove. + +from __future__ import with_statement +import contextlib, Queue as queue, socket, threading, time + +...@co...ntextmanager +def locking(lock): + lock.acquire() + try: yield + finally: lock.release() + +def listen(port, handler): + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(('', port)); + s.listen(1); + while 1: + t,_ = s.accept(); + threading.Thread(target = handler, args = (t,)).start() + +q = queue.Queue() + +def handle_source(s): + f = s.makefile() + name = f.readline().strip() + print 'new source', name + try: + while 1: + line = f.readline() + if line == '': break + x, y = map(float, line.split()) + q.put(('source', (name, (x, y)))) + finally: + q.put(('source', (name, None))) + print 'source', name, 'stopped' + +def first(xs, x): return xs[0] if len(xs) > 0 else x +def last(xs, x): return xs[-1] if len(xs) > 0 else x + +def pump(): + active = set() + sinks = [] + data = {} + ordered_names = [] + start_time = None + while 1: + msgtype, msg = q.get() + if msgtype == 'source': + name, value = msg + if name not in active: + active.add(name) + data[name] = (last(ordered_names, None), []) + ordered_names.append(name) + #start_time = None + if value is None: # source stopped + ordered_names.remove(name) + active.remove(name) + for n in data: + if data[n][0] == name: + data[n] = (data[name][0], data[n][1]) + break + else: # source append + x, y = value + x = int(x) / 1000 + if start_time is None: + start_time = min([x] + [first(series, (x,y))[0] for pred, series in data.itervalues()]) + x -= start_time + pred, series = data[name] + if len(series) == 0 or series[-1][0] != x: + y += data[pred][1][-1][1] if pred is not None else 0 + series.append((x, y)) + for sink in sinks: sink.put((name, (x, y))) + elif msgtype == 'sink': + sink = msg + sink.put( dict( (name, series + []) + for name, (pred,series) in data.iteritems() ) ) + sinks.append(sink) + +def handle_sink(s): + print 'new sink', repr(s.recv(4096)) + s.send(''' +HTTP/1.1 101 Web Socket Protocol Handshake\r +Upgrade: WebSocket\r +Connection: Upgrade\r +WebSocket-Origin: http://hammer.csail.mit.edu:8888\r +WebSocket-Location: ws://hammer.csail.mit.edu:9877/ + '''.strip()) + s.send('\r\n\r\n') + qq = queue.Queue() + q.put(('sink', qq)) + data = qq.get() + if True: + s.send('\x00') + for d in data: + for x, y in data[d]: + s.send('%s %s %s\n' % (d, x, y)) + s.send('\xff') + print 'sent historical data' + while 1: + if s.recv(4096) == '': break + s.send('\x00') + sent_sthg = False + while 1: + if qq.empty() and sent_sthg: break + msg = qq.get() + d, (x, y) = msg + s.send('%s %s %s\n' % (d, x, y)) + sent_sthg = True + s.send('\xff') + print 'client closed' + s.close() + +threading.Thread(target = listen, args = (9876, handle_source)).start() +threading.Thread(target = listen, args = (9877, handle_sink)).start() +pump() Property changes on: real-time-plotter/trunk/src/server.py ___________________________________________________________________ Added: svn:executable + * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |