Skip to content

Instantly share code, notes, and snippets.

@straypacket
Last active December 19, 2015 08:19
Show Gist options
  • Save straypacket/5924557 to your computer and use it in GitHub Desktop.
Save straypacket/5924557 to your computer and use it in GitHub Desktop.
Tornado websocket server and html client
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import time
import random
# Preload data
# ... use from previous gists
#import numpy as np
#a = kk_df[['DATE_REGISTERED','URL']].sort(['DATE_REGISTERED'])
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print 'new connection'
#self.write_message("Hello World")
parse_data(self)
def on_message(self, message):
print 'message received: %s' % message
def on_close(self):
print 'connection closed'
application = tornado.web.Application([
(r'/', WSHandler),
])
def parse_data(self):
prev_date = a['DATE_REGISTERED'].iloc[0]
c = []
for x in range(len(a)):
now = a['DATE_REGISTERED'].iloc[x]
time.sleep((now - prev_date).seconds/100.0)
prev_date = now
# Make request
print "[%s] %s [%d]" % (now, a['URL'].iloc[x], len(c))
path = a['URL'].iloc[x].split('/')
if len(path) > 2:
root = path[:-1][1]
if root not in c:
c.append(root)
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (c.index(root)+1,5)
self.write_message(msg)
else:
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (0,5)
self.write_message(msg)
def random_data(self):
sleep = 0.1
while 1:
if random.random() > 1.5:
msg = '{"type": "bar", "id": %d, "markers": [%d], "measures": [%d,%d], "ranges": [%d,%d,%d]}' % (random.randrange(0, 4, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1),random.randrange(100, 200, 1))
else:
msg = '{"type": "bubble", "color": %d, "radius": %d}' % (random.randrange(0, 4, 1),random.randrange(4, 40, 1))
self.write_message(msg)
time.sleep(sleep)
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Live demo</title>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
padding-top: 40px;
position: relative;
width: 960px;
}
button {
position: absolute;
right: 10px;
top: 10px;
}
.bullet { font: 10px sans-serif; }
.bullet .marker { stroke: #000; stroke-width: 2px; }
.bullet .axis line, .bullet .axis path { stroke: #666; stroke-width: .5px; fill: none; }
.bullet .range.s0 { fill: #eee; }
.bullet .range.s1 { fill: #ddd; }
.bullet .range.s2 { fill: #ccc; }
.bullet .measure.s0 { fill: lightsteelblue; }
.bullet .measure.s1 { fill: steelblue; }
.bullet .title { font-size: 14px; font-weight: bold; }
.bullet .subtitle { fill: #999; }
rect{
fill: white;
}
circle {
stroke: #000;
stroke-opacity: .5;
}
</style>
</head>
<body>
<div id="body">
<div id="chart"></div>
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="bullet.js"></script>
<script>
var margin = {top: 5, right: 40, bottom: 50, left: 120},
width = 192 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var chart = d3.bullet()
.orient("bottom")
.width(width)
.height(height);
var svg_bar;
d3.json("bullets.json", function(error, data) {
svg_bar = d3.select("body").selectAll("svg")
.data(data)
.enter().append("svg")
.attr("class", "bullet")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
var title = svg_bar.append("g")
.style("text-anchor", "end")
.attr("transform", "translate(" + width + "," + (height + 20) + ")");
title.append("text")
.attr("class", "title")
.text(function(d) { return d.title; });
title.append("text")
.attr("class", "subtitle")
.attr("dy", "1em")
.text(function(d) { return d.subtitle; });
});
function randomize(d) {
if (!d.randomizer) d.randomizer = randomizer(d);
d.ranges = d.ranges.map(d.randomizer);
d.markers = d.markers.map(d.randomizer);
d.measures = d.measures.map(d.randomizer);
return d;
}
function randomizer(d) {
var k = d3.max(d.ranges) * .2;
return function(d) {
return Math.max(0, d + k * (Math.random() - .5));
};
}
// ==========
// Websockets
// ==========
var wsUri = "ws://127.0.0.1:8888/";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt) {
console.log("CONNECTED");
//doSend("WebSocket rocks");
}
function onClose(evt) {
console.log("DISCONNECTED");
}
function onMessage(evt) {
//console.log('GOT DATA: ' + evt.data);
var new_data = JSON.parse(evt.data);
console.log(new_data);
if (new_data['type'] == "bubble") {
makeNode(new_data['radius'],new_data['color']);
}
else {
var id = new_data['id'];
svg_bar.data()[id].ranges = new_data['ranges'];
svg_bar.data()[id].markers = new_data['markers'];
svg_bar.data()[id].measures = new_data['measures'];
svg_bar.transition().duration(1000).call(chart);
}
}
function onError(evt) {
console.log('ERROR: ' + evt.data);
}
function doSend(message) {
console.log("SENT: " + message); websocket.send(message);
}
window.addEventListener("load", init, false);
// ========
// Floaters
// ========
var w = 960,
h = 500;
var nodes = d3.range(30).map(function(i) {
if (i < 15) {
console.log("Low");
return {radius: 15,
fixed:true,
type:i,
x: (i+1) * (w / 16),
y: (h/2)-(h/4)};
}
else {
console.log("High");
return {radius: 15,
fixed:true,
type:i,
x: (i+1-15) * (w / 16),
y: (h/2)+(h/4)};
}
}),
color = d3.scale.category20();
var force = d3.layout.force()
.gravity(0)
.charge(0)
.nodes(nodes)
.size([w, h]);
force.start();
var svg = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
svg.append("svg:rect")
.attr("width", w)
.attr("height", h);
svg.selectAll("circle")
.data(nodes)
.enter().append("svg:circle")
.attr("r", function(d) { return d.radius - 2; })
.style("fill", function(d, i) { return color(d.type); });
force.on("tick", function(e) {
var q = d3.geom.quadtree(nodes),
k = e.alpha * .1,
i = 0,
n = nodes.length,
o;
while (++i < n) {
o = nodes[i];
if (o.fixed) continue;
c = nodes[o.type];
o.x += (c.x - o.x) * k;
o.y += (c.y - o.y) * k;
q.visit(collide(o));
}
svg.selectAll("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
function makeNode(radius,type) {
var p1 = [w/2,10],
node = {radius: radius, type: type, x: p1[0], y: p1[1], px: w/2, py: 10};
svg.append("svg:circle")
.data([node])
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.radius - 2; })
.style("fill", function(d) {return color(d.type);})
.transition()
.delay(3000)
.attr("r", 1e-6)
.each("end", function() { nodes.splice(31, 1); })
.remove();
nodes.push(node);
force.resume();
};
function collide(node) {
var r = node.radius + 4,
nx1 = node.x - r,
nx2 = node.x + r,
ny1 = node.y - r,
ny2 = node.y + r;
return function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x,
y = node.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = node.radius + quad.point.radius;
if (l < r) {
l = (l - r) / l * .5;
node.px += x * l;
node.py += y * l;
}
}
return x1 > nx2
|| x2 < nx1
|| y1 > ny2
|| y2 < ny1;
};
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment