plotting multiple sensor values using drawnow in python - python-2.7

I am having 7 sensors which is connected to a micro controller , the controller a sends data to a pc using serial port , i am trying to plot the sensors values in real-time using python drawnow function , can anybody help me in giving the correct syntax for the same to plot the all the sensors in the same figure

How about this for 4 sensors:
import time
import matplotlib.pyplot as plt
from drawnow import *
sensors = 4
x = dict([(s,[]) for s in range(0,sensors)]) # initialize dictionary of sensor stream values
def makePlot():
plt.subplot(411)
plt.plot(x[0],'r')
plt.subplot(412)
plt.plot(x[1],'g')
plt.subplot(413)
plt.plot(x[2],'b')
plt.subplot(414)
plt.plot(x[3],'c')
for i in range(0,100): # simulate passage of time
time.sleep(1) # 1-sec delay for each loop
for s in range(0,sensors):
x[s].append(i*s)
drawnow(makePlot)

Related

Remove weekends in finance plots with volume overlay [duplicate]

I've been having some difficulty with Matplotlib's finance charting. It seems like their candlestick charts work best with daily data, and I am having a hard time making them work with intraday (every 5 minutes, between 9:30 and 4 pm) data.
I have pasted sample data in pastebin. The top is what I get from the database, and the bottom is tupled with the date formatted into an ordinal float for use in Matplotlib.
Link to sample data
When I draw my charts there are huge gaps in it, the axes suck, and the zoom is equally horrible. http://imgur.com/y7O8A
How do I make a nice readable graph out of this data? My ultimate goal is to get a chart that looks remotely like this:
http://i.imgur.com/EnrTW.jpg
The data points can be in various increments from 5 minutes to 30 minutes.
I have also made a Pandas dataframe of the data, but I am not sure if pandas has candlestick functionality.
If I understand well, one of your major concern is the gaps between the daily data.
To get rid of them, one method is to artificially 'evenly space' your data (but of course you will loose any temporal indication intra-day).
Anyways, doing this way, you will be able to obtain a chart that looks like the one you have proposed as an example.
The commented code and the resulting graph are below.
import numpy as np
import matplotlib.pyplot as plt
import datetime
from matplotlib.finance import candlestick
from matplotlib.dates import num2date
# data in a text file, 5 columns: time, opening, close, high, low
# note that I'm using the time you formated into an ordinal float
data = np.loadtxt('finance-data.txt', delimiter=',')
# determine number of days and create a list of those days
ndays = np.unique(np.trunc(data[:,0]), return_index=True)
xdays = []
for n in np.arange(len(ndays[0])):
xdays.append(datetime.date.isoformat(num2date(data[ndays[1],0][n])))
# creation of new data by replacing the time array with equally spaced values.
# this will allow to remove the gap between the days, when plotting the data
data2 = np.hstack([np.arange(data[:,0].size)[:, np.newaxis], data[:,1:]])
# plot the data
fig = plt.figure(figsize=(10, 5))
ax = fig.add_axes([0.1, 0.2, 0.85, 0.7])
# customization of the axis
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.tick_params(axis='both', direction='out', width=2, length=8,
labelsize=12, pad=8)
ax.spines['left'].set_linewidth(2)
ax.spines['bottom'].set_linewidth(2)
# set the ticks of the x axis only when starting a new day
ax.set_xticks(data2[ndays[1],0])
ax.set_xticklabels(xdays, rotation=45, horizontalalignment='right')
ax.set_ylabel('Quote ($)', size=20)
ax.set_ylim([177, 196])
candlestick(ax, data2, width=0.5, colorup='g', colordown='r')
plt.show()
I got tired of matplotlib's (and plotly's) bad performance and lack of such features you request, so implemented one of my own. Here's how that works:
import finplot as fplt
import yfinance
df = yfinance.download('AAPL')
fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']])
fplt.show()
Not only are days in which the exchange is closed left out automatically, but also has better performance and a nicer api. For something that more resembles what you're ultimately looking for:
import finplot as fplt
import yfinance
symbol = 'AAPL'
df = yfinance.download(symbol)
ax = fplt.create_plot(symbol)
fplt.candlestick_ochl(df[['Open', 'Close', 'High', 'Low']], ax=ax)
fplt.plot(df['Close'].rolling(200).mean(), ax=ax, legend='SMA 200')
fplt.plot(df['Close'].rolling(50).mean(), ax=ax, legend='SMA 50')
fplt.plot(df['Close'].rolling(20).mean(), ax=ax, legend='SMA 20')
fplt.volume_ocv(df[['Open', 'Close', 'Volume']], ax=ax.overlay())
fplt.show()

