我发现图像对象的get_window_extent方法全部为零。
例如
import numpy as np
import matplotlib.pyplot as plt
im = np.array([[0.25, 0.75, 1.0, 0.75], [0.1, 0.65, 0.5, 0.4], \
[0.6, 0.3, 0.0, 0.2], [0.7, 0.9, 0.4, 0.6]])
fig = plt.figure()
ax = plt.subplot()
ax.set_xlim(0,1)
ax.set_ylim(0,1)
im_obj = ax.imshow(im, extent = [0.25, 0.75, 0.25, 0.75], interpolation = 'nearest')
生成以下图
现在我想在显示坐标中获取图像大小,所以我执行以下操作:
fig.canvas.draw()
renderer = fig.canvas.renderer
im_bbox = im_obj.get_window_extent(renderer)
问题是print im_bbox
产生Bbox('array([[ 0., 0.],\n [ 0., 0.]])')
。方法.get_window_extent(renderer)
可以正常使用文本,线条和补丁,因此我看到它不适用于图像时有点惊讶。这是一个错误,还是我做错了什么?
如果重要,我使用Matplotlib 1.3.0和TkAgg后端。
编辑:
这是解决显示坐标
中的图像边界框的工作im_ext = im_obj.get_extent()
im_pts = np.array([[im_ext[0], im_ext[2]], [im_ext[1], im_ext[3]]])
bbox = mpl.transforms.Bbox(im_pts)
fig.canvas.draw()
bbox = bbox.transformed(ax.transData)
现在print bbox
生成Bbox('array([[ 236.375, 148.2 ],\n [ 433.975, 345.8 ]])')
。我也确认这些值是正确的。以下代码:
from matplotlib.patches import Rectangle
rect = Rectangle([bbox.x0, bbox.y0], \
bbox.width, bbox.height, \
linewidth = 8, color = [1,0,0], \
fill = False)
fig.patches.append(rect)
fig.canvas.draw()
plt.savefig('wtf.png', dpi = mpl.rcParams['figure.dpi'])
生成以下图
这种解决方法应该是健壮的,但它并不简单。在我将图像边界框从轴坐标转换为显示(像素)坐标之前,我花了一些时间才弄清楚我必须做fig.canvas.draw()
。如果没有fig.canvas.draw()
,则转换操作不正确。我猜matplotlib需要先绘制所有内容,以便知道如何转换为显示坐标。
因此,最初的问题仍然存在。为什么im_obj.get_window_extent(renderer)
给出一个全零的边界框?
答案 0 :(得分:3)
你得到全部零的原因是,在你至少渲染一次艺术家(通过调用draw()
完成)之前,它无法知道它有多大。这是matplotlib懒惰的结果,并且在 之前不做渲染艺术家的工作。
您的解决方法是正确的,基本上是mpl在内部执行tight_layout
之类的操作,并使用紧密的边界框进行保存。