Incorrect Rectangle Location In Matplotlib
Solution 1:
As usual, the revelation happens when posting the question ... The problem here is that the units are not pixels, they're dots. When the figure is initialized, it is set up with a default dots per inch (fig.set_dpi()
and fig.get_dpi()
allow you to change/inquire the current figure's resolution). Of course, things can't be that easy -- When you save the figure, the dpi changes based on your rc settings for the particular backend. For me with the default backend and png output, this goes to 100 dpi. One thing which is invariant here, however is the figure size fig.get_size_inches()
. So, if I scale my results, things seem to turn our a little more consistently ...
def get_useful_info(fig):
dpi = fig.get_dpi()
pngdpi = 100
scale_x = pngdpi / dpi
scale_y = pngdpi / dpi
for ax in fig.get_axes():
for rect in ax.monkey_rectangles:
corners = rect.get_bbox().corners()[::3]
pos = ax.transData.transform(corners)
left = pos[0,0] * scale_x
width = (pos[1,0] - pos[0,0]) * scale_x
bottom = pos[0,1] * scale_y
height = (pos[1,1] - pos[0,1]) * scale_y
yield left, width, bottom, height
I have a sinking feeling that this isn't the full solution though -- After all, we're still working in dots. I'm not completely sure how a dot translates to a pixel for png images ... My hope is that the display engine (in my particular case, a web browser) renders each dot in a single pixel and doesn't care about the image's reported size. I suppose that only some experimentation will sort that one out ...
Solution 2:
As you are referring to web-browsers, I assume you are building image maps?
import matplotlib.pyplot as plt
x = range(10)
y = range(1, 11)
fig = plt.figure()
ax = fig.add_subplot(111)
bars = ax.bar(x, y, width=.5, label="foo")
ax.monkey_rectangles = bars
ax.legend()
def fig_fraction_info(fig):
for ax in fig.get_axes():
inv = fig.transFigure.inverted()
# transformations are applied left to right
my_trans = ax.transData + inv
for rect in ax.monkey_rectangles:
corners = rect.get_bbox().corners()[::3]
pos = my_trans.transform(corners)
left = pos[0,0]
width = pos[1,0] - pos[0,0]
bottom = pos[0,1]
height = pos[1,1] - pos[0,1]
yield left, width, bottom, height
I think something like this is what you want. If you feed this data and the png into the next level of code you can sort out exactly where everything is.
Issues like this are (I think) a consequence of way that matplotlib abstracts the backend from the front end. Thinking about the size in pixels doesn't make a lot of sense for vector outputs.
Alternately:
dpi = 300
...
fig.set_dpi(dpi)
...
fig.savefig(..., dpi=dpi)
Post a Comment for "Incorrect Rectangle Location In Matplotlib"