Update plot in for loop in function - python-3.x

I'm trying to call a function like in the example below, and plot while running the code. The real values that I get as y-data are not really random numbers, but the point is that I would like it to get updated real-time. The plot in my example code below is just empty though and isn't getting updated.
import numpy as np
import matplotlib.pyplot as plt
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
fig, ax = plt.subplots()
sc = ax.scatter(x_data, y_data)
plt.draw()
for i in range(0, number_of_runs):
x_data.append(i+1)
y_data.append(rnd.randint(0,100))
sc.set_offsets(np.c_[x_data, y_data])
fig.canvas.draw_idle()
plt.pause(0.1)
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
multiple_runs(100)
UPDATE:
Thanks #ImportanceOfBeingErnest , I got the code to work. However my problem right now is that the figure closes down as soon as it's finished, is there anyway to keep it open? I tried using plt.waitforbuttonpress() but I get a strange error from QTimer, not sure how or why. This is my working example code;
import numpy as np
import matplotlib.pyplot as plt
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
plt.draw()
for i in range(0, number_of_runs):
x_data.append(i+1)
y_data.append(rnd.randint(0,100))
x_data2.append(i+1)
y_data2.append(rnd.randint(0,100))
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
fig.canvas.draw_idle()
plt.pause(0.1)
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
multiple_runs(100)
UPDATE2:
I tried using FuncAnimation, but getting the error TypeError: update() missing 2 required positional arguments: 'y' and 'y2'. I still need to use the for-loop because in my real code I'm using the previous values of y, to calculate the next values of y. This is my example code which is giving me the error;
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
def update(i, y, y2):
x_data.append(i+1)
y_data.append(y)
x_data2.append(i+1)
y_data2.append(y2)
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
print ('Total time after run number ' + str(i+1) + ': ' + str(time.time() - initial_time))
for i in range(0, number_of_runs):
y = rnd.randint(0,100)
y2 = rnd.randint(0,100)
update(i,y,y2)
ani = FuncAnimation(fig, update, frames=number_of_runs, interval=100, repeat=False)
plt.show()
multiple_runs(100)

As commented, I would recommend to use FuncAnimation. This would look as follows in your case. Note that in order to close the window, one would need to press q or close it with the mouse.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random as rnd
import time
initial_time = time.time()
def multiple_runs(number_of_runs):
x_data, y_data = [], []
x_data2, y_data2 = [], []
fig, ax = plt.subplots(2, sharex = True)
sc = ax[0].scatter(x_data, y_data)
sc2 = ax[1].scatter(x_data2, y_data2)
ax[0].set(xlim=(0,100), ylim=(0,100))
ax[1].set(xlim=(0,100), ylim=(0,100))
def get_ydata(i):
y = rnd.randint(0,100)
y2 = rnd.randint(0,100)
return y, y2
def update(i):
y, y2 = get_ydata(i)
x_data.append(i+1)
y_data.append(y)
x_data2.append(i+1)
y_data2.append(y2)
sc.set_offsets(np.c_[x_data, y_data])
sc2.set_offsets(np.c_[x_data2, y_data2])
ani = FuncAnimation(fig, update, frames=number_of_runs, interval=100, repeat=False)
plt.show()
multiple_runs(100)

Related

How to set Timestamp (pandas Datetime) to xlim of plot with FunctAnimation?

I want to limit my graph from left and set (the current time - 2 hours) to xlim. I tried to add to the "update" function this
self.ax.set_xlim(left=max(self.data.iloc[0, 0], self.data.iloc[-1, 0] - pd.Timedelta(hours=2)))
But this is doesn't work. Could anyone help me do this, please?
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from datetime import datetime
import pandas as pd
def to_pd(wt, wf):
p = pd.DataFrame({"Date": [wt], "Cost": [wf]})
p["Date"] = pd.to_datetime(p["Date"], format='%Y-%m-%d %H:%M:%S')
return p
fig = plt.figure(figsize=(18,8), dpi=90)
class Graph():
def __init__(self):
self.ax = fig.add_subplot()
self.start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.data = to_pd(self.start_time,0)
self.line, = self.ax.plot(self.data.Date,self.data.Cost)
def update(self,i):
self.current_time = (self.data.iloc[-1,0]+pd.Timedelta(minutes=1)).strftime('%Y-%m-%d %H:%M:%S')
self.data = self.data.append(to_pd(self.current_time,(-1)**i))
self.line.set_data(self.data.Date, self.data.Cost)
self.ax.relim()
self.ax.autoscale_view()
return self.line,
object = Graph()
def animate(i):
return object.update(i)
anim = FuncAnimation(fig, animate, frames=200,interval=100, blit=True)
plt.show()
Solved, but I think there is more convenient way. But, here what am done, just added it into the 'update' function, it's clear all old data:
if self.data.iloc[-1, 0] - pd.Timedelta(hours=2) >= self.data.iloc[0, 0]:
self.data = self.data[self.data.Date > self.data.iloc[0, 0]]

