Search code examples
pythonimagematplotlibplot

Problem exporting images with matplot lib


Working on an Ising model simulation in Matplotlib and at the end I need to export a figure as an image and every image is coming back blank. I figure it has to do with the message <Figure size 640x480 with 0 Axes> but I cannot figure out what I need to do to fix that message or fix the problem of figures not exporting properly.

Here's the code for creating the plot. I looked at other stack overflow posts and attempted to fix the issue, such as adding axes manually or defining the figure or making sure everything was defined in the right order and nothing seemed to fix the problem.

M = 1000
plot = np.zeros(M)
fig = plt.figure
ax = plt.axes(xlim=(0, M), ylim=(-400,400))

for x in range(M):
    plot[x] = x
    
xarr = range(0, M)
ax.plot(xarr, plot, 'r-')
plt.ylabel("Magnetism")
plt.xlabel("Steps")
plt.show()
plt.savefig("output_mplot.png")

Solution

  • TLDR: plt.show() before plt.savefig() forces you to close active figure before saving.

    When working with matplotlib, you have the choice between 2 interfaces: the Axes interface and the pyplot interface. The Axes interface is object-based and explicit, the pyplot interface is function-based and implicit.

    Here you are mixing up the two, creating the ax and plotting on it explicitly with the Axes interface (ax = plt.axes(...) and ax.plot(...)), and tweaking and saving with the pyplot interface (plt.ylabel(...), plt.savefig(...) etc.).

    Mixing is ok, but it might be better to stay consistent with one.

    Coming to your problem. The pyplot interface is implicit, meaning that it works on the last active figure and axe. So when you call plt.savefig() it searches for the last active figure. However, before that you called plt.show(), which interrupts the execution and displays the figure. So when plt.savefig() is executed, it means that you closed the figure and so no figure is active at that time.

    In short, your particular issue can be solved by removing the line plt.show() or by putting it last.

    However, I recommend you the explicit Axes interface, you will be less prone to such errors. See:

    import numpy as np
    import matplotlib.pyplot as plt
    
    M = 1000
    x = np.arange(0, M)
    y = np.arange(0, M)
    
    fig, ax = plt.subplots(figsize=(10, 4))
    
    ax.plot(x, y, "r-")
    
    ax.set_xlim(0, M)
    ax.set_ylim(-400, 400)
    
    ax.set_ylabel("Magnetism")
    ax.set_xlabel("Steps")
    
    fig.savefig("output_mplot.png")
    
    fig.show()  # plt.show() displays *all* active figures
    

    Note: Also, fig = plt.figure should probably have been fig = plt.figure()