Tkinter 回调异常:matplotlib 动画

Posted

技术标签:

【中文标题】Tkinter 回调异常:matplotlib 动画【英文标题】:Tkinter Callback Exception: matplotlib animation 【发布时间】:2018-04-20 15:18:00 【问题描述】:

我正在使用 Arduino 通过 I2C 与传感器通信。从传感器获取数据后,Arduino 通过串行通信将其输出为字符串。字符串看起来像这样:

"-3.46,-8.4,4.64,7.5,35.3,4.32,-9.0,\r\n"

然后我使用 Python 读取传入数据,将其分割(丢弃 \r\n),然后通过 matplotlib.animation 实时显示用户选择的数据集。在我的计算机上使用脚本时,它可以正常工作,但是当尝试在另一台计算机上使用它时,我收到 Tkinter 回调异常错误。

Python 脚本:

port = 'com4'       # Configure which port the Arduino is connected to.
baud = 19200        # Configure baud rate
ind  = 0            # Determine which data point you want displayed on the graph. [0-6]
import numpy as np
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import time
import re
import xlwt


if serial.Serial(port,baud).is_open:
    serial.Serial(port,baud).close()

ser = serial.Serial(port,baud,timeout=1)
ser.reset_input_buffer()
ser.readline()

class Scope(object):
    def __init__(self, ax, maxt=4, dt=0.04):
        self.ax = ax
        self.dt = dt
        self.maxt = maxt
        self.tdata = [-dt]
        self.ydata = [0]
        self.line = Line2D(self.tdata, self.ydata)
        self.ax.add_line(self.line)
        self.ax.set_ylim(yMin, yMax)
        self.ax.set_xlim(0, self.maxt)

    def update(self, y):
        lastt = self.tdata[-1]
        if lastt > self.tdata[0] + self.maxt:  # reset the arrays
            self.tdata = [self.tdata[-1]]
            self.ydata = [self.ydata[-1]]
            self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt)
            self.ax.figure.canvas.draw()

        t = self.tdata[-1] + self.dt
        self.tdata.append(t)
        tArray.append(t)
        self.ydata.append(y)
        self.line.set_data(self.tdata, self.ydata)
        return self.line,


def emitter():
    while True:
        val = ser.readline()
        allData = val.split(",")
        yArray.append(allData[:-1])     # discarding return line characters from the serial read.

        yield allData[ind]

fig, ax = plt.subplots()
scope = Scope(ax)

# pass a generator in "emitter" to produce data for the update func
ani = animation.FuncAnimation(fig, scope.update, emitter, interval=10,blit=True)
plt.show()

print yArray

