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:
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)