Repository navigation
Description
Bug report
Bug summary
When transforming BoundingBox objects their width and height are calculated wrong. This happens, supposedly, for backends that have a different dpi setting from 72. The issue is present, e.g., for the backends "svg", "pdf", "cairo" (pdf, ps, svg). It is not present, e.g., for the backends "ps", "png".
Code for reproduction
# Plot BoundingBox of Text object with PS backend
import matplotlib as mpl
mpl.use("PS")
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.plot([0, 1], [1, 0], "bo", ms=20)
text = ax.text(x=0.3, y=0.1, s="sample text", fontsize=20, family="Serif")
fig.savefig("bbox.ps")
bbox_display = text.get_window_extent()
bbox_data = bbox_display.inverse_transformed(ax.transData)
bbox_data_2 = ax.transData.inverted().transform_bbox(bbox_display)
print(f"bbox_display = {bbox_display}")
print(f" width = {bbox_display.width} height = {bbox_display.height}")
print(f"bbox_data = {bbox_data}")
print(f"bbox_data = {bbox_data_2}")
print(f" width = {bbox_data.width} height = {bbox_data.height}")
rect_data = mpl.patches.Rectangle(
(bbox_data.x0, bbox_data.y0), bbox_data.width, bbox_data.height,
fill=False, lw=0.2, color="g")
ax.add_patch(rect_data)
fig.savefig("bbox.ps")# Try the same with PDF backend
import matplotlib as mpl
mpl.use("PDF")
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.plot([0, 1], [1, 0], "bo", ms=20)
text = ax.text(x=0.3, y=0.1, s="sample text", fontsize=20, family="Serif")
fig.savefig("bbox.pdf")
bbox_display = text.get_window_extent()
bbox_data = bbox_display.inverse_transformed(ax.transData)
bbox_data_2 = ax.transData.inverted().transform_bbox(bbox_display)
factor = 100 / 72
print(f"bbox_display = {bbox_display}")
print(f" width = {bbox_display.width} height = {bbox_display.height}")
print(f"bbox_data = {bbox_data}")
print(f"bbox_data = {bbox_data_2}")
print(f" width = {bbox_data.width} height = {bbox_data.height}")
print(f" ~width = {bbox_data.width * factor} ~height = {bbox_data.height * factor}")
rect_data = mpl.patches.Rectangle(
(bbox_data.x0, bbox_data.y0), bbox_data.width, bbox_data.height,
fill=False, lw=0.2, color="r")
ax.add_patch(rect_data)
rect_data_corrected = mpl.patches.Rectangle(
(bbox_data.x0, bbox_data.y0), bbox_data.width * factor, bbox_data.height * factor,
fill=False, lw=0.2, color="g", ls="--")
ax.add_patch(rect_data_corrected)
fig.savefig("bbox.pdf")Actual outcome
PS output
bbox_display = Bbox(x0=171.22909090909093, y0=70.14774999999999, x1=288.9634659090909, y1=89.50712499999999)
width = 117.734375 height = 19.359375
bbox_data = Bbox(x0=0.30000000000000004, y0=0.08281973379629631, x1=0.6626450842853944, y1=0.1628436053240741)
bbox_data = Bbox(x0=0.30000000000000004, y0=0.08281973379629631, x1=0.6626450842853944, y1=0.1628436053240741)
width = 0.3626450842853943 height = 0.08002387152777779
PDF output
bbox_display = Bbox(x0=237.8181818181818, y0=99.04374999999999, x1=355.5525568181818, y1=118.40312499999999)
width = 117.734375 height = 19.359375
bbox_data = Bbox(x0=0.30000000000000004, y0=0.0876302083333334, x1=0.5611044606854839, y1=0.1452473958333334)
bbox_data = Bbox(x0=0.30000000000000004, y0=0.0876302083333334, x1=0.5611044606854839, y1=0.1452473958333334)
width = 0.2611044606854839 height = 0.0576171875
~width = 0.36264508428539427 ~height = 0.08002387152777778
Expected outcome
I expect that the BoundingBoxes for both used backends have the same width and height in Axes coordinates. However, this is not the case. The BoundingBox in the PDF version can be transformed to the correct size via multiplication of its width and height by the factor 100 / 72. Therefore, I assume that the default dpi of the backends plays a role here and is not handled properly.
Matplotlib version
- Operating system: Ubuntu 19.04
- Matplotlib version: 3.1.1
- Matplotlib backends: PDF (but several more are affected)
- Python version: 3.7.4
- Jupyter version (if applicable): 1.0.0
- Other libraries:
Matplotlib was installed via conda.
Possibly related issues


Activity
griai commentedon Mar 3, 2020
One possible workaround (for the pdf backend) is to explicitly set the dpi of the figure, i.e., put this line of code directly after the figure creation with the
plt.subplots()call:So, this workaround confirms that the
fig.dpisetting is not handled properly in the transformation of the BoundingBox.Note that this has nothing to do with the keyword argument
dpiin the call totext.get_window_extent(). Specifying this with different values changes the anchor point of the BoundingBox, thus shifting it alltogether. But we need to only changewidthandheight.Note further that changing the
fig.dpichanges width and height of the BoundingBox for both, the PS and the PDF backend. But it does not do so for the AGG backend and PNG output. I think, I'm still missing something ...timhoffm commentedon Mar 4, 2020
Thanks for the clear and detailed report.
ImportanceOfBeingErnest commentedon Mar 4, 2020
I think the real problem here is that you cannot get the extention of a text without rendering it first; but rendering requires a DPI, even for backends that are pixel-independent in their output.
As you have seen you need to actually save the image first, in order to be able to use
.get_window_extent(), because that requires a renderer. So with that renderer you get the bounding box of the text in pixel space. And pixel space for the pdf backend is always defined via a dpi of 72.A workaround which avoids the dpi coming out of sync would be to use the
aggbackend throughout and only saving the figure via the respective vector backend:QuLogic commentedon Mar 19, 2020
I'm not sure what you're trying to do here, but if this is strictly what you're looking for (and not just some simplified case), a simpler workaround is to use the
bboxparameter. That is:The default
boxstyleissquare,pad=0.3so if you want it flush, then pass a style with an explicit padding:github-actions commentedon Jul 10, 2023
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!