matplotlib Help using python 2.7

Hi I am trying to make a scatter plot and annotate data points with real value of each point
but just the yLabel value
it mean take real value of the point and plot it near to the point
python code
import serial # import Serial Library
import time #import time
import numpy # Import numpy
import matplotlib.pyplot as plt #import matplotlib library
from drawnow import *
temperature= []
vitesse= []
charge= []
current= []
arduinoData = serial.Serial('com5', 9600) #Creating our serial object named arduinoData
plt.ion() #Tell matplotlib you want interactive mode to plot live data
cnt=0
def makeFig(): #Create a function that makes our desired plot
plt.subplot(2,2,1)
plt.title('Live Streaming Temperature Sensor Data')
plt.ylabel('Temperature C')
plt.grid(True)
plt.plot(temperature, 'ro-')
plt.subplot(2,2,2)
plt.title('Live Streaming Speed Sensor Data')
plt.ylabel('Speed KM/H')
plt.grid(True)
plt.plot(vitesse, 'bo-')
plt.subplot(2,2,3)
plt.title('Live Streaming SOC Sensor Data')
plt.ylabel('Battery Charge %')
plt.grid(True)
plt.plot(charge, 'go-')
plt.subplot(2,2,4)
plt.title('Live Streaming Current Sensor Data')
plt.ylabel('Current A')
plt.grid(True)
plt.plot(current, 'yo-')
while True: # While loop that loops forever
while (arduinoData.inWaiting()==0): #Wait here until there is data
pass #do nothing
arduinoString = arduinoData.readline() #read the line of text from the serial port
dataArray = arduinoString.split(';') #Split it into an array called dataArray
temp = float (dataArray[0])
vite = float (dataArray[1])
char = float (dataArray[2])
curr = float (dataArray[3])
temperature.append(temp) #Build our temperature array by appending temp readings
vitesse.append(vite) #Build our vitesse array by appending temp readings
charge.append(char) #Build our charge array by appending temp readings
current.append(curr) #Build our current array by appending temp readings
drawnow(makeFig) #Call drawnow to update our live graph
plt.pause(0.00001)
cnt=cnt+1
if(cnt>50):
temperature.pop(0)
vitesse.pop(0)
charge.pop(0)
current.pop(0)
any ideas ?????
use the annotate() function to create labels attached to specific points in your plot.
see http://matplotlib.org/users/annotations_intro.html
and http://matplotlib.org/examples/pylab_examples/annotation_demo2.html
If I understood what you were looking for, you should use plt.ticklabel_format(useOffset=False) at the end of every subplot. So that, you are going to fix the y scale. Use plt.ylim(m,n) to set the limits of the y axe, where "m" is the beggining of the axe and "n" is the end.

Plot sine wave of higher frequencies

I am sending serial data from uart to pc and trying to plot sine wave(using Python) sent from function generator through ADC12 of MSP430F5438A.
I am able to plot the wave for lower sampling frequencies(<120Hz) but when I increase the sampling frequency the digits get concatenated i.e. if two values 2563 , 2879 are sent through uart then python reads them as 25632879. So, I am not able to plot the graph as values are not correct.
I am sending the values without new line between them, if I send with new line then the values are not read correctly - python reads them with space in between so then again I get another error: could not convert string to float.
I tried data = ser.readline() as well but no luck
I am attaching the code below.Please see if anything can be done to solve this problem.
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()
Thanks
I can think of two ways for doing this reliably:
Use a delimiter . All you need is to parse the value correctly:
line = serial.readline()
reading = int(line)
If you don't want to use a delimiter then send a formatted reading from the msp:
uint8_t buffer[5];
snprintf(buffer, 4, "%04d", reading);
uart_print(buffer);
this way you will always get 4 characters per reading, so you can do this in the python code:
line = serial.read(4)
reading = int(line)
I'd still go for the first alternative, though.

