How to position suptitle?

1. What do figure coordinates mean?

Figure coordinates go 0 to 1, where (0,0) is the lower left corner and (1,1) is the upper right corner. A coordinate of y=1.05 is hence slightly outside the figure.

enter image description here

2. what is the effect on figure size when specifying y to suptitle?

Specifying y to suptitle has no effect whatsoever on the figure size.

3a. How do I manually adjust figure size and spacing to add a figure title per panel and a suptitle for the entire figure?

First, one would not add an additional linebreak. I.e. if you want to have 2 lines, don't use 3 linebreaks (\n). Then one can adjust the subplot parameters as desired to leave space for the titles. E.g. fig.subplots_adjust(top=0.8) and use a y <= 1 for the title to be inside the figure.

import matplotlib.pyplot as plt
import numpy as np

data = np.random.random(size=100)
fig, axes = plt.subplots(2, 2, figsize=(10, 5))
fig.subplots_adjust(top=0.8)

axes[0,0].plot(data)
axes[0,0].set_title("\n".join(["this is a really long title"]*2))
axes[0,1].plot(data)
axes[1,1].plot(data)

fig.suptitle("\n".join(["a big long suptitle that runs into the title"]*2), y=0.98)

plt.show()

enter image description here

3b. ... while maintaining the size of each ax in the figure?

Maintaining the size of the axes and still have enough space for the titles is only possible by changing the overall figure size.

This could look as follows, where we define a function make_space_above which takes the array of axes as input, as well as the newly desired top margin in units of inches. So for example, you come to the conclusion that you need 1 inch of margin on top to host your titles:

import matplotlib.pyplot as plt
import numpy as np

data = np.random.random(size=100)
fig, axes = plt.subplots(2, 2, figsize=(10, 5), squeeze = False)

axes[0,0].plot(data)
axes[0,0].set_title("\n".join(["this is a really long title"]*2))
axes[0,1].plot(data)
axes[1,1].plot(data)

fig.suptitle("\n".join(["a big long suptitle that runs into the title"]*2), y=0.98)


def make_space_above(axes, topmargin=1):
    """ increase figure size to make topmargin (in inches) space for 
        titles, without changing the axes sizes"""
    fig = axes.flatten()[0].figure
    s = fig.subplotpars
    w, h = fig.get_size_inches()

    figh = h - (1-s.top)*h  + topmargin
    fig.subplots_adjust(bottom=s.bottom*h/figh, top=1-topmargin/figh)
    fig.set_figheight(figh)


make_space_above(axes, topmargin=1)    

plt.show()

enter image description here

(left: without calling make_space_above; right: with call to make_space_above(axes, topmargin=1))


Short Answer

For those coming from Google for adjusting the title position on a scatter matrix, you can simply set the y parameter to a value slightly lower than 1:

plt.suptitle('My Title', y=0.92)