Matplotlib在GUI中崩溃
我想在一个图形界面(gui)中用tkinter和imshow来绘制一个矩阵。问题是,经过几次更新后,界面就崩溃了。我在网上找不到解决办法。你能帮我吗?
这是我的代码:
from numpy import *
from Tkinter import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
root = Tk()
f1 = Figure()
canvas = FigureCanvasTkAgg(f1, master=root)
canvas.show()
canvas.get_tk_widget().pack(fill="x")
a = f1.add_subplot(111)
a.get_axes().set_frame_on(True)
ini = [[i] * 100 for i in range(100)]
cax = a.matshow(ini)
while True:
mat = random.randint(0, 2**16-1, (1000, 1000))
cax.set_data(mat)
canvas.draw()
root.mainloop()
谢谢你的建议fhdrsdg,但这样做会导致窗口在重绘时卡住,这很烦人,特别是当之前有很多事情要处理的时候。
这是我的代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Tkinter import Button, Label, Text, Checkbutton, Radiobutton, Frame, Tk, Entry, INSERT, StringVar, IntVar, Toplevel, END
from ttk import Notebook, Combobox
from numpy import arange, zeros, array, uint16, empty, divide, random, ravel
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from matplotlib import cm
from matplotlib.image import AxesImage
import time
from threading import Thread
import os
class Image_direct(Thread):
def __init__(self):
Thread.__init__(self)
self.encore = True
def run(self):
"""This loop can be long ~10s"""
while self.encore:
time.sleep(1)
app.cax.set_extent((0, 1023, 1023, 0))
mat = random.randint(0, 2**16-1, (1024, 1024)).astype("uint16")
app.update_camera(mat)
def stop(self):
self.encore = False
class Deu(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.creer_applets()
def creer_applets(self):
self.fen4 = Frame(fen)
self.fen4.pack(side="bottom", fill="both")
self.fen1 = Frame(fen, width=200)
self.fen1.pack(side="left", fill="both", expand=False)
self.note = Notebook(fen, width=1)
self.tab_mat = Frame(self.note)
self.note.add(self.tab_mat, text = "Caméra", compound="top")
self.note.pack(side="left", fill="both", expand=True)
self.fen3 = Frame(fen, width=250)
self.fen3.pack(side="left", fill="both", expand=False)
Button(self.fen4, text="Quit", command=self.aurevoir).pack(fill="x", side="top")
self.interp = StringVar()
self.interp.set("none")
liste_interp = ["none", "nearest", "bilinear", "bicubic", "spline16", "spline36", "hanning", "hamming", "hermite", "kaiser", "quadric", "catrom", "gaussian", "bessel", "mitchell", "sinc", "lanczos"]
self.choix_interp = Combobox(self.tab_mat, textvariable=self.interp, state="readonly", width=10)
self.choix_interp['values'] = liste_interp
self.cmap = StringVar()
self.cmap.set("jet")
palettes = sorted(m for m in cm.datad if not m.endswith("_r"))
self.choix_palette = Combobox(self.tab_mat, textvariable=self.cmap, state="readonly", width=10)
self.choix_palette['values'] = palettes
self.bouton_palette = Button(self.tab_mat, text="Changer la palette", command=self.changer_cmap)
self.f1 = Figure()
self.canvas1 = FigureCanvasTkAgg(self.f1, master=self.tab_mat)
self.canvas1.show()
self.canvas1.get_tk_widget().pack(fill="both", expand=1)
NavigationToolbar2TkAgg(self.canvas1, self.tab_mat)
self.a = self.f1.add_subplot(111)
self.bg = self.canvas1.copy_from_bbox(self.a.bbox)
self.a.get_axes().set_frame_on(True)
ini = random.randint(0, 2**16-1, (1024, 1024))
self.cax = self.a.matshow(ini, cmap=self.cmap.get(), interpolation=self.interp.get(), picker=True, alpha=1.0)
self.a.format_coord = lambda x, y: 'x=%d, y=%d, z=%d' % (x, y, ini[round(y), round(x)])
self.cbar = self.f1.colorbar(self.cax)
self.cbar.set_label("coups")
self.bouton_palette.pack(side="left")
self.choix_interp.pack(side="left")
self.choix_palette.pack(side="left")
Button(self.tab_mat, text=">", command=lambda: self.changer_cbar(1)).pack(side="right")
self.cbar_auto = IntVar()
self.chb3 = Checkbutton(self.tab_mat, text="Auto?", variable=self.cbar_auto, onvalue=1, offvalue=0, indicatoron=0, command=lambda: self.changer_cbar(0))
self.chb3.select()
self.chb3.pack(side="right")
Button(self.tab_mat, text="<", command=lambda: self.changer_cbar(-1)).pack(side="right")
self.bouton_direct_on = Button(self.fen3, width=20, text="Démarrer le direct", command=self.image_direct_on)
self.bouton_direct_on.place(x=0, y=400)
self.bouton_direct_off = Button(self.fen3, width=20, text="Arrêter le direct", command=self.image_direct_off)
self.bouton_direct_off.config(state="disabled")
self.bouton_direct_off.place(x=0, y=430)
def changer_cbar(self, sens):
if sens == -1:
self.cbar.set_clim(vmin=self.cax.get_array().min(), vmax=0.9*self.cbar.get_clim()[1])
elif sens == 0 and self.cbar_auto.get():
self.cbar.set_clim(vmin=self.cax.get_array().min(), vmax=self.cax.get_array().max())
elif sens == 1:
self.cbar.set_clim(vmin=self.cax.get_array().min(), vmax=2*self.cbar.get_clim()[1])
self.cax.set_clim(self.cbar.get_clim())
self.canvas1.restore_region(self.bg)
self.a.draw_artist(self.f1)
self.canvas1.blit(self.f1.bbox)
def changer_cmap(self):
self.cax.set_cmap(self.cmap.get())
self.cax.set_interpolation(self.interp.get())
self.canvas1.draw()
def update_camera(self, mat):
xmin = min([int(i) for i in app.a.get_xlim()])
xmax = max([int(i) for i in app.a.get_xlim()])
ymin = min([int(i) for i in app.a.get_ylim()])
ymax = max([int(i) for i in app.a.get_ylim()])
self.a.format_coord = lambda x, y: 'x=%d, y=%d, z=%d' % (x, y, mat[round(y), round(x)])
self.cax.set_data(mat)
self.changer_cbar(0)
def image_direct_on(self):
self.bouton_direct_off.config(state="normal")
self.bouton_direct_on.config(state="disabled")
self.dire = Image_direct()
self.dire.setDaemon(True)
self.dire.start()
def image_direct_off(self):
self.bouton_direct_off.config(state="disabled")
self.bouton_direct_on.config(state="normal")
self.dire.stop()
del self.dire
def aurevoir(self):
try:
self.dire.isAlive()
except:
pass
else:
self.dire.stop()
fen.quit()
fen.destroy()
if __name__ == '__main__':
fen = Tk()
fen.geometry("1300x750")
app = Deu(fen)
fen.mainloop()
奇怪的是:
当光标在图像上时会崩溃
在linux系统下没有崩溃。
当光标悬停在图像上,或者我放大/缩小图像时,崩溃可能在几秒钟或几分钟内发生。然后窗口变成白色,会弹出一个提示框,显示“pythonw.exe没有响应”。Idle没有任何提示。我完全搞不清楚状况 :/
1 个回答
0
我觉得问题出在运行这个while True
循环上。你可以试着用after
方法来限制每次重复之间的时间。下面的代码每100毫秒更新一次画布。
from numpy import *
from Tkinter import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
root = Tk()
f1 = Figure()
canvas = FigureCanvasTkAgg(f1, master=root)
canvas.show()
canvas.get_tk_widget().pack(fill="x")
a = f1.add_subplot(111)
a.get_axes().set_frame_on(True)
ini = [[i] * 100 for i in range(100)]
cax = a.matshow(ini)
def redraw():
mat = random.randint(0, 2**16-1, (1000, 1000))
cax.set_data(mat)
canvas.draw()
root.after(100, redraw)
redraw()
root.mainloop()