1

I'm using an Arduino to communicate with a sensor via I2C. After getting the data from the sensor, the Arduino outputs it in a string via Serial communication. The string looks something like this like this:

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

I am then using Python to read incoming data, segment it out (discarding \r\n), and then displaying a data set, of the users choosing, in real time via matplotlib.animation. When using the script on my computer, it works fine, but when trying to use it on another computer, I receive a Tkinter Callback Exception error.

The Python Script:

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

The Error Message:

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'

I've pinpointed it to the if statement in scope.update, specifically:

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

because when commenting these lines out, the program continues to run (albeit meaninglessly because it doesn't update the graph).

Running python --version && pip freeze on the working system results in:

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

... on the non-working system:

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
6
  • Which distribution of Python are you using on the systems? Is it the same? Commented Apr 20, 2018 at 15:20
  • We're both using Python 2.7 Commented Apr 20, 2018 at 15:23
  • Can you run this on both system? python --version && pip freeze Commented Apr 20, 2018 at 15:39
  • also, are you sure you are not received None for y on the second system? Commented Apr 20, 2018 at 15:40
  • I can't reproduce this issue, but as a wild guess try this: self.tdata[:] = [self.tdata[-1]] and self.ydata[:] = [self.ydata[-1]]. Commented Apr 20, 2018 at 16:02

2 Answers 2

1

Solved!

The problem subsides by reverting the non-working computer's matplotlib version from 2.2.2 to 2.0.2. While this solves the problem, I'm not sure what the underlying reason is behind the issue.

Sign up to request clarification or add additional context in comments.

1 Comment

In such a case, please provide a minimal reproducible example, i.e. a code that reproduces the problem and can be run as is, without the need to buy an arduino board etc. Once you have such example, it will be easier to find out what problem there is. If this is a bug with matplotlib, one should of course fix it, but at the moment it is not clear if it is. Maybe it's just that you don't convert your data to floats?
0

I came across this thread while trying to troubleshoot the exact same exception callback. I've found that the issue is caused by matplotlib functions for update plots which contain string-like objects. Maybe this is a bug somewhere in matplotlib, but I've solved it by converting my y-values to int before appending to the ydata array. In the case of your code, my implementation is:self.ydata.append(int(y)) Maybe float would work as well as suggested by ImportanceOfBeingErnest

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.