I am trying to plot a realtime graph using matplotlib's FuncAnimation class. The data is coming from arduino using pyserial library. I have tried the following code to plot in real time but the graph is empty, I can see the axes, ticks etc but not the plot. Can anyone help me what I am doing wrong here?
Thank you in advance.
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import serial
import os
import numpy as np
import datetime
import pandas as pd
fig = plt.figure()
port= 'COM10'
baudrate = 9600
timeout = 2
ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout)
def animate(i):
j = 0
while True:
try:
loadcells = ser.readline()
loadcells = loadcells.decode('utf-8').rstrip().replace('\t','').split(',')
print(loadcells)
loadcell1 = float(loadcells[0])
# loadcell2 = loadcells[1]
plt.cla()
plt.plot(loadcell1)
plt.pause(0.001)
j+=1
# plt.plot(loadcell2)
except Exception as e:
print(e)
continue
except KeyboardInterrupt as e1:
print(e1)
ser.close()
anim = FuncAnimation(fig, animate,
frames = 200,
interval = 0.1,
blit = False)
plt.tight_layout()
plt.show()
You should not have an infinite loop in animate(). FuncAnimation works by calling animate() repeatedly at a pre-defined interval (interval=0.1).
You need to rewrite your animate() function where you read the serial port, plot the result, and return (no pause() either).
Related
Appreciating your time and effort to go through my code and helping me to find the solution.
I am using FuncAnimation of Matplotlib to refresh/update my plot every 1min.
The Data is extracted using Yahoo finance every 1min. But I am getting following error:
in _draw_frame
self._drawn_artists = self._func(framedata, *self._args)
TypeError: 'NoneType' object is not callable
Below is my code:
import yfinance as yf
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def Get_Data():
Data = yf.download(tickers="VIPIND.NS",interval="1m", period="1d")
Data.reset_index(inplace = True)
Data['Datetime'] = Data['Datetime'].dt.tz_convert('Asia/Kolkata').dt.tz_localize(None)
Data['Datetime'] = pd.to_datetime(Data['Datetime'])
Data=Data.set_index('Datetime')
print("Refreshed")
plt.figure(1)
plt.cla()
plt.xticks()
plt.plot(Data['Close'], linewidth = 2)#,label = f'Close at {Data.index[-1]}')
plt.title(f'Close Price at {Data.index[-1]}')
plt.xlabel("Time")
plt.show()
return
LivePlot = FuncAnimation(plt.gcf(),Get_Data(),interval=60000)
Please guide me on where am I going wrong ? and how to resolve this issue.
Regards
Sudhir
I am doing my first matplotlib animation graph. and It's not working.please someone explain me,why??
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np
n = 100
X = np.random.randn(n)
def update(curr):
if curr == n:
a.event_source.stop()
plt.cla()
bins = np.arange(-4,4, 0.5)
plt.hist(X[:curr], bin=bins)
plt.axis([-4,4,0,30])
plt.annotate("n={}".format(curr),(3,27))
fig = plt.figure()
a = animation.FuncAnimation(fig, update, interval=100)
P.S. I am coding on jupyter notebook
I got my answer. It's a typo in plt.hist call. The parameter is bins not bin.
plt.hist(X[:curr], bins=bins)
I have a small program that is plotting some data. The program runs without any errors and displays the plot, but it is removing every other x-axis value. What should I be doing to get all twelve axis labels to display properly?
The program:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas.plotting import register_matplotlib_converters
print('NumPy: {}'.format(np.__version__))
print('Pandas: {}'.format(pd.__version__))
print('-----')
display_settings = {
'max_columns': 14,
'expand_frame_repr': False, # Wrap to multiple pages
'max_rows': 50,
'show_dimensions': False
}
pd.options.display.float_format = '{:,.2f}'.format
for op, value in display_settings.items():
pd.set_option("display.{}".format(op), value)
file = "e:\\python\\dataquest\\unrate.csv"
unrate = pd.read_csv(file)
print(unrate.shape, '\n')
unrate['DATE'] = pd.to_datetime(unrate['DATE'])
print(unrate.info(), '\n')
print(unrate.head(12), '\n')
register_matplotlib_converters()
plt.xticks(rotation=90)
plt.plot(unrate['DATE'][0:12], unrate['VALUE'][0:12])
plt.show()
I am getting as output: (I am using PyCharm)
I believe I should be getting: (From Dataquests built in IDE)
#Quang Hong, You were on the right track. I had to adjust the interval value and the date format as follows:
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=30))
Now I get this output:
I'm trying to open up multiple plots but I ran into a few problems. When I tried to create plots using threading, python would first open a number of windows, then close all but the first.
In another question it was recommended that I use multiprocessing which I have tried. The code runs without error, it just doesn't show any plot.
I'm trying to get something very simple to work before moving on to my main project.
# Import the necessary packages and modules
import matplotlib.pyplot as plt
import numpy as np
#from threading import Thread
import multiprocessing
def plot(datax, datay, name):
# Prepare the data
x = datax
y = datay**2
# Plot the data
plt.scatter(x, y, label=name)
# Add a legend
plt.legend()
# Show the plot
plt.show()
#plot(3,3,)
'''
for i in range(10):
t = Thread(target=plot, args=(i,i+1,i,))
t.start()
'''
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
update:
for some reason, multiprocessing stopped working again. I tried creating a function multiP() only to open the processes but it didn't work when I added the input('value: '). scine I can't figure out how to send data to a specific thread I'm going to save data like this: dat = [[x,y0,y1,...yn],[x,y0,y1,...yn],...] and each plot process with check the if something was added to dat.
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows
def plot(datax, datay, name):
x = datax
y = datay**2
plt.scatter(x, y, label=name)
plt.legend()
plt.show()
def multiP():
if __name__ == "__main__":
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
if True:
#input('Vlaue: ') # while commented plots are shown
multiP()
The following code produces two figures as desired.
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
#multiprocessing.freeze_support() # <- may be required on windows
def plot(datax, datay, name):
x = datax
y = datay**2
plt.scatter(x, y, label=name)
plt.legend()
plt.show()
def multiP():
for i in range(2):
p = multiprocessing.Process(target=plot, args=(i, i, i))
p.start()
if __name__ == "__main__":
input('Value: ')
multiP()
Taking ImportanceOfBeingErnest answer, I leave below an implementation which only shows one window and waits for the window to close, which can be very handy. Every time it is called, it displays a new window with the corresponding image (a new pocess will be started for each image). I used a lot to view images when stopped at some breakpoint during debug.
# Library packages needed
import numpy as np
import datetime
import sys
import queue
import multiprocessing
# Plot related packages
import matplotlib.pyplot as plt
def showImage(img: np.ndarray, title: str = str(datetime.datetime.today())):
"""Show an image in a new process without blocking. Usefull for debugging.
Args:
img (np.ndarray): Image to be shown
title (str, optional): Title to be shown. Defaults to
str(datetime.datetime.today()).
"""
def plot(q, title):
fig = plt.figure()
fig.suptitle(title)
try:
q.get(True, 2.0) # Wait a couple of seconds
except queue.Empty:
print('Not image received to plot...quitting')
sys.exit()
plt.imshow(img)
plt.show()
sys.exit()
# Create a queue to share data between process
q = multiprocessing.Queue()
# Create and start the process
proc = multiprocessing.Process(None, plot, args=(q, title))
proc.start()
q.put(img)
To run it, just save this to a show_image.py file and call
from show_image.py import showImage
show_image(img, title)
Python 3.5, windows 10 Pro.
I'm trying to continuously plot an 8x8 array of pixels (for the sake of the question I'll just use random data, but in the real thing I'm reading from a serial port).
I can do it using a while loop, but I need to switch over to matplotlib.animation.FuncAnimation and I can't get it to work. I've tried looking at the help files and tried to follow examples from matplotlib.org here, but I've not been able to follow it.
Can someone help me figure out how to continuously plot an 8x8 array of pixels using FuncAnimation and pcolormesh? Here is what I've got so far:
import scipy as sp
import matplotlib.pyplot as plt
from matplotlib import animation
plt.close('all')
y = sp.rand(64).reshape([8,8])
def do_something():
y = sp.rand(64).reshape([8,8])
fig_plot.set_data(y)
return fig_plot,
fig1 = plt.figure(1,facecolor = 'w')
plt.clf()
fig_plot = plt.pcolormesh(y)
fig_ani = animation.FuncAnimation(fig1,do_something)
plt.show()
If you want to see the while loop code, just so you know exactly what I'm trying to reproduce, see below.
import scipy as sp
import matplotlib.pyplot as plt
plt.figure(1)
plt.clf()
while True:
y = sp.rand(64).reshape([8,8])
plt.pcolormesh(y)
plt.show()
plt.pause(.000001)
I was able to find a solution using imshow instead of pcolormesh. In case anyone else is struggling with the same issues I had, I've posted the working code below.
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Hz = sp.rand(64).reshape([8,8]) # initalize with random data
fig = plt.figure(1,facecolor='w')
ax = plt.axes()
im = ax.imshow(Hz)
im.set_data(sp.zeros(Hz.shape))
def update_data(n):
Hz = sp.rand(64).reshape([8,8]) # More random data
im.set_data(Hz)
return
ani = animation.FuncAnimation(fig, update_data, interval = 10, blit = False, repeat = False)
fig.show()