Matplotlib, Tkinter, Serial Multiprocessing - python-3.x

I created a code (using Tkinter, Python3 and matplotlid) that could read data from different serial ports, save them to csv, then create graphs and finally preview data in GUI. The code was splited in two different scripts. The main script contained reading data, save data to csv an priview of data and the other script contained the graph creation.
Today I rewrote the code using the answer of #user2464430 here. The code is working, but I can't update the GUI. Opens once and then no refresh with new data.
The following code is a part of total code.
My code is:
from PIL import ImageTk, Image
import tkinter as Tk
import multiprocessing
from queue import Empty, Full
from time import strftime
import serial
import numpy as np
import matplotlib.pyplot as plt
from drawnow import *
from pylab import *
import pandas as pd
from datetime import timedelta
from datetime import datetime
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import locale
import os
class GuiApp(object):
def __init__(self, image):
self.root = Tk.Tk()
self.root.resizable(width=False, height=False)
self.root.geometry("1600x800+0+0")
C = Canvas(self.root, bg="black", width=1600, height=800)
def BasicLabels():
....... # in this stage create multiple axis labels
Î¥AxisLabels()
BasicLabels()
def ValueLabels():
....... # Read and munipulate datas from CSV file and print in in labels
ValueLabels()
C.pack()
def GenerateData(q): #Read Serial Ports and store data to CSV file
file_exists = os.path.isfile("BigData.csv")
header = [["Daytime,T1"]]
if not file_exists:
with open("BigData.csv", "a+") as csvfile:
np.savetxt(csvfile, header, delimiter=",", fmt="%s", comments="")
while True:
try:
ser1 = serial.Serial(port="COM4", baudrate=9600)
read_ser1 = ser1.readline()
if read_ser1 == "":
read_ser1 = "Missing Value"
else:
read_ser1 = ser1.readline()
read_ser1 = str(read_ser1[0 : len(read_ser1)].decode("utf-8"))
# print("COM4:", read_ser1)
ser1.close()
except:
print("Failed 1")
read_ser1 = "9999,9999,9999,9999,9999"
daytime = strftime(" %d-%m-%Y %H:%M:%S")
rows = [
daytime
+ ","
+ read_ser1.strip()
]
with open("BigData.csv", "a+") as csvfile:
np.savetxt(csvfile, rows, delimiter=",", fmt="%s", comments="")
CreateGraphs()
def CreateGraphs():
#Code to generate graph. Called every time i have new line in CSV.
if __name__ == "__main__":
# Queue which will be used for storing Data
q = multiprocessing.Queue()
q.cancel_join_thread() # or else thread that puts data will not term
gui = GuiApp(q)
t1 = multiprocessing.Process(target=GenerateData, args=(q,))
t1.start()
gui.root.mainloop()
t1.join()
The graphs are generating after while True in GenerateData.
All datas for labels and graphs are coming from CSV file and not directly from serial port.
Is it possible to update GUI with latest datas from CSV and created graphs?
Thank for your time.

Related

recording EEG data using python ,brain flow and saving it into csv file. I an unable time stamp and channel name title in CSV file

EEG device is OpenBCI and board is Cyton and daisy.My sample code is here:
from datetime import datetime
import argparse
import numpy as np
import pandas as pd
import csv
import mne
from brainflow.board_shim import BoardShim, BrainFlowInputParams, LogLevels, BoardIds
from brainflow.data_filter import DataFilter
import time
def main():
BoardShim.enable_dev_board_logger()
# use synthetic board for demo
params = BrainFlowInputParams()
board = BoardShim(BoardIds.SYNTHETIC_BOARD.value, params)
board.prepare_session()
board.start_stream()
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
BoardShim.log_message(LogLevels.LEVEL_INFO.value, 'start sleeping in the main thread')
time.sleep(10)
data = board.get_board_data()
board.stop_stream()
board.release_session()
eeg_channels = BoardShim.get_eeg_channels(BoardIds.SYNTHETIC_BOARD.value)
# demo for downsampling, it just aggregates data
for count, channel in enumerate(eeg_channels):
print('Original data for channel %d:' % channel)
print(data[channel])
print("Current Time =", current_time)
# demo how to convert it to pandas DF and plot data
# eeg_channels = BoardShim.get_eeg_channels(BoardIds.SYNTHETIC_BOARD.value)
# df = pd.DataFrame(np.transpose(data))
# print('Data From the Board')
# print(df.head(10))
# demo for data serialization using brainflow API, we recommend to use it instead
pandas.to_csv()
DataFilter.write_file(data, 'test.csv', 'w') # use 'a' for append mode
# writing the data in csv file
restored_data = DataFilter.read_file('test.csv')
restored_df = pd.DataFrame(np.transpose(restored_data))
print('Data From the File')
print(restored_df.head(5))
if __name__ == "__main__":
main()

