Bug summary
x-tick labels using LaTeX are vertically misaligned when you call savefig() with dpi=300. The misalignment occurs when two labels have a superscript and subscript, while the third misaligned label only has a superscript.
Code for reproduction
import sys
import matplotlib
import matplotlib.pyplot as plt
print(matplotlib.__version__)
print(matplotlib.get_backend())
print(sys.version)
idxs = list(range(3))
labels = ["$w^{(2)}_1$", "$w^{(2)}_2$", "$b^{(2)}$"]
fig, ax = plt.subplots(figsize=(3, 3))
ax.set_xlim(-0.5, 2.5)
ax.set_ylim(-3, 3)
ax.set_xticks(idxs, labels)
ax.set_yticks([])
ax.tick_params(which="both", length=0)
fig.tight_layout()
fig.savefig("test.png", dpi=300)
Actual outcome
Here is the image produced by the code. You can see that the $b^{(2)}$ label is vertically misaligned; it's higher than the other two labels.
Expected outcome
Here is the same image if you run the code without the dpi arg in savefig(). You can see that the $b^{(2)}$ label is vertically aligned with the other two labels.
Additional information
[EDIT: slight fix to code] Here's the reproduction code modified to use a workaround:
import sys
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.artist import Artist
from matplotlib.figure import Figure
print(matplotlib.__version__)
print(matplotlib.get_backend())
print(sys.version)
def get_center(fig: Figure, artist: Artist) -> tuple[float, float]:
renderer = fig.canvas.get_renderer() # type: ignore # get_renderer() not in base class
bbox = artist.get_window_extent(renderer)
fig_box = bbox.transformed(fig.transFigure.inverted())
x = (fig_box.xmin + fig_box.xmax) / 2
y = (fig_box.ymin + fig_box.ymax) / 2
return x, y
idxs = list(range(3))
labels = ["$w^{(2)}_1$", "$w^{(2)}_2$", "$b^{(2)}_1$"] # add subscript to b2
fig, ax = plt.subplots(figsize=(3, 3))
ax.set_xlim(-0.5, 2.5)
ax.set_ylim(-3, 3)
ax.set_xticks(idxs, labels)
ax.set_yticks([])
ax.tick_params(which="both", length=0)
fig.tight_layout() # call the layout function before fixing the label
orig_b2_label = ax.get_xticklabels()[-1]
orig_b2_x, orig_b2_y = get_center(fig, orig_b2_label) # measure while it's still visible
orig_b2_label.set_visible(False)
b2_label = fig.text(
orig_b2_x, orig_b2_y, "$b^{(2)}$", ha="center", va="center", transform=fig.transFigure
)
b2_label.set_in_layout(False)
fig.savefig("test-workaround.png", dpi=300)
Here is the image with the workaround:
(Feel free to let me know if there is a better workaround.)
Operating system
Ubuntu 24
Matplotlib Version
3.10.9
Matplotlib Backend
module://backend_interagg
Python version
Python 3.12.3
Jupyter version
No response
Installation
uv
Bug summary
x-tick labels using LaTeX are vertically misaligned when you call
savefig()withdpi=300. The misalignment occurs when two labels have a superscript and subscript, while the third misaligned label only has a superscript.Code for reproduction
Actual outcome
Here is the image produced by the code. You can see that the
$b^{(2)}$label is vertically misaligned; it's higher than the other two labels.Expected outcome
Here is the same image if you run the code without the
dpiarg insavefig(). You can see that the$b^{(2)}$label is vertically aligned with the other two labels.Additional information
[EDIT: slight fix to code] Here's the reproduction code modified to use a workaround:
Here is the image with the workaround:
(Feel free to let me know if there is a better workaround.)
Operating system
Ubuntu 24
Matplotlib Version
3.10.9
Matplotlib Backend
module://backend_interagg
Python version
Python 3.12.3
Jupyter version
No response
Installation
uv