5

I'm trying to use both ax.set_title() and plt.suptitle() to incorporate a title and a subtitle to a graph, but the two seem to not share the same alignment. For example, the following:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

cats = ('One', 'Two')
vals = (12, 4) 

ax.barh(cats, vals, align='center')
plt.suptitle('Title')
ax.set_title('Title')
plt.show()

Gives us the following misaligned titles:

Misaligned titles with short y labels

How can I get these two titles to align properly? I thought it may be something to do with ax.title aligning to the axis and plt.suptitle aligning to the figure, but testing a much longer y label doesn't seem to affect the offset:

fig, ax = plt.subplots()

cats = ('One million tiny engines running at one hundred miles per hour', 'Two')
vals = (12, 4) 

ax.barh(cats, vals, align='center')
plt.suptitle('Title')
ax.set_title('Title')
plt.show()

Misaligned titles with long y label

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
asongtoruin
  • 9,794
  • 3
  • 36
  • 47
  • Could it be a bug, where the position is calculated using two different methods, which consistently produce a slight offset? Otherwise, there's this option:https://stackoverflow.com/questions/1388450/giving-graphs-a-subtitle-in-matplotlib. It's not very clean though. – J.Doe Oct 07 '19 at 19:36
  • Suptitle is usually imagined as a title that is above many subplots, not a single subplot, so as noted below, it is centred on the figure, not the axes. If you want a 2-line title, you can just do `ax.set_title('First Line\nSecond Line')` – Jody Klymak Oct 07 '19 at 21:56

3 Answers3

12

matplotlib aligns suptitle to the figure, and title to the subplot. You can manually jiggle the suptitle using fig.subplotpars:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

cats = ('One', 'Two')
vals = (12, 4) 

# Mid point of left and right x-positions
mid = (fig.subplotpars.right + fig.subplotpars.left)/2

ax.barh(cats, vals, align='center')
plt.suptitle('Title',x=mid)
ax.set_title('Title')
plt.show()

Fixed title

Enjoy!

asongtoruin
  • 9,794
  • 3
  • 36
  • 47
soyapencil
  • 509
  • 4
  • 9
  • 1
    Thanks, this is ideal. I've added in an image of the fixed graph to make the correction clearer to anyone who finds this answer in future. Also, welcome to SO! Looks like you're making a great start to me. – asongtoruin Oct 07 '19 at 20:02
  • 1
    With tight layout, you need to do it twice: before tight_layout() -- to reserve some vertical space; and after -- to actually align it horizontally, because x coordinates will change – banderlog013 Oct 04 '21 at 14:44
3

I know this isn't the perfect answer and basically a repost of my comment, but here goes nothing:

fig, ax = plt.subplots()

cats = ('hour', 'Two')
vals = (12, 4) 
ax.barh(cats, vals, align='center')
plt.figtext(.5,.95,'Foo Bar', fontsize=18, ha='center')
plt.figtext(.5,.9,'lol bottom text',fontsize=10,ha='center')
plt.show()

You need to manually adjust the .95 and .9 values depending on the font sizes though.

J.Doe
  • 224
  • 1
  • 4
  • 19
  • This is definitely an interesting way to do it, and would be useful for other alignments of the text, but @soyapencil's answer is more suitable in my situation I think. – asongtoruin Oct 07 '19 at 20:03
1

If you really don't need subtitle

fig, ax = plt.subplots()

cats = ('One million tiny engines running at one hundred miles per hour', 'Two')
vals = (12, 4) 

ax.barh(cats, vals, align='center')
ax.set_title('Title\nTitle')
plt.show()
Jody Klymak
  • 4,979
  • 2
  • 15
  • 31