class matplotlibSwitchGraphs: def __init__(self, master): self.master = master self.frame = Frame(self.master) self.fig, self.ax = config_plot() self.graphIndex = 0 self.canvas = FigureCanvasTkAgg(self.fig, self.master) self.config_window() self.draw_graph('janvier') self.frame.pack(expand=YES, fill=BOTH) def config_window(self): self.canvas.mpl_connect("key_press_event", self.on_key_press) toolbar = NavigationToolbar2Tk(self.canvas, self.master) toolbar.update() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) self.button = Button(self.master, text="Quit", command=self._quit) self.button.pack(side=BOTTOM) self.button_back = Button(self.master, text="Graphique précédent", command=self.back_graph) self.button_back.pack(side=BOTTOM) self.button_next = Button(self.master, text="Graphique suivant", command=self.next_graph) self.button_next.pack(side=BOTTOM) def draw_graph(self, month): if(month == 'année'): df_temp = pd.DataFrame(columns = ['Température']) for column in df: for value in df[column]: df_temp = df_temp.append({'Températeure':value},ignore_index=True) df_temp.dropna() self.ax.clear() self.ax.plot(df_temp['Température']) self.ax.set(title='Année') self.canvas.draw() else: self.ax.clear() self.ax.plot(df[month]) self.ax.set(title=month) self.canvas.draw() def on_key_press(event): key_press_handler(event, self.canvas, toolbar) def _quit(self): self.master.quit() def next_graph(self): if self.graphIndex == 0: self.draw_graph('février') self.graphIndex = 1 elif self.graphIndex == 1: self.draw_graph('mars') self.graphIndex = 2 elif self.graphIndex == 2: self.draw_graph('avril') self.graphIndex = 3 elif self.graphIndex == 3: self.draw_graph('mai') self.graphIndex = 4 elif self.graphIndex == 4: self.draw_graph('juin') self.graphIndex = 5 elif self.graphIndex == 5: self.draw_graph('juillet') self.graphIndex = 6 elif self.graphIndex == 6: self.draw_graph('août') self.graphIndex = 7 elif self.graphIndex == 7: self.draw_graph('septembre') self.graphIndex = 8 elif self.graphIndex == 8: self.draw_graph('octobre') self.graphIndex = 9 elif self.graphIndex == 9: self.draw_graph('novembre') self.graphIndex = 10 elif self.graphIndex == 10: self.draw_graph('décembre') self.graphIndex = 11 elif self.graphIndex == 11: self.draw_graph('janvier') self.graphIndex = 0 elif self.graphIndex == 12: self.draw_graph('année') self.graphIndex = 12 def back_graph(self): if self.graphIndex == 0: self.draw_graph('décembre') self.graphIndex = 11 elif self.graphIndex == 11: self.draw_graph('novembre') self.graphIndex = 10 elif self.graphIndex == 10: self.draw_graph('octobre') self.graphIndex = 9 elif self.graphIndex == 9: self.draw_graph('septembre') self.graphIndex = 8 elif self.graphIndex == 8: self.draw_graph('août') self.graphIndex = 7 elif self.graphIndex == 7: self.draw_graph('juillet') self.graphIndex = 6 elif self.graphIndex == 6: self.draw_graph('juin') self.graphIndex = 5 elif self.graphIndex == 5: self.draw_graph('mai') self.graphIndex = 4 elif self.graphIndex == 4: self.draw_graph('avril') self.graphIndex = 3 elif self.graphIndex == 3: self.draw_graph('mars') self.graphIndex = 2 elif self.graphIndex == 2: self.draw_graph('février') self.graphIndex = 1 elif self.graphIndex == 1: self.draw_graph('janvier') self.graphIndex = 0 elif self.graphIndex == 12: self.draw_graph('année') self.graphIndex = 12 def main(): root = Tk() matplotlibSwitchGraphs(root) root.mainloop() def show_graph(): main() fenetre = Tk() fenetre.title("Data tp 1") fenetre.geometry('800x800') canvas=Canvas(fenetre,bg='#FFFFFF',width=800,height=800,scrollregion=(0,0,1500,1500)) hbar=Scrollbar(fenetre,orient=HORIZONTAL) hbar.pack(side=BOTTOM,fill=X) hbar.config(command=canvas.xview) vbar=Scrollbar(fenetre,orient=VERTICAL) vbar.pack(side=RIGHT,fill=Y) vbar.config(command=canvas.yview) canvas.config(width=800,height=800) canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) canvas.pack(side=LEFT,expand=True,fill=BOTH) for index, column in enumerate(df): canvas.create_text(100,(index*120)+20,fill="black",font="Times 15 bold", text="Mois : "+str(column)) canvas.create_text(100,(index*120)+40,fill="black",font="Times 10", text="Moyenne : "+str(df[column].mean())) canvas.create_text(100,(index*120)+60,fill="black",font="Times 10", text="Ecart type : "+str(df[column].std())) canvas.create_text(100,(index*120)+80,fill="black",font="Times 10", text="Minimum : "+str(df[column].min())) canvas.create_text(100,(index*120)+100,fill="black",font="Times 10", text="Maximum : "+str(df[column].max())) b = Button(fenetre, text="Afficher les graphiques", width=10, command=show_graph,background="white",foreground="black",activebackground="white",activeforeground="black") b.place(x=300, y=20, anchor="nw", width=150, height=30) fenetre.mainloop()
class App: #constructor def __init__(self): self.data=data self.fewarrows=0 self.MakeWindow() self.refreshDataFrame() self.refreshPicFrame() self.fixent=1 #UGLY FIX FOR ENTRIES/ENTRIESIJ # self.root.mainloop() -maybe needed for Windows OS #makes frames and frames within frames needed for correct display def MakeWindow (self): self.root=tk.Tk() self.root.wm_title("Data Input and Graphical Output") self.outsideframed1=tk.Frame(self.root,width=300, height=800) self.outsideframepic=tk.Frame(self.root,width=675, height=800) self.outsideframed1.pack(side=tk.LEFT,fill=None,expand=False) self.outsideframepic.pack(side=tk.LEFT,fill=None,expand=False) self.outsideframed1.pack_propagate(False) self.outsideframepic.pack_propagate(False) self.framed1=tk.Frame(self.outsideframed1,width=200, height=100) self.framed1.pack(side=tk.LEFT,fill=None,expand=False) self.framepic=tk.Frame(self.outsideframepic,borderwidth=5,relief=tk.RIDGE) self.framepic.pack(side=tk.TOP,fill=tk.BOTH,expand=1) #BIG-BAD self.refreshDataFrame() self.refreshPicFrame() #makes the plot: boxes and the (fancy) arrows connecting them def createBoxGraph(self): TextBox.list_box=[] #CLEAR ALL PREVIOUS!!! f = plt.figure(facecolor = 'white') f.set_size_inches(8,10) a = f.add_subplot(111) a.axis('off') for index in range(len(data.b)): xy=data.bxy[index] TextBox(a,xy[0],xy[1],data.b[index],index,data.labels[index],data.boxcolor[index]) id=0 if (self.fewarrows==0): for i in range(len(data.b)): for j in range(len(data.b)): if i!=j and data.a[i][j]!=0: arrow=ArrowObject(a,i,j,id) id=id+1 else: i=self.box_id for j in range(len(data.b)): if i!=j and data.a[i][j]!=0: arrow=ArrowObject(a,i,j,id) id=id+1 j=self.box_id for i in range(len(data.b)): if i!=j and data.a[i][j]!=0: arrow=ArrowObject(a,i,j,id) id=id+1 plt.show(block=False) #coding trick to close extra figures accidentally created in canvas---- openfigs=plt.get_fignums() last=openfigs[-1] plt.close(last) #coding trick to close extra figures accidentally created in canvas---- return f #used to scale the sizes of the textboxes def scalebox(vector): data2=[0 for i in range(len(vector))] minbox,maxbox=2,30 minb,maxb=min(vector),max(vector) if minb!=maxb: data2=[(vector[i]-minb)/(maxb-minb) for i in range(len(vector))] vectornew=[(maxbox-minbox)*data2[i]+minbox for i in range(len(vector))] else: vectornew=[(minbox+maxbox)/2. for i in range(len(vector))] return vectornew #Euler numerical integration of the ordinary differential equations def recalculate(self,pass_data): #UGLY FIX FOR ENTRIES/ENTRIESIJ---------------------------------------- if self.fixent==1: self.data.z[0]=[eval((self.entries[i][1].get())) for i in range(len(self.entries))] if self.fixent==2: column=[eval((self.entriesIJ[i][1].get())) for i in range(len(self.entriesIJ))] self.data.ca[:,self.box_id]=column #UGLY FIX FOR ENTRIES/ENTRIESIJ---------------------------------------- self.fewarrows=0 pass_data.tt=0 for i in range (1,pass_data.numdata): mtanh=np.tanh(pass_data.z[i-1]) cterm=np.dot(pass_data.ca,mtanh) pass_data.dx=pass_data.dt*(pass_data.ma*pass_data.z[i-1] + pass_data.ba + cterm) pass_data.tt=pass_data.tt+pass_data.dt pass_data.t[i]=pass_data.tt pass_data.z[i]=pass_data.z[i-1]+pass_data.dx for j in range(pass_data.numc): pass_data.z[i][j]=max(pass_data.z[i][j],0.) #holding values constant if pass_data.hold==1: pass_data.z[i][pass_data.jfix]=pass_data.jvalue #make new plot App.MakePlot(data) #scale b's from z[-1] vector=data.z[-1] data.b=App.scalebox(vector) #set z[0]=z[-1] for the NEXT iteration pass_data.z[0]=pass_data.z[-1] #CLEAR and REFRESH DATA and PIC frames App.ClearFrame(self.framed1) App.ClearFrame(self.framepic) self.refreshDataFrame() self.refreshPicFrame() #makes plot of x(i) vs. time def MakePlot(pass_data): print('\nYour plot is ready') localtime = time.asctime( time.localtime(time.time()) ) x_start=pass_data.z[0] x_final=pass_data.z[-1] plt.figure() plt.axes([0.1,.075,.8,.7]) plt.plot(pass_data.t,pass_data.z[:,0:pass_data.numc]) #print labels on lines xtext=25 for i in range (pass_data.numc): ytext=pass_data.z[-1,i] varis=str(i) #first variable is 0 plt.text(xtext,ytext,varis) xtext=xtext-1 programname='teal.py, tealclass.py, data.py '+localtime param1='\n input files= '+str(pass_data.fnamec)+' ' +str(pass_data.fnameb)+' '+str(pass_data.fnamem) +' '+str(pass_data.fnamebtextbxy) + ' dt='+str(pass_data.dt) start=App.displayinput(pass_data.z[0],75) finish=App.displayinput(pass_data.z[-1],75) param2='\nstart= ' + start + '\nfinish= ' + finish titlelsl=programname+param1 + param2 plt.title(titlelsl, fontsize=8) plt.show(block=False) #IMPORTANT: to SHOW graph but NOT stop execution #rounds numbers for x(start), x(final) in the title of plot x(i) vs. time def displayinput(vector1,number): #creates string to print from np.array(vector1) #that is approximately number characters per line c='' v1=vector1.tolist() v2=[round(v1[i],6) for i in range (len(v1))] a=str(v2) a2=a.replace(' ','') a3=list(a2) a3[0],a3[-1]='','' numend=0 for i in range(0,len(a3)): if (a3[i]==',' and numend >= number): numend=0 a3[i]=',\n' numend=numend+1 c=''.join(a3) c2=c.replace(',',', ') return c2 #clear and refresh ONLY the left initial condition dataframe def refreshDataFrame(self): self.fixent=1 #UGLY FIX FOR ENTRIES/ENTRIESIJ App.ClearFrame(self.framed1) #frame and buttons on top newframe=tk.Frame(self.framed1) newframe.pack(side=tk.TOP,pady=0) tk.Label(newframe,text='initial conditions',fg='blue').pack(side=tk.LEFT,padx=30,pady=5) tk.Button(newframe,text='original',command= self.resetIC).pack(side=tk.RIGHT,padx=30,pady=5) newframe2=tk.Frame(self.framed1) newframe2.pack(side=tk.TOP,pady=0) cal1=tk.Button(newframe2,text='CALCULATE',command=(lambda: self.recalculate(data))) cal1.pack(side=tk.LEFT,padx=30,pady=5) tk.Button(newframe2,text='ENTER',command=self.refreshPicFrame).pack(side=tk.LEFT,padx=30,pady=5) #frame for entry widgets for initial conditions self.framecanvas=tk.Frame(self.framed1) self.framecanvas.pack(side=tk.BOTTOM,pady=0) #adding the scroll bar sizescroll=31*data.numc self.canvas = tk.Canvas(self.framecanvas,width=400,height=800,scrollregion=(0,0,sizescroll,sizescroll)) #FROM LAUNY self.canvas.pack(side=tk.LEFT) scrollbar = tk.Scrollbar(self.framecanvas, command=self.canvas.yview) scrollbar.pack(side=tk.LEFT, fill='y') self.canvas.config(width=280,height=800) self.canvas.configure(yscrollcommand = scrollbar.set) self.frame = tk.Frame(self.canvas) self.canvas.create_window((0,0), window=self.frame, anchor='nw') # creating the initial condition entry widgets fields=data.labels default=[str(i) for i in range(len(data.labels))] entries = [] self.data.zround=[str(round(self.data.z[-1,i],6)) for i in range(len(self.data.z[0]))] for field in fields: row = tk.Frame(self.frame) lab = tk.Label(row, width=12, text=field, anchor='w') ent = tk.Entry(row,width=10) row.pack(side=tk.TOP, padx=5, pady=0, expand=1) lab.pack(side=tk.LEFT,expand=1) ent.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.Y) ent.insert(10,self.data.zround[fields.index(field)]) entries.append((field, ent)) self.entries=entries #TRANSFORM ALL ENTRIES INTO STARTING VALUES FOR COMPUTATION self.data.z[0]=[eval((entries[i][1].get())) for i in range(len(entries))] self.outsideframed1.pack(expand=1) #KEEPING THIS FOR THE MOMENT HERE return #redraw the textboxes and the arrows connecting them def refreshPicFrame(self): #UGLY FIX FOR ENTRIES/ENTRIESIJ---------------------------------------- if self.fixent==1: self.data.z[0]=[eval((self.entries[i][1].get())) for i in range(len(self.entries))] if self.fixent==2: column=[eval((self.entriesIJ[i][1].get())) for i in range(len(self.entriesIJ))] self.data.ca[:,self.box_id]=column #UGLY FIX FOR ENTRIES/ENTRIESIJ---------------------------------------- #scale b's from z[0] - NOT Z[-1] like in A NEW CALCULATION vector=data.z[0] self.data.b=App.scalebox(vector) #set z[0]=z[-1] for the NEXT iteration App.ClearFrame(self.framepic) self.canvas=tk.Canvas(self.framepic,width=800, height=2400) f=self.createBoxGraph() self.canvas = FigureCanvasTkAgg(f, master=self.framepic) self.canvas.show() self.canvas._tkcanvas.pack() cid=f.canvas.mpl_connect('button_press_event',self.onclick) #clear and refresh ONLY the left cij adjacency matrix dataframe def refreshCIJFrame(self): self.fixent=2 #UGLY FIX FOR ENTRIES/ENTRIESIJ App.ClearFrame(self.framed1) fromto='FROM '+data.labels[self.box_id]+' TO' #frame and top buttons newframe=tk.Frame(self.framed1) newframe.pack(side=tk.TOP,pady=0) tk.Label(newframe,text=fromto,bg='thistle1',fg='red').pack(side=tk.LEFT,padx=5) tk.Button(newframe,text='ALL Cij',command= self.FullrefreshPicFrame).pack(side=tk.LEFT,padx=5) tk.Button(newframe,text='IC',command= self.refreshDataFrame).pack(side=tk.LEFT,padx=5) newframe2=tk.Frame(self.framed1) newframe2.pack(side=tk.TOP,pady=0) cal2=tk.Button(newframe2,text='CALCULATE',command=(lambda: self.recalculate(data))) cal2.pack(side=tk.LEFT,padx=30,pady=5) tk.Button(newframe2,text='ENTER',command=self.refreshPicFrame).pack(side=tk.LEFT,padx=30,pady=5) #frame for entry widgets for cij adjacency matrix self.framecanvas=tk.Frame(self.framed1) self.framecanvas.pack(side=tk.BOTTOM,pady=0) #adding the scroll bar sizescroll=31*data.numc self.canvas = tk.Canvas(self.framecanvas,width=400,height=800,scrollregion=(0,0,sizescroll,sizescroll)) #FROM LAUNY self.canvas.pack(side=tk.LEFT) scrollbar = tk.Scrollbar(self.framecanvas, command=self.canvas.yview) scrollbar.pack(side=tk.LEFT, fill='y') self.canvas.config(width=280,height=800) self.canvas.configure(yscrollcommand = scrollbar.set) self.frame = tk.Frame(self.canvas) self.canvas.create_window((0,0), window=self.frame, anchor='nw') # creating the cij adjacency matrix entry widgets fields=self.data.labels entriesIJ = [] for field in fields: row = tk.Frame(self.frame) lab = tk.Label(row, width=15, text=field, anchor='w',bg='thistle1') entIJ = tk.Entry(row,bg='thistle1') row.pack(side=tk.TOP, padx=5, pady=1, expand=1) lab.pack(side=tk.LEFT,expand=1) entIJ.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.Y) entIJ.insert(10,self.data.ca[fields.index(field)][self.box_id]) entriesIJ.append((field, entIJ)) self.entriesIJ=entriesIJ #TRANSFORM ALL ENTRIES INTO STARTING VALUES FOR COMPUTATION column=[eval((self.entriesIJ[i][1].get())) for i in range(len(self.entriesIJ))] self.data.ca[:,self.box_id]=column self.outsideframed1.pack(expand=1) return #return the textbox id that was clicked def onclick(self,event): for box in TextBox.list_box: contains, attrd = box.text.contains(event) if(contains): id=box.id print('\nid,bname(id)= ',id, data.labels[id]) # print('box_%d' % id) # print('box_' + data.bname[id]) # print('show vars ') # self.update_dataFrame(id) self.box_id=id self.fewarrows=1 self.refreshCIJFrame() # TextBox.selected_box_id=id return; #reset the initial conditions to the input data ic(i) default values def resetIC(self): self.data.z[-1]=[self.data.ica[i] for i in range(len(self.data.z[0]))] self.refreshDataFrame() #not used def FullrefreshPicFrame(self): self.fewarrows=0 self.refreshPicFrame() #not used, but nice to have to end execution def myquit(self): print ('\n I did press CLOSE!') self.root.destroy() #removes ALL widgets in frame #seemed a better option than forget def ClearFrame(frame): for widget in frame.winfo_children(): widget.destroy() # frame.pack_forget() #not used #thought needed for binding scroll bar, apparently not def on_configure(event): # update scrollregion after starting 'mainloop' # when all widgets are in canvas # self.canvas=canvas canvas.configure(scrollregion=canvas.bbox('all')) #summing postive and negtive into two seperate arrays # pass_data.negindex/posindex are not needed # to excute run App.sumpn(pass_data) def sumpn(pass_data): negkeys={} # will be used for get the keys to be used in the summing poskeys={} pass_data.avg=0 pass_data.avgpos=0 pass_data.avgneg=0 for x in range(0,len(pass_data.btextbxydata)): if (pass_data.btextbxydata[x][1]=="gray"): #pass_data.negindex.append(x) pass_data.negfin[x]=pass_data.z[-1][x] negkeys=list(pass_data.negfin.keys()) else: #pass_data.posindex.append(x) pass_data.posfin[x]=pass_data.z[-1][x] poskeys=list(pass_data.posfin.keys()) #adding the positve and negative values for i in range(0,len(negkeys)): pass_data.sumneg+=pass_data.negfin[negkeys[i]] pass_data.avgneg=(pass_data.sumneg/len(negkeys)) if(i==(len(negkeys)-1)): pass_data.sumneg=0 pass_data.negfin={} for j in range(0,len(poskeys)): pass_data.sumpos+=pass_data.posfin[poskeys[j]] pass_data.avgpos=(pass_data.sumpos/len(poskeys)) if(j==(len(poskeys)-1)): pass_data.sumpos=0 pass_data.posfin={} pass_data.avg=pass_data.avgpos-pass_data.avgneg pass_data.avgpos=0 pass_data.avgneg=0
class GUI(): def __init__(self, tempDir): self.tempDir = tempDir self.done = False self.bg = "#f0f0f0" self.btnCol = "light grey" self.files = [] self.scales = [1 for x in range(10)] self.empty = [True for x in range(10)] self.data = [0 for x in range(10)] self.figures = [0 for x in range(10)] self.views = [-1 for x in range(10)] self.addresses = [0 for x in range(10)] self.resultTypes = [0 for x in range(10)] self.current = 0 def main_menu(self): #Displays the main menu page #========== Setup root = tk.Tk() root.configure(bg=self.bg) root.state("zoomed") h = root.winfo_screenheight() #========== Weighting root.rowconfigure(1, weight=1) root.rowconfigure(3, weight=1) root.rowconfigure(5, weight=1) root.rowconfigure(7, weight=1) root.rowconfigure(9, weight=1) root.columnconfigure(0, weight=1) #========== Widgets #===== Row 0, 1, 2 tk.Frame(root, bg=self.bg, height=round(h * 0.1)).grid(row=0, column=0) tk.Label(root, bg=self.bg, text="Microscope image analyser", justify="center", font=("Arial", round(h * 0.06))).grid(row=1, column=0) tk.Frame(root, bg=self.bg, height=round(h * 0.1)).grid(row=2, column=0) #===== Row 3, 4 tk.Button(root, bg=self.btnCol, text="Image analysis", justify="center", font=("Calibri", round(h * 0.03)), width=30, command=partial(self.select_file, root, "Select image to analyse", ("Png files", "*.png"), 0)).grid(row=3, column=0) tk.Frame(root, bg=self.bg).grid(row=4, column=0) #===== Row 5, 6 tk.Button(root, bg=self.btnCol, text="Load saved data", justify="center", font=("Calibri", round(h * 0.03)), width=30, command=partial(self.select_file, root, "Select results file", ("Text files", "*.txt"), 1)).grid(row=5, column=0) tk.Frame(root, bg=self.bg).grid(row=6, column=0) #===== Row 7, 8 tk.Button( root, bg=self.btnCol, text="View results", justify="center", font=("Calibri", round(h * 0.03)), width=30, command=lambda: [root.destroy(), self.results()]).grid(row=7, column=0) tk.Frame(root, bg=self.bg).grid(row=8, column=0) #===== Row 9 tk.Button(root, bg=self.btnCol, text="Quit", justify="center", font=("Calibri", round(h * 0.03)), width=30, command=root.destroy).grid(row=9, column=0) #===== Row 10 tk.Frame(root, height=round(h * 0.2)).grid(row=10, column=0) #========== Mainloop root.mainloop() def plot_histogram(self): #Creates a figure containing a histogram fig = Figure() fig.patch.set_facecolor(self.bg) plot = fig.gca() #Creates plot for histogram to be on plot.hist(self.data[self.current], 30) #Plot histogram with 30 bins plot.yaxis.set_major_locator( MaxNLocator(integer=True)) #Make ticks integers plot.set_xlabel("Diameter", fontsize=20) #Set label size plot.set_ylabel("Frequency", fontsize=20) plot.tick_params(labelsize=15) #Set tick label size self.figures[self.current] = fig #Record new figure def remove_entry(self, index, refresh, root=None): #Removes an item from the stored results, given the index def remove(array, index): #Removes 1 item from a list given its index return [array[x] for x in range(len(array)) if x != index] self.files = remove(self.files, index) self.scales = remove(self.scales, index) self.scales.append(1) self.empty = remove(self.empty, index) self.empty.append(True) self.data = remove(self.data, index) self.data.append(0) self.figures = remove(self.figures, index) self.figures.append(0) self.views = remove(self.views, index) self.views.append(-1) self.addresses = remove(self.addresses, index) self.addresses.append(0) self.resultTypes = remove(self.resultTypes, index) self.resultTypes.append(0) if refresh: if self.current > index: self.current -= 1 if self.current >= len(self.files) and len(self.files) > 0: self.current = len(self.files) - 1 root.destroy() self.results() def results(self): #Displays analysis results page #========== Setup root = tk.Tk() root.configure(bg=self.bg) root.state("zoomed") w = root.winfo_screenwidth() h = root.winfo_screenheight() #========== Weighting / padding root.rowconfigure(0, pad=h * 0.05) root.rowconfigure(12, pad=h * 0.05) root.columnconfigure(1, weight=1) root.columnconfigure(2, weight=1) root.columnconfigure(3, weight=1) root.columnconfigure(4, weight=1) #========== Widgets #===== Row 0 tk.Button( root, bg=self.btnCol, text="Main menu", justify="center", font=("Calibri", round(h * 0.02)), command=lambda: [root.destroy(), self.main_menu()]).grid( row=0, column=0, sticky="NW") self.resultsTitle = tk.StringVar() tk.Label(root, bg=self.bg, textvariable=self.resultsTitle, justify="center", font=("Arial", round(h * 0.04))).grid(row=0, column=0, columnspan=6) #===== Other results tk.Label(root, bg=self.bg, text="Other results:", justify="left", font=("Calibri", round(h * 0.03))).grid(row=1, column=5) self.others = [] for x in range(10): try: self.others.append( tk.Button(root, bg=self.btnCol, text=self.files[x], justify="left", font=("Calibri", round(h * 0.02)), width=20, command=partial(self.set_results, x, root))) except IndexError: self.others.append( tk.Button(root, bg=self.btnCol, text="", justify="left", font=("Calibri", round(h * 0.02)), width=20, command=partial(self.set_results, x, root))) self.others[x].grid(row=x + 2, column=5) tk.Button(root, bg=self.btnCol, text="X", justify="center", font=("Arial", round(h * 0.02)), width=2, command=partial(self.remove_entry, x, True, root)).grid(row=x + 2, column=6) #===== Row 12 tk.Label(root, bg=self.bg, text="Scale:", font=("Calibri", round(h * 0.03))).grid(row=12, column=0, sticky="E") root.bind("<Return>", partial(self.update_scale, root)) self.scaleEntry = tk.StringVar() tk.Entry(root, textvariable=self.scaleEntry, font=("Calibri", round(h * 0.03)), width=10).grid(row=12, column=1, sticky="W") tk.Button(root, bg=self.btnCol, text="Original image", width=15, font=("Calibri", round(h * 0.03)), command=partial(self.set_view, root, 1)).grid(row=12, column=2) tk.Button(root, bg=self.btnCol, text="Analysed image", width=15, font=("Calibri", round(h * 0.03)), command=partial(self.set_view, root, 2)).grid(row=12, column=3) tk.Button(root, bg=self.btnCol, text="Histogram", width=15, font=("Calibri", round(h * 0.03)), command=partial(self.set_view, root, 0)).grid(row=12, column=4) tk.Button(root, bg=self.btnCol, text="Save", width=10, font=("Calibri", round(h * 0.03)), command=self.save).grid(row=12, column=5) self.set_results(self.current, root) self.set_view(root, 0) root.mainloop() def save(self): #Writes the scale adjusted diameters to txt file in csv format name = self.files[self.current] #Get shorter identifier name = name[:name.rindex(".")] + "-results.txt" address = filedialog.asksaveasfilename(title="Save results file", initialfile=name, filetype=(("Text files", "*.txt"), ("All files", "*.*"))) file = open(address, "w+") file.write(','.join([str(X) for X in self.data[self.current]])) file.close( ) #Store diameters including scale adjustment, fstring used so it is 1 argument def select_file(self, root, title, filetype, resultType): #Allows the user to select an image file from a directory file = filedialog.askopenfilename(title=title, filetypes=(filetype, ("All files", "*.*"))) if file != "": #If operation not cancelled self.files.append(file[file.rindex("/") + 1:]) #Get filename only if len(self.files) > 10: #If list full, replace oldest item self.remove_entry(0, False) self.current = 9 self.current = len(self.files) - 1 self.addresses[self.current] = file self.resultTypes[self.current] = resultType root.destroy() if resultType == 0: #Image analysis pic = image(file, self.tempDir) #Do overall analysis particles = pic.create_objects() #Do particle analysis self.data[self.current] = [P.diameter for P in particles] elif resultType == 1: #Reading results file text = open(file, "r").read() self.data[self.current] = text.split(",") self.data[self.current] = [ float(X) for X in self.data[self.current] ] self.plot_histogram() #Create histogram figure self.results() def set_results(self, new, root): #Changes to a new set of analysis results if len(self.files) > new: #If results exist self.others[self.current].config( relief="raised") #Deselect previous self.current = new self.others[self.current].config(relief="sunken") #select current self.resultsTitle.set( f"Results - {self.files[self.current]}") #Change title if self.empty[self.current]: self.scaleEntry.set("") #If no scale set don't display scale else: self.scaleEntry.set(str(float(self.scales[self.current] * 127))) #Else do display scale self.set_view(root) def set_view(self, root, view=None): #Changes to viewing histogram, original image, or analysed image w = root.winfo_screenwidth() h = root.winfo_screenheight() if self.views[self.current] == 0: try: self.histogram.destroy() #Destroy histogram except Exception: pass elif self.views[self.current] == 1 or self.views[ self.current] == 2: #If previous was image try: self.picWidget.destroy() #Destroy image except Exception: pass if view != None: self.views[self.current] = view #Update to new view if self.views[self.current] == 0: self.histogram = FigureCanvasTkAgg( self.figures[self.current], master=root).get_tk_widget() #Get widget self.histogram.config(width=round(w * 0.75), height=round(h * 0.7)) #Resize cavas self.histogram.grid(row=1, column=0, rowspan=11, columnspan=5) #Place canvas elif self.views[self.current] == 1 or self.views[self.current] == 2: if self.resultTypes[self.current] == 0: if self.views[self.current] == 1: file = self.addresses[ self.current] #Get shorter version of file name pic = ImageTk.PhotoImage( Image.open(file)) #Get original image else: file = self.files[self.current] file = self.tempDir + "\\" + file[:file.rindex( '.')] + "-analysed" + file[file.rindex('.'):] pic = ImageTk.PhotoImage( Image.open(file)) #Get analysed image self.picWidget = tk.Label(root, image=pic, width=round(w * 0.75), height=round(h * 0.7)) #Image label self.picWidget.image = pic #Stops the image being discarded by memory manager self.picWidget.grid(row=1, column=0, rowspan=11, columnspan=5) else: self.views[self.current] = 0 self.set_view(root, 0) def update_scale(self, root, key): #Records the scale if it is valid old = self.scales[self.current] try: self.scales[self.current] = float( self.scaleEntry.get()) / 127 #Get scale if self.scales[self.current] > 0: for x in range(len(self.data[ self.current])): #Adjust each item to new scale self.data[ self.current][x] *= self.scales[self.current] / old self.plot_histogram() #Replot histogram self.empty[ self.current] = False #Record that scale has been set self.set_results(self.current, root) #Redraw canvas else: self.scales[self.current] = old except ValueError: pass #Unless not valid