Matplotlib的draw()函数会导致窗口冻结

4

我正在尝试使用matplotlib创建一个图表以反映实时结果。由于移动窗口、更改窗口或点击操作会导致图表冻结,所以我可能没有做好。以下是我所说的示例。

import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

def function1(fig, varse):
  ax = fig.add_subplot(111, projection='3d')
  color_grade_classes = ['#80FF00','#FFFF00','#FF8000', '#FF0000']
  varse = varse +1
  ax.set_xlabel('X')
  ax.set_ylabel('Y')
  for colors, rows  in zip(color_grade_classes, [3,2,1,0] ):  
    indexs = np.arange(5)
    heights = [varse,varse/2,varse/3,0,0]
    ax.bar(indexs, heights, zs = rows,  zdir='y', color=colors, alpha=0.8)
  plt.ion()
  plt.draw()
  plt.show()
  plt.ioff()
  return varse

varse = 0
plt.ion()
fig = plt.figure()
plt.ioff()
while(1):
  varse = function1(fig, varse)
4个回答

2
我解决的方法是使用tk作为GUI:
import matplotlib
matplotlib.use('TkAgg')

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import random
import numpy as np
import sys
import Tkinter as tk
import time

def function1(fig, ax):
    ax.cla()
    color_grade_classes = ['#80FF00','#FFFF00','#FF8000', '#FF0000']
    varsi =  random.randint(1, 100)

    for colors, rows  in zip(color_grade_classes, [3,2,1,0] ):  
        indexs = np.arange(5)
        heights = [varsi,varsi/2,varsi/3,0,0]
        ax.bar(indexs, heights, zs = rows,  zdir='y', color=colors, alpha=0.8)
    return fig

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.root.wm_title("Embedding in TK")

        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111, projection='3d')
        self.ax.set_xlabel('X')
        self.ax.set_ylabel('Y')
        self.fig = function1(self.fig, self.ax)

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
        self.toolbar = NavigationToolbar2TkAgg( self.canvas, self.root )
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        self.label = tk.Label(text="")
        self.label.pack()
        self.update_clock()
        self.root.mainloop()

    def update_clock(self):
        self.fig = function1(self.fig,self.ax)
        self.canvas.show()
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        now = time.strftime("%H:%M:%S")
        self.label.configure(text=now)
        self.root.after(1000, self.update_clock)

app=App()

使用这种方法可以在展示图表后保持对其的控制,避免在移动窗口时出现冻结。


1

这可能是这个问题的重复。

无论如何,我对你做动画的方式持怀疑态度。这看起来不像matplotlib动画示例中的任何一个,并且也没有遵循(我认为是旧的)这里的建议

大多数这些示例都以plt.show()结尾;就像任何其他事件驱动的GUI编程系统一样(因为这就是matplotlib的本质),如果您想要正确地工作,您需要将控制权交给其事件循环并学习在该框架的提供的动画中工作的方法。


2
我不同意对Matplotlib的普遍质疑。根据我的经验,大部分建议使用的动画方式都相当不好,而采用更加友好的matplotlib.pylab.ion()方法则是一个好主意。如果要寻求交互式绘图的解决方案,可以考虑我在这里提供的答案。它应该能够进行基本动画方面的修改。 - ely
问题也出现在basic_example动画中。我不确定如何在plt.show()之后允许新数据进入,它不会挂起,但也不会更新! - user1170056
EMS,我尝试了你的示例解决方案,但当我移动窗口时它也会挂起。 - user1170056

1

我曾经尝试实时绘制一些曲线时遇到了同样的问题。一个快速解决方法是在你的绘图函数中添加一个绘图暂停。

import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

def function1(fig, varse):
  ax = fig.add_subplot(111, projection='3d')
  color_grade_classes = ['#80FF00','#FFFF00','#FF8000', '#FF0000']
  varse = varse +1
  ax.set_xlabel('X')
  ax.set_ylabel('Y')
  for colors, rows  in zip(color_grade_classes, [3,2,1,0] ):  
    indexs = np.arange(5)
    heights = [varse,varse/2,varse/3,0,0]
    ax.bar(indexs, heights, zs = rows,  zdir='y', color=colors, alpha=0.8)
  plt.draw()
  plt.pause(0.001)
  return varse

varse = 0
plt.ion()
fig = plt.figure()
plt.show()

while(1):
  varse = function1(fig, varse)

0
我用一种非常简单的方法解决了它。在我的Python主文件的末尾,我在代码的结尾添加了plt.show()。
from matplotlib import pyplot as plt
#.
#. My code here 
#.

# Last line of code:
plt.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接