Skip to content

Loading…

Request: pickle-based pylab backend for ZMQ shell #2322

Open
tkf opened this Issue · 7 comments

4 participants

@tkf

It seems that matplotlib is going to support pickling figures (matplotlib/matplotlib#1020). Wouldn't it be nice to have a new pylab backend which sends png/svg figure and also pickled figure? This way, you can get inline figure in the notebook client but also GUI figure in the terminal client. You can even choose GUI backend to use at the client side.

I guess there will be a trouble when the ZMQ shell and client use different matplotlib version so you will need to detect incompatible version some how.

@pelson

It seems that matplotlib is going to support pickling figures

Yes. Though it should be said that it is pretty experimental (colorbars and legends are yet to work for instance). The ability to pickle the figure into a binary/ascii form for things such as the notebook was definitely one of my motivators. It should be said very explicitly here though: Pickled files are not secure. It is possible to inject arbitrary code into a pickle dump.. The most cited article on this can be found here.

@tkf

@pelson Thanks for the comment. To clarify, my suggestion is to use pickle for kernel-client messaging, not for saving figure. This won't bring security risk as long as you trust kernel, right? I think notebook client can simply discard pickle data since it is useless for Javascript.

@takluyver
IPython member
@tkf

There were PR to support chaning backend (#2179) so I guess having interactive plot while having inline figure is a wanted feature. As matplotlib support backend switching only once and it does not work well when kernel is not local, I don't think switching backend is ultimate solution.

I am not sure how to solve problem with large figure. For notebook, you can filter it in notebook server. Is it possible (or planned) to client to "subscribe" to certain display type? If you can do that, then you can reduce unused transmission of large pickle data. Or you can expose it as magic command (something like %plotgui fig where fig is a figure object) so that user can have interactive figure only when s/he want.

@takluyver
IPython member
@minrk
IPython member

pickled objects should probably use the data_pub messages, which doesn't have to b64-encode for use in JSON messages. These messages also won't arrive at the notebook frontend, which doesn't support raw buffer data.

@tkf

Following advice from @minrk, supporting pickled figure in client side was pretty easy.

diff --git a/IPython/frontend/terminal/console/interactiveshell.py b/IPython/frontend/terminal/console/interactiveshell.py
index 1291822..9a40975 100644
--- a/IPython/frontend/terminal/console/interactiveshell.py
+++ b/IPython/frontend/terminal/console/interactiveshell.py
@@ -28,6 +28,7 @@
 from IPython.core import page
 from IPython.utils.warn import warn, error, fatal
 from IPython.utils import io
+from IPython.zmq.serialize import unserialize_object

 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
 from IPython.frontend.terminal.console.completer import ZMQCompleter
@@ -152,6 +153,15 @@ def handle_iopub(self):
                     if sub_msg["content"]["execution_state"] == "busy" :
                         pass

+                elif msg_type == 'data_message':
+                    if 'pickled_matplotlib' in sub_msg['content']['keys']:
+                        # Unserializing buffers adds figures to
+                        # matplotlib stack, so there is no need to
+                        # bind the unserialized object.
+                        unserialize_object(sub_msg['buffers'])
+                        from matplotlib import pyplot
+                        pyplot.show()
+
                 elif msg_type == 'stream' :
                     if sub_msg["content"]["name"] == "stdout":
                         print(sub_msg["content"]["data"], file=io.stdout, end="")

Then you can try it by running this in ipython console:

from IPython.zmq.datapub import publish_data
from matplotlib import pyplot

fig = pyplot.figure()
pyplot.plot([1, 2, 3, 0, 2])
publish_data({'pickled_matplotlib': fig})
@minrk minrk removed the type-enhancement label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.