我正在制作一个带条形图,我正试图在图上找到它们的绝对位置(以像素为单位),以便以后进一步处理。在我看来,这应该可以从matplotlib关于轴实例的转换信息中找出。具体来说,我正在使用ax.transData
从数据坐标(我知道框位置)到显示坐标。这是一些代码:
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 get_useful_info(fig):
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]
width = pos[1,0] - pos[0,0]
bottom = pos[0,1]
height = pos[1,1] - pos[0,1]
yield left, width, bottom, height
fig.savefig('foo.png')
for l, w, b, h in get_useful_info(fig):
print l, w, b, h
这将打印以下内容:
80.0 24.8 48.0 38.4
129.6 24.8 48.0 76.8
179.2 24.8 48.0 115.2
228.8 24.8 48.0 153.6
278.4 24.8 48.0 192.0
328.0 24.8 48.0 230.4
377.6 24.8 48.0 268.8
427.2 24.8 48.0 307.2
476.8 24.8 48.0 345.6
526.4 24.8 48.0 384.0
所以,matplotlib认为我的盒子是24.8单位(我假设的像素)宽。这很好,除非我实际去测量盒子宽度,我得到更像32像素宽的东西。这里的差异是什么?
答案 0 :(得分:3)
像往常一样,在发布问题时会发生启示......这里的问题是单位不是像素,它们是点。初始化图形时,它设置为每英寸默认点数(fig.set_dpi()
和fig.get_dpi()
允许您更改/查询当前图形的分辨率)。当然,事情不是那么容易 - 当您保存图形时,dpi会根据特定后端的rc设置而变化。对于我的默认后端和png输出,这将达到100 dpi。然而,这里不变的一件事是图形尺寸fig.get_size_inches()
。所以,如果我扩展我的结果,事情似乎会变得更加一致......
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
我有一种沉闷的感觉,虽然这不是完整的解决方案 - 毕竟,我们仍然在点工作。我不完全确定一个点如何转换为png图像的像素...我希望显示引擎(在我的特定情况下,一个Web浏览器)在一个像素中呈现每个点并且不关心图像的报告大小。我想只有一些实验才会对那个进行排序......
答案 1 :(得分:1)
正如您所说的网络浏览器,我假设您正在构建图像映射?
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
我觉得这样的事情就是你想要的。如果您将此数据和png提供给下一级代码,您可以精确地找出所有内容的位置。
这样的问题(我认为)是matplotlib从前端抽象后端的方式的结果。考虑像素大小对矢量输出没有多大意义。
可替换地:
dpi = 300
...
fig.set_dpi(dpi)
...
fig.savefig(..., dpi=dpi)