Split title of a figure in matplotlib into multiple lines


I use matplotlib to create a figure with 4 sub-plots in it.

I would like to split one of my title of a subplot, such that each line would be in the centered with respect to subplot.

I tried

import matplotlib.pylab as plt

fig = plt.figure(num=0,figsize=(8.27, 11.69), dpi=300)
ax  = fig.add_subplot(2, 2, 1)
ax.set_title(r'Normalized occupied \ Neighbors')

and what I get is that Neighbors is indented to the left side.

How could I correct this?

Asked By: Eagle



I get the correct alignment when I format the string this way:

import matplotlib.pylab as plt

fig = plt.figure()#num=0,figsize=(8.27, 11.69), dpi=300)
ax  = fig.add_subplot(2, 2, 1)
ax.set_title('Normalized occupied n Neighbors')


enter image description here

Answered By: Yann

A better solution which is compatible with r prefix (especially when one needs to use LaTeX markup) is to divide the title text into two (or more parts), e.g.,

import matplotlib.pylab as plt

fig = plt.figure()
plt.title('My Titlen' + r'$alpha - omega$ are LaTeX Markup')
Answered By: AlQuemist

In addition to the previous answers, if someone wants to automate the operation I have coded a function to make this easy.
here is it:

def split_title_line(title_text, split_on='(', max_words=5):  # , max_words=None):
    A function that splits any string based on specific character
    (returning it with the string), with maximum number of words on it
    split_at = title_text.find (split_on)
    ti = title_text
    if split_at > 1:
        ti = ti.split (split_on)
        for i, tx in enumerate (ti[1:]):
            ti[i + 1] = split_on + tx
    if type (ti) == type ('text'):
        ti = [ti]
    for j, td in enumerate (ti):
        if td.find (split_on) > 0:
            tw = td.split ()
            t2 = []
            for i in range (0, len (tw), max_words):
                t2.append (' '.join (tw[i:max_words + i]))
            ti[j] = t2
    ti = [item for sublist in ti for item in sublist]
    ret_tex = []
    for j in range (len (ti)):
        for i in range(0, len(ti)-1, 2):
            if len (ti[i].split()) + len (ti[i+1].split ()) <= max_words:
                mrg = " ".join ([ti[i], ti[i+1]])
                ti = [mrg] + ti[2:]

    if len (ti[-2].split ()) + len (ti[-1].split ()) <= max_words:
        mrg = " ".join ([ti[-2], ti[-1]])
        ti = ti[:-2] + [mrg]
    return 'n'.join (ti)


In: split_title_line ('Primary school completion (% of girls)')


Primary school completion 
(% of girls)

In: split_title_line ('Primary school completion in the country as % of girls')

Primary school completion in the
country as % of girls

For your question to split titles in matplotlib or so, you can add this ax.set_title(split_title_line(r'Normalized occupied Neighbors', max_words=2))

Hope that everyone benefits from this.

Answered By: Mohammad ElNesr

Would just like to add my 2 cents: the problem here is more general and revolves around correctly inserting newlines to breakup the text from a single long line into a visually pleasing, aesthetic block. Hence, here is my contribution, which is quite similar to Mohammed’s and simply splits a string into 5-word chunks. It should be straightforward to customize it to your needs (delimiter to split on, length etc.)

def pretty_name(text):
  words = text.split("_")
  total_string = ""
  for counter, word in enumerate(words):
    if counter>0 and counter % 5 == 0:
      total_string +="n{}".format(word)
      total_string +=" {}".format(word)
  return total_string.lstrip()

In Matplotlib 3.1.1, both plt.title() and ax.set_title() allow passing text properties as kwargs, so you can pass wrap=True:

plt.title('My long title that I want to wrap and stay center-aligned', wrap=True)


fig, [ax1, ax2] = plt.subplots(2, 1)
ax1.set_title('My long title that I want to wrap and stay center-aligned', wrap=True)
Answered By: Nicholas Masso
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.