How to dynamic plot with data from database instead of .txt?

I have a code that mimics a sensor, putting random values and timestamps on a txt file. From this file, being constantly updated, I can dynamic plot those values. Now my idea is to do the same thing, but getting data from a database. I'm already able to save whatever data comes for my server into the database. The thing now is the dynamic plot area.
My code for saving data into the table:
while True:
data = conn.recv(2048).decode('utf-8')
if not data:
break
#print('Servidor recebeu :', repr(data))
t = dt.datetime.now().strftime('%H:%M:%S')
c.execute('INSERT INTO edgedata VALUES (?,?)', (data, t))
con.commit()
My code for dynamic plotting from .txt file:
#!/usr/bin/env python
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
print("inside animate")
pullData = open("datatest.txt","r").read()
dataArray = pullData.split('\n')
xar = []
yar = []
for eachLine in dataArray:
if len(eachLine)>1:
x,y = eachLine.split(',')
xar.append(str(x))
yar.append(float(y))
ax1.clear()
ax1.plot(xar,yar)
plt.xlabel('Hora')
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.ylabel('Valor Dado')
plt.title('Pseudo-Sensor x Hora')
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Any help will be appreciated. Thanks in advance!
This code did the job for me. Thanks
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
print("inside animate")
con = sqlite3.connect('edgedb')
c = con.cursor()
c.execute('SELECT data, timestamp FROM edgedata')
data = c.fetchall()
datas = []
dates = []
for row in data:
datas.append(row[1])
dates.append(float(row[0]))
ax1.clear()
ax1.plot_date(datas,dates,'-')
plt.xlabel('Hora')
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.ylabel('Valor Dado')
plt.title('Pseudo-Sensor x Hora')
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()

Can we save our trained dataset into xml format using pickle

Can we able to store our own trained dataset in xml format using pickle?
import numpy as np
import random
import pickle
import matplotlib
gui_env = [i for i in matplotlib.rcsetup.interactive_bk]
non_gui_backends = matplotlib.rcsetup.non_interactive_bk
print ("Non Gui backends are:", non_gui_backends)
print ("Gui backends I will test for", gui_env)
for gui in gui_env:
print ("testing", gui)
try:
matplotlib.use(gui,warn=False, force=True)
from matplotlib import pyplot as plt
print (" ",gui, "Is Available")
plt.plot([1.5,2.0,2.5])
fig = plt.gcf()
fig.suptitle(gui)
print ("Using ..... ",matplotlib.get_backend())
except:
print (" ",gui, "Not found")
import os
import cv2
from tqdm import tqdm
DATADIR = "Datasets/PetImages"
CATEGORIES = ["Dog", "Cat"]
training_data = []
IMG_SIZE = 50
def create_training_data():
for category in CATEGORIES:
path = os.path.join(DATADIR,category)
class_num = CATEGORIES.index(category)
for img in tqdm(os.listdir(path)):
try:
img_array = cv2.imread(os.path.join(path,img) ,cv2.IMREAD_GRAYSCALE)
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
training_data.append([new_array, class_num])
except Exception as e:
pass
random.shuffle(training_data)
X = []
y = []
for features,label in training_data:
X.append(features)
y.append(label)
print(X[0].reshape(-1, IMG_SIZE, IMG_SIZE, 1))
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
pickle_out = open("X.xml","wb")
pickle.dump(X, pickle_out)
pickle_out.close()
pickle_out = open("y.xml","wb")
pickle.dump(y, pickle_out)
pickle_out.close()
create_training_data()
print(len(training_data))

Main thread not in main loop error in threading module

