• 0

using python matplotlib to read serial data and plot bar graph dynamically


Question

I'm new to the matplotlib library but saw there is a new animation function for dynamic graphs. In this code I am reading serial data then parsing it and inputting it into a bar graph.  This all works fine if there is no dynamic animation.  I added the functions to get it dynamic but it keeps erroring out with "AttributeError: 'function' object has no attribute 'FuncAnimation'" and I'm not sure why.  I also have another code for the "manual way" to update the graph but I've read this isn't as efficient.  This way works though but only for a few updates before the graph freezes. At this point whatever I can get working would be fine. Thank you.

from matplotlib import pyplot as plt
from matplotlib import animation
import serial

# sensor data placeholder
sensorSerial = [" "," "," "," "," "," "," "," "," "]
humidityData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]
tempData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]

# bar details
bar_width = 0.25
opacity = 0.4

# create serial port
serobject = serial.Serial("COM4", 9600)

# create subplot object for 2 y-axis scales
fig, ax = plt.subplots()
# set graph colors
ax.set_axis_bgcolor('black')
fig.patch.set_facecolor('black')
ax.tick_params(axis='x', colors='white', length=0)
# setup axis ticks
ax.set_yticks(range(0,100,20))
ax.set_xticks(range(1,10))
# add x axis labels
ax.set_xticklabels(('Sensor1', 'Sensor2', 'Sensor3', 'Sensor4'))
tempBar = ax.bar([],[])
humidBar = ax.bar([],[])

def init():
    tempBar.set_data([],[])
    humidBar.set_data([],[])
    return tempBar, humidBar

def animation(i):
    # get sensor string data and parse
    data1 = serobject.readline().split(" ")
    data2 = serobject.readline().split(" ")

    # add data to arrays
    sensorSerial[0] = data1[0]
    humidityData[0] = int(data1[1])
    tempData[0] = int(data1[2])

    sensorSerial[1] = data2[0]
    humidityData[1] = int(data2[1])
    tempData[1] = int(data2[2])
    
    # create new bar graphs
    tempBar = ax.bar([i+0.25 for i in range(1,10)], tempData, bar_width, alpha=opacity,
            color='r', label='Temperature', edgecolor='white', linewidth = 3)
    humidBar = ax.bar([i+0.5 for i in range(1,10)], humidityData, bar_width, alpha=opacity,
            color='b', label='Humidity', edgecolor='white', linewidth = 3)
    return tempBar, humidBar

anim = animation.FuncAnimation(fig, animation, init_func=init)
plt.show()
#import libraries
import matplotlib.pyplot as plt
import serial
import time
import matplotlib.animation as animation

# sensor data placeholder
sensorSerial = [" "," "," "," "," "," "," "," "," "]
humidityData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]
tempData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]

# bar details
bar_width = 0.25
opacity = 0.4

# create serial port
serobject = serial.Serial("COM4", 9600)

# create subplot object for 2 y-axis scales
fig, ax = plt.subplots()
# set graph colors
ax.set_axis_bgcolor('black')
fig.patch.set_facecolor('black')
ax.tick_params(axis='x', colors='white', length=0)
# setup axis ticks
ax.set_yticks(range(0,100,20))
ax.set_xticks(range(1,10))
# add x axis labels
ax.set_xticklabels(('Sensor1', 'Sensor2', 'Sensor3', 'Sensor4'))
tempBar = ax.bar([],[])
humidBar = ax.bar([],[])

# dynamic plotting
plt.ion()
# show plot
plt.show()

while(True):
    # get sensor string data and parse
    data1 = serobject.readline().split(" ")
    data2 = serobject.readline().split(" ")

    # add data to arrays
    sensorSerial[0] = data1[0]
    humidityData[0] = int(data1[1])
    tempData[0] = int(data1[2])

    sensorSerial[1] = data2[0]
    humidityData[1] = int(data2[1])
    tempData[1] = int(data2[2])
    #remove old data from plot
    tempBar.remove()
    humidBar.remove()
    # redraw new data
    tempBar = ax.bar([i+0.25 for i in range(1,10)], tempData, bar_width, alpha=opacity,
            color='r', label='Temperature', edgecolor='white', linewidth = 3)
    humidBar = ax.bar([i+0.25*2 for i in range(1,10)], humidityData, bar_width, alpha=opacity,
            color='b', label='Humidity', edgecolor='white', linewidth = 3)
    plt.draw()

