I want to understand the decoration space limits of the "constrained" layout engine of Matplotlib. In my use case, I have to add a lot of decoration (such as different axes ticks and labels) to the right of the plot and I am running into limits that I cannot find documented.
The little test below shows an "x"
being moved more and more to the right. Somewhere around x_pos=1.3
, constrained starts to move the "x"
out of the visible area. Another observation is that a tiny bit of window resize fixes this, i.e. it brings the "x"
back to the visible.
Do you have any advises how to tame the beast?
from matplotlib import pyplot as plt
TEST_DECORATION = dict(s="x", horizontalalignment="center", verticalalignment="center")
def decorated_plot(x_pos: float):
"""Create (empty) plot w/ decoration at defined horizontal axes position."""
fig = plt.figure(layout="constrained")
ax = fig.add_subplot()
ax.text(x=x_pos, y=0.5, transform=ax.transAxes, **TEST_DECORATION)
ax.set_title(f"x = {x_pos}")
plt.show()
def main():
# explore the behavior for different values...
for x_pos in [1.1, 1.2, 1.25, 1.3, 1.32, 1.4]:
decorated_plot(x_pos)
if __name__ == "__main__":
main()
I think the problem comes from defining your "x" position relative to the size of the axes. Each time constrained layout runs, the size of the axes changes and so the location of the "x" relative to the axes also changes. I'm not sure but I think constrained layout looks at where artists currently are in the figure, rather than directly knowing that the "x" should be a certain fraction of the axes size out. You can get a more robust result by putting it a fixed distance from the side of the axes, if that suits your use case. annotate
gives a lot more options than text
for controlling the position. For example, here I put the "x" a certain multiple of the font size from the right of the axes:
from matplotlib import pyplot as plt
TEST_DECORATION = dict(horizontalalignment="center", verticalalignment="center")
def decorated_plot(x_pos: float):
"""
Create (empty) plot w/ decoration at defined distance in font sizes
from the right of the axes.
"""
fig = plt.figure(layout="constrained")
ax = fig.add_subplot()
ax.annotate("x", (1, 0.5), xycoords=ax.transAxes, xytext=(x_pos, 0),
textcoords='offset fontsize', **TEST_DECORATION)
ax.set_title(f"x = {x_pos}")
plt.show()
def main():
# explore the behavior for different values...
for x_pos in range(5, 41, 5):
decorated_plot(x_pos)
if __name__ == "__main__":
main()
Sample outputs: