diff --git a/Software/COSI_Measure/server_GUI.py b/Software/COSI_Measure/server_GUI.py new file mode 100644 index 0000000000000000000000000000000000000000..5e55fd9c4e762544b9e64030f508665b2feece3c --- /dev/null +++ b/Software/COSI_Measure/server_GUI.py @@ -0,0 +1,519 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Mar 12 11:28:20 2019 + +@author: sileme01 +""" +import struct +from Tkinter import * +import ttk +from binascii import hexlify +from binascii import unhexlify +import scandir +import math +import time +import re +import numpy as np +import os +#from pathlib import Path #pathlib2 in python 2.7 +import shutil +import subprocess +import asyncore, socket +import threading +from datetime import datetime as date +cts = date.now() +dt_string = cts.strftime("%d_%m_%Y_%H_%M_%S") + +import tkinter.font as font +import matplotlib +matplotlib.use("TkAgg") +matplotlib.rcParams['agg.path.chunksize'] = 10000 +imagedpi = 70 +#from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk) #try the line below if error occurs +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg +print('matplotlib: {}'.format(matplotlib.__version__)) +print('numpy: {}'.format(np.__version__)) +from matplotlib import pyplot as plt +import scandir +import ctypes + + +from datetime import datetime +class MainClass: + def __init__(self,master): + self.master = master +#-----------------------------Ethernet Settings---------------------------------------------# + self.TCP_IP = "192.168.101.253" + self.TCP_PORT = 7001 + self.BUFFER_SIZE = 1024 + self.data = "XXXX" + self.s = None +#-----------------------------Flags for internal checks-------------------------------------# + self.sending = False + self.sendingInit = True + self.exitSignal = False + self.customFileFlag = False +#---------------------------------------------------------------------------------# + self.dstPathName = "Measurements1" + self.dirIndex = 1 + self.workingDir = os.getcwd() + self.FileCheckRate = float(0.05) + def StartGui(self,master): + self.e1 = Entry(master) + self.e1.delete(0,END) + self.e1.insert(0,"347") + self.e2 = Entry(master) + self.e2.delete(0,END) + self.e2.insert(0,"499") + self.e3 = Entry(master) + self.e3.delete(0,END) + self.e3.insert(0,"76") + self.e4 = Entry(master) + self.e4.delete(0,END) + self.e4.insert(0,"54") + self.e5 = Entry(master) + self.e5.delete(0,END) + self.e5.insert(0,"204") + self.e6 = Entry(master) + self.e6.delete(0,END) + self.e6.insert(0,"75") + self.e7 = Entry(master) + self.e7.delete(0,END) + self.e7.insert(0,"287") + self.e8 = Entry(master) + self.e8.delete(0,END) + self.e8.insert(0,"287") + self.e9 = Entry(master) + self.e9.delete(0,END) + self.e9.insert(0,"1") + self.e10 = Entry(master) + self.e10.delete(0,END) + self.e10.insert(0,"7001") + + def doExit(): + self.exitSignal = True + time.sleep(0.5) + master.quit() + master.destroy() + + self.l = 0 + self.m = 0 + self.colormap = "jet" # coolwarm + def arrangeData(arg0): + while 1: + isAmpFileExits = os.path.isfile(str(arg0)) + if(isAmpFileExits): + if(arg0 == "OP.dat"): + file_object = open(arg0, "r") + data_op_field = file_object.readlines() #Open the file of the receiver. + x = 0 + SignalAvg = np.array(np.zeros((5))) + for i in range(540,545): #Get an average of a few data points. To be displayed in the GUI + raw = re.split("(\s+)",data_op_field[i]) + SignalAvg[x] = raw[4] + x = x +1 + self.mean_op1[self.l,self.m] = np.mean(SignalAvg) + file_object.close() + self.op_plt.imshow(self.mean_op1,self.colormap,vmin=0, vmax=np.amax(self.mean_cp2),origin='lower') #Display the data in the corresponding point + self.op_canvas.draw() #Update the GUI + shutil.move(arg0,self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) #we are done with the data. Move it to a corresponding directory + return "OK" + elif(arg0 == "CP.dat"): #Get an average of a few data points. To be displayed in the GUI + file_object = open(arg0, "r") + data_cp_field = file_object.readlines() + SignalAvg = np.array(np.zeros((5))) + x = 0 + for i in range(540,545): + raw = re.split("(\s+)",data_cp_field[i]) + SignalAvg[x] = raw[4] + x = x +1 + self.mean_cp2[self.l,self.m] = np.mean(SignalAvg) + + file_object.close() + self.cp_plt.imshow(self.mean_cp2,self.colormap,vmin=0, vmax=np.amax(self.mean_cp2),origin='lower') #Display the data in the corresponding point + self.cp_canvas.draw() + shutil.move(arg0,self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) #we are done with the data. Move it to a corresponding directory + return "OK" + + elif(arg0 == "WC.dat"): #Repeat it for the worst case part + file_object = open(arg0, "r") + data_wc_field = file_object.readlines() + SignalAvg = np.array(np.zeros((5))) + x = 0 + for i in range(540,545): + raw = re.split("(\s+)",data_wc_field[i]) + SignalAvg[x] = raw[4] + x = x +1 + self.mean_wc[self.l,self.m] = np.mean(SignalAvg) + file_object.close() + self.wc_plt.imshow(self.mean_wc,self.colormap,vmin=0, vmax=np.amax(self.mean_cp2),origin='lower') + self.wc_canvas.draw() + shutil.move(arg0,self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) + shutil.move("wcvec.dat",self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) #save the worstcase vector file. We are done with the point + #This part is for the snake path. When one line finishes, it slides to the next location. + if (self.m % 2 == 0): + self.l = self.l + 1 + if self.l == self.a: + self.l = self.a-1 + self.m = self.m + 1 + else: + self.l = self.l -1 + if(self.l== -1): + self.l = 0 + self.m = self.m +1 + if self.m == self.b: + self.m=0 + return "OK" + elif(arg0 == "Dmatrix.dat"): + #goTMaTcalc() + shutil.move(arg0,self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) + return "OK" + time.sleep(self.FileCheckRate) + + + def sendCoordinates(): + print(self.currCoorIndex) + if(int(coordinatesPassFileX[self.currCoorIndex]) != 999): + rawCoX = [int(d) for d in str(int(coordinatesPassFileX[self.currCoorIndex]))] + rawCoY = [int(d) for d in str(int(coordinatesPassFileY[self.currCoorIndex]))] + rawCoZ = [int(d) for d in str(int(coordinatesPassFileZ[self.currCoorIndex]))] + #Save coordinates + file_object = open(workingDir+dt_string+'coordinatefile.dat', 'a') + file_object.write("X"+str(int(coordinatesPassFileX[self.currCoorIndex]))+" Y"+ str(int(coordinatesPassFileY[self.currCoorIndex]))+ " Z"+ str(int(coordinatesPassFileZ[self.currCoorIndex]))) + file_object.close() + if((coordinatesPassFileX[self.currCoorIndex]<100) and (coordinatesPassFileX[self.currCoorIndex] > 9)): + self.x1 = str(0) + self.x2 = str(rawCoX[0]) + self.x3 = str(rawCoX[1]) + elif(coordinatesPassFileX[self.currCoorIndex]>99): + self.x3 = str(rawCoX[2]) + self.x2 = str(rawCoX[1]) + self.x1 = str(rawCoX[0]) + elif(coordinatesPassFileX[self.currCoorIndex]<10): + self.x1 = str(0) + self.x2 = str(0) + self.x3 = str(rawCoX[0]) + if((coordinatesPassFileY[self.currCoorIndex]<100) and (coordinatesPassFileY[self.currCoorIndex] > 9)): + self.y1 = str(0) + self.y2 = str(rawCoY[0]) + self.y3 = str(rawCoY[1]) + elif(coordinatesPassFileY[self.currCoorIndex]>99): + self.y3 = str(rawCoY[2]) + self.y2 = str(rawCoY[1]) + self.y1 = str(rawCoY[0]) + elif(coordinatesPassFileY[self.currCoorIndex]<10): + self.y2 = str(0) + self.y1 = str(0) + self.y3 = str(rawCoY[0]) + if((coordinatesPassFileZ[self.currCoorIndex]<100) and (coordinatesPassFileZ[self.currCoorIndex] > 9)): + self.z1 = str(0) + self.z2 = str(rawCoZ[0]) + self.z3 = str(rawCoZ[1]) + elif(coordinatesPassFileZ[self.currCoorIndex]>99): + self.z3 = str(rawCoZ[2]) + self.z2 = str(rawCoZ[1]) + self.z1 = str(rawCoZ[0]) + elif(coordinatesPassFileZ[self.currCoorIndex]<10): + self.z2 = str(0) + self.z1 = str(0) + self.z3 = str(rawCoZ[0]) + print("Waiting for Cosi to complete operation") + if(self.sendingInit == True): + self.s.send("MOV" + self.x1 + self.x2 + self.x3 + self.y1 + self.y2 + self.y3 + self.z1 + self.z2 + self.z3) + self.sendingInit = False + self.currCoorIndex = self.currCoorIndex + 1 + self.data = self.s.recv(self.BUFFER_SIZE) + self.sending = False + #startPath() + else: + print("Finished!") + self.currCoorIndex = 0 + def pathFromFile(): + self.file_object = open("PathFile.txt", "r") + self.coordinatesPassFile = self.file_object.readlines() + global coordinatesPassFileX,coordinatesPassFileY,coordinatesPassFileZ + coordinatesPassFileX = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + coordinatesPassFileY = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + coordinatesPassFileZ = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + + self.currCoorIndex = 0 + self.dirIndex = 1 + for i in range(len(self.coordinatesPassFile)): + raw = re.split("(\s+)",self.coordinatesPassFile[i]) + coordinatesPassFileZ[i] = raw[4] + coordinatesPassFileY[i] = raw[2] + coordinatesPassFileX[i] = raw[0] + coordinatesPassFileZ[-1] = "999" + coordinatesPassFileY[-1] = "999" + coordinatesPassFileX[-1] = "999" + self.cp_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.op_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.wc_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + + self.mean_cp2 = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.mean_op1 = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.mean_wc = np.zeros((len(xCorr), len(yCorr)),dtype = float) + + colormap = "jet" + self.wc_plt.imshow(self.wc_mat,colormap) + self.op_plt.imshow(self.op_mat,colormap) + self.cp_plt.imshow(self.cp_mat,colormap) + def preparePath(): + xCorrStart = int(self.e1.get()) + xCorrStop = int(self.e2.get()) + xResolution = int(self.e3.get()) + yCorrStart = int(self.e4.get()) + yCorrStop = int(self.e5.get()) + yResolution = int(self.e6.get()) + zCorrStart = int(self.e7.get()) + zCorrStop = int(self.e8.get()) + zResolution = int(self.e9.get()) + xCorr = np.arange(xCorrStart,xCorrStop+1,xResolution) + self.a = len(xCorr) + yCorr = np.arange(yCorrStart,yCorrStop+1,yResolution) + self.b = len(yCorr) + zCorr = np.arange(zCorrStart,zCorrStop+1,zResolution) + z = 0 + passListSize = len(xCorr)*len(yCorr)*len(zCorr) + self.passList = ["" for x in range(passListSize)] + offset = len(yCorr) - 1 + for k in range (len(zCorr)): + for i in range(len(yCorr)): + for j in range(len(xCorr)): + if(i % 2 == 0): + self.passList[z] = (str(xCorr[j])+ " "+ str(yCorr[i])+ " " + str(zCorr[k])) # +"\n") + else: + self.passList[z] = (str(xCorr[len(xCorr)-1-j])+ " "+ str(yCorr[i])+ " " + str(zCorr[k])) #+"\n") + z = z + 1 + + self.cp_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.op_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.wc_mat = np.zeros((len(xCorr), len(yCorr)),dtype = float) + + self.mean_cp2 = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.mean_op1 = np.zeros((len(xCorr), len(yCorr)),dtype = float) + self.mean_wc = np.zeros((len(xCorr), len(yCorr)),dtype = float) + + colormap = "jet" # coolwarm + self.wc_plt.imshow(self.wc_mat,colormap) + self.op_plt.imshow(self.op_mat,colormap) + self.cp_plt.imshow(self.cp_mat,colormap) + self.coordinatesPassFile = self.passList + global coordinatesPassFileX,coordinatesPassFileY,coordinatesPassFileZ + coordinatesPassFileX = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + coordinatesPassFileY = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + coordinatesPassFileZ = np.array(np.zeros(len(self.coordinatesPassFile)+1)) + self.currCoorIndex = 0 + self.dirIndex = 1 + for i in range(len(self.coordinatesPassFile)): + raw = re.split("(\s+)",self.coordinatesPassFile[i]) + coordinatesPassFileZ[i] = raw[4] + coordinatesPassFileY[i] = raw[2] + coordinatesPassFileX[i] = raw[0] + coordinatesPassFileZ[-1] = "999" + coordinatesPassFileY[-1] = "999" + coordinatesPassFileX[-1] = "999" + def printPath(): + for i in range (len(self.passList)): + print(self.passList[i]) + ##TODO Write Path to a file + + def connectToCosi(): + self.TCP_PORT = 7001 + self.s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) + self.s.connect((self.TCP_IP, self.TCP_PORT)) + def SendOK(): + self.s.send("OK") + self.data = self.s.recv(self.BUFFER_SIZE) + print ("received data:"), self.data + def CloseConn(): + self.s.send("CLOSECONN") + self.data = self.s.recv(self.BUFFER_SIZE) + print ("Response from the COSI:"), self.data + self.s.close() + def startPath(): + while self.sending == False: + if ("MOVOK"== self.data) and (self.sendingInit == False): + self.sending = True + self.s.send("MOV" + self.x1 + self.x2 + self.x3 + self.y1 + self.y2 + self.y3 + self.z1 + self.z2 + self.z3) + self.currCoorIndex = self.currCoorIndex + 1 + sendCoordinates() + break; + elif("MOVOK"== self.data) and (self.sendingInit == True): + self.sending = True + #self.currCoorIndex = self.currCoorIndex + 1 + sendCoordinates() + break; + + + def DmatrixLoop(): + #Check and assure Ethernet Connection with COSI + if self.s : + print("Cosi seems to be connectted") + else: + connectToCosi() + #Prepare Path File + #Check the key. if the path is from a custom file the keys should match. Otherwise take them from the GUI + #Key: 347 499 76 54 204 75 287 287 1 + if ((int(self.e1.get())== 347) and (int(self.e2.get())== 499) and (int(self.e3.get())== 76) and (int(self.e4.get())== 54) and (int(self.e5.get())== 204) and (int(self.e6.get())== 75) and (int(self.e7.get())== 287) and (int(self.e8.get())== 287) and (int(self.e9.get())== 1)): + customFileFlag = True + else: + customFileFlag = False + if(customFileFlag): + pathFromFile() + else: + preparePath() + self.currCoorIndex = 0 + + SendOK() #Ping COSI + print("Send OK OK") + if ("MOVOK" == self.data): #wait for ACK + #LoopStart + print("Starting Mapping") + for i in range (len(self.passList)): + + #Save files to here + os.makedirs(self.workingDir+ "/" +self.dstPathName+"/"+str(self.dirIndex)) + + #MOV to Position + startPath() + time.sleep(1) # For safety, decrease vibration etc. This can be adjusted. This is an emprical setting. + + #Send the composite pulse and obtain 'wcvec.dat' + subprocess.Popen('./rec_m4i_tdfilter_2ch_tds 297233750. 297233750.',shell=True) + + time.sleep(2) #Receiver needs some time to settle (2 second is for safety. It can run much faster. This part can be optimized) + + #Start transmitter + p = subprocess.Popen('./pex_m4i_CP 0 0.5',shell=True) + + p.communicate() # Wait for transmitter from the system. This is more safer than an emprical timing + time.sleep(1.2) # The reveiver code may still need some time to complete file writing operation. + + #Start the receiver first + subprocess.Popen('./rec_m4i_tdfilter_2ch_tds 297233750. 297233750. > CP.dat',shell=True) + + time.sleep(2) #Receiver needs some time to settle (2 second is safer) + + #Start transmitter + p = subprocess.Popen('./pex_m4i_CP 1 0.5',shell=True) + + p.communicate() # Wait for transmitter from the system. This is more safer than an emprical timing + time.sleep(1.2) # The reveiver code may still need some time to complete file writing operation. + arrangeData("CP.dat") #check the file and copy to a relevant place. + #Start the receiver first + subprocess.Popen('./rec_m4i_tdfilter_2ch_tds 297233750. 297233750. > OP.dat',shell=True) + + time.sleep(2) #Receiver needs some time to settle (2 second is safer) + + #Start transmitter + p = subprocess.Popen('./pex_m4i_OP 1 0.5',shell=True) + + p.communicate() # Wait for transmitter from the system. This is more safer than an emprical timing + time.sleep(1.2) # The reveiver code may still need some time to complete file writing operation. + arrangeData("OP.dat") #check the file and copy to a relevant place. + #Start the receiver first + subprocess.Popen('./rec_m4i_tdfilter_2ch_tds 297233750. 297233750. > WC.dat',shell=True) + + time.sleep(2) #Receiver needs some time to settle (2 second is safer) + + #Start transmitter + p = subprocess.Popen('./pex_m4i_WC 1 0.5',shell=True) + + p.communicate() # Wait for transmitter from the system. This is more safer than an emprical timing + time.sleep(1.2) # The reveiver code may still need some time to complete file writing operation. + arrangeData("WC.dat") #check the file and copy to a relevant place. + self.dirIndex = self.dirIndex + 1 + CloseConn() #Finished the loop. Close the connection. + def DmatrixLoopTHR(): + self.thrGetSeqStats = threading.Thread(name='DThread',target=DmatrixLoop) #Set the thread. Threading is nesc. to see the GUI updates + self.thrGetSeqStats.start() +#-----------------------GUI Arrangement Data------------------------ + buttonRowValue = 17 + xTextColVal = 0 + yTextColVal = 3 + zTextColVal = 6 + xtextRowValue = 13 + ytextRowValue = 13 + ztextRowValue = 13 + xEntryRowValue = xtextRowValue + yEntryRowValue = ytextRowValue + zEntryRowValue = ztextRowValue + xEntryColValue = xTextColVal + 1 + yEntryColValue = yTextColVal + 1 + zEntryColValue = zTextColVal + 1 +#-----------------------End Gui arrangements--------------------------------# + self.e1.grid(row=xEntryRowValue , column=xEntryColValue)#,sticky=W) + self.e2.grid(row=xEntryRowValue+1, column=xEntryColValue)#,sticky=W) + self.e3.grid(row=xEntryRowValue+2, column=xEntryColValue)#,sticky=W) + self.e4.grid(row=yEntryRowValue , column=yEntryColValue,sticky=E) + self.e5.grid(row=yEntryRowValue+1, column=yEntryColValue,sticky=E) + self.e6.grid(row=yEntryRowValue+2, column=yEntryColValue,sticky=E) + self.e7.grid(row=zEntryRowValue , column=zEntryColValue)#,sticky=W) + self.e8.grid(row=zEntryRowValue+1, column=zEntryColValue)#,sticky=W) + self.e9.grid(row=zEntryRowValue+2, column=zEntryColValue)#,sticky=W) + self.refRate = 10 + #Initialize the matrices and do a dummy fill. + self.cp_mat = np.zeros((17, 17),dtype = float) + self.op_mat = np.zeros((17, 17),dtype = float) + self.wc_mat = np.zeros((17, 17),dtype = float) + self.cp_mat.fill(0.5) + self.op_mat.fill(0.5) + self.wc_mat.fill(0.5) + plt.rcParams.update({'font.size': 20}) + + #Create the figures and their canvas + #CP + cp_fig = plt.figure(figsize=(6,6), dpi=imagedpi) + self.cp_plt = cp_fig.add_subplot(111) + plt.title("Circular Polarization") + self.cp_plt.imshow(self.cp_mat,"coolwarm") + self.cp_canvas = FigureCanvasTkAgg(cp_fig, master) + self.cp_canvas.draw() + self.cp_canvas.get_tk_widget().grid(row=0, column=0,columnspan=3, rowspan=12,sticky=W+E+N+S) + + #OP + OP_fig = plt.figure(figsize=(6,6), dpi=imagedpi) + self.op_plt = OP_fig.add_subplot(111) + self.op_plt.imshow(self.op_mat,"coolwarm") + plt.title("Orthogonal Projection") + self.op_canvas = FigureCanvasTkAgg(OP_fig, master) + self.op_canvas.draw() + self.op_canvas.get_tk_widget().grid(row=0, column=3,columnspan=3, rowspan=12,sticky=W+E+N+S) + + #WC + WC_fig = plt.figure(figsize=(6,6), dpi=imagedpi) + self.wc_plt = WC_fig.add_subplot(111) + self.wc_plt.imshow(self.wc_mat,"coolwarm") + plt.title("Worst Case") + self.wc_canvas = FigureCanvasTkAgg(WC_fig, master) + self.wc_canvas.draw() + self.wc_canvas.get_tk_widget().grid(row=0, column=6,columnspan=3, rowspan=12,sticky=W+E+N+S) + + #Some font settings for appearance + CloseConnbuttonFont = font.Font(size=11, weight='bold') # Font Family family='Courier', + exitbuttonFont = font.Font(size=12, weight='bold') # Font Family family='Courier', + mappingbuttonFont = font.Font(size=12, weight='bold') # Font Family family='Courier', + #Label settings for the path + Label(master, text = "xCorrStart").grid (row = xtextRowValue , column=xTextColVal,sticky=W) + Label(master, text = "xCorrStop").grid (row = xtextRowValue+1, column=xTextColVal,sticky=W) + Label(master, text = "xResolution").grid (row = xtextRowValue+2, column=xTextColVal,sticky=W) + Label(master, text = "yCorrStart").grid (row = ytextRowValue , column=yTextColVal) + Label(master, text = "yCorrStop").grid (row = ytextRowValue+1, column=yTextColVal) + Label(master, text = "yResolution").grid (row = ytextRowValue+2, column=yTextColVal) + Label(master, text = "zCorrStart").grid (row = ztextRowValue , column=zTextColVal) + Label(master, text = "zCorrStop").grid (row = ztextRowValue+1, column=zTextColVal) + Label(master, text = "zResolution").grid (row = ztextRowValue+2, column=zTextColVal) + ####Buttons#### + Button(master, text = "Close Connection" , command=CloseConn ,font=CloseConnbuttonFont, bg='#12FF00').grid(row =buttonRowValue, column = 4) + Button(master, text = "Start Mapping" , command=DmatrixLoopTHR ,font=mappingbuttonFont , bg='#0052cc', fg='#ffffff').grid(row =buttonRowValue, column = 7) + Button(master, text = "Exit" , command=doExit ,font=exitbuttonFont , bg='#FF0000', fg='#ffffff').grid(row =buttonRowValue, column = 0) + #Seperators + sep1= ttk.Separator(master , orient =HORIZONTAL).grid(row =ztextRowValue+3, column = 0, columnspan= 99 , sticky = "ewns") + sepx= ttk.Separator(master , orient =VERTICAL).grid(row =ztextRowValue , column = xTextColVal+2, rowspan= 3, sticky = "nse") + sepy= ttk.Separator(master , orient =VERTICAL).grid(row =ztextRowValue , column = yTextColVal+2, rowspan= 3, sticky = "nse") + sepz= ttk.Separator(master , orient =VERTICAL).grid(row =ztextRowValue , column = zTextColVal+2, rowspan= 3, sticky = "nse") + mainloop() +master = Tk() +test = MainClass(master) +test.StartGui(master)