Python3下在Tk Canvas中同时嵌入图片与Matplotlib绘图的实现问题
解决方案
方案1:修复原有draw_figure函数适配新版环境
你原有逻辑不需要大改,报错核心是新版Matplotlib的tkagg模块路径、renderer调用规则和Python3的字节/字符串兼容问题,修正后的函数如下:
from matplotlib.backends.backend_agg import FigureCanvasAgg import tkinter as tk from PIL import Image, ImageTk def draw_figure(canvas, figure, loc=(0, 0)): figure_canvas_agg = FigureCanvasAgg(figure) figure_canvas_agg.draw() # 把渲染结果直接转PIL图像,避开底层tkagg的blit兼容问题 buf = figure_canvas_agg.buffer_rgba() img = Image.frombuffer("RGBA", figure_canvas_agg.get_width_height(), buf, "raw", "RGBA", 0, 1) photo = ImageTk.PhotoImage(img, master=canvas) # 居中放置 canvas.create_image(loc[0] + img.width/2, loc[1] + img.height/2, image=photo) # 保留引用防止被回收 return photo
注意点:调用函数后返回的photo对象必须和你之前的fig_photo_objects一样存到全局变量或者实例属性里,否则图表会被垃圾回收清空。
方案2:用官方推荐的FigureCanvasTkAgg实现
如果想完全适配新版Matplotlib,不需要把Figure转成图片再放Canvas,可以直接用create_window方法把Matplotlib的画布组件放到你现有Canvas的指定位置,和你之前放的PIL图片完全不冲突:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg def draw_figure(canvas, figure, loc=(0,0)): # 生成Tk适配的画布组件 figure_canvas = FigureCanvasTkAgg(figure, master=canvas) figure_canvas.draw() # 把画布组件放到Canvas指定位置 canvas.create_window(loc[0], loc[1], window=figure_canvas.get_tk_widget(), anchor="nw") # 保留画布引用防止被回收 return figure_canvas
这个方案的优势是保留了Matplotlib图表的交互能力(比如缩放、平移、悬浮显示坐标),如果你不需要交互就选方案1,性能更好。
重构可选优化
如果你后续需要调整布局,也可以把现有Canvas和图表分别放到不同的Frame容器里,不需要在同一个Canvas上混放,维护起来更简单,但如果你要保持原有坐标定位逻辑,上面两个方案都可以直接替换原有draw_figure函数使用。
内容的提问来源于stack exchange,提问作者Kevin H.
相关产品推荐
相关产品推荐

