-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
WebAgg backend #1426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WebAgg backend #1426
Conversation
I should add that the "Zoom to Rect" functionality isn't drawing a rectangle yet, but that's coming. |
@@ -500,7 +500,7 @@ class Animation(object): | |||
''' | |||
def __init__(self, fig, event_source=None, blit=False): | |||
self._fig = fig | |||
self._blit = blit | |||
self._blit = blit and fig.canvas.supports_blit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a little unfriendly. If I ask for blitting, I would expect to get it - otherwise I should get an error. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This deserves some explanation. Some backends, such as WebAgg, do not support blitting. In the case of WebAgg, it's because blitting is not possible -- we don't have direct access to the window/screen buffers anyway, so there is no advantage to it. This allows code that was written to expect blitting (such as all of the examples/animation
examples) to still work. There should be consistent behavior across backends, even when certain features are not available.
Note: Tornado should probably get a mention in the setup "optional dependencies" list. |
|
||
|
||
class FigureCanvasWebAgg(backend_agg.FigureCanvasAgg): | ||
supports_blit = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell, this isn't a fundamental property of this approach (i.e. in the future, we will be able to blit). Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No -- there is no way to blit directly to the screen/window hardware so there is no advantage to that approach. It could be faked, but I'm not sure why...
Sadly, using web sockets means I can't use this backend with Firefox 10 (released January 31, 2012) - see http://en.wikipedia.org/wiki/WebSocket#Browser_support I was able to test your previous tech demo, so I wonder if we can provide a fallback capability to less able browsers? |
self.write_message(diff, binary=True) | ||
|
||
def __init__(self): | ||
super(WebAggApplication, self).__init__([ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add an index page (and maybe a 404 error page), which lists all of the available figures (for bonus points, it would be nice to use the figure.get_label
for that).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I planned to do this, but forgot to mention it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My plan here is to provide a page with "thumbnails" of all of the open figures (with the figure.get_label
beneath it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea! Extra bonus points for that! 😄
Mike: This is awesome stuff! The approach you have taken here is pragmatic in that it achieves 80% of what is really required (interactive figures in the web browser which are easily shareable to local users). Obviously, the approach falls short of being able to have the figures disconnected from a python/matplotlib server and globally shareable (securely), but realistically that requirement can only be met by re-writing large chunks of matplotlib in JavaScript which really does not sit well for a community driven Python package. I've left quite a few comments: I hope you find them useful - the majority of them are relating to documentation/commenting. Other than that, I would be in favour of merging this early and labelling it an experimental feature (and getting it out for users to try in 1.3.x). Great stuff! |
I hadn't considered the minimum requirements for WebSockets. Unfortunately, the approach used in the original tech demo made sharing these plots a lot more complicated -- since there was no way to "push" images to the browser, the browsers had to poll occasionally, and to stay in sync (i.e. to not drop frames) full frames would have to be pushed on polling. This approach with WebSockets is a lot cleaner and less likely to fail. But sure, if supporting the older browsers is deemed important, we do have a possible solution for a backward compatibility mode -- but I'd prefer not to have the complication if we can avoid it. I should also add that the IPython notebook requires websockets, so there is incentive on a number of fronts for users to need a more recent browser. |
Note that IPython is considering to replace pure websockets with SockJS which should increase the browser coverage: ipython/ipython#2321 |
@jenshnielsen: Thanks for the pointer. I'll look into that. |
Regarding WebSocket browser coverage: It is specifically the binary websocket messages (that are used for the image data) that don't work with Firefox < 11. The text-based messages appear to work fine, with a simple Firefox compatibility hack. SockJS looks like a nice solution, and the built-in support for broadcasting messages is a nice convenience we could use here. However, it doesn't yet support binary messages, so it doesn't really address our needs. Even if it does support binary messages, I'm not sure there's any way to do it without base64 encoding, which will probably add a lot of overhead. I'm also not too keen, as IPython has done, or including a bunch of external code to make this work... (There might be a way to get pip to require it etc.) I don't want to grow a dependency on IPython for this basic usage, either (nothing wrong with IPython, but I do like that it is easy/simple to get this going without it). Anyway, I haven't decided either way yet about using SockJS -- that will require some experimentation. |
Yes, all of the above was done in Firefox 10. The context menu issue is going to be tricky. I am not particularly keen on mapping to the middle button, but that may have to be what happens. We would need to advertise that fact. This may also cause conflicts with any existing code that utilized the middle mouse button already (I have to check to see if mplot3d was using it at all...). The hanging issue with Firefox might have been spurious. I only noticed it happening very badly once, so it could have been unrelated. |
@mdboom - I'm a big fan of getting new features of such value in quickly for early adopters to pick up and try out (and report bugs before the next release). I'd be willing to put some effort in this week to get this merged - if your keen, would you mind getting this into a state where you are happy with it, and I will do a thorough once over before merging (assuming everybody else is happy with that). After that, I presume it is about getting similar functionality into the ipython notebook? Have you had an attempt, or are you hopeful that someone from the ipython dev team will meet us half way? Cheers, |
I think this is not far from a shape where it should be merged. I spent a little time trying to support browsers that don't support binary WebSockets, but I'm not sure it's feasible -- it really complicates things. Firefox 17 LTS is now out, superceding the Firefox 10 LTS, so the issue that there's a Firefox LTS that doesn't support this is all but moot now. In any case we should add some browser detection code and warnings if the browser is likely too old. Other than that, here's my TODO list:
I think we can then merge this before tacking the IPython integration. I'm sure they're excited about this -- but I'm not sure about the best way to go about integrating this. Will need to bring some IPython experts on board. |
@mdboom As far as I can tell in it's current state it would be rather difficult to integrate this in any direct way to an ipython notebook due to it's reliance on the tornado websockets since in ipython notebooks the kernel running the webserver is different than the notebook kernel, but @ellisonbg is the real expert on the notebook so he would be the one to ask. This is already incredibly useful though as a way to have an interactive figure in a browser for a remote ipython notebook session. It might be good to change the default port though because currently it can't be used alongside an ipython notebook since they both try to use localhost:8888 and they get confused. I think any direct integration of matplotlib into an ipython notebook will require the interactivity to be done using js callbacks to the local ipython kernel but I may be wrong. |
…using image resampling.
The current MouseEvent docstring has no mention of this issue so I did not remove anything there. This code was originally added to account for difficulties in preventing the context menu in chrome 23 matplotlib#1426 (comment)
This adds a WebAgg backend based on the approach I described here:
http://mdboom.github.com/blog/2012/10/11/matplotlib-in-the-browser-its-coming/
It's not complete, but I thought I would post this early to give it lots of browser testing and make sure that the fundamental approach is sound.
This does not integrate with IPython (though that's the plan) -- it is just a standalone backend, and the only additional dependency is Tornado.
To try it out, set your backend to
WebAgg
, make a figure and callpyplot.show()
. By default, a webbrowser tab will be opened showing the figure (though the webbrowser behavior is configurable). Some fun examples to try areexamples/animation/double_pendulum_animated.py
andexamples/event_handling/lasso.py
.Each of the existing figures is available on its own page (just like their own window in a GUI backend), and the URLs are of the form:
I don't have a lot of experience with browser programming, so the CSS and layout is a little clunky. I'd encourage improvements there, as well as any reports of any examples that don't seem to work.