I'm facing a problem working with multiple threads in Python. Let me give the context, I'm trying to read values from an oscilloscope and make a histogram in real time. But the problem is the plotting in real time make my measurements very slow.
So I thought to read the values from the oscilloscope in one thread and then plot the histogram in another thread - which should fix the slowness. Since I'm a beginner with python and I'm getting a lot of errors.
This is my code I wrote:
import time
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import PercentFormatter
from numpy.core.shape_base import block
import pyvisa
import os
from matplotlib.pyplot import figure, step
from scipy.signal import find_peaks
import queue
import threading
def acquisition(queue, name):
rm = pyvisa.ResourceManager()
rta = rm.open_resource('TCPIP::192.168.100.101::INSTR')
path='Desktop/Laboratorio/Programacion-
Automatizacion/Pyvisa/Output/'
rta.write("MEASurement1:TIMeout:AUTO")
valuep = []
aux = 0
#Comprobamos que no existen ya esos ficheros
if os.path.isfile(path + name + '.txt'):
os.remove(path + name + '.txt')
if os.path.isfile(path + name + '.png'):
os.remove(path + name + '.png')
start_time = time.time()
aux
entries=1000
gain=0
completed = 0
while len(valuep) < entries:
if rta.query("*OPC?"):
p1=float(rta.query("CURSor1:Y1Position?"))
if rta.query("*OPC?"):
p2=float(rta.query("CURSor1:Y2Position?"))
r=(p1-p2)
valuep.append(r)
a = np.array(valuep)
completed = len(valuep)/entries*100
print(str(completed) + ' %\n')
hist, bin_edges = np.histogram(a, 300)
bin_edges = bin_edges[1:]
peaks, _ = find_peaks(hist, distance=10, prominence=10)
sumDelta = 0
if len(peaks) >= 2:
sumDelta = 0
for i in range(len(peaks)-1):
deltaV=bin_edges[peaks[i+1]]-bin_edges[peaks[i]]
sumDelta += deltaV
gain=(sumDelta/(len(peaks)-1))/(50*1.602e-19)
if completed == 10 or completed == 20 or completed == 30 or
completed == 40 or completed == 50 or completed == 60 or
completed == 70 or completed == 80 or completed == 90 or
completed == 100:
auxLen = np.arange(0 , len(valuep) , 1)
with open(path + name + '.txt', 'w') as f:
f.write(str(gain) + ' | ' + str(round((time.time() -
start_time)/60, 3)) + '\n')
for i in auxLen:
f.write(str(valuep[i]))
f.write('\n')
message = a
queue.put(message)
rta.close()
def histogram(queue, name):
while True:
message = queue.get()
plt.cla()
# plt.xlabel("Vs | %=" + str(round(len(valuep)/entries*100, 3)) + " | Time: " + str(round((time.time() - start_time)/60, 3)) + " min")
plt.ylabel("Bins")
plt.yscale('log')
hist, bin_edges = np.histogram(message, 300)
bin_edges = bin_edges[1:]
plt.plot(bin_edges, hist)
# plt.plot(bin_edges[peaks], hist[peaks], "x")
plt.show()
plt.tight_layout()
if __name__ == "__main__":
print('Input code name: ')
name = input()
q = queue.Queue()
acquire = threading.Thread(target=acquisition, args=(q, name,))
hist = threading.Thread(target=histogram, args=(q, name,))
acquire.start()
hist.start()
acquire.join()
hist.join()
q.join()
plt.plot()
The function acquire
reads values from oscilloscope and return it to a queue as a numpy array.
The error is:
UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.
I really appreciate your help and any comments, to how should I proceed. Thanks in advance.
This is the code I had at first:
#librerias
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import PercentFormatter
import pyvisa
import time
import os
from itertools import count
from matplotlib.animation import FuncAnimation
from matplotlib.pyplot import figure, step
from scipy.signal import find_peaks
#Abrir sesion VISA
rm = pyvisa.ResourceManager()
rta = rm.open_resource('TCPIP::192.168.100.101::INSTR')
print('Input code name: ')
name=input()
path='Desktop/Laboratorio/Programacion-Automatizacion/Pyvisa/Output/'
rta.write("MEASurement1:TIMeout:AUTO")
rta.write("SYSTem:COMMunicate:INTerface:ETHernet:TRANsfer FD100")
rta.write("FORM BIN") # // Set BIN data format
valuep = []
aux = 0
#Comprobamos que no existen ya esos ficheros
if os.path.isfile(path + name + '.txt'):
os.remove(path + name + '.txt')
if os.path.isfile(path + name + '.png'):
os.remove(path + name + '.png')
start_time = time.time()
def animate(i):
global aux
entries=1000
gain=0
if rta.query("*OPC?"):
p1=float(rta.query("CURSor1:Y1Position?"))
if rta.query("*OPC?"):
p2=float(rta.query("CURSor1:Y2Position?"))
r=(p1-p2)
valuep.append(r)
a = np.array(valuep)
plt.cla()
plt.xlabel("Vs | %=" + str(round(len(valuep)/entries*100, 3)) + " | Time: " + str(round((time.time() - start_time)/60, 3)) + " min")
plt.ylabel("Bins")
plt.yscale('log')
hist, bin_edges = np.histogram(a, 300)
bin_edges = bin_edges[1:]
plt.plot(bin_edges, hist)
peaks, _ = find_peaks(hist, distance=10, prominence=10)
sumDelta = 0
if len(peaks) >= 2:
sumDelta = 0
for i in range(len(peaks)-1):
deltaV=bin_edges[peaks[i+1]]-bin_edges[peaks[i]]
sumDelta += deltaV
gain=(sumDelta/(len(peaks)-1))/(50*1.602e-19)
#print(gain)
plt.plot(bin_edges[peaks], hist[peaks], "x")
plt.show()
plt.tight_layout()
#Escritura fichero CSV
if len(valuep) == entries:
auxLen = np.arange(0 , len(valuep) , 1)
with open(path + name + '.txt', 'w') as f:
f.write(str(gain) +'\n')
for i in auxLen:
f.write(str(valuep[i]))
f.write('\n')
plt.savefig(path + name + '.png')
ani = FuncAnimation(plt.gcf(), animate, interval=0.013)
plt.tight_layout()
plt.show()
rta.close()
This code work just like I want, but very very slow, Im speaking that plotting with aniFunction need 96min for 15000 acquisition and without anifunc need 26min for 30000 acquisition, thats why Im trying with threads.