Skip to content
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

flush plots before script finishes #133

Open
kb1ooo opened this issue Mar 11, 2020 · 9 comments
Open

flush plots before script finishes #133

kb1ooo opened this issue Mar 11, 2020 · 9 comments

Comments

@kb1ooo
Copy link

kb1ooo commented Mar 11, 2020

Is it possible to push/flush inline plots to cell output while a script is running. E.g. if you were to make plots at every iteration of a loop, they won't render until the loop is completed. Is there a way (without doing native plots) to flush plots? This is pretty important for looking at progress of iterative optimization runs, e.g. deep learning training.

Thanks

@blink1073
Copy link
Contributor

blink1073 commented Mar 12, 2020

In theory, we could inject a matlab function that prints figures to a known location and then have a python thread that looks for changes in that directory, then triggers an image display on the kernel. You would then be able to call that function from within your loop. If someone were willing to take that effort up, I could offer pointers.

@kb1ooo
Copy link
Author

kb1ooo commented Mar 12, 2020

@blink1073 ok, interesting. Do you think it would be possible to push updates to the same plot as well? I might be willing to take this on depending on the effort involved.

@kb1ooo
Copy link
Author

kb1ooo commented Mar 12, 2020

@blink1073 regarding your suggestion, would it not be possible to do something synchronous? As long as you are injecting a custom "plotting" matlab function, is there no way to invoke an image display directly after that call?

@kb1ooo
Copy link
Author

kb1ooo commented Mar 12, 2020

@blink1073 what about the following (inspired by a great hack a web based Terminal program called wetty uses, which allows you to download files via writing to the terminal in between escape sequences). So, what if you inject a custom matlab function that prints the figure somewhere (like you suggested) and then writes the filename to stdout in between some escape sequences. Modify your _PseudoStream class to intercept the escape sequence, pull the filename out and call Display on the image. Otherwise, the _PseudoStream prints to the stream as it does now.

@dsblank
Copy link
Member

dsblank commented Mar 12, 2020

I had a similar idea that I listed either here, or in the matlab_kernel's parent. I was always hoping that we could do it in some kind of "standard" way, so that it was as hacky as it could be :) Let me see if I can find some notes...

@kb1ooo
Copy link
Author

kb1ooo commented Apr 7, 2020

@blink1073 @dsblank I made a first pass at this on my fork based on the approach I described above. Please check out my fork if you would like, and let me know what you think. I heavily commented the kernel code, but I'll repeat some of it here. I wrote a variation of the _PseudoStream class called _PseudoStreamFig which looks for start '\033[5i' and end '\033[4i' escape sequence delimiters in the stdout stream. Anything not between those delimiters it passes to the stdout writer just as the original _PseudoStream class did. In between the delimiters, it looks for a URI of the form fig://urlencoded_filename.png/gcf?id=12&rm=1, which communicates the figure filename, the gcf id (which I would like to use in the future to update figure if possible through the metakernel), and then rm=1 or rm=0 to signify whether the file should be removed after rendering.

So, to communicate that a fig should be rendered in jupyter you call a function from matlab which looks something like:

function jupFigRender(fig)

    if nargin == 0
        fig = gcf;
    end

    gcfid = num2str(get(fig,'Number'));
    dpi = 96;
    filename = [tempname '.png'];
    print(fig,'-dpng',sprintf('-r%i', dpi), filename);
    drawnow('update'); % flushes stdout buffer
    fprintf(1,'%s[5ifig://%s/gcf?id=%s&rm=1%s[4i',...
        27,urlencode(filename),gcfid,27)
    drawnow('update'); % flushes stdout buffer
end

If you have suggestions on how to elegantly make something like this function a no-op when you aren't running code from jupyter, that would be helpful. Also, I'd really like to update this to be able to assign a display id and then also use update_display from ipython. Is this possible through the metakernel interface?

@blink1073
Copy link
Contributor

blink1073 commented Apr 7, 2020

Looks good so far!

  • You could set a property on 0 during kernel startup and check for that property in the script.
  • We don't currently support update_display, but here's what you'd need to do:
    • Update Display to include transient
    • Add an UpdateDisplay method to that class that generates an UpdateDisplay message.

@kb1ooo
Copy link
Author

kb1ooo commented Apr 7, 2020

Looks good so far!

* You could [set](http://www.ece.northwestern.edu/local-apps/matlabhelp/techdoc/ref/set.html) a property on `0` during kernel startup and check for that property in the script.

Ok cool, so you mean add something like 'UserData': 'jupyter' to the default properties dictionary in handle_plot_settings?

* We don't currently support `update_display`, but here's what you'd need to do:
  
  * Update [`Display`](https://github.com/Calysto/metakernel/blob/master/metakernel/_metakernel.py#L625) to include [`transient`](https://jupyter-client.readthedocs.io/en/stable/messaging.html#display-data)
  * Add an `UpdateDisplay` method to that class that generates an `UpdateDisplay` [message](https://jupyter-client.readthedocs.io/en/stable/messaging.html#update-display-data).

Great, thanks.

@blink1073
Copy link
Contributor

Ok cool, so you mean add something like 'UserData': 'jupyter' to the default properties dictionary in handle_plot_settings?

Yeah, that sounds right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants