Home > Blockchain >  How to update a title's position in matplotlib when it has been drawn already
How to update a title's position in matplotlib when it has been drawn already

Time:11-08

I'm trying to automatically move matplotlib Text instances above some annotations which are not taken into account by plt.tight_layout or constrained_layout.

However, I can't seem to get the title positions to update using Text.set_position and redrawing afterwards (neither when using e.g. fig.canvas.draw() every update nor when calling title_text_instance.draw(renderer=fig.canvas.get_renderer())).

The text itself seems to update fine, and so does another annotation, which is weird as both title and annotation are Text objects.

Why doesn't the title position update in the code below?

Animation for illustration; the title text and annotation positions update as expected, but its position remains fixed:

Title text and annotation positions update as expected, but its position remains fixed.k

Code:

#!/usr/bin/env/python3
import matplotlib.pyplot as plt
import matplotlib as mpl

N_FRAMES: int = 10
# Setting up the example.
mpl.use("TkAgg")
fig, ax = plt.subplots(figsize=(2, 1), dpi=300)
ax.plot(range(10), range(10))
t = ax.set_title("Example title", fontsize=6, alpha=.8, clip_on=False)

atext1 = '\n'.join(['Overlapping extra-axis annotation',
                    'above which I want to move the title',
                    'undetected by tight_layout or constrained_layout'])
atext2 = 'this annotation moves just fine...'
a1 = ax.annotate(atext1, xycoords='axes fraction', xy=(.25, 1),
                 rotation=10, clip_on=False, fontsize=3, color='r', alpha=.6)
a2 = ax.annotate(atext2, xycoords='axes fraction', xy=(.5, .5),
                 clip_on=False, fontsize=4, color='g')
fig.canvas.draw()
plt.tight_layout()
# ^^ Leaving out plt.tight_layout doesn't
# make a difference w.r.t position updates

for yoffset in range(N_FRAMES):
    new_position = (t.get_position()[0], t.get_position()[1] - .5   (yoffset / 2))
    newpostext = '('   ', '.join(f'{pos:.2f}' for pos in new_position)   ')'

    # Changing positions
    print(f'Set new position to', newpostext)
    t.set_position(new_position)  # Doesn't work
    a2.set_position(new_position)  # Works fine

    t.set_text(f"Supposedly repositioned title position: \n (x, y) = {newpostext}")
    plt.pause(.5)

plt.get_current_fig_manager().window.resizable(False, False)
plt.show(block=False)
plt.close(fig)

CodePudding user response:

There is an internal property _autotitlepos for the title which is set to True unless you explicitly specify the y position of the title. So in order to be able to manually set the title position you need to supply a value for y when setting the title, e.g. the default value of 1:

t = ax.set_title("Example title", fontsize=6, alpha=.8, clip_on=False, y=1)

(minimum matplotlib version 3.3.0, see PR #17127)

  • Related