Python -> reminder not popping

I am doing a project on a notification program that reads an excel file as you edit it and then sends a notification on the time you set the reminder.
The code is here:
import pandas as pd
import datetime
from plyer import notification
def remind(title, message):
notification.notify(title=title, message=message, timeout=10)
if __name__ == '__main__':
while True:
df = pd.read_excel("./reminder.xlsx")
for index, item in df.iterrows():
time = datetime.datetime.now().strftime("%H:%M:%S")
if time == item['Time']:
remind(item['Title'], item['Message'])
else:
continue
The program is running fine but the reminder is not popping up
i am working on python 3.7.9 on win8 (64-bit)
from numpy import nan
import pandas as pd
import datetime
from plyer import notification
import time
def notifyMe(title, message,icon):
notification.notify(
title=title,
message=message,
app_icon = icon,
timeout=10)
if __name__ == '__main__':
notifyMe("Hello","We are in together in these tough time","virusicon.ico")
df = pd.read_excel("reminder.xlsx")
df["Icon"] = df["Icon"].astype(str)
df["Heading"] = df["Heading"].astype(str)
df["Message"] = df["Message"].astype(str)
number_of_rows = len(df.index)
while True:
flag = True
for item in range(0,number_of_rows):
now = datetime.datetime.strptime(datetime.datetime.now().strftime("%H:%M:%S"),"%H:%M:%S")
x = datetime.datetime.strptime(df['Time'][item].strftime("%H:%M:%S"),"%H:%M:%S")
if x==now:
print(True)
print(df['Heading'][item], df['Message'][item],df["Icon"][item])
if df["Icon"][item]=="nan":
df["Icon"][item]=""
if df["Message"][item]=="nan":
df["Message"][item]=""
if df["Heading"][item]=="nan":
df["Heading"][item]=""
notifyMe(df['Heading'][item], df['Message'][item],df['Icon'][item])
time.sleep(1)
if now<=x:
flag = False
if flag:
exit()
Format of the xslx file
You can try this. It may help you

Why is multiprocessing not working with python dash framework - Python3.6

