Saving matplotlib subplot figure to image file

17,244

Solution 1

Remove the line plt.figure(figsize=(12, 9)) and it will work as expected. I.e. call savefig before show.

The problem is that the figure being saved is the one created by plt.figure(), while all the data is plotted to ax which is created before that (and in a different figure, which is not the one being saved).

For saving the figure including the legend use the bbox_inches="tight" option

plt.savefig('test.png', bbox_inches="tight")

Of course saving the figure object directly is equally possible,

fig.savefig('test.png', bbox_inches="tight")

For a deeper understanding on how to move the legend out of the plot, see this answer.

Solution 2

Additional add-up on @ImportanceOfBeingErnest's answer, when bbox_inches='tight', 'pad_inches=0.1' may need to set to larger values.

Share:
17,244
Hendy
Author by

Hendy

Updated on June 24, 2022

Comments

  • Hendy
    Hendy almost 2 years

    I'm fairly new to matplotlib and am limping along. That said, I haven't found an obvious answer to this question.

    I have a scatter plot I wanted colored by groups, and it looked like plotting via a loop was the way to roll.

    Here is my reproducible example, based on the first link above:

    import matplotlib.pyplot as plt
    import pandas as pd
    from pydataset import data
    
    df = data('mtcars').iloc[0:10]
    df['car'] = df.index
    
    fig, ax = plt.subplots(1)
    plt.figure(figsize=(12, 9))
    for ind in df.index:
        ax.scatter(df.loc[ind, 'wt'], df.loc[ind, 'mpg'], label=ind)
    ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
    # plt.show()
    # plt.savefig('file.png')
    

    Uncommenting plt.show() yields what I want:

    good plot

    Searching around, it looked like plt.savefig() is the way to save a file; if I re-comment out plt.show() and run plt.savefig() instead, I get a blank white picture. This question, suggests this is cause by calling show() before savefig(), but I have it entirely commented out. Another question has a comment suggesting I can save the ax object directly, but that cuts off my legend:

    chopped legend

    The same question has an alternative that uses fig.savefig() instead. I get the same chopped legend.

    There's this question which seems related, but I'm not plotting a DataFrame directly so I'm not sure how to apply the answer (where dtf is the pd.DataFrame they're plotting):

    plot = dtf.plot()
    fig = plot.get_figure()
    fig.savefig("output.png")
    

    Thanks for any suggestions.


    Edit: to test the suggestion below to try tight_layout(), I ran this and still get a blank white image file:

    fig, ax = plt.subplots(1)
    plt.figure(figsize=(12, 9))
    for ind in df.index:
        ax.scatter(df.loc[ind, 'wt'], df.loc[ind, 'mpg'], label=ind)
    ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
    fig.tight_layout()
    plt.savefig('test.png')