如何计算matplotlib文本标注尺寸并按数据坐标偏移避免遮挡数据点
问题背景
我们需要计算matplotlib中文本标签以数据坐标为单位的高度、宽度,从而根据标签尺寸向指定方向偏移,避免标签遮挡下方的数据点,最好能在绘制文本前就获取到对应尺寸。
初始示例代码如下:
import matplotlib.pylab as pylab pylab.figure() x, y = 5, 7 text = 'label' pylab.plot(x, y, 'k.') pylab.text(x, y, text, color='red') pylab.show()
上述代码运行后,文本直接覆盖在数据点上方,视觉效果差。
问题分析
你尝试用get_window_extent获取文本包围盒是正确的思路,但这个方法返回的是画布像素坐标下的包围盒参数,而非你需要的数据坐标,所以直接用这些数值绘制包围盒、或者设置偏移都会出现坐标不匹配的问题:
- 不加
transform=None的绘制方式:默认用数据坐标系解析像素数值,绘制的红框位置完全错位 - 加
transform=None的绘制方式:直接使用像素坐标系绘制,包围盒位置正确但和数据坐标不互通,没法用来做数据层面的偏移
解决方案
要把像素坐标的包围盒转换为数据坐标,只需要调用坐标轴对象的transData.inverted()转换方法即可,同时注意:
- 必须先调用
fig.canvas.draw()触发文本渲染,才能拿到准确的包围盒参数,不存在绘制前就获取尺寸的方法,因为文本渲染尺寸依赖画布DPI、字体、坐标轴范围等多个渲染阶段才确定的参数 - 跨操作系统注意:不同系统的默认字体、字体渲染引擎有差异,相同文本的实际渲染尺寸可能出现细微偏差,建议如果需要跨平台一致的效果,手动指定统一的字体文件
完整实现代码如下:
import matplotlib.pylab as pylab fig = pylab.figure() ax = pylab.gca() x, y = 5, 7 text = 'label' pylab.plot(x, y, 'k.') # 先创建文本对象(此时还未渲染,无准确尺寸) t = pylab.text(x, y, text, color='red') # 触发画布渲染,计算文本实际尺寸 fig.canvas.draw() # 获取像素坐标下的包围盒 bbox_pixel = t.get_window_extent(renderer=fig.canvas.get_renderer()) # 转换为数据坐标下的包围盒 bbox_data = bbox_pixel.transformed(ax.transData.inverted()) # 此时可以拿到数据坐标下的文本宽高 text_width = bbox_data.x1 - bbox_data.x0 text_height = bbox_data.y1 - bbox_data.y0 # 示例1:绘制数据坐标下的文本包围盒(和数据坐标系完全匹配) pylab.plot( [bbox_data.x0, bbox_data.x1, bbox_data.x1, bbox_data.x0, bbox_data.x0], [bbox_data.y0, bbox_data.y0, bbox_data.y1, bbox_data.y1, bbox_data.y0], 'g-' ) # 示例2:将文本向上偏移自身高度的1/2,避免遮挡数据点 t.set_position((x, y + text_height/2)) pylab.show()
偏移方式说明
如果你需要将文本向其他方向偏移,直接基于拿到的text_width和text_height调整坐标即可:
- 向右偏移:x坐标加
text_width * 偏移比例 - 向左偏移:x坐标减
text_width * 偏移比例 - 向下偏移:y坐标减
text_height * 偏移比例
内容的提问来源于stack exchange,提问作者nickponline
相关产品推荐
相关产品推荐