错误信息:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1542, in __call__
    return self.func(*args)
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 592, in callit
    func(*args)
  File "C:\Python27\lib\site-packages\matplotlib\backends\_backend_tk.py", line 88, in _on_timer
    TimerBase._on_timer(self)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 1373, in _on_timer
    ret = func(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 1481, in _step
    still_going = Animation._step(self, *args)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 1217, in _step
    self._draw_next_frame(framedata, self._blit)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 1237, in _draw_next_frame
    self._post_draw(framedata, blit)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 1260, in _post_draw
    self._blit_draw(self._drawn_artists, self._blit_cache)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 1275, in _blit_draw
    a.axes.draw_artist(a)
  File "C:\Python27\lib\site-packages\matplotlib\axes\_base.py", line 2622, in draw_artist
    a.draw(self._cachedRenderer)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\lines.py", line 738, in draw
    self.recache()
  File "C:\Python27\lib\site-packages\matplotlib\lines.py", line 656, in recache
    yconv = self.convert_yunits(self._yorig)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 200, in convert_yunits
    return ax.yaxis.convert_units(y)
  File "C:\Python27\lib\site-packages\matplotlib\axis.py", line 1526, in convert_units
    ret = self.converter.convert(x, self.units, self)
  File "C:\Python27\lib\site-packages\matplotlib\category.py", line 65, in convert
    unit.update(values)
AttributeError: 'NoneType' object has no attribute 'update'

我已将其定位到scope.update 中的if 语句,具体来说:

self.tdata = [self.tdata[-1]]
self.ydata = [self.ydata[-1]]

因为在注释掉这些行时,程序会继续运行(尽管没有任何意义,因为它没有更新图表)。

工作系统上运行python --version && pip freeze会导致:

Python 2.7.13
appdirs==1.4.3
certifi==2018.1.18
chardet==3.0.4
configobj==5.0.6
cycler==0.10.0
Cython==0.28
decorator==4.0.11
enum34==1.1.6
et-xmlfile==1.0.1
functools32==3.2.3.post2
future==0.16.0
idna==2.6
ipython-genutils==0.2.0
iso8601==0.1.12
jdcal==1.3
matplotlib==2.0.2
mpltools==0.2.0
mpmath==0.19
nose==1.3.7
numpy==1.13.0rc1+mkl
openpyxl==2.4.7
packaging==16.8
panda==0.3.1
pandas==0.22.0
patsy==0.5.0
pyparsing==2.2.0
pyperclip==1.5.27
pyserial==3.4
python-dateutil==2.6.0
pytz==2017.2
PyVISA==1.8
pywin32==221
PyYAML==3.12
requests==2.18.4
scikit-learn==0.19.1
scipy==0.19.0
seaborn==0.8.1
six==1.10.0
sklearn==0.0
sympy==1.0
traitlets==4.3.2
urllib3==1.22
vispy==0.5.3
xlwt==1.3.0

...在非工作系统上:

Python 2.7.13
backports.functools-lru-cache==1.5
cycler==0.10.0
et-xmlfile==1.0.1
jdcal==1.3
kiwisolver==1.0.1
matplotlib==2.2.2
numpy==1.13.1
openpyxl==2.4.8
pyparsing==2.2.0
pyserial==3.4
python-dateutil==2.7.2
pytz==2018.4
six==1.11.0
xlwt==1.3.0

【问题讨论】:

您在系统上使用哪个 Python 发行版?是一样的吗? 我们都在使用 Python 2.7 你能在两个系统上运行这个吗? python --version && pip freeze 另外,您确定在第二个系统上没有收到Noney 吗? 我无法重现此问题,但大胆猜测一下:self.tdata[:] = [self.tdata[-1]] self.ydata[:] = [self.ydata[-1]] 【参考方案1】:

解决了!

通过将非工作计算机的matplotlib 版本从2.2.2 恢复为2.0.2,问题得到解决。虽然这解决了问题,但我不确定问题背后的根本原因是什么。

【讨论】:

在这种情况下,请提供minimal reproducible example,即重现问题并可以按原样运行的代码,无需购买arduino板等。一旦你有了这样的例子,会更容易找出问题所在。如果这是 matplotlib 的一个错误,当然应该修复它,但目前尚不清楚是否是。也许只是您没有将数据转换为浮点数?【参考方案2】:

我在尝试对完全相同的异常回调进行故障排除时遇到了这个线程。我发现这个问题是由 matplotlib 函数引起的,用于更新包含类似字符串的对象的图。也许这是 matplotlib 中的某个错误,但我已经通过在附加到 ydata 数组之前将我的 y 值转换为 int 来解决它。对于您的代码,我的实现是:self.ydata.append(int(y)) 也许 float 会像 ImportanceOfBeingErnest 建议的那样工作

【讨论】:

以上是关于Tkinter 回调异常:matplotlib 动画的主要内容,如果未能解决你的问题,请参考以下文章

tkinter 与 matplotlib

matplotlib 在 tkinter 画布中的缩放功能

tkinter的GUI设计:界面与逻辑分离-- 与 matplotlib 结合

用Tkinter打造GUI开发工具(49)在Tkinter窗口上动态显示matplotlib.pyplot图形

用Tkinter打造GUI开发工具(49)在Tkinter窗口上动态显示matplotlib.pyplot图形

tkinter内嵌Matplotlib系列之解读官网教材