Graph Sensor Data with Python and Matplotlib real time - python

I want to plot a graph using matplotlib. I am sensing data from sensor and putting that data into excel file. but I am not able to get desired output.
i am attaching the sample code link here.
Also I am attaching my code which I modified. can anyone help in this matter
import datetime as dt
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import xlrd
hsif = pd.read_excel('C:\\Users\\Hp\\Desktop\\Sensor.xlsx','Sheet2', skiprows=3)
data = hsif.columns.values[3]
print(data)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
xs = []
ys = []
# This function is called periodically from FuncAnimation
def animate(i, xs, ys):
# Read data from sensor
temp_c = data
# Add x and y to lists
xs.append(dt.datetime.now().strftime('%H:%M '))
ys.append(temp_c)
# Limit x and y lists to 20 items
xs = xs[-20:]
ys = ys[-20:]
# Draw x and y lists
ax.clear()
ax.plot(xs, ys)
# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('Call OI over Time')
plt.ylabel('Numbers')
# Set up plot to call animate() function periodically
ani = animation.FuncAnimation(fig, animate, fargs=(xs, ys), interval=1000)
plt.show()

I hope this answer is sufficient. :S that last one got deleted pretty quick lol
so i cant offer code for your situation, but i can help point you in the right direction..
I was able to achieve a live graph from sensor readings every second by doing the following
get the date and time with
timeObj = time.localtime(Epoch)
thedate = '%d-%d-%d' % (timeObj.tm_mon, timeObj.tm_mday, timeObj.tm_year)
thetime = '%d:%d:%d' % (timeObj.tm_hour, timeObj.tm_min, timeObj.tm_sec)
you could combine date and time into a single string, but i don't use date on my graphs. I wanted them in separate lists. Then, in your animate function, which is called every second. youre going to want to add a dataframe. I used pandas to open a csv (sorry i dont have experience opening excel), which automatically makes a dataframe when opened like so: (dateparse makes the time readable by matplotlib)
dateparse = lambda x: pd.datetime.strptime(x, '$H:$M:$S')
def animate(e):
headers = ['date', 'time', 'sensor']
SonarDataF = pd.read_csv('livegraph.csv', parse_dates=True, date_parser=dateparse, names=headers, skiprows=1)
then in the next lines of animate call a function to add the time and reading into the dataframe.
new_row = {'date': thedate, 'time': thetime, 'sensor': distance}
SonarDataF = SonarDataF.append(new_row, ignore_index=True)
your next few lines will check your data, once it gets to 20 rows, it deletes 1 row with every entry, which happens every 1000ms based on animation
num_rows = SonarDataF.shape[0] # limits rows allowed in graph csv
if num_rows > 20:
SonarDataF = SonarDataF.iloc[1:]
and now you have to save your new data readings pulled with the animate function into your csv (or excel, youll have to look up how to do that)
I save to 2 different files. 1 has 20 lines for the graph. and 1 is a log with every reading ever taken. if you want to go back and check readings from previous times you can open the second file and choose what to plot
SonarDataF.to_csv('livegraph.csv', index=False) # saves updated dataframe to be reloaded on next animate
lognumbers = {'date': thedate, 'time': thetime, 'sensor': sensor} # saves new time and reading to full log
csv_file = "LogData.csv"
try:
with open(csv_file, 'a') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=headers)
for data in lognumbers:
writer.writerow(lognumbers)
except IOError:
print('fuck')
# get time, and convert it for matplotlib
tim3 = SonarDataF['time']
rTime = [datetime.strptime(t, '%H:%M:%S') for t in tim3]
rSensor = SonarDataF['sensor'].astype(float)
a.clear()
a.plot(rTime,rSensor)
if you'd like to see my code that i pulled these examples from, see my question which has a working example of grabbing data from a sensor
pi4 GUI + matplotlib: Reading sensor, read/write csv, and updating matplotlib with static labels

Related

Matplotlib incorrect X & Y-axis despite correct data

My code creates 4 stock graphs (data taken from yahoo with pandas datareader) with matplotlib. The problem i SOMETIMES get is the X & Y-axis on the first graph created in the sequence of 4 graphs being created one after the other looks like this:
Matplotlib scales it entirely wrong, the numbers given to it are not years ranging from 1970 to 2020, It is only given 5 days. But as stated earlier it only sometimes happens and when the code creates the other 3 graphs there are absolutely no problems. I believe this is due to some issue happening when it creates a graph that ranges from 5-10 dollars and then quickly another graph that ranges from 50-100 dollars. I do have a time sleep between every graph being created but it doesn't seem to work.
I also can't scale it manually every time because the code has to create graphs of various stocks with various ranges on the axis.
#Libraries
import pandas as pd
import pandas_datareader as web
import matplotlib.pyplot as plt
import datetime
date = datetime.date.today()
def Graphmaker(ticker, start, end, interval):
stock_data = web.DataReader(ticker, data_source = "yahoo", start = start, end = end) #Gets information
plt.plot(stock_data['Close']) #Plots
plt.autoscale()
plt.axis('off') #Removes axis
graph = plt.gcf()
#
plt.switch_backend('agg')
#
plt.draw()
#plt.show()
date = datetime.date.today()
file_name = "graph_" + ticker + "_" + interval + "_day_graph_" + str(date) + ".png"
graph.savefig('Data/test/' + file_name, dpi=100) #Saves graph, Adds the graph image to be tested which later gets moved to 'train'
plt.clf() #Without this the graphs stack on each other and create incorrect lines
return(file_name) #Passing the file name back to main which gets passed to predictor

