463 lines
18 KiB
Python
463 lines
18 KiB
Python
|
|
from tkinter.colorchooser import askcolor
|
|
from tkinter import filedialog
|
|
from tkinter import messagebox
|
|
import tkinter as tk
|
|
import csv
|
|
import numpy as np
|
|
from configparser import ConfigParser
|
|
import pandas as pd
|
|
import config
|
|
|
|
import matplotlib.pyplot as plt
|
|
#matplotlib.use("TkAgg")
|
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk
|
|
from matplotlib.figure import Figure
|
|
from numpy import arange, sin, pi,cos
|
|
import fnmatch
|
|
import time
|
|
####################################### object
|
|
|
|
class Jfsphoto (object):
|
|
|
|
def __init__(self):
|
|
self.nm = 0
|
|
self.nmi = 0
|
|
self.nm2 = 0
|
|
self.nm2i = 0
|
|
self.nm_left = 0
|
|
self.nm_right = 0
|
|
self.nm_step = 0
|
|
self.tnm_left = tk.StringVar()
|
|
self.tnm_right = tk.StringVar()
|
|
self.tnm_step = tk.StringVar()
|
|
self.nmData16 = np.zeros(3694, np.uint16)
|
|
########## nm scale checkButton default nm-scale is off
|
|
self.nm_checked = tk.IntVar()
|
|
self.nm_checked.set(0)
|
|
########## darkline
|
|
self.darkData16 = np.zeros(3694, np.float32)
|
|
self.darkline_checked = tk.IntVar()
|
|
self.darkline_checked.set(0)
|
|
########## baseline of the lightsource transmission or absorption
|
|
self.baseData16 = np.zeros(3694, np.float32)
|
|
self.baseline_checked = tk.IntVar()
|
|
self.baseline_checked.set(0)
|
|
self.baseline_start=0
|
|
self.baseline_end=0
|
|
self.abs_trans= tk.IntVar()
|
|
########## set to transition
|
|
self.abs_trans.set(1)
|
|
########## dataframe to load and save photometer data
|
|
self.pandas_count = 0
|
|
self.df = pd.DataFrame()
|
|
######### jfs math
|
|
self.ok = tk.IntVar()
|
|
self.ok.set(0)
|
|
|
|
def do_calibrate(self):
|
|
win = tk.Toplevel()
|
|
win.geometry("450x200+100+100")
|
|
self.lab1 = tk.Label(win, text='Please enter filenames and nm of the peaks').grid(row=0,column=0,columnspan=6)
|
|
########## first peak
|
|
self.tnm = tk.StringVar()
|
|
self.tnm.set(str(self.nm))
|
|
self.tnmi = tk.StringVar()
|
|
self.tnmi.set(str(self.nmi))
|
|
self.lab2 = tk.Label(win,text='first Peak nm').grid(row=1,column=0)
|
|
self.en1 = tk.Entry(win,textvariable=self.tnm, width= 10).grid(row=1,column=1)
|
|
self.bt1 = tk.Button(win,text="select File",command=lambda: self.openfile(1)).grid(row=1,column=2)
|
|
self.lnm = tk.Label(win,textvariable =self.tnm).grid(row=1,column=3)
|
|
self.lnm = tk.Label(win,text =" nm by index ").grid(row=1,column=4)
|
|
self.lmi = tk.Label(win,textvariable=self.tnmi).grid(row=1,column=5)
|
|
########## second peak
|
|
self.tnm2 = tk.StringVar()
|
|
self.tnm2.set(str(self.nm2))
|
|
self.tnm2i = tk.StringVar()
|
|
self.tnm2i.set(str(self.nm2i))
|
|
self.lab3 = tk.Label(win,text='second Peak nm').grid(row=2,column=0)
|
|
self.en2 = tk.Entry(win,textvariable=self.tnm2, width= 10).grid(row=2,column=1)
|
|
self.bt2 = tk.Button(win,text="select File",command=lambda: self.openfile(2)).grid(row=2,column=2)
|
|
self.lnm2 = tk.Label(win,textvariable =self.tnm2).grid(row=2,column=3)
|
|
self.lnm2 = tk.Label(win,text =" nm by index ").grid(row=2,column=4)
|
|
self.lm2i = tk.Label(win,textvariable=self.tnm2i).grid(row=2,column=5)
|
|
########### calibration
|
|
self.tnm_left.set(str(self.nm_left))
|
|
self.tnm_right.set(str(self.nm_right))
|
|
self.tnm_step.set(str(self.nm_step))
|
|
self.lab4 = tk.Label(win,text="left border [nm]").grid(row=3,column=0)
|
|
self.lab5 = tk.Label(win,textvariable=self.tnm_left).grid(row=3,column=1)
|
|
self.lab6 = tk.Label(win,text="right border [nm]").grid(row=3,column=2)
|
|
self.lab7 = tk.Label(win,textvariable=self.tnm_right).grid(row=3,column=3)
|
|
self.lab8 = tk.Label(win,text="[nm]/point").grid(row=3,column=4)
|
|
self.lab9 = tk.Label(win,textvariable=self.tnm_step).grid(row=3,column=5)
|
|
self.bt3 = tk.Button(win,text="Calibrieren",command=self.calibrate,state=tk.DISABLED)
|
|
self.bt3.grid(row=4,column=0)
|
|
self.bt4 = tk.Button(win,text="Load Config",command=self.conf_read).grid(row=4,column=1)
|
|
self.bt5 = tk.Button(win,text="Save Config",command=self.conf_write).grid(row=4,column=2)
|
|
########### dialog modal
|
|
win.focus_set()
|
|
win.grab_set()
|
|
win.wait_window()
|
|
|
|
def do_msg(self,txt):
|
|
self.mroot = tk.Tk()
|
|
self.mroot.minsize(100,50)
|
|
self.mroot.title(" Info ")
|
|
self.label = tk.Label(self.mroot, text=txt,bg="yellow",fg="blue")
|
|
self.label.pack()
|
|
self.button = tk.Button(self.mroot, text='OK', width=25, command=self.mroot.destroy)
|
|
self.button.pack()
|
|
self.mroot.mainloop()
|
|
|
|
############ Darkline
|
|
def do_save_darkline(self,dark):
|
|
x = np.min(dark)
|
|
if (x < 3700):
|
|
self.do_msg(" This is not a Darkline ")
|
|
return 0
|
|
else :
|
|
self.darkData16 = dark*1.0
|
|
return 1
|
|
|
|
def get_darkline_checked(self):
|
|
return self.darkline_checked.get()
|
|
|
|
############ Baseline depends on the capacity of the light source block spektralrange if the intensity is to low
|
|
def do_save_baseline(self,base):
|
|
### no margin at all
|
|
doIt = True
|
|
#### no left margin
|
|
left = True
|
|
x = np.max(base)
|
|
if (x < 500):
|
|
self.do_msg(" This is not a Baseine \n Is the Lightsouce switch on ? ")
|
|
return 0
|
|
else:
|
|
for i in range(0,3694):
|
|
if (base[i] < 200) :
|
|
if doIt:
|
|
if left:
|
|
self.baseline_start = i
|
|
else:
|
|
self.baseline_end = i
|
|
doIt = False
|
|
self.baseData16[i] = 0
|
|
else:
|
|
## 300 should be in the ini file job!
|
|
if (base[i] > 300):
|
|
left = False
|
|
self.baseData16[i] = base[i]*1.0
|
|
#print(self.baseline_start," ",self.baseline_end)
|
|
return 1
|
|
|
|
def get_baseline_checked(self):
|
|
return self.baseline_checked.get()
|
|
|
|
############ Calibration and Load/Save Configuration Part 2
|
|
def checkit(self):
|
|
self.nm = int(self.tnm.get())
|
|
self.nmi = int(self.tnmi.get())
|
|
self.nm2 = int(self.tnm2.get())
|
|
self.nm2i = int(self.tnm2i.get())
|
|
if ((self.nm > 0) & (self.nmi > 0) & (self.nm2 > 0) & (self.nm2i > 0)):
|
|
self.bt3.config(state = tk.NORMAL)
|
|
|
|
|
|
def calibrate(self):
|
|
self.nm_step = round((self.nm2 - self.nm)/(self.nm2i-self.nmi),5)
|
|
self.nm_left = round(self.nm-(self.nm_step*self.nmi),0)
|
|
self.nm_right = round(self.nm2 + self.nm_step*(3694-self.nm2i),0)
|
|
self.tnm_left.set(str(self.nm_left))
|
|
self.tnm_right.set(str(self.nm_right))
|
|
self.tnm_step.set(str(self.nm_step))
|
|
|
|
|
|
def nm_scale_ok(self):
|
|
if ((self.nm_left > 0) & (self.nm_right > 0)):
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
def get_nm_checked(self):
|
|
if (self.nm_scale_ok()):
|
|
return self.nm_checked.get()
|
|
else:
|
|
return 0
|
|
|
|
def set_nm_scale(self):
|
|
if (self.nm_scale_ok):
|
|
self.nmData16 = np.linspace(self.nm_left,self.nm_right,3694)
|
|
|
|
|
|
def get_nm_scale(self):
|
|
self.set_nm_scale()
|
|
return self.nmData16
|
|
|
|
def add_kinetic(self,name):
|
|
self.df[str(name)]=config.rxData16
|
|
toc = time.perf_counter()
|
|
print(f"{name} time {toc :0.4f} sec")
|
|
|
|
def start_kinetic(self):
|
|
self.col_list = list(self.df.columns.values.tolist())
|
|
##### delete remaining _trans and _abs
|
|
##filtered = fnmatch.filter(self.col_list,'*_*')
|
|
self.df.drop(self.col_list,axis=1,inplace=True)
|
|
toc = time.perf_counter()
|
|
print(f"start time {toc :0.4f} sec")
|
|
|
|
|
|
def save_pandas(self):
|
|
filename = filedialog.asksaveasfilename(defaultextension=".csv", title="Save file as")
|
|
try:
|
|
self.df['baseline']=self.baseData16
|
|
self.df['darkline']=self.darkData16
|
|
self.df['nmscale']=self.nmData16
|
|
self.df['p1']=config.rxData16
|
|
self.df.to_csv(filename)
|
|
except IOError:
|
|
messagebox.showerror("By the great otter!","There's a problem saving the file.")
|
|
|
|
def save_kinetics(self):
|
|
filename = filedialog.asksaveasfilename(defaultextension=".csv", title="Save file as")
|
|
try:
|
|
self.df.to_csv(filename)
|
|
except IOError:
|
|
messagebox.showerror("By the great otter!","There's a problem saving the file.")
|
|
|
|
def load_kinetics(self):
|
|
filename = filedialog.askopenfilename(defaultextension=".csv", title="Open file ")
|
|
try:
|
|
self.listbox.delete(0,tk.END)
|
|
self.df = pd.read_csv(filename,index_col=0)
|
|
self.calculate()
|
|
self.show_first_look()
|
|
except IOError:
|
|
messagebox.showerror("By the great otter!","There's a problem loding the file.")
|
|
|
|
def load_pandas(self):
|
|
filename = filedialog.askopenfilename(defaultextension=".csv", title="Open file ")
|
|
try:
|
|
self.df = pd.read_csv(filename,index_col=0)
|
|
config.rxData16=self.df['p1'].copy()
|
|
self.do_save_baseline(self.df['baseline'])
|
|
self.do_save_darkline(self.df['darkline'])
|
|
self.baseline_checked.set(1)
|
|
self.darkline_checked.set(1)
|
|
self.nm_checked.set(1)
|
|
except IOError:
|
|
messagebox.showerror("By the great otter!","There's a problem saving the file.")
|
|
|
|
def openfile(self,xx):
|
|
rxData16 = np.zeros(3694, np.uint16)
|
|
filename = filedialog.askopenfilename(defaultextension=".dat", title="Open file")
|
|
line_count = 0
|
|
try:
|
|
with open(filename) as csvfile:
|
|
readCSV = csv.reader(csvfile, delimiter=' ')
|
|
|
|
for row in readCSV:
|
|
if (line_count == 3):
|
|
self.SHsent = int(row[1])
|
|
self.ICGsent = int(row[6])
|
|
if (line_count > 3):
|
|
rxData16[line_count-4] = int(row[1])
|
|
line_count += 1
|
|
if (xx==1):
|
|
self.nmi = np.argmin(rxData16)
|
|
self.tnmi.set(str(self.nmi))
|
|
if (xx==2):
|
|
self.nm2i = np.argmin(rxData16)
|
|
self.tnm2i.set(str(self.nm2i))
|
|
self.checkit()
|
|
except IOError:
|
|
messagebox.showerror("By the great otter!","There's a problem opening the file.")
|
|
|
|
def reset_settings(self):
|
|
self.baseline_checked.set(0)
|
|
self.darkline_checked.set(0)
|
|
self.nm_checked.set(0)
|
|
|
|
def conf_write(self):
|
|
config = ConfigParser()
|
|
config.read('config.ini')
|
|
lis = config.sections()
|
|
if ('main' not in lis):
|
|
config.add_section('main')
|
|
config.set('main','nm_left',str(self.nm_left))
|
|
config.set('main','nm_right',str(self.nm_right))
|
|
config.set('main','nm_step',str(self.nm_step))
|
|
|
|
with open('config.ini','w') as f:
|
|
config.write(f)
|
|
|
|
def conf_read(self):
|
|
config = ConfigParser()
|
|
try:
|
|
config.read('config.ini')
|
|
self.nm_left = float(config.get('main','nm_left',fallback='0'))
|
|
self.tnm_left.set(config.get('main','nm_left',fallback='0'))
|
|
self.nm_right = float(config.get('main','nm_right',fallback='0'))
|
|
self.tnm_right.set(config.get('main','nm_right',fallback='0'))
|
|
self.nm_step = float(config.get('main','nm_step',fallback='0'))
|
|
self.tnm_step.set(config.get('main','nm_step',fallback='0'))
|
|
self.set_nm_scale()
|
|
except IOError:
|
|
print("By the great otter!","No config.ini file")
|
|
|
|
|
|
def do_math(self):
|
|
stati = [("Raw",1),("Raw + Baseline",2),("Transmission",4),("Absorbanz",3)]
|
|
|
|
win = tk.Toplevel()
|
|
self.center = tk.Frame(win, bg='gray2', width=800, height=400, padx=3, pady=3)
|
|
self.center.grid_rowconfigure(0, weight=1)
|
|
self.center.grid_columnconfigure(1, weight=1)
|
|
self.center.grid(row=1, sticky="nsew")
|
|
self.ctr_mid = tk.Frame(self.center, width=250, height=300, padx=3, pady=3)
|
|
self.ctr_right = tk.Frame(self.center, width=200, height=300, padx=3, pady=3)
|
|
self.ctr_mid.grid(row=0, column=0, sticky="nsew")
|
|
self.ctr_right.grid(row=0, column=1, sticky="ns")
|
|
self.fig = plt.Figure(figsize=(8,4),dpi=120)
|
|
plt.rc('legend',fontsize=8)
|
|
self.ax1 = self.fig.add_subplot(111)
|
|
self.canvas = FigureCanvasTkAgg(self.fig, master = self.ctr_mid)
|
|
self.canvas._tkcanvas.pack(side = tk.TOP, fill = tk.BOTH, expand = 1)
|
|
self.toolbarFrame = tk.Frame(master=self.center,padx=5,pady=5)
|
|
self.toolbarFrame.grid(row=1,columnspan=2, sticky="w")
|
|
self.toolbar1 = NavigationToolbar2Tk(self.canvas, self.toolbarFrame)
|
|
#### Buttons
|
|
n = 0
|
|
for txt,val in stati:
|
|
tk.Radiobutton(master=self.ctr_right,text=txt,variable=self.ok,command=self.look,value=val,padx=5,pady=5).grid(row=n,column=0,sticky="w")
|
|
n=n+1
|
|
self.listbox = tk.Listbox(master=self.ctr_right,selectmode = "multiple")
|
|
self.listbox.grid(row=7,column=0,sticky='w')
|
|
self.kbtn1 = tk.Button(master=self.ctr_right,text="show selected",command=self.show_selected,width=15)
|
|
self.kbtn1.grid(row=14,column=0,sticky="w")
|
|
self.kbtn = tk.Button(master=self.ctr_right,text="Load Kinetic / Data",command=self.load_kinetics,width=15)
|
|
self.kbtn.grid(row=15,column=0,sticky="w")
|
|
self.kbtn = tk.Button(master=self.ctr_right,text="Save Kinetic / Data",command=self.save_kinetics,width=15)
|
|
self.kbtn.grid(row=16,column=0,sticky="w")
|
|
|
|
#self.scrollbar = tk.Scrollbar(master=self.ctr_right)
|
|
#self.listbox.config(yscrollcommand =self.scrollbar.set)
|
|
#self.scrollbar.config(command = self.listbox.yview)
|
|
|
|
|
|
if self.calculate() :
|
|
self.show_first_look()
|
|
else:
|
|
t = arange(0.0, 3.0, 0.01)
|
|
s = sin(2*pi*t)
|
|
self.ax1.plot(t, s, linewidth=0.6)
|
|
|
|
|
|
win.focus_set()
|
|
win.grab_set()
|
|
win.wait_window()
|
|
|
|
def show_selected(self):
|
|
self.col_list = [self.listbox.get(i) for i in self.listbox.curselection()]
|
|
self.look()
|
|
|
|
def calculate(self):
|
|
self.ok.set(0)
|
|
if 'baseline' in self.df.columns:
|
|
self.get_kin_list()
|
|
self.do_get_range()
|
|
for xx in self.col_list:
|
|
self.do_absorbanz(xx)
|
|
for xx in self.col_list:
|
|
self.do_transmission(xx)
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_kin_list(self):
|
|
self.col_list = list(self.df.columns.values.tolist())
|
|
##### delete remaining _trans and _abs
|
|
filtered = fnmatch.filter(self.col_list,'*_*')
|
|
self.df.drop(filtered,axis=1,inplace=True)
|
|
self.col_list = list(self.df.columns.values.tolist())
|
|
self.col_list.remove('baseline')
|
|
self.col_list.remove('darkline')
|
|
self.col_list.remove('nmscale')
|
|
|
|
def show_first_look(self):
|
|
self.ax1.clear()
|
|
for xx in self.col_list:
|
|
self.df.plot(x = 'nmscale',y = xx, linewidth=0.6,ax=self.ax1)
|
|
self.listbox.insert(tk.END, xx)
|
|
self.ok.set(1)
|
|
self.canvas.draw()
|
|
|
|
def kini(self):
|
|
self.load_kinetics("kini.dat")
|
|
self.calculate()
|
|
self.show_first_look()
|
|
|
|
|
|
def do_get_range(self):
|
|
self.right = 0
|
|
self.left = 0
|
|
#### count for random not zero values in the start of the baseline
|
|
count = 0
|
|
b = self.df['baseline']
|
|
for i in range(0,3694):
|
|
if b[i]==0:
|
|
if (self.left > 0 and self.right==0):
|
|
self.right=i
|
|
else:
|
|
count += 1
|
|
if (self.left==0 and count > 5):
|
|
self.left=i
|
|
|
|
def do_absorbanz(self,xx):
|
|
y = self.df['darkline'] - self.df[xx]
|
|
b = self.df['baseline']
|
|
c = np.zeros(3694, np.float32)
|
|
for i in range(0,3694):
|
|
if b[i]==0:
|
|
c[i] = 1
|
|
else:
|
|
#c[i] = y[i]/b[i]
|
|
c[i] = np.log10(b[i]/y[i])
|
|
self.df[xx+'_abs'] = c
|
|
|
|
def do_transmission(self,xx):
|
|
y = self.df['darkline'] - self.df[xx]
|
|
b = self.df['baseline']
|
|
c = np.zeros(3694, np.float32)
|
|
for i in range(0,3694):
|
|
if b[i]==0:
|
|
c[i] = 1
|
|
else:
|
|
c[i] = y[i]/b[i]
|
|
#c[i] = np.log10(b[i]/y[i])
|
|
self.df[xx+'_trans'] = c
|
|
|
|
def look(self):
|
|
self.ax1.clear()
|
|
if self.ok.get()==1:
|
|
for xx in self.col_list:
|
|
self.df.plot(x = 'nmscale',y = xx, linewidth=0.6,ax=self.ax1)
|
|
elif self.ok.get()==2:
|
|
for xx in self.col_list:
|
|
self.df.plot(x = 'nmscale',y = xx, linewidth=0.6,ax=self.ax1)
|
|
self.df.plot(x = 'nmscale',y = 'baseline', color='blue',linewidth=0.6,ax=self.ax1)
|
|
self.df.plot(x = 'nmscale',y = 'darkline', color='black',linewidth=0.6,ax=self.ax1)
|
|
elif self.ok.get()==3:
|
|
for xx in self.col_list:
|
|
self.df.plot(x = 'nmscale',y = xx+'_abs', linewidth=0.6,ax=self.ax1)
|
|
self.ax1.set_xlim([self.nm_left+self.left*self.nm_step, self.nm_left+self.right*self.nm_step])
|
|
elif self.ok.get()==4:
|
|
for xx in self.col_list:
|
|
self.df.plot(x = 'nmscale',y = xx+'_trans',linewidth=0.6,ax=self.ax1)
|
|
self.ax1.set_xlim([self.nm_left+self.left*self.nm_step, self.nm_left+self.right*self.nm_step])
|
|
else:
|
|
t = arange(0.0, 3.0, 0.01)
|
|
s = sin(2*pi*t)
|
|
self.ax1.plot(t, s, linewidth=0.6)
|
|
self.canvas.draw() |