Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
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
Ejemplo n.º 3
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