Plotting dates only when frequency changes

I have been trying to plot date against frequency.
This is how my data set looks like:
2017-07-04,13
2018-04-11,13
2017-08-17,13
2017-08-30,13
2018-04-26,12
2018-01-03,12
2017-07-05,11
2017-06-21,11
This is the code I have tried:
with open('test.csv', 'w') as f:
writer = csv.writer(f)
writer.writerows(temp)
### Extract data from CSV ###
with open('test.csv', 'r') as n:
reader = csv.reader(n)
dates = []
freq = []
for row in reader:
dates.append(row[0])
freq.append(row[1])
fig = plt.figure()
graph = fig.add_subplot(111)
# Plot the data as a red line with round markers
graph.plot(dates, freq, 'r-o')
graph.set_xticks(dates)
graph.set_xticklabels(
[dates]
)
plt.show()
This is the result I got:
The xlabels are very cluttered. I want the dates in the labels to be displayed only when there is a change of value.
I don't know how to do that.
Help is appreciated.
Thanks!
Firstly, I would strongly encourage you to use the pandas library and its DataFrame object to handle your data. It has some very useful functions, such as read_csv, which will save you some work.
To have matplotlib space the xticks more sensibly, you'll want to convert your dates to datetime objects (instead of storing your dates as strings).
Here I'll read your data in with pandas, parse the dates and order by date:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# Read data
df = pd.read_csv('/path/to/test.csv', names=['date', 'freq'], parse_dates=['date'])
# Sort by date
df.sort_values(by='date', inplace=True)
You can then go ahead and plot the data (you'll need the latest version of pandas to automatically handle the dates):
fig, ax = plt.subplots(1, 1)
# Plot date against frequency
ax.plot(df['date'], df['freq'], 'r-o')
# Rotate the tick labels
ax.tick_params(axis='x', rotation=45)
fig.tight_layout()
If you only wanted to display dates when the frequency changes, the following would work
ax.set_xticks(df.loc[np.diff(df['freq']) != 0, 'date'])
though I wouldn't recommend it (the unequal spacing looks messy)

Newbie Matplotlib and Pandas Plotting from CSV file

I haven't had much training with Matplotlib at all, and this really seems like a basic plotting application, but I'm getting nothing but errors.
Using Python 3, I'm simply trying to plot historical stock price data from a CSV file, using the date as the x axis and prices as the y. The data CSV looks like this:
(only just now noticing to big gap in times, but whatever)
import glob
import pandas as pd
import matplotlib.pyplot as plt
def plot_test():
files = glob.glob('./data/test/*.csv')
for file in files:
df = pd.read_csv(file, header=1, delimiter=',', index_col=1)
df['close'].plot()
plt.show()
plot_test()
I'm using glob for now just to identify any CSV file in that folder, but I've also tried just designating one specific CSV filename and get the same error:
KeyError: 'close'
I've also tried just designating a specific column number to only plot one particular column instead, but I don't know what's going on.
Ideally, I would like to plot it just like real stock data, where everything is on the same graph, volume at the bottom on it's own axis, open high low close on the y axis, and date on the x axis for every row in the file. I've tried a few different solutions but can't seem to figure it out. I know this has probably been asked before but I've tried lots of different solutions from SO and others but mine seems to be hanging up on me. Thanks so much for the newbie help!
Here on pandas documentation you can find that the header kwarg should be 0 for your csv, as the first row contains the column names. What is happening is that the DataFrame you are building doesn't have the column close, as it is taking the headers from the "second" row. It will probably work fine if you take the header kwarg or change it to header=0. It is the same with the other kwargs, no need to define them. A simple df = pd.read_csv(file) will do just fine.
You can prettify this according to your needs
import pandas
import matplotlib.pyplot as plt
def plot_test(file):
df = pandas.read_csv(file)
# convert timestamp
df['timestamp'] = pandas.to_datetime(df['timestamp'], format = '%Y-%m-%d %H:%M')
# plot prices
ax1 = plt.subplot(211)
ax1.plot_date(df['timestamp'], df['open'], '-', label = 'open')
ax1.plot_date(df['timestamp'], df['close'], '-', label = 'close')
ax1.plot_date(df['timestamp'], df['high'], '-', label = 'high')
ax1.plot_date(df['timestamp'], df['low'], '-', label = 'low')
ax1.legend()
# plot volume
ax2 = plt.subplot(212)
# issue: https://github.com/matplotlib/matplotlib/issues/9610
df.set_index('timestamp', inplace = True)
df.index.to_pydatetime()
ax2.bar(df.index, df['volume'], width = 1e-3)
ax2.xaxis_date()
plt.show()

How to filter csv with matplotlib using dates on the x-axis and rainfall on the y-axis?

I have a csv file with all two columns one that says 'Date' and the other that has the rainfall amount in inches called 'Rainfall'. I am not sure how to go about this, so far my approach has not been working. I also need to skip the first 5 lines before I enter into the 'Date' and 'Rainfall' column.
Here is the code I have so far:
import matplotlib.pyplot as plt
import csv
x = []
y = []
with open('1541553208_et.csv','r') as csvfile:
plots = csv.reader(csvfile, delimiter=',')
for row in plots:
for i in row:
x.append(row[0])
y.append(row[1])
plt.plot(x,y, label='Loaded from file!')
plt.xlabel('Dates')
plt.ylabel('Evaporation (inches)')
plt.title('Eden_7')
plt.legend()
plt.show()
When I run the code I get the following incorrect results:
I want to have it so that each months rainfall data is clustered into one
Here is an example of what I am going on:
I am trying to get the same effect as the top. How could this be done?
Thank you
You may have a simpler time using the pandas library instead of the csv library.
For instance, pandas allows you to store the csv file directly into a data structure called a dataframe. This will allow you to group on dates or rainfall and plot the data.
import pandas as pd
# rain will be an dataframe instance
rain = pd.read_csv(csvfile)
rain = rain.groupby(rain['rainfall'])
rain.plot(kind='bar')
plt.show()
Play around with it, pandas is very powerful.
You can find the pandas documentation here: https://pandas.pydata.org/pandas-docs/stable/
While this may not be an immediate solution, it may help in the long run.
Using pandas library will be easier as previously mentioned. Following your csv library can you try to run this,
import matplotlib.pyplot as plt
import csv
x = []
y = []
f = open('1541553208_et.csv')
csv_f = csv.reader(f,delimiter=',')
for row in csv_f:
x.append(row[0])
for row in csv_f:
y.append(row[1])
plt.plot(x,y, label='Loaded from file!')
plt.xlabel('Dates')
plt.ylabel('Evaporation (inches)')
plt.title('Eden_7')
plt.legend()
plt.show()

Can a matplotlib figure object be pickled then retrieved?

I am trying to pickle a matplotlib Figure object to be able to regenerate the graph with x and y data and labels and title at a later time. Is this possible?
When trying to use open and dump to pickle I get this traceback:
#3rd Party Imports and built-in
import random
import matplotlib.pyplot as plt
import pickle as pk
#Initializing lists for x and y values. Voltage trim and current measure is our x and y in this case.
voltage_trim = range(100, 150)
current_meas = []
# A change of parameters modelled by a multiplier in this case
multiplier = range(1,4)
# Initializing lists to store the output current if wanted
current_storage = []
# Required for Matplotlib
plt.close()
plt.ion() #Required method call in order for interactive plotting to work
# SPECIFY GRAPH
fig1 = plt.figure()
ax = fig1.add_subplot(1,1,1) # Creates an axis in order to have multiple lines
plt.title('Voltage Trim Vs Current \nsome fancy sub-title here')
plt.xlabel('Voltage Trim / V')
plt.ylabel('Current Measured/ A')
plt.grid(True)
color_choices = ['k', 'g','r','b','k','c', 'm', 'y'] # Add more according to number of graphs
# MAIN TEST LOOPS
for this_mult in multiplier:
current_meas = [] # Clears the output list to graph with different multipier
#Enumerates input in order to manipulate it below
for index, value in enumerate(voltage_trim):
#Generating random current values in this case
current_meas.append(random.randint(0,10)*this_mult)
print index ,'Generating results...'
print index, value
# Increments index so that lists match dimensiosn and graphing is possible
index += 1
# Optional real time plotting function, comment out if not wanted
live_plotting = ax.plot(voltage_trim[:index], current_meas, color = color_choices[this_mult])#,label = 'Line'+str(this_mult)
# A pyplot method that pauses the loop, updates the graph and continues to enable for real time graphing, set to small number to be considered insignificant
plt.pause(1e-124)
# Deletes the real time line to save memory in the loop
live_plotting[0].remove()
# This is the actual storage of plot objects, specify legend label here, and all other arguments the same
ax.plot(voltage_trim, current_meas,color = color_choices[this_mult],marker = 'o', label = 'Line'+str(this_mult))
#Stores the measured current (A)
current_storage.append(current_meas)
#Calls legend - must be in outer loop
plt.legend()
f = open('testt','wb')
pk.dump(fig1, f)
f.close()
Yes. Try
import pickle
import matplotlib.pyplot as plt
file = open('myfile', 'wb')
fig = plt.gcf()
pickle.dump(fig, file)
file.close()
Then to read
file = open('myfile', 'rb')
pickle.load(file)
plt.show()
file.close()

Categories

Resources