3 ms·
I tried showing the flies using matplotlib.animation.FuncAnimation in a notebook, animating even 1000 frames is slow and it warns the animation becomes too larg
by kzrdude 5y ago
I tried showing the flies using matplotlib.animation.FuncAnimation in a notebook, animating even 1000 frames is slow and it warns the animation becomes too large. Maybe there's a better way to do it? Preferably in a notebook interface.
- immmmmm 5y agopyqtgraph is a nice matplotlib replacement when speed matters, but doesn't work in a notebook
- kzrdude 5y agoI ended up writing some very rudimentary HTML canvas + javascript drawing code into the notebook and for my purposes it's fast and does the job. Just to note to others, that this is a possibility within a Jupyter notebook. One obvious benefit is that it can start rendering "live" and continuously and doesn't have to generate the whole animation before starting to show it.
- maverickleopard 5y agoHow exactly do you that and can you interop with python?
- kzrdude 5y agoI just used this in the Jupyter notebook (toldya it was very simple, written today :). It interoperates with python by being passed data to the draw call. Usage like: c = Canvas(); c.draw(xs); xs is a numpy array of shape (N, 2), the points to draw on the canvas. It's not fancy. But it drew animations faster than matplotlib (I ran this for thousands of frames, just to watch the simulation). import IPython.display as ipydisplay import json import numpy as np class Canvas: def __init__(self, canvas_id=None, width=500, height=500): self.display_id = None self._canvas_id = canvas_id or ('canvas_' + str(np.random.randint(0, 10000))) display(ipydisplay.HTML(f""" <canvas id="{self._canvas_id}" width="{width}" height="{height}" style="border:1px solid #d3d3d3;"> Your browser does not support the HTML5 canvas tag.</canvas> """)) def draw(self, xs, world_size): xs_string = json.dumps(xs.tolist()) obj = ipydisplay.HTML(f""" <script> var c = document.getElementById("{self._canvas_id}"); var ctx = c.getContext("2d"); var xs = {xs_string}; var size = {world_size}; ctx.clearRect(0, 0, c.width, c.height); var scale = c.width / size; for (let i = 0; i < xs.length; i++) {{ ctx.fillRect(xs[i][0] * scale, c.height - xs[i][1] * scale, 2, 2) }} </script> """) if self.display_id: ipydisplay.update_display(obj, display_id=self.display_id) return self.display_id self.display_id = display(obj, display_id=True).display_id
- maverickleopard 5y agoThat's awesome. I'm probably gonna start using this instead of matplotlib
- kzrdude 5y agoMaybe just use ipycanvas instead - it's on PyPI :) It works the same way except it's not a hack. I found it after I posted. I went through: - matplotlib animations (super slow, not live) - writing an image with PIL and updating display (flickers) - custom html+canvas code - ipycanvas I call display() on the canvas and then run the draw update loop on the canvas later in the same cell. That way the canvas is first displayed and then "live" updated.
- maverickleopard 5y agoOh wow even better. Thanks for enlightening me on this