Jason S
Jason S

Reputation: 189786

matplotlib tight_layout + gridspec + fig.suptitle looks bad

I have a very nice GridSpec graph using Matplotlib 2.2.2 but I can't make a pretty title for the figure as a whole. Example:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
%matplotlib inline

def example(tl):
    fig = plt.figure(figsize=(14,8))
    hr = [3,3,3,1,1]
    wr = [3,1]
    ny = len(hr)
    nx = len(wr)
    gs = gridspec.GridSpec(ny,nx,
                        height_ratios=hr,
                        width_ratios=wr,
                        hspace=0.08, wspace=0.1)
    for j in xrange(nx):
        ax = [fig.add_subplot(gs[0,j])]
        ax += [fig.add_subplot(gs[i,j], sharex=ax[0]) for i in xrange(1,ny)]
        for axi in ax:
              axi.plot([0,1,2],[0,1,4])    
    fig.suptitle('The quick brown fox jumps over the lazy dog.')
    if tl:
        gs.tight_layout(fig)

If I run example(False) for no tight layout I get a huge amount of space above the figures:

enter image description here

If I run example(True) for a tight layout I get negative space:

enter image description here

How can I fix this and get a figure-level title with a proper amount of margin from the subplots?

Upvotes: 5

Views: 5263

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339430

tight_layout() does not take figure level artists into account.

Use constrained_layout

However, there is a relatively new alternative, called constrained_layout. Using this, the figure title will be included. Note that for this to work you need to supply the figure to the GridSpec via it's figure argument.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

def example(tl):
    fig = plt.figure(figsize=(14,8), constrained_layout=tl)
    hr = [3,3,3,1,1]
    wr = [3,1]
    ny = len(hr)
    nx = len(wr)
    gs = gridspec.GridSpec(ny,nx, figure=fig,
                        height_ratios=hr,
                        width_ratios=wr,
                        hspace=0.08, wspace=0.1)
    for j in range(nx):
        ax = [fig.add_subplot(gs[0,j])]
        ax += [fig.add_subplot(gs[i,j], sharex=ax[0]) for i in range(1,ny)]
        for axi in ax:
              axi.plot([0,1,2],[0,1,4])    
    fig.suptitle('The quick brown fox jumps over the lazy dog.')


example(True)
plt.show()

enter image description here

Update top margin

Alternatively you can update the top margin after calling tight_layout. E.g. as

gs.update(top=0.95)

Code:

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

def example(tl):
    fig = plt.figure(figsize=(14,8))
    hr = [3,3,3,1,1]
    wr = [3,1]
    ny = len(hr)
    nx = len(wr)
    gs = gridspec.GridSpec(ny,nx, figure=fig,
                        height_ratios=hr,
                        width_ratios=wr,
                        hspace=0.08, wspace=0.1)
    for j in range(nx):
        ax = [fig.add_subplot(gs[0,j])]
        ax += [fig.add_subplot(gs[i,j], sharex=ax[0]) for i in range(1,ny)]
        for axi in ax:
              axi.plot([0,1,2],[0,1,4])    
    fig.suptitle('The quick brown fox jumps over the lazy dog.')
    if tl:
        gs.tight_layout(fig)
        gs.update(top=0.95)


example(True)
plt.show()

enter image description here

Upvotes: 8

Related Questions