Jupyter/IPython传至Qt自定义前端的Matplotlib图像尺寸异常致坐标转换失效
自定义前端对接Jupyter内核的Matplotlib坐标失配问题
项目基础情况
- 自行开发了基于Qt/PyQt的自定义前端,对接Jupyter/IPython内核长期运行稳定
- 使用
%matplotlib inline模式时,内核可将Matplotlib生成的图像以PNG字节流形式传输到前端,完成静态图像展示
预期实现的功能
- 为静态图像增加点击交互能力:用户点击图像上的点位时,将该点的像素坐标回传至内核,转换为Matplotlib体系下对应的数据坐标(即显示坐标)
- 理论实现路径:通过Matplotlib的axes对象完成像素坐标到数据坐标的转换,参考调用方式为
ax.transData.inverted().transform(pixel_coordinate_x, pixel_coordinate_y)
实际遇到的问题
- 坐标转换结果与用户实际点击位置完全不匹配
- 初步排查确认核心矛盾:前端接收到的PNG图像尺寸,和内核端设定的Matplotlib绘图尺寸不一致
- 实例参考:代码设置
fig = plt.figure(figsize=(6,4))时,内核内查询到的figure尺寸完全符合6英寸×4英寸的预期,但前端实际收到的PNG等效尺寸为5.3英寸×3.5英寸
- 实例参考:代码设置
已经做过的排查操作(均无明显效果)
- 修改Matplotlib的savefig.dpi rcParams参数为80DPI,匹配前端显示设置,问题没有改善
- 创建figure时同时显式指定dpi参数、全局设置savefig的dpi参数,尺寸偏差依然存在:
- 代码写法:
fig = plt.figure(figsize=(6,4), dpi=80.0) - 代码写法:
plt.rcParams['savefig.dpi'] = 80.0
- 代码写法:
- 尝试手动偏移补偿:打印
ax.bbox.corners()得到numpy格式的边界坐标数组,将数组第一行的[60. 40.]作为像素坐标的偏移量做修正,最初好像有临时效果,但稳定性极差,根本没法做到准确匹配- 打印得到的ax边界坐标具体值:
[[ 60. 40.] [ 60. 288.] [432. 40.] [432. 288.]]
可复现问题的最小代码
plt.rcParams['savefig.dpi'] = 80.0 import random fig = plt.figure(figsize=(6,4), dpi=80.0) x = range(0, 10) y = [random.random() for i in x] plt.plot(x, y, 'bo-') ax = fig.gca() ax.yaxis.set_label_text('YVAL') fig.set_facecolor('#ff0000') print fig.bbox.corners() print ax.bbox.corners()
按照设置的6英寸×4英寸尺寸、80DPI参数计算,figure的预期像素尺寸应该是480×320(也就是6英寸×80DPI、4英寸×80DPI),但前端实际收到的PNG尺寸为429×283。
收到的图像尺寸可通过以下代码校验:
img = IPython.core.pylabtools.print_figure(fig)) from PyQt4.QtGui import QImage img2 = QImage.fromData(img) print img2.width() print img2.height()
目前已经把能想到的排查思路都试过了,希望Matplotlib/Jupyter/IPython方向的专家能帮忙找到图像尺寸不匹配的根本原因,最终实现准确的像素坐标转数据坐标的功能。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

