2

In a python interactive session the following code is run:

import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.show()

how do I let show() not block and not actually show the image, but instead store it in a file? I can not change the code to plt.savefig('figure.png'). (There is a very good reason for this, I can explain if interested.)

The way to go seems to be specifying a custom backend renderer but so far no success. Is it possible to take an existing backend renderer and change the show() method to save to a file? (Lets say "figure%d.png" with %d the amount of times show() has been called so far.)

Other suggestions next to a custom backend renderer are welcome as well. In IPython notebook if you execute plt.show(), it manages to take the image and place it beneath the active code block. How's that done?

Anonymous
  • 572
  • 3
  • 15
  • 1
    I am very interested in the reason behind your need. Could you please explain why you can not use plt.savefig() instead? By the way, you can let show() not block just using plt.show(block=False). It will show the image while returning the prompt. – Alejandro Sep 16 '15 at 16:37
  • @Alejandro I want to send code and execute it on a remote server. If plt.show() is called, I want the server to store the image locally and send it back to the caller as a response so that it can simply be displayed as if the instruction was executed locally. – Anonymous Sep 16 '15 at 17:06
  • You might also consider something like `http://mpld3.github.io/` or http://stackoverflow.com/questions/5515278/plot-matplotlib-on-the-web. – Ed Smith Sep 16 '15 at 17:17

2 Answers2

1

You could use the solution from here for creating a figure without a gui. This uses FigureCanvasAgg (which is the gui built by default, you could probably use a different one). The show in pyplot can then be monkey patched,

import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg

def show(fig=None):

    if fig == None:
        fig = plt.gcf()
    canvas = FigureCanvasAgg(fig)
    canvas.print_figure("./out.png", dpi=80)

plt.show = show    
plt.plot([1,2,3])
plt.show()

Not sure if this avoid the problem you have with savefig?

Community
  • 1
  • 1
Ed Smith
  • 12,716
  • 2
  • 43
  • 55
  • I've thought about monkey-patching but that brings up a different question. Can I have the show function patched in a new module with the exact same name, so that the code `import matplotlib.pyplot as plt plt.plot([1,2,3]) plt.show()` would work? Basically abstracting the patching away from the user. (And just have the new module with the patch sitting in the working directory?) – Anonymous Sep 16 '15 at 17:11
  • As you want to run this on a server and *never* plan to show a display window, I guess you could change the `matplotlib` server code for `show` (with a warning message when called). Maybe more explicit is to define a custom version of the matplotlib module for use on your server which imports and patches any functions you need to (using https://pypi.python.org/pypi/wrapt). – Ed Smith Sep 16 '15 at 17:35
0

I ended up creating a custom backend for matplotlib. In the matplotlib package there's a backends folder which includes a backend_template.py.

From this I basically removed everything except the functions show, new_figure_manager and new_figure_manager_given_figure. The latter I slightly adapted to:

canvas = FigureCanvasAgg(figure)
manager = FigureManagerBase(canvas, num)
return manager

I left new_figure_manager untouched and at the end of the file I've set FigureCanvas = FigureCanvasAgg so that I am basically reusing most of the functionality of the Agg backend. Then you can implement the show function however you want.

The final step is to set up a matplotlibrc config file and add a line backend : module://matplotlib_custom_backend.

Anonymous
  • 572
  • 3
  • 15