5

I used pickle to dump matplotlib figure as shown in an answer in SO. Below is the code snippet-

import pickle
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,2,3],[10,-10,30])
pickle.dump(fig, open('fig.pickle', 'wb'))

Below is the code snippet to load the pickled figure-

import pickle
figx = pickle.load(open('fig.pickle', 'rb'))
figx.show()

The above code shows following error-

AttributeError: 'NoneType' object has no attribute 'manager'
Figure.show works only for figures managed by pyplot, normally created by pyplot.figure().

I am using Python 3.6.3 on Ubuntu 14.04 LTS 64 Bit OS. Below are the more details of my environment-

> import matplotlib
> matplotlib.__version__
'2.1.0'
> matplotlib.get_backend()
'Qt5Agg'
> import sys
> sys.version_info
sys.version_info(major=3, minor=6, micro=3, releaselevel='final', serial=0)

PS: My questions seem similar to this question asked at SO. However, it is different since the provided answer is not running and throwing exceptions.

ravi
  • 6,140
  • 18
  • 77
  • 154
  • Possible duplicate of [Store and reload matplotlib.pyplot object](https://stackoverflow.com/questions/7290370/store-and-reload-matplotlib-pyplot-object) – DYZ Mar 27 '18 at 03:34
  • @DyZ: Please have a look on the updated question. Thanks! – ravi Mar 27 '18 at 03:48
  • I cannot reproduce your error. Also when I replace `figx.show()` by `plt.show()` I am able to load the figure. – Tom de Geus Mar 27 '18 at 05:31
  • @TomdeGeus: Replacing by `plt.show()` doesn't show anything. `figx.show()` shows error reported above. I don't know the exact steps to reproduce but it is showing on my machine. – ravi Mar 27 '18 at 05:38
  • How do you rund this code? Which matplotlib version and which backend are you using? What does `print(figx)` and `print(figx.canvas)` print? – ImportanceOfBeingErnest Mar 27 '18 at 08:00
  • @ImportanceOfBeingErnest: both the code snippets are stored in separate python files and executed independently. `print(figx)` returns `Figure(640x480)` and `print(figx.canvas)` returns `None` – ravi Mar 27 '18 at 09:29
  • Ok, so for this to work `figx.canvas` should of course not be `None` but rather `FigureCanvasXY` with XY denoting the backend. Which backend are you using and which matplotlib version? – ImportanceOfBeingErnest Mar 27 '18 at 10:13
  • @ImportanceOfBeingErnest: It seems that `Qt5Agg` is the backend. Please see the updated question. – ravi Mar 28 '18 at 09:35

2 Answers2

18

You need a canvas manager before you can show your figure. The same concept from question Matplotlib: how to show a figure that has been closed applies, you can create a function to make a dummy figure and steal its manager, as below (credit to Jean-Sébastien who wrote the answer above).

def show_figure(fig):

    # create a dummy figure and use its
    # manager to display "fig"  
    dummy = plt.figure()
    new_manager = dummy.canvas.manager
    new_manager.canvas.figure = fig
    fig.set_canvas(new_manager.canvas)

With this function you can then run:

show_figure(figx)
figx.show()
Nathan Kiner
  • 373
  • 3
  • 9
  • Super helpful. I found I could also replace the two lines in the second block with this one line `plt.show(show_figure(figx))` ; I had called `import matplotlib.pyplot as plt` above. – Wayne Feb 15 '20 at 19:33
  • Any idea on how to revise the above to load 3D plots? Current code does load them, but it is not possible to zoom in or rotate. – SaTa Nov 28 '20 at 16:47
-1

The pyplot figure manager is needed to display the plot. You can create an instance and use the imported figure by doing this:

plt.new_figure_manager(1).canvas.figure = figx
Stever530
  • 9
  • 2
  • There is a better way. The function plt._backend_mod.new_figure_manager_given_figure(1,figx) is much cleaner! – Stever530 Feb 16 '23 at 20:06