I'm making an oscilloscope with python and Arduino UNO. And I'm having two strange problems. First, I would like to emphasize that my code works, but I want to understand why these problems happen.
Firstly, if I try to title my figure, my code stops working. I've commented and ended with 3 question marks ??? the three lines concerned.
See code:
My second question is why the buttons are not colorful (they are all black) and not clickable. See image
import serial
import numpy as np
import matplotlib.pyplot as plt
from drawnow import *
voltsent = [] #le signal reçu en chaine de caractères
signalsentfloat = [] #le signal reçu converti en float
ser = serial.Serial("com9",115200)
#affichage interactive des données
plt.ion()
cnt = 0
def figuresignal(): #fonction qui affiche le siganl analogue
#fig = plt.figure() ???
plt.grid(True)
#plt.legend(loc='upper left')
plt.subplot(2,1,1)
#fig.suptitle('Visualisation de signaux générés par le GBF') ???
plt.ylabel('Signal')
plt.plot(voltsent, '.')
plt.subplot(2,1,2)
plt.ylabel('Fourrier Transform')
plt.plot(voltsentFT, '-')
while True: #while loop that loops forever
while(ser.inWaiting()==0) :#wait here until there is a data
pass
signalsent = ser.readline() #read line of text from serial port
signalsentfloat = float(signalsent) #convert it
voltsent.append(signalsentfloat) #append its values to array
voltsentFT = np.fft.fft(voltsent)
drawnow(figuresignal) #call drawnow to update our the graph
#plt.pause(.000001)
cnt = cnt+1
if(cnt>50):
voltsent.pop(0)
fig = plt.figure() creates a new figure. So you would end up with a lot of figures, eventually leading the application to crash. What you want instead is to have one single figure, so put fig = plt.figure() outside the loop.
Since this would still plot a lot of lines on top of each other, the better option is to update the lines.
import serial
import numpy as np
import matplotlib.pyplot as plt
voltsent = [] #le signal reçu en chaine de caractères
signalsentfloat = [] #le signal reçu converti en float
ser = serial.Serial("com9",115200)
#affichage interactive des données
plt.ion()
cnt = 0
fig = plt.figure()
fig.suptitle(u'Visualisation de signaux générés par le GBF')
ax = plt.subplot(2,1,1)
ax.grid(True)
ax.set_ylabel('Signal')
line1, = ax.plot([],".")
ax2 = plt.subplot(2,1,2)
ax2.grid(True)
ax2.set_ylabel('Fourrier Transform')
line2, = ax2.plot([],"-")
def figuresignal(): #fonction qui affiche le siganl analogue
line1.set_data(np.arange(len(voltsent)),voltsent )
line2.set_data(np.arange(len(voltsentFT)),voltsentFT )
while True: #while loop that loops forever
while(ser.inWaiting()==0) :#wait here until there is a data
pass
signalsent = ser.readline() #read line of text from serial port
signalsentfloat = float(signalsent) #convert it
voltsent.append(signalsentfloat) #append its values to array
voltsentFT = np.fft.fft(voltsent)
figuresignal()
plt.pause(.001)
cnt = cnt+1
if(cnt>50):
voltsent.pop(0)
I've found a solution to my problem in above question by following a tutorial on Toptechboy.com
To give a title to my graph I used the function : plt.title('Le titre ici')
Related
I have programmed Raspberry Pi 3 to plot ECG SIgnal. I have used matplotlib library in Python2.7. Arduino board has been used to acquire the analog inputs.
the GUI created contains 2 subplots that reads signal from 2 analog pins of the arduino.
Now i need to detect the R peaks from the live ECG signal.
I have tried several codes to detect but i am unable to detect it in the same plot.
Please suggest how do i add the r-peak detection code in the code below of the real-time ECG signal plotting.
This is my code below:-
import serial
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
ser = serial.Serial('/dev/ttyACM0', 115200)
n = 200
fig = plt.figure(figsize=(12,9))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)
ch1, = ax1.plot([], [], 'b', label = 'Channel 1')
ch2, = ax2.plot([], [], 'r', label = 'Channel 2')
axes = [ax1, ax2]
for ax in axes:
ax.set_xlim(0, n+1)
ax.set_ylim(0, n-1)
ax.set_ylabel('values')
ax.legend(loc='upper right')
ax.grid(True)
ax1.set_title('Real-time ECG plot')
ax2.set_xlabel('Values')
t = list(range(0,n))
channel1 = [0] * n
channel2 = [0] * n
def init():
ch1.set_data([], [])
ch2.set_data([], [])
return ch1, ch2,
def animate(i):
while (ser.inWaiting() == 0):
pass
arduinoString = ser.readline()
dataArray = arduinoString.split(',')
channel1.append(float(dataArray[0]))
channel2.append(float(dataArray[1]))
channel1.pop(0)
channel2.pop(0)
ch1.set_data(t, channel1)
ch2.set_data(t, channel2)
return ch1, ch2, ch3,
delay = 0
anim = animation.FuncAnimation(fig, animate, init_func=init,interval=delay, blit=True)
plt.show()
ser.close()
I am trying to do a multipectral camera calibration using Open Cv2 and Python 2.7, and the code is working well with the pictures that I have from the 3 monochrome sensors (RED, NIR, and GRE) and the RGB ones. The only pictures that are not working in the code are the pictures from the REG sensor (Red Green).
The code reads the pictures, converts them to gray and then finds the corners, the SubPixels, and finally producres a camera calibration matrix.
I have built the code with multiple print in each part so that I will know which is the exact part that is not working, so I know that it is not working for the REG case in the cv2.findChessboardCorners line.
ret, Bords_Trouves = cv2.findChessboardCorners(Images_en_gris, Lignes_et_Collones, None)
So my question is :
What's not working in the code ? Or is it a problem with the REG sensor pictures, I would have to try another approach to convert them to gray ? Or what ?
Here is all the code:
# -*- coding: utf-8 -*-
import numpy as np
import cv2
import glob
import math
import pickle
import matplotlib.pyplot as plt
critere = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_COUNT, 10, 0.01)
Lignes = 13
Collones = 13
Collones_et_Lignes = (Collones, Lignes)
Lignes_et_Collones = (Lignes, Collones)
Points_Reels = np.zeros((Lignes*Collones, 3), np.float32)
Points_Reels[:, :2] = np.mgrid[0:Lignes, 0:Collones].T.reshape(-1, 2)
# Préparer deux tableaux pour sauvegarder les points objet et points images de totues les images trouvées.
Tableau_points_reels = []
Tableau_points_imaginaires = []
# Les photos du damier qu'on a pris pour le test
Source = "C:/Users/Mourad/Desktop/Calib1804/REG/"
Mes_Images = glob.glob(Source + '*.TIF')
print "les images ont bien étaient récupérées." if Mes_Images else "PROBLEME: images non récupérés !! "
for leo, fname in enumerate(Mes_Images):
print("Image : " + fname)
#if leo > 10:
# break
image_originale = cv2.imread(fname)
Images_en_gris = cv2.cvtColor(image_originale, cv2.COLOR_BGR2GRAY)
print "les images ont bien étaient transformés en gris." if Images_en_gris.all() else "PROBLEME: images non transformés en gris!! "
ret, Bords_Trouves = cv2.findChessboardCorners(Images_en_gris, Lignes_et_Collones, None)
print str(len(Bords_Trouves)) + " Bords trouvés" if ret else "PROBLEME: Bords Non trouvés !!"
Tableau_points_reels.append(Points_Reels)
PL = (11, 11)
Plus_de_precision = cv2.cornerSubPix(Images_en_gris, Bords_Trouves[1], PL, (-1, -1), critere)
print "Sub pixels trouvées" if Plus_de_precision else "PROBLEME: Pas de sub pixels trouvées"
Tableau_points_imaginaires.append(Bords_Trouves)
# far = cv2.drawChessboardCorners(image_originale, Lignes_et_Collones, Bords_Trouves, ret)
#cv2.imshow("Bords trouvées déssinés sur l'image originale", image_originale)
#cv2.waitKey(500)
#()
print "Nombre de points réels trouvés: " + str(len(Tableau_points_reels))
print "Nombres de points imaginaires trouvés: " + str(len(Tableau_points_imaginaires))
h, w = Images_en_gris.shape[:2]
derik, matrice, distortion, vecteur_de_rotation, vecteur_de_translation = cv2.calibrateCamera(Tableau_points_reels, Tableau_points_imaginaires, (w, h), None, None, flags=cv2.CALIB_RATIONAL_MODEL)
print "La matrice de calibration est: "
print matrice
print "La distortion est egale a: "
print distortion
print "Le vecteur de rotation est egal a: "
print vecteur_de_rotation
print "Le vecteur de translation est egal a: "
print vecteur_de_translation
print "\n La matrice de calibration trouvée et données récupérés" if derik else "PROBLEME: Pas de calibration"
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(matrice, distortion, (w, h), 1, (w, h))
# undistortion
Image_calibree = cv2.undistort(image_originale, matrice, distortion, None, newcameramtx)
fgh = cv2.imread("C:/Users/Mourad/Desktop/Calib1804/RGB/IMG_700101_000800_0000_RGB.JPG")
h, w = fgh.shape[:2]
x, y, w, h = roi
Image_calibree = Image_calibree[y:y+h, x:x+w]
cv2.imwrite('Desktop/imagecalibre.png', Image_calibree)
plt.subplot(121), plt.imshow(fgh), plt.title('image originale')
plt.subplot(122), plt.imshow(Image_calibree), plt.title('image calibree')
plt.show()
Erreur_totale = 0
for i in xrange(len(Tableau_points_reels)):
imgpoints2, _ = cv2.projectPoints(Tableau_points_reels[i], vecteur_de_rotation[i], vecteur_de_translation[i], matrice, distortion)
Erreur = cv2.norm(Tableau_points_imaginaires[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2)
Erreur_totale += Erreur
print "Erreur totale: ", Erreur_totale/len(Tableau_points_reels)
cv2.destroyAllWindows()
If that same piece of code worked for the images from other sensors there has to be something wrong with the pictures you hand to cv2.findChessboardCorners.
Try visualizing the images with cv2.imshow before the go into the function. Probably the color conversion is wrong because with cv2.COLOR_BGR2GRAY a 3-channel image is converted to grayscale but you should have two channels, if I understood your format right.
cv2.findChessboardCorners should also work with color images so the easiest solution may just be skipping the color conversion if that's what messes up your images.
Using Matplotlib and a for loop, is it possible to display a plot for a given period of time and then have it close when the for loop is done?
I have tried the following, but the plot simply remains open and the loop doesn't end:
import matplotlib.pyplot as plt
import psychopy
x = [34.00,108.00,64.00,99.00,99.00,51.00]
y = [5.00,17.00,11.00,8.00,14.00,5.00]
scatter(x, y, color = "black")
clock = core.Clock()
while clock.getTime() < 10.0:
plt.show()
plt.close()
Thanks
You can use interactive mode plt.ion() in combination with plt.pause().
E.g. to show your window for 5 seconds:
import matplotlib.pyplot as plt
x = [34.00,108.00,64.00,99.00,99.00,51.00]
y = [5.00,17.00,11.00,8.00,14.00,5.00]
plt.scatter(x, y, color = "black")
plt.ion()
plt.draw()
plt.pause(5)
I am trying to extract just the alpha carbon coordinates and plot them in a 3D representation. The top half of the following code works fine, but I can't seem to plot my results.
import re
import glob
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
coord = []
pattern = re.compile('ATOM\s{5,}\d+\s{2}CA\s{2,}\w{3}\s\w\s{2,}\d+\s{6}\d+\.\d+\s\d+\.\d+\s{2}\d+\.\d+', flags=re.S)
for file in glob.glob('file_rank_1.pdb'):
with open(file) as fp:
for result in pattern.findall(fp.read()):
output = result[-22:]
coord = " ".join(output.split())
coord = coord.replace(" ",",")
c = coord.split(',')
print(c)
X,Y,Z = (c)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X,Y,Z)
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
plt.show()
My results from running the above looks like...
['72.438', '109.283', '43.980']
['75.664', '110.907', '45.079']
['74.354', '111.094', '48.594']
['73.380', '107.449', '48.722']
['76.614', '106.603', '46.958']
['79.740', '105.625', '48.895']
['82.425', '107.703', '47.318']
['80.088', '110.405', '46.265']
['78.710', '110.389', '49.818']
['82.235', '110.471', '51.200']
['82.841', '113.550', '49.133']
['79.233', '114.754', '49.675']
['78.633', '113.745', '53.295']
['77.041', '117.182', '53.503']
['73.963', '116.530', '51.505']
['73.696', '113.058', '52.933']
TypeError: Cannot cast array data from dtype('float64') to dtype('<U32') according to the rule 'safe'
The above code opens the graph interface, but it remains blank. There is also a full screen of red file messages from the interactive shell that I left off to try to save space in this question.
How can I plot the numbers found in c? Thanks
There are a few things to point out:
1) In the following block, c is a list of strings not floats.
with open(file) as fp:
for result in pattern.findall(fp.read()):
output = result[-22:]
coord = " ".join(output.split())
coord = coord.replace(" ",",")
c = coord.split(',')
print(c)
You can change them using:
[float(i) for i in c]
2) When you set X,Y,Z = (c), that c is only the last item in the loop. So you should append each c within the loop to collect all coordinates.
3) You might want to use numpy for array manipulations.
So hopefully the following will work:
import re
import numpy as np
import glob
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
points = []
pattern = re.compile('ATOM\s{5,}\d+\s{2}CA\s{2,}\w{3}\s\w\s{2,}\d+\s{6}\d+\.\d+\s\d+\.\d+\s{2}\d+\.\d+', flags=re.S)
for file in glob.glob('file_rank_1.pdb'):
with open(file) as fp:
for result in pattern.findall(fp.read()):
output = result[-22:]
coord = " ".join(output.split())
coord = coord.replace(" ",",")
c = coord.split(',')
c = [float(i) for i in c] # change them to float
points.append(c)
print(c)
X,Y,Z=np.array(points).T
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X,Y,Z)
ax.set_xlabel('x axis')
ax.set_ylabel('y axis')
ax.set_zlabel('z axis')
plt.show()
import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
from collections import deque
port = "COM11"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
a1 = deque([0.0]*100)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([0,1000])
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
print(a1)
a1.appendleft((data))
datatoplot = a1.pop()
line.set_ydata(a1)
plt.draw()
I am getting a plot between serial port values and sample points. I want to plot serial plot values vs time. Is there a way to convert sample points to time values, something like how to we convert sample point to frequency values using freqs = scipy.fftpack.fftfreq(n, d)
Thanks
If you want to plot the data against time from the start of the program, then:
import time
t0 = time.time()
tlist = deque([np.nan] * 100)
while 1:
# read the serial data ...
# when you have read a sample, capture the time difference
# and put it into a queue (similarly to the data values)
deltat = time.time() - t0
dlist.appendleft((deltat))
# remember to pop the data, as well
dlist.pop()
a1.pop()
# set the x and y data
line.set_xdata(tlist)
line.set_ydata(a1)
# draw it
plt.draw()
Now you have the number of seconds from the start of the program on the X axis.
If you want to have the real time shown, then use datetime.datetime objects:
import datetime
dlist = deque([datetime.datetime.now()] * 100)
while 1:
# capture the serial data ...
dilst.appendleft((datetime.datetime.now()))
# everything else as above
This should give you a plot with real time on the X axis.
import sys
import serial
import numpy as np
import matplotlib.pyplot as plt
import time
from collections import deque
from scipy import arange
port = "COM13"
baud = 9600
timeout=1
ser = serial.Serial()
ser.port = port
ser.baudrate = baud
ser.timeout = timeout
t0=time.time()
tlist = deque([np.nan]*10)
a1 = deque([0.0]*10)
#ax = plt.axes(xlim=(0, 100), ylim=(0, 1000))
line, = plt.plot(a1)
plt.ion()
plt.ylim([-100,100])
plt.grid(b=True,which= 'major' , color= 'g' , linestyle= '--')
#plt.grid(b=True,which= 'minor' , color= '-m' , linestyle= '--')
try:
ser.open()
except:
sys.stderr.write("Error opening serial port %s\n" % (ser.portstr) )
sys.exit(1)
#ser.setRtsCts(0)
while 1:
# Read from serial port, blocking
data = ser.read(1)
# If there is more than 1 byte, read the rest
n = ser.inWaiting()
data = data + ser.read(n)
#sys.stdout.write(data)
#print(a1)
#data1=int(data)-128
deltat = time.time() - t0
tlist.appendleft((deltat1))
datatoplot = tlist.pop()
a1.appendleft((data))
datatoplot = a1.pop()
line.set_xdata(tlist)
line.set_ydata(a1)
plt.hold(False)
plt.draw()
This is the complete code I used, and yes I had already changed that line.pop . But as I explained earlier in the comment I am not able to get the time values in x axis