-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Nbagg backend #3008
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
Nbagg backend #3008
Conversation
Cool! Thanks for taking this project up! |
@@ -9,13 +8,12 @@ mpl.get_websocket_type = function() { | |||
return MozWebSocket; | |||
} else { | |||
alert('Your browser does not have WebSocket support.' + | |||
'Please try Chrome, Safari or Firefox ≥ 6. ' + | |||
'Please try Chrome, Safari or Firefox ��� 6. ' + |
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.
It appears that (maybe) your editor borked the utf-8 here.
Very cool! I can report that it works on Google Chrome 35 on Linux. It seems to be significantly slower for panning and zooming than the "raw" WebAgg backend. I wonder where the overheads are. |
I've throttled the mouse events to 20ms, and there is no binary web sockets, so I suspect they are the cause. I've not tested this over a slow network - it might be that we need to do more to handle high latency connections. |
I should have mentioned -- the testing I did was locally on the same machine. We probably need to investigate dynamic throttling somehow based on the latency. |
Hi Phil, This looks very promising! @sratcliffe and I plumbed our mplh5canvas backend into the notebook back in 2012 at EuroSciPy but that was before the comm protocol, which made it very hacky and we didn't take it further. This is definitely a cleaner approach. I can confirm that nbagg works on Chrome 34 and Safari 7 on Mac OS X 10.9.2. Chrome has this funny issue that the antialiasing of the canvas lags any change to it by several seconds. So if you update the plot by zooming or panning, there is a slight loss of quality in the lines and text which corrects itself after up to 3 seconds (presumably by antialiasing kicking in). Safari seems snappier and does not have the antialiasing issue. I can also confirm @mdboom's observation that panning is a bit laggy even when connected to localhost. When the pan cursor is let go, the plots shifts after maybe 100-250 ms. This is not as obvious with zooming, which does not require such high-speed updating as panning (i.e. the plot is not expected to move while you draw the reticule). I could also get the plot to become unresponsive by panning 3 or 4 times in quick succession (I have a knack for breaking plotting interfaces - ask @sratcliffe :-)). Looking forward to the end result! |
@pelson This is fantastic work. Good job. This would be a great thing to announce and demo at SciPy this year. |
This is great a few comments though: tl;dr: make the nbagg backend an IPython Full explanation: I think that this should almost certainly be implemented as a
|
I agree with @ellisonbg that using the widget architecture is something to be seriously considered. I think "widgets have a clearly defined place in each cell for their display" is a disadvantage, not an advantage, but other than that, I think his list of advantages is pretty good. |
Warning: ongoing subtle design discussion about widgets/comms: Keep in mind though @jasongrout - even if we start to treat widgets like regular output and allow them to be interleaved with regular output - widgets will still have "a clearly defined place in each cell for their display" - there will just be multiple of them with the same CSS class, UI, etc. The important thing is that However the question of how widgets relate to and interleave with regular output is something that we are thinking about in the background. We don't plan on making any changes to how that works soon, but we realize the limitations of our current approach of one widget area per cell that is separate from output. |
Warning: this continues the subtle discussion @ellisonbg mentions: You said: (sorry; that's probably just the technical, picky, mathematician part of me taking apart the grammar to extract exact meaning...). |
I completely agree - the "a" in my original statement was a bit ambiguous. |
Thanks for the feedback @ellisonbg - the only advantage I needed to read was:
And you had me convinced. Whilst clearly I've been able to reverse engineer a solution based on a unique div id, I fully accept it is a hack that I'd love to get rid of, so if the Widget infrastructure can help in that regard, I'm all for it. Out of interest, did I miss anything with regards to the save event? It really does look like the Not having read up on the new widgeting system, my only slight concern is the ability to hook into the existing JS interface construction that I've inherited from the WebAgg backend, but that really is much of a muchness, and in truth is only about 30 lines of JS. @mdboom et al. - I think there are some things in here we want to keep, and some things in here which will be superseded once we make use of the Widget infrastructure. As such I suggest we merge this as an experimental feature and iterate on what is here, rather than rejecting outright. Of course, I would say that... so does anybody else have a view on this? |
If you're trying to iterate, I think you ought to look at the custom message handlers that widgets provide. They basically provide a way for the python and javascript sides of a widget to communicate. You can probably basically swap in the current infrastructure into a widget. Basically, you'll need to create a new view class with a render function that renders the matplotlib image to the Long-term, breaking out the parts of the interface that are nicely represented as state that needs to be synced between python and javascript and putting that into the model is the way to go, I think. |
We are very interested in this widget-based approach for Vispy, which would provide an interactive web backend in the IPython notebook. I'm wondering whether it would be sensible to standardize a bit the custom messages sent between Python and Javascript. Things like mouse actions, key pressed, etc. on the one hand, and images on the other hand, are likely to be similar between matplotlib, vispy and other visualization projects. We're also considering another type of backend where we'd not stream PNG images from Python to Javascript, but raw WebGL commands. |
I'm fine with merging this and iterating toward the widget-based approach. It does seem that this is creates a performance regression -- even for the "raw" WebAgg backend -- and I'd like to at least resolve that before merging. I think the event throttling is maybe not the way to go. I think instead we need to do event queuing such that intermediate mouse moves can be ignored if the updates get behind. That way we always get maximum throughput rather than setting an arbitrary upper limit on performance. What happens if we just take the throttling out for now, and then do something more adaptive in a subsequent PR? |
Right now, the state of the widget in syncing is throttled, but state changes are merged. By default, IIRC, it allows 3 state change messages out. Any more state changes than that (for example, rapidly moving mouse) get merged into a single state change that is sent out. So if you set the throttle to 1, and use the state syncing to sync a current mouse position between python and javascript, then I think you can have your queuing for free. I would be interested in performance regressions with the widget system. It seems like there might be some, especially compared to the original webagg because we can't use binary web sockets with the widgets. |
Sounds reasonable. I'll get onto rebasing this and removing the throttling. |
@tacaswell Getting this into 1.4 would be very nice! |
@person can I delegate the triageing if this for 1.4.0 to you? |
Tagging an 1.4.0, we can always punt later. |
I've finally got around to updating this PR. Thanks for the nudge @tacaswell. Other than that, I think this is good to go. |
Dealt with the conflict and merged. |
Thanks for merging @tacaswell. Good to have this in before SciPy'14! 👍 |
Just discovered this. It's a really great development. Quick suggestion: adding some kind of 'snapshot' button that e.g. saves to .png would be extremely handy for the kind of in-notebook fast data exploration + prototyping that this is presumably intended to facilitate. Load up interactive plot, explore, change parameters, see something interesting; save snapshot; carry on exploring. |
Can you expand a bit on what you want? There is currently a x at the top Do you want a download option or the ability to create a gallery on the fly? On Tue, Nov 18, 2014, 20:16 John Griffiths notifications@github.com wrote:
|
"an 'x' at the top right" -- right, because the first thing I think when I On Tue, Nov 18, 2014 at 8:19 PM, Thomas A Caswell notifications@github.com
|
The underlying WebAgg control has an option to save the file, but it seems NbAgg doesn't. (I'm surprised I'm just noticing that). @pelson: Any reason why the save dropdown isn't available for NbAgg? |
Thanks, didn't know about the 'x'. That does help. In general I prefer to be able to save important figures to separate files though; keeping them squirreled away in the notebook can be a little restrictive. I played around a bit and a reasonable working solution seems to be to simply define a function like def save_and_show_fig(fname):
fig.canvas.print_figure(fname)
return Image(fname) At least for the slider demo, this allows me to play around with the figure interactively and output the current state to separate cells as desired, as well as saving to file. Incidentally, I also tried adding a 'save button' to the slider example saveax = plt.axes([0.2, 0.025, 0.1, 0.04])
savebutton = Button(saveax, 'Save', color=axcolor, hovercolor='0.975')
fignum = 1
def savepng(event):
fig.canvas.print_png('/tmp/savefig_%s.png' %fignum)
fignum+=1
savebutton.on_clicked(savepng) ...but this didn't work. In any case the simpler option above is probably more useful as does both the saving and the printing of static images to new cells. |
@JohnGriffiths Can you make a new issue summarizing the current state of this? It will make it easier for us to keep track of it. |
@mdboom - no major reason. The save button would be a reasonable extension, I seem to remember not knowing what end point to use (i.e. how to map a URL that can actually be downloaded in the IPython notebook's domain). @JohnGriffiths - at one point, I considered the possibility allowing users to "snapshot" an image, carry on interacting, "snapshot" another, and be able to look at each of the snapshots in the resulting (static) notebook, but it sounds like this isn't really what you want. Instead, you just want to save the figure to disk, right? FWIW, if you have a reference to the figure, the nbagg backend is not blocking, so you can always simply do |
Yes, the snapshot saving is the primary thing I'm interested in here. Saving to disk would be a separate but complementary feature. Perhaps it could be a configurable option in the snapshots. Regarding the snapshots: it would useful to output these in some kind of 'gallery viewer' - i.e. a single cell which you can click-and-browse through the selected snapshots. A very simple version of this using static interactive widgets from ipywidgets would be: from ipywidgets import StaticInteract, DropDownWidget
from IPython.display import Image
imgs = <list of .png files>
labs = <list of brief labels>
def show_static_img(img):
i = Image(img)
return i
StaticInteract(show_static_img,
img = DropDownWidget(imgs),
labels=labs) This gives you a cell with a drop-down menu for looking at the saved snapshots, which works in static views with nbviewer. I'm sure this could be made a lot slicker. Some version of a single-cell snapshot gallery like this would IMHO be the perfect complement to the nbagg backend; dramatically increase its usefulness. |
Implements the nbAgg backend for interactive figures in the IPython notebook, using IPython's comm protocol.
@jasongrout's excellent proof of concept
CommFigure
in #2524 was used as an initial base (which itself made good use of @mdboom and my own work on the WebAgg backend), but I've removed theCommFigure
concept and have instead plumbed this into a real matplotlib backend.As a result, using IPython notebook v2.0 I am able to run the following code in the notebook to achieve an interactive figure:
I've currently only been able to test this with Firefox 24.4, so any feedback from other browsers would be valuable.
There are a few features I've not added at this point (but would like to do so):
%matplotlib nbagg
(in IPython itself)