plot goes to zero in between

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 using msp430f5438a board.If I send the data with a new line between each data then I am not able to plot the data because in python the sometimes data gets printed as 78_9, 7_89,_789 where _ means space so python gives me a error cannot convert string to float. But If I say send the data from uart without any new line between them then I get a nice plot but in the plot after some irregular short intervals the plot goes to zero and then becomes fine again although I checked in hyperterminal I am not receiving any zero values
My question is:
Are the two cases I described are related to each other?What can be done to rectify this problem of plot going to zero in between?Because of this I am not getting a smooth wave.
Thanks
The problem might be in the way you handle the serial interface. As you are not parsing the serial input when it comes, it is possible that you receive two messages as follows:
1.23
4.56
7.
and
89
10.11
etc. This is because your code may split the input at any point. It may be so fast that you get one digit at a time, which is probably not what you wanted.
I suggest that if you pad your data with newlines and if the data is good in a terminal program, you use the readline method.
while 1:
# read a line from the input
line = ser.readline()
# try to make a float out of it
try:
a1.appendleft(float(line))
except ValueError:
# in case we got bad input, print it and go to the next line
print "Received an invalid line '{0}'".format(line)
continue
# do the plotting
This most probably fixes your problem.
Reading asynchronous serial line is surprisingly complicated, you usually need to parse the input in-the-fly with timeouts. Fortunately, this is done by pyserial when using readline.

scikit-learn PCA doesn't have 'score' method

I am trying to identify the type of noise based on that article:
Model selection with Probabilistic (PCA) and Factor Analysis (FA)
I am using scikit-learn-0.14.1.win32-py2.7 on win8 64bit
I know that it refers on version 0.15, however at the version 0.14 documentation it mentions that the score method is available for PCA so I guess it should normally work:
sklearn.decomposition.ProbabilisticPCA
The problem is that no matter which PCA I will use for the *cross_val_score*, I always get a type error message saying that the estimator PCA does not have a score method:
*TypeError: If no scoring is specified, the estimator passed should have a 'score' method. The estimator PCA(copy=True, n_components=None, whiten=False) does not.*
Any ideas why is that happening?
Many thanks in advance
Christos
X has 1000 samples of 40 features
here is a portion of the code:
import numpy as np
import csv
from scipy import linalg
from sklearn.decomposition import PCA, FactorAnalysis
from sklearn.cross_validation import cross_val_score
from sklearn.grid_search import GridSearchCV
from sklearn.covariance import ShrunkCovariance, LedoitWolf
#read in the training data
train_path = '<train data path>/train.csv'
reader = csv.reader(open(train_path,"rb"),delimiter=',')
train = list(reader)
X = np.array(train).astype('float')
n_samples = 1000
n_features = 40
n_components = np.arange(0, n_features, 4)
def compute_scores(X):
pca = PCA()
pca_scores = []
for n in n_components:
pca.n_components = n
pca_scores.append(np.mean(cross_val_score(pca, X, n_jobs=1)))
return pca_scores
pca_scores = compute_scores(X)
n_components_pca = n_components[np.argmax(pca_scores)]
Ok, I think I found the problem. it is not working with PCA, but it does work with PPCA
However, by not providing a cv number the cross_val_score automatically sets 3-fold cross validation
that created 3 sets with sizes 334, 333 and 333 (my initial training set contains 1000 samples)
Since nympy.mean cannot make a comparison between sets with different sizes (334 vs 333), python rises an exception.
thx