Windows下TkAgg后端全屏显示matplotlib图表内容偏移问题
Windows 10下TkAgg后端Matplotlib全屏显示图片网格内容超出屏幕的解决方法
问题场景
我编写了Python函数,用Matplotlib的pyplot全屏显示3×3图片网格。在Windows 10系统的TkAgg交互式后端环境下,窗口打开后图表部分内容超出屏幕,无法完整显示预期的3×3网格。尝试通过plt.get_current_fig_manager().window.state('zoomed')设置全屏时出现该问题,调整figsize为1×1英寸无效果,手动退出全屏再重新进入后图表可正常显示。
原代码如下:
from PIL import Image import matplotlib.pyplot as plt def imageGrid(data_obj, grid=(3,3), start_idx=0): # 设置画布尺寸为1×1英寸 figure = plt.figure(figsize=(1,1)) cols, rows = grid idx = start_idx for i in range(1, cols * rows + 1): img = data_obj[idx] figure.add_subplot(rows, cols, i) plt.axis("off") plt.imshow(img, cmap="gray") idx += 1 plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1) # 设置窗口全屏(此代码导致内容溢出) plt.get_current_fig_manager().window.state('zoomed') plt.show() list_of_images = [Image.open("Screenshot 2023-08-30 170601.png") for i in range(9)] imageGrid(list_of_images)
问题原因
在TkAgg后端中,先定义小尺寸画布再调用state('zoomed')会导致图表布局与窗口尺寸不同步:窗口被强制放大到全屏,但图表的子图位置、边距等布局参数是基于初始小尺寸计算的,没有随窗口放大自动重新适配,最终导致内容溢出屏幕。
解决方法
方法1:延迟触发全屏,等待布局完成
利用Tkinter的after()方法,给Matplotlib留足布局计算时间,再设置窗口全屏:
from PIL import Image import matplotlib.pyplot as plt import tkinter as tk def imageGrid(data_obj, grid=(3,3), start_idx=0): figure = plt.figure(figsize=(1,1)) cols, rows = grid idx = start_idx for i in range(1, cols * rows + 1): img = data_obj[idx] figure.add_subplot(rows, cols, i) plt.axis("off") plt.imshow(img, cmap="gray") idx += 1 plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1) # 延迟100毫秒设置全屏,确保布局完成 def set_fullscreen(): plt.get_current_fig_manager().window.state('zoomed') root = tk.Tk() root.withdraw() # 隐藏默认Tk窗口 root.after(100, set_fullscreen) plt.show() list_of_images = [Image.open("Screenshot 2023-08-30 170601.png") for i in range(9)] imageGrid(list_of_images)
方法2:基于屏幕尺寸设置初始画布
先获取屏幕分辨率,直接将画布尺寸设置为与屏幕匹配的大小,让初始布局就适配全屏窗口:
from PIL import Image import matplotlib.pyplot as plt import tkinter as tk def imageGrid(data_obj, grid=(3,3), start_idx=0): # 获取屏幕尺寸 root = tk.Tk() screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() root.destroy() # 根据屏幕尺寸和DPI设置画布大小 dpi = 100 figure = plt.figure(figsize=(screen_width/dpi, screen_height/dpi), dpi=dpi) cols, rows = grid idx = start_idx for i in range(1, cols * rows + 1): img = data_obj[idx] figure.add_subplot(rows, cols, i) plt.axis("off") plt.imshow(img, cmap="gray") idx += 1 plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1) plt.get_current_fig_manager().window.state('zoomed') plt.show() list_of_images = [Image.open("Screenshot 2023-08-30 170601.png") for i in range(9)] imageGrid(list_of_images)
方法3:设置全屏后强制刷新布局
在设置全屏后,手动触发图表布局刷新,让Matplotlib重新计算子图位置:
from PIL import Image import matplotlib.pyplot as plt def imageGrid(data_obj, grid=(3,3), start_idx=0): figure = plt.figure(figsize=(1,1)) cols, rows = grid idx = start_idx for i in range(1, cols * rows + 1): img = data_obj[idx] figure.add_subplot(rows, cols, i) plt.axis("off") plt.imshow(img, cmap="gray") idx += 1 plt.subplots_adjust(wspace=0, hspace=0, left=0, right=1, bottom=0, top=1) plt.get_current_fig_manager().window.state('zoomed') # 强制刷新布局 figure.canvas.draw() plt.show() list_of_images = [Image.open("Screenshot 2023-08-30 170601.png") for i in range(9)] imageGrid(list_of_images)
效果验证
三种方法均可实现3×3图片网格在全屏窗口中完整显示,无需手动调整窗口。其中方法1兼容性最好,方法2更贴合屏幕原生分辨率,可根据实际需求选择。
内容的提问来源于stack exchange,提问作者Matee
相关产品推荐
相关产品推荐