I'm trying to implement multiprocessing library for splitting up a dataframe into parts, process it on multiple cores of CPU and then concatenate the results back into a final dataframe in a python dash application. The code works fine when I try it outside of the dash application (when I run the code standalone without enclosing it in a dash application). But when I enclose the same code in a dash application, I get an error. I have shown the code below:
I have tried the multiprocessing code out of the dash framework and it works absolutely fine.
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import flask
import dash_table_experiments as dt
import dash_table
import dash.dependencies
import base64
import time
import os
import pandas as pd
from docx import *
from docx.text.paragraph import Paragraph
from docx.text.paragraph import Run
import xml.etree.ElementTree as ET
import multiprocessing as mp
from multiprocessing import Pool
from docx.document import Document as doctwo
from docx.oxml.table import CT_Tbl
from docx.oxml.text.paragraph import CT_P
from docx.table import _Cell, Table
from docx.text.paragraph import Paragraph
import io
import csv
import codecs
import numpy as np
app = dash.Dash(__name__)
application = app.server
app.config.supress_callback_exceptions = True
app.layout = html.Div(children=[
html.Div([
html.Div([
html.H4(children='Reader'),
html.Br(),
],style={'text-align':'center'}),
html.Br(),
html.Br(),
html.Div([
dcc.Upload(html.Button('Upload File'),id='upload-data',style = dict(display = 'inline-block')),
html.Br(),
]
),
html.Div(id='output-data-upload'),
])
])
#app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename')])
def update_output(contents, filename):
if contents is not None:
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
document = Document(io.BytesIO(decoded))
combined_df = pd.read_csv('combined_df.csv')
def calc_tfidf(input1):
input1 = input1.reset_index(drop=True)
input1['samplecol'] = 'sample'
return input1
num_cores = mp.cpu_count() - 1 #number of cores on your machine
num_partitions = mp.cpu_count() - 1 #number of partitions to split dataframe
df_split = np.array_split(combined_df, num_partitions)
pool = Pool(num_cores)
df = pd.concat(pool.map(calc_tfidf, df_split))
pool.close()
pool.join()
return len(combined_df)
else:
return 'No File uploaded'
app.css.append_css({'external_url': 'https://codepen.io/plotly/pen/EQZeaW.css'})
if __name__ == '__main__':
app.run_server(debug=True)
The above dash application takes as input any file. Upon uploading the file in the front end, a local CSV file (any file, in my case it is combined_df.csv) is loaded into a dataframe. Now I want to split the dataframe into parts using multiprocessing, process it and combine it back. But the above code results in the following error:
AttributeError: Can't pickle local object 'update_output..calc_tfidf'
What's wrong with this piece of code?
Okay I've figured it out now!. The problem is that the function calc_tfidf was not defined as a global function. I changed the function to be a global function and it worked perfect.
Simple checks when left unsolved at times might lead to days of redundant efforts! :(

how to push live panda Dataframe and index it to fit it in my Tkinter table?

I am trying to push my mqtt data to my tkinter table, which i have created using pandastable module. I am getting data in form of a list. So i first created a csv file, and i labeled it manually. And then i pushed my list to that csv file. So, i have two part in my table, first it will take converted dataframe from my csv file and is like the history part of table and then i need to push my recent dataframe(which is in same format as my previous dataframes with my csv file's column index as my dataframe column index ) to that table while its open. And also i am saving my recent datframes in csv file, so this process can in circle every time i open my table.Problem is i can't figure where i am going wrong.
this is my table script:
import tkinter as tk
import pandas as pd
from pandastable import Table, TableModel
from threading import Thread
import time
import datetime
import numpy as np
#import mqtt_cloud_rec
#import tkintermqtt
prevframe = pd.read_csv('mqttresult.csv')
class TestApp(tk.Frame):
"""Basic test frame for the table"""
def __init__(self, parent=None):
self.parent = parent
tk.Frame.__init__(self)
self.main = self.master
self.main.geometry('800x600+200+100')
self.main.title('Mqtt Result Table')
f = tk.Frame(self.main)
f.pack(fill=tk.BOTH,expand=1)
#df = TableModel.getSampleData(rows=5)
self.table = pt = Table(f, dataframe=prevframe, showtoolbar=True )
pt.show()
self.startbutton = tk.Button(self.main,text='START',command=self.start)
self.startbutton.pack(side=tk.TOP,fill=tk.X)
self.stopbutton = tk.Button(self.main,text='STOP',command=self.stop)
self.stopbutton.pack(side=tk.TOP,fill=tk.X)
# self.table.showPlotViewer()
return
def update(self,data):
table=self.table
#plotter = table.pf
#opts = plotter.mplopts
#plotter.setOption('linewidth',3)
#plotter.setOption('kind','line')
#opts.widgets['linewidth'].set(3)
#opts.widgets['kind'].set('line')
date_today=str(datetime.date.today())
time_today=time.strftime("%H:%M:%S")
datalist=[date_today,time_today]+self.data
datalist1=np.array(datalist)
datalist2=pd.DataFrame(data=datalist1 ,columns=['Date','Time','power state','Motor state','Mode','Voltage','Current','Power Factor','KW','KWH','total Runtime'])
#self.table = Table(dataframe=datalist2, showtoolbar=True )
self.dataframe.loc[len(self.dataframe)]=datalist2
table.model.df=self.dataframe
table.redraw()
#table.multiplecollist=range(0,10)
#table.plotSelected()
time.sleep(.1)
if self.stop == True:
return
return
def start(self):
self.stop=False
t = Thread(target=self.update)
t.start()
def stop(self):
self.stop = True
return
app = TestApp()
#launch the app
app.mainloop()
Convert this to a dictionary instead of a Dataframe and I think it will work:
datalist=[date_today,time_today]+self.data
datalist1=np.array(datalist)
datalist2=pd.DataFrame(data=datalist1 ,columns=['Date','Time','power state','Motor state','Mode','Voltage','Current','Power Factor','KW','KWH','total Runtime'])

How to select a particular csv file and plot the graph from the multiple csv files folder using browser button in python

How I can select a particular csv file from a folder which contains 'n' number of csv files and all csv files are of the same kind with 3 columns only the values are different. So, my aim is to select a single csv file by clicking the browser button and then the graph should get plotted with the selection I made.
Sample csv file points
z,x,y
23,0,0
23,0.05387,6.66634
23,0.11799,13.787
23,0.19989,22.9338
23,0.3072,35.0772
23,0.56904,63.648
23,0.84889,91.5284
23,1.22228,123.65
23,1.72457,156.606
23,1.95494,167.717
23,2.25261,178.844
23,2.59162,186.982
23,2.91377,190.805
23,3.23132,190.89
120,0,0
120,0.08749,5.44471
120,0.16471,9.48296
120,0.31905,16.8751
120,0.82326,37.8111
120,1.45144,56.0784
120,2.24965,72.0364
120,3.01642,82.2629
120,3.82591,89.1323
120,4.91071,94.4476
120,6.15553,97.6881
120,7.45795,99.0951
120,8.31468,98.7398
160,0,0
160,0.1142,5.59709
160,0.24587,10.7453
160,0.77917,27.9152
160,1.50412,42.5702
160,2.4017,53.905
160,3.49796,62.7076
160,4.77411,69.3479
160,6.24681,74.2705
160,7.93673,77.5658
160,9.78794,79.1005
160,10.1071,78.9901
I have written a code but with my code I always need to change the 'filename'
in the 'filename.csv' and then need to select from the browser according to filename. I want to make it easy without changing the filename any csv file can be selected.
from tkinter import *
import csv
import os
import tkinter as tk
import sys
from tkinter import filedialog
import pandas as pd
import matplotlib.pyplot as plt
import math
#from sympy import *
from tkinter import ttk
class Application(Frame):
def __init__(self, master = None):
Frame.__init__(self,master)
self.grid()
self.createWidgets()
def createWidgets(self):
top = self.winfo_toplevel()
self.menuBar = Menu(top)
top["menu"] = self.menuBar
self.subMenu = Menu(self.menuBar)
self.menuBar.add_cascade(label = "File", menu = self.subMenu)
self.subMenu.add_command( label = "Read Data",command = self.readCSV)
def readCSV(self):
x=[]
y=[]
z=[]
self.filename = filedialog.askopenfilename()
df=pd.read_csv('GF30.csv', error_bad_lines=False)
read = csv.reader(df, delimiter = ",")
fig = plt.figure()
data_list = []
ax= fig.add_subplot(111)
buttons = next(read)
df.set_index('x', inplace=True)
df.groupby('z')['y'].plot(legend=True,ax=ax)
leg = ax.legend(bbox_to_anchor = [1.1, 0.7], fancybox=True, shadow=True)
leg.get_frame().set_alpha(0.4)
plt.show()
print
for btn in buttons:
new_btn = Button(self, text="btn", command = self.btnClick)
new_btn.pack()
self.root.mainloop()
def btnClick(self):
root.destroy()

Resources