Skip to content

Instantly share code, notes, and snippets.

@mivade
Created January 9, 2016 13:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mivade/6585e3b31f43ef47d66a to your computer and use it in GitHub Desktop.
Save mivade/6585e3b31f43ef47d66a to your computer and use it in GitHub Desktop.

Testing using Pygal to render plots server-side and embed them in a web page via a <canvas>.

"""Demo of using Pygal to plot and stream images to a web page."""
import os.path
import numpy as np
import pygal
from pygal.style import Style
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.locks import Event
from tornado.web import Application, RequestHandler
from tornado.websocket import WebSocketHandler
from tornado.options import options
path = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p))
chart_options = pygal.Config()
chart_options.show_legend = False
chart_options.width = 600
chart_options.height = 300
chart_options.x_title = 'Points'
chart_options.y_title = 'Amplitude'
chart_options.range = (-2, 2)
chart_style = Style(
background='transparent',
plot_background='transparent')
done = Event()
class MainHandler(RequestHandler):
def get(self):
self.render('index.html')
class ImageSocket(WebSocketHandler):
image = None
def open(self):
pass
def on_message(self, msg):
if msg == 'ready' and ImageSocket.image is not None:
self.write_message(ImageSocket.image)
def on_close(self):
pass
def make_app(debug=True):
return Application(
[
(r'/', MainHandler),
(r'/plot', ImageSocket)
],
debug=debug,
template_path=path('.'),
static_path=path('.')
)
def gen_data(points=2048):
x = np.linspace(-10, 10, points)
while True:
y = np.sin(x) + np.random.choice((-1, 1), points) * (np.random.random(points))
yield x, y
async def make_plot(data):
chart = pygal.Line(chart_options)
x, y = next(data)
chart.raw_series = []
chart.add('', y, show_dots=False)
return chart
async def main():
while not done.is_set():
source = gen_data()
chart = await make_plot(source)
data = chart.render_data_uri()
ImageSocket.image = data
await gen.sleep(0.005)
if __name__ == "__main__":
app = make_app()
app.listen(8989)
options.parse_command_line()
try:
IOLoop.current().run_sync(main)
except KeyboardInterrupt:
done.set()
<!doctype html>
<html>
<head>
<title>Pygal!</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="{{ static_url('style.css') }}" />
</head>
<body>
<canvas id="placeholder" width="800" height="800"></canvas>
<div id="test"></div>
<script type="text/javascript">
window.onload = function () {
var sock = connect();
var image = new Image();
var canvas = document.querySelector('#placeholder');
var ctx = canvas.getContext('2d');
function connect() {
sock = new WebSocket('ws://' + window.location.host + '/plot');
return sock;
}
function ready() {
if (sock.readyState === 1) {
sock.send('ready');
}
}
image.onload = function () {
var hRatio = canvas.width / image.width,
vRatio = canvas.height / image.height,
ratio = Math.min(hRatio, vRatio);
canvas.globalAlpha = 1;
ctx.drawImage(image, 0, 0, image.width, image.height,
0, 0, image.width*ratio, image.height*ratio);
};
sock.onopen = function () {
ready();
};
sock.onmessage = function (msg) {
image.src = msg.data;
document.querySelector('#test').innerHTML = image;
window.setTimeout(ready, 75);
};
};
</script>
</body>
</html>
body {
background-color: #000000;
}
canvas {
background-color: rgba(255, 255, 255, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment