I'm stacking multiple graphs using matplotlib-pyplot. This is my minimal reproducable example:
from matplotlib import pyplot as plt
from numpy import linspace, sqrt, pi
fig, ax = plt.subplots(3, 1, sharex=True)
plt.subplots_adjust(hspace=0)
def zr(w0, l):
return pi*w0**2/l
def w0(l, L, R):
return sqrt(l/pi * sqrt(L*(R-L)))
def width(z, l):
return w0(l, 0.55, 1) * sqrt(1 + (z / zr(w0(l, 0.55, 1), l))**2)
x = linspace(0, 1, 5)
y = width(x, 5.54e-6)
for i in range(3):
#Do some analysis here, then plot the fit
ax[i].set_xlabel("z / m")
ax[i].set_ylabel("$d(w)$ / mm")
ax[i].ticklabel_format(axis='y', style='sci', scilimits=(0, 0))
ax[i].grid("both", linestyle=":")
#The Fix i tried:
ax[i].get_yaxis().get_offset_text().set_position((0,0.7))
ax[1].errorbar(x, y, xerr = 0.025, yerr = 0.2*1e-3, color = "black", linestyle = "")
plt.show()
Unfortunately in my example, the offset modifier intersects with the data in the graph above.
To fix that I want to move it below the spine.
I originally tried this answer, as can be seen above, but I was unable to observe any change.
EDIT: I did a little bit of experimenting. Before the canvas is drawn the position is set correctly, but the offset text is empty:
>>> ax[2].get_yaxis().get_offset_text()
Text(0, 0.7, '')
But after the canvas is drawn the position changes:
>>> fig.canvas.draw()
>>> ax[1].get_yaxis().get_offset_text()
Text(0, 303.3666666666667, '1e−3')
This also holds for plt.plot()
which almost certainly calls canvas.draw()
Based on the answer suggested by jared I was abled to find a workaround.
fig.canvas.draw() #This forces the text to be set
#Replace offset text
for i in range(3):
offset_text = ax[i].get_yaxis().get_offset_text()
ax[i].annotate(offset_text.get_text(), xy = (.01, .85), xycoords='axes fraction')
offset_text.set_visible(False)
This forces the canvas to render, takes the offset text and replaces it with an annotation.