24

Say I create a plot:

import matplotlib.pyplot as plt
plt.clf()
import numpy as np
props = np.random.randint(0,100,(200,))
x=np.arange(1,201,1)
plt.plot(x,props,c='k')
plt.xlabel('blah blah blah blah blah blah\n blah blah blah blah blah')
plt.ylabel('blah blah blah blah blah blah blah blah blah')
fig=plt.gcf()
fig.set_size_inches(3.75,3.75)#14, 23)
plt.savefig('testfig.png',dpi=300)

When using Ipython (via Spyder), the plot presents ok. However when I looked at the saved image, it presents thus:

enter image description here

As you can see, the text is cut off. What is recommended practice for dealing with this?

I have got round it by increasing the figure size, and re-sizing afterwards. However, my aim is to produce a set of images with a consistent text size (figure size varies); so this approach is not ideal.

Note. Whilst a similar question exists, this question is distinct in that it:

  • deals with both xlabel and ylabel.
  • combines with set_size_inchesfunction
  • seeks to ensure consistent text size with differing figure sizes.
  • seeks to find out why Ipython output differs from savefig
atomh33ls
  • 26,470
  • 23
  • 104
  • 159
  • 2
    Did you try: ```plt.tight_layout()``` (right) before savefig? [docs](https://matplotlib.org/users/tight_layout_guide.html) – sascha Jul 21 '17 at 13:46
  • I think @tom is right that this is a duplicate; although the solution of using `bbox_inches = "tight"`, which is especially interesting here, where the outcome is compared to the IPython inline output, was probably not available at the time the duplicate question was asked. – ImportanceOfBeingErnest Jul 21 '17 at 15:35
  • @ImportanceOfBeingErnest agreed. There are probably other, more recent, duplicate targets that one could link to too; its a very common question on here. – tmdavison Jul 21 '17 at 15:36
  • @ImportanceOfBeingErnest and tom: fair enough, I was expecting something to come up from a search, or when I typed in the question - perhaps something did and I missed it. However it is still worth keeping this as it may prove useful to future searchers, I'd say. – atomh33ls Jul 21 '17 at 15:42
  • Related question: https://stackoverflow.com/questions/6774086/why-is-my-xlabel-cut-off-in-my-matplotlib-plot – Anton Tarasenko Jun 05 '20 at 21:58
  • 1
    I don't think the question should be closed since the question is talking about `IPython` but the given related question is not. That makes difference. – C.K. Oct 05 '21 at 03:18

3 Answers3

55

The Ipython console in Spyder uses the inline backend, which saves the figure as png and displays the output image. When saving, it uses the option bbox_inches = "tight".

So in order to obtain the same figure as shown in the console, you may decide to use this option as well - it basically extends or shrinks the bounding box such that all objects in the canvas are displayed.

plt.savefig('testfig.png',dpi=300, bbox_inches = "tight")

Alternatively, you can make sure that all objects are already inside the figure boundaries before saving or showing the figure. This can either be accomplished using

plt.tight_layout()

which tries to do that automatically, or you can use

plt.subplots_adjust(left=0.3, right=0.9, bottom=0.3, top=0.9)

where the parameters denote the margins on each side in units of fractions of figure size (30% space on the left, 10% space on the right, etc.).

ImportanceOfBeingErnest
  • 289,005
  • 45
  • 571
  • 615
6

matplotlib has a function called tight_layout , which automatically adjusts subplot params so that the subplot(s) fits in to the figure area.

As stated in the docs, it's flagged as experimental, but is commonly used.

In my experience it should be called as late as possible (e.g. before using savefig) and probably after calls which change the geometry (like fig.set_size_inches).

In the plt.show() gui-window, one of the buttons is doing exactly this call too.

(converted to answer from earlier comment)

sascha
  • 30,370
  • 6
  • 65
  • 104
1

I think the answer is given elsewhere on stackoverflow. Briefly, you should chane the fontsize of your label-text:

plt.ylabel('Example', fontsize=40)
plt.xlabel('Example', fontsize=40)

Of course, change the number 40 (trial and error) to a more suitable value.

I don't know if this is a fix or a work-around. And neither do I know if this helps.