Matplotlib tight_layout () does not take suptitle into account

If I add subtitles to the matplotlib figure, it will be overlaid with subheading headers. Does anyone know how easy it is to take care of this? I tried the tight_layout() function, but that only worsens the situation.

Example:

 import numpy as np import matplotlib.pyplot as plt f = np.random.random(100) g = np.random.random(100) fig = plt.figure() fig.suptitle('Long Suptitle', fontsize=24) plt.subplot(121) plt.plot(f) plt.title('Very Long Title 1', fontsize=20) plt.subplot(122) plt.plot(g) plt.title('Very Long Title 2', fontsize=20) plt.tight_layout() plt.show() 
+151
python matplotlib
Nov 23 '11 at 20:12
source share
8 answers

You can configure the subtask geometry in the tight_layout call tight_layout as follows:

 fig.tight_layout(rect=[0, 0.03, 1, 0.95]) 

As stated in the documentation ( https://matplotlib.org/users/tight_layout_guide.html ):

tight_layout() only considers tag labels, axis labels, and names. In this way, other artists can be circumcised as well as overlap.

PS The community recommended that I post my comment as an answer.

+130
Jul 18 '17 at 8:36
source share

You can manually adjust the interval using plt.subplots_adjust(top=0.85) :

 import numpy as np import matplotlib.pyplot as plt f = np.random.random(100) g = np.random.random(100) fig = plt.figure() fig.suptitle('Long Suptitle', fontsize=24) plt.subplot(121) plt.plot(f) plt.title('Very Long Title 1', fontsize=20) plt.subplot(122) plt.plot(g) plt.title('Very Long Title 2', fontsize=20) plt.subplots_adjust(top=0.85) plt.show() 
+105
Nov 23 '11 at 20:16
source share

One thing you can easily change in the code is the fontsize , which you use for titles. However, I'm going to suggest that you do not just want to do this!

Some alternatives to using fig.subplots_adjust(top=0.85) :

Normally tight_layout() does a pretty good job of positioning everything in good places so that they don't overlap. The reason tight_layout() does not help in this case, because tight_layout() does not take into account the value of fig.suptitle (). GitHub has an open problem: https://github.com/matplotlib/matplotlib/issues/829 [closed in 2014 due to the need for a full geometry manager - shifted to https://github.com/matplotlib/matplotlib/issues/ 1109 ].

If you are reading a stream, there is a solution to your problem involving GridSpec . The key should leave some space at the top of the picture when calling tight_layout using rect kwarg. For your problem, the code will look like this:

Using GridSpec

 import numpy as np import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec f = np.random.random(100) g = np.random.random(100) fig = plt.figure(1) gs1 = gridspec.GridSpec(1, 2) ax_list = [fig.add_subplot(ss) for ss in gs1] ax_list[0].plot(f) ax_list[0].set_title('Very Long Title 1', fontsize=20) ax_list[1].plot(g) ax_list[1].set_title('Very Long Title 2', fontsize=20) fig.suptitle('Long Suptitle', fontsize=24) gs1.tight_layout(fig, rect=[0, 0.03, 1, 0.95]) plt.show() 

Result:

using gridspec

Maybe GridSpec little too much for you, or your real problem will include a lot more subplots on a much larger canvas or other complications. A simple hack is to simply use annotate() and lock the coordinates for the 'figure fraction' to mimic a suptitle . However, you may need to make some more subtle adjustments if you look at the result. Note that this second solution does not use tight_layout() .

Simplified solution (although it may need to be customized)

 fig = plt.figure(2) ax1 = plt.subplot(121) ax1.plot(f) ax1.set_title('Very Long Title 1', fontsize=20) ax2 = plt.subplot(122) ax2.plot(g) ax2.set_title('Very Long Title 2', fontsize=20) # fig.suptitle('Long Suptitle', fontsize=24) # Instead, do a hack by annotating the first axes with the desired # string and set the positioning to 'figure fraction'. fig.get_axes()[0].annotate('Long Suptitle', (0.5, 0.95), xycoords='figure fraction', ha='center', fontsize=24 ) plt.show() 

Result:

simple

[Using Python 2.7.3 (64-bit) and matplotlib 1.2.0]

+49
Oct 28 '13 at 4:32
source share

An alternative and easy-to-use solution is to adjust the coordinates of the suptitle text in the drawing using the y argument in the suptitle call (see docs )

 import numpy as np import matplotlib.pyplot as plt f = np.random.random(100) g = np.random.random(100) fig = plt.figure() fig.suptitle('Long Suptitle', y=1.05, fontsize=24) plt.subplot(121) plt.plot(f) plt.title('Very Long Title 1', fontsize=20) plt.subplot(122) plt.plot(g) plt.title('Very Long Title 2', fontsize=20) plt.show() 
+18
Feb 09 '15 at 16:42
source share

I struggled with the matplotlib cropping methods, so now I just made a function to do this by calling bash ImageMagick mogrify command , which works well and gets all the extra free space from the edge of the figure. To do this, you need to use UNIX / Linux, use the bash and install ImageMagick .

Just call the call after your savefig() call.

 def autocrop_img(filename): '''Call ImageMagick mogrify from bash to autocrop image''' import subprocess import os cwd, img_name = os.path.split(filename) bashcmd = 'mogrify -trim %s' % img_name process = subprocess.Popen(bashcmd.split(), stdout=subprocess.PIPE, cwd=cwd) 
+4
Aug 27 '14 at 12:56 on
source share

A tight layout does not work with suptitle, but constrained_layout works. Check out this question. Increase the size / spacing of subplots with a variety of subplots in matplotlib.

I found that adding sites immediately looked better, i.e.

 fig, axs = plt.subplots(rows, cols, contrained_layout=True) # then iterating over the axes to fill in the plots 

But it can also be added at the time of creating the shape:

 fig = plt.figure(constrained_layout=True) ax1 = fig.add_subplot(cols, rows, 1) # etc 
+2
Jul 09 '19 at 10:37
source share

As already mentioned, by default, a dense layout does not account for subtitles. However, I found that you can use the bbox_extra_artists argument to pass the subtitle as a bounding box, which should be considered:

 st = fig.suptitle("My Super Title") plt.savefig("figure.png", bbox_extra_artists=[st], bbox_inches='tight') 

This forces the calculation of the suptitle layout to take into account the suptitle , and it looks as you expect.

+1
Jun 23 '19 at 19:56 on
source share

I had a similar problem that occurred when using tight_layout for a very large grid of charts (over 200 additional charts) and rendering in Jupyter notepad. I made a quick decision that always places your suptitle a certain distance above your upper sub-raft:

 import matplotlib.pyplot as plt n_rows = 50 n_col = 4 fig, axs = plt.subplots(n_rows, n_cols) #make plots ... # define y position of suptitle to be ~20% of a row above the top row y_title_pos = axs[0][0].get_position().get_points()[1][1]+(1/n_rows)*0.2 fig.suptitle('My Sup Title', y=y_title_pos) 

For variable-size subplots, you can still use this method to get the top of the topmost subplot, and then manually determine the extra amount to add to the subtitle.

0
Mar 11 '19 at 21:02
source share



All Articles