import time
import datetime as dt
import urllib.request
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
import matplotlib.animation as Animation
from matplotlib import style
import matplotlib
import csv
import threading
style.use('fivethirtyeight')
fig = plt.figure()
def usd_in_bitcoin():
try:
resp = urllib.request.urlopen("https://bitcoinwisdom.com/")
except Exception as e:
print(e)
text = resp.read()
soup = BeautifulSoup(text, 'html.parser')
intermediate = soup.find('tr', {"id": "o_btcusd"})
ans = intermediate.find('td', {'class': 'r'})
return ans.contents[0]
def write_to_file(interval):
while True:
value = str(usd_in_bitcoin())
unix_time = str(time.time())
print(unix_time, value)
with open('bitcoin_usd.csv', 'a+') as file:
file.write(unix_time)
file.write("," + str(value))
file.write('\n')
time.sleep(interval)
def animate(i):
with open('bitcoin_usd.csv') as csv_file:
readcsv = csv.reader(csv_file, delimiter=',')
xs = []
ys = []
for row in readcsv:
if len(row) > 1:
x, y = [float(s) for s in row]
xs.append(dt.datetime.fromtimestamp(x))
ys.append(y)
print(len(xs))
dates = matplotlib.dates.date2num(xs)
# print(dates)
fig.clear()
plt.plot_date(dates, ys)
def plotting():
ani = Animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
def main():
# plotting()
b = threading.Thread(name='making graph', target=plotting)
# a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
# a.start()
b.start()
if __name__ == '__main__':
main()
In the above block of code, I am trying to plot the value of a bitcoin in usd by using scraping and then putting the value in a csv file.
Then I read the csv file to plot the graph.
Both plotting and scraping seem to work fine but if I do both of them simultaneously, I am getting an error saying main thread not in main loop. I searched a lot but was not able to solve this problem
The problem here is with the sequence of lines in main()
Try this:
def main():
a = threading.Thread(name='updating_csv', target=write_to_file, args=(5,))
a.start()
b = threading.Thread(name='making graph', target=plotting)
b.start()
plotting()

How to run two python scripts in parallel on Windows

I currently have two python scripts, one is for writing data into a file and the other one is for reading data continuously from that file at the same time and do plotting. I want to create a third script which can automatically run these two scripts at the same time ( actually one slightly ahead of another because the file needs to be created for the other script to read from it).
So here is my code:
import serial
import sys
import Queue
import threading
import scipy.io
import numpy as num
from mpl_toolkits.mplot3d import *
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib.animation as animation
import time
from time import sleep
AngleText = open ("data2.txt" , "w") # open file for writing data
a= 1
b= 1
c =1
for x in range (0,20):
count = 0
sleep(0.5)
AngleText.writelines (str(a)+',')
AngleText.writelines (str(b)+',')
AngleText.writelines (str(c)+'\n')
count = count +1
a= a + 1
b= b + 2
c= c + 3
AngleText.flush()
And the plotting script:
from mpl_toolkits.mplot3d import *
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import matplotlib
import threading as thrd
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
def animate(i):
pullData = open ('data2.txt','r').read()
dataArray = pullData.split('\n')
xar = []
yar = []
zar = []
for eachLine in dataArray:
if len(eachLine)>1:
x,y,z = eachLine.split(',')
xar.append(float(x))
yar.append(float(y))
zar.append(float(z))
tx = xar.pop(0)
Floatx= float(tx)
ty = yar.pop(0)
Floaty= float(ty)
tz = zar.pop(0)
Floatz= float(tz)
x1 = [164, 94, 0, -100.5]
x2 = [164, 94, 0, -100.5]
y1= [-72.5, -103.5, -103.5, -134.5]
y2= [72.5, 103.5, 103.5, 134.5]
z1 = [112, 60, 3, 3]
z2 = [112, 60, 3, 3]
ax.plot(x1, y1, z1, color = 'b')
plt.hold(True)
ax.plot(x2, y2, z2, color = 'r')
plt.hold(True)
ax.scatter(Floatx, Floaty, Floatz)
plt.hold(False)
ani = animation.FuncAnimation(fig,animate, interval = 25)
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_zlabel('z label')
plt.show()
Any advice would be appreciated!
My current solution is:
import os
from subprocess import *
import time
from time import sleep
p = Popen([r'testing.py'], shell=True, stdin=PIPE, stdout=PIPE)
output = p.communicate()
print output[0]
sleep(0.5)
#run child script 2
p = Popen([r'realPlot2.py'], shell=True, stdin=PIPE, stdout=PIPE)
output = p.communicate()
print output[0]
By running the above code, the graph won't be able to show until the writing function is finished.
use the multiprocessing class. you can start a new process to write to the file, then call p.join() to make the main function wait for the first process to finish, then start the second process. see here:
http://docs.python.org/2/library/multiprocessing.html

Resources