6 answers to this question

Recommended Posts

  • 0

You named your own function animation, which is clobbering over the matplotlib.animation object.

 

e.g.

def animation(i):

...

... = animation.FuncAnimation(fig, animation, ...)

Just switch the call to matplotlib.animation.FuncAnimation(...) instead. That is what I use.

  • 0

okay, that fixed that but now i get "AttributeError: 'BarContainer' object has no attribute 'axes'" but dont see a reference to the line where the error is at. here is my full error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
    return self.func(*args)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 276, in resize
    self.show()
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 348, in draw
    FigureCanvasAgg.draw(self)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_agg.py", line 451, in draw
    self.figure.draw(self.renderer)
  File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\figure.py", line 1040, in draw
    self.canvas.draw_event(renderer)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 1693, in draw_event
    self.callbacks.process(s, event)
  File "C:\Python27\lib\site-packages\matplotlib\cbook.py", line 527, in process
    proxy(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\cbook.py", line 405, in __call__
    return mtd(*args, **kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 832, in _end_redraw
    self._post_draw(None, self._blit)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 778, in _post_draw
    self._blit_draw(self._drawn_artists, self._blit_cache)
  File "C:\Python27\lib\site-packages\matplotlib\animation.py", line 791, in _blit_draw
    if a.axes not in bg_cache:
AttributeError: 'BarContainer' object has no attribute 'axes'
from matplotlib import pyplot as plt
from matplotlib import animation
import serial

# sensor data placeholder
sensorSerial = [" "," "," "," "," "," "," "," "," "]
humidityData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]
tempData = [.01, .01, .01, .01,.01,.01,.01,.01,.01]

# bar details
bar_width = 0.25
opacity = 0.4

# create serial port
serobject = serial.Serial("COM4", 9600)

# create subplot object for 2 y-axis scales
fig, ax = plt.subplots()
# set graph colors
ax.set_axis_bgcolor('black')
fig.patch.set_facecolor('black')
ax.tick_params(axis='x', colors='white', length=0)
# setup axis ticks
ax.set_yticks(range(0,100,20))
ax.set_xticks(range(1,10))
# add x axis labels
ax.set_xticklabels(('Sensor1', 'Sensor2', 'Sensor3', 'Sensor4'))
tempBar = ax.bar([],[])
humidBar = ax.bar([],[])

def init():
    tempBar = ax.bar([],[])
    humidBar = ax.bar([],[])
    return tempBar, humidBar

def animator(i):
    # get sensor string data and parse
    data1 = serobject.readline().split(" ")
    data2 = serobject.readline().split(" ")

    print(data1)
    print(data2)

    # add data to arrays
    sensorSerial[0] = data1[0]
    humidityData[0] = int(data1[1])
    tempData[0] = int(data1[2])

    sensorSerial[1] = data2[0]
    humidityData[1] = int(data2[1])
    tempData[1] = int(data2[2])
    
    # create new bar graphs
    tempBar = ax.bar([i+0.25 for i in range(1,10)], tempData, bar_width, alpha=opacity,
            color='r', label='Temperature', edgecolor='white', linewidth = 3)
    humidBar = ax.bar([i+0.5 for i in range(1,10)], humidityData, bar_width, alpha=opacity,
            color='b', label='Humidity', edgecolor='white', linewidth = 3)
    return tempBar, humidBar

anim = animation.FuncAnimation(fig, animator, init_func=init, frames=100, interval=2000, blit=True)
plt.show()
  • 0

I believe it doesn't like your return value for animation() or init(). When I've used animatefunc(), I haven't actually return anything (for example if I'm using ax.pcolormesh). I would try without the returns and see if it works that way. You can also try returning your ax or your plot there. I'm not 100% how the return works, but it looks like it is to tell the animator what part of the plot to update. Perhaps, if you don't return anything it just updates everything?

  • 0

hmm, with the return gone for init function i get "TypeError: 'NoneType' object is not iterable" taking out the return for the animator function does nothing. 

 

returning 'ax' gives me a "TypeError: 'AxesSubplot' object is not iterable" error.

 

returning 'plt' gives me a "TypeError: 'module' object is not iterable" error.

 

This is the guide i followed and it works that way and seemed straigh forward but alas im here

http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/


EDIT: oh, so i changed it so both functions only return tempBar and not both and it works that way but doenst show humidBar at all. I guess it didnt like the double return.  Is there any way to have it update more bars?

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Amazon Deals: Samsung Q990F Q900F Q800F 2025 Dolby Atmos soundbars with wireless subwoofers by Sayan Sen While separate AV receivers with hi-fi speakers are generally the preferred way to listed to music and watch movies/shows by audiophiles, the more general folks often prefer soundbars instead as they offer a capable all in one solution that is still plenty good. Currently Nakamichi is running discounts on multiple products from its Dragaon lineup as well as its Shockwafe model. If you are looking for more options to choose from Samsung has its Q-series products at lowest prices (purchase links towards the end of article). Q990F The flagship Q990F is an 11.1.4 system and the single subwoofer unit on it houses two opposite-facing 8-inch subwoofer drivers. Thus, together they move around the same amount of air as a single 12-inch subwoofer unit. In addition to increasing the bass by +3 dB, dual opposing drivers are also said to help reduce vibrations of the subwoofer cabinet by cancelling out the resonance. Samsung also says that the bass is "AI-optimized" but we are not sure if it actually helps or if it's just a buzz term here. Aside from the bass, dialogue in movies is the second most important thing, and Samsung claims great vocal clarity from its front speakers thanks to AVA (Active Voice Amplifier) Pro feature that is said to detect noise disturbances and amplify dialogue to make it more audible over such surrounding noises. Q900F Feature wise the Q900F is similar to the 990F model except it has fewer channels and it is a 7.1.2 setup. Finally the Q800F is a 5.1.2 system and it has a passive radiator instead of the additonal subwoofer driver unit. Get the Samsung Q series soundbars at the links below: Samsung Q990F 11.1.4ch Wireless Dolby Atmos, Q-Symphony, Game Mode Pro, Adaptive Sound (HW-Q990F, 2025): $1497.99 (Shipped and Sold by Amazon US) Samsung HW-Q900F 7.1.2 ch Wireless Dolby Atmos, Q-Symphony: $997.99 (Shipped and Sold by Amazon US) Samsung Q800F 5.1.2ch Q Series Soundbar + Subwoofer, Wireless Dolby Atmos, Q-Symphony, Game Mode Pro, Smart Integration (HW-Q800F, 2025): $697.99 (Shipped and Sold by Amazon US) This Amazon deal is US-specific and not available in other regions unless specified. If you don't like it or want to look at more options, check out the Amazon US deals page here. Get Prime (SNAP), Prime Video, Audible Plus or Kindle / Music Unlimited. Free for 30 days. As an Amazon Associate, we earn from qualifying purchases.
    • They are shifting into AI now. Don't you see?
    • Exactly. No need to pay to rent a license. I'd rather own it.
  • Recent Achievements

    • One Month Later
      Helen Shafer earned a badge
      One Month Later
    • One Month Later
      ambani880 earned a badge
      One Month Later
    • Week One Done
      ambani880 earned a badge
      Week One Done
    • First Post
      artistro08 earned a badge
      First Post
    • First Post
      paul29 earned a badge
      First Post
  • Popular Contributors

    1. 1
      +primortal
      498
    2. 2
      ATLien_0
      223
    3. 3
      Michael Scrip
      196
    4. 4
      Xenon
      160
    5. 5
      +FloatingFatMan
      138
  • Tell a friend

    Love Neowin? Tell a friend!