Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Why doesn't matplotlib save the whole figure by default? #17118

Copy link
Copy link
Closed
@rraadd88

Description

@rraadd88
Issue body actions

savefig saves cropped images by default.

Bug summary

It's probably an issue that almost everybody who uses matplotlib would have encountered. If you generate a figure - which often contains axis labels and legends - and save it with default settings, you'll get a cropped image.

It's a duplicate of my question on stackoverflow.

Code for reproduction

import matplotlib.pyplot as plt
def plot():
    plt.figure(figsize=[3,3],linewidth=5,edgecolor='r') 
    ax=plt.subplot()
    ax.plot(range(10),range(10),label='label')
    ax.set_xlabel('xlabel\nxlabel\nxlabel')
    ax.set_ylabel('ylabel\nylabel\nylabel')
    ax.legend(bbox_to_anchor=[1,1])
plot()    
plt.savefig('no_tight_layout.png')

Actual outcome

no_tight_layout.png

Expected outcome

If I generate the same plot in a jupyter notebook, without using tight_layout option, I see that all the elements of the plot are contained within the figure boundaries (shown in red).

jupyter notebook

This figure is generated in the output cell of a jupyter notebook(!).
Then why it is not saved as it is? Why the saved image is by default different from the image jupyter notebook?
In my opinion this is a very fundamental issue with matplotlib.
Would't it make the lives of the users easier, if by default, all the elements are contained in the saved figure without the need of any workarounds?

(Thanks to stackoverflow), we know few workarounds but each has a caveat of its own..

Workaround #1: from within matplotlib: use of tight_layout option.

plot()    
plt.savefig('tight_layout.png',bbox_inches='tight')

tight_layout.png

It works for simple figures.
However, in my experience, it is not reliable option in the case of more complex, multi-panel figures.
tight_layout often fails with errors such as these:

UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
UserWarning: tight_layout not applied: number of rows in subplot specifications must be multiples of one another.

Workaround #2: from outside of matplotlib: save the image in SVG format and then convert to png. For example using --export-area-drawing option in the inkscape command line UI or "resize to page" option in the inkscape's GUI.

However, in this case you have to depend on external softwares which are difficult to add as dependencies in python packages (currently conda only hosts Windows version of inkscape).

So my question is..

Why doesn't matplotlib save the whole figure by default?


Matplotlib version

  • Operating system: Ubuntu 18.04
  • Matplotlib version: 3.1.2 (this is issue reproducible in previous version too.)
  • Matplotlib backend (print(matplotlib.get_backend())):
  • Python version: 3.6.5
  • Jupyter version (if applicable): 1.0
  • Other libraries:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.