Open kb1ooo opened 4 years ago
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.
@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.
@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?
@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.
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...
@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?
Looks good so far!
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.
Ok cool, so you mean add something like 'UserData': 'jupyter' to the default properties dictionary in handle_plot_settings?
Yeah, that sounds right.
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