/
Gui.py
191 lines (160 loc) · 8.45 KB
/
Gui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
import pandas as pd
import os
from clustering import Clustering
import PIL
from PIL import ImageTk
class Clustering_Gui:
""" Responsible for the display of all UI and input validity """
def __init__(self, master):
"""" Initialization of all parameters of the class, buttons, labels """
self.master = master
master.title("K Means Clustering")
master.minsize(750, 400)
self.num_of_clusters = 0
self.num_of_runs = 0
self.cluster_ok = False
self.runs_ok = False
self.cluster = Clustering()
self.file_path = StringVar()
self.file_name_entered = Entry(master, width=100, textvariable=self.file_path)
self.file_name_entered.grid(column=0, columnspan=3, row=0)
self.file_path.trace('w', self.showPreProcessButton)
self.button = Button(master, text="Browse A File", command=self.fileDialog)
self.button.grid(column=3, row=0, pady=5)
self.error_file_path = StringVar()
self.error_file_label = Label(master, textvariable=self.error_file_path, foreground="red", width=40)
self.error_file_label.grid(column=0, row=1, pady=10)
self.num_cluster_label = Label(master, text="Number of clusters k")
self.num_cluster_label.grid(column=0, row=2)
self.num_cluster_text = StringVar()
self.num_cluster_text.set(self.num_of_clusters)
self.num_cluster_entry = Entry(master, width=15, textvariable=self.num_cluster_text)
self.num_cluster_entry.grid(column=1, row=2)
self.num_cluster_text.trace('w', self.validate_cluster)
self.error_cluster_text = StringVar()
self.error_cluster_label = Label(master, textvariable=self.error_cluster_text, foreground="red", width=40)
self.error_cluster_label.grid(column=2, row=2)
self.num_runs_label = Label(master, text="Number of runs")
self.num_runs_label.grid(column=0, row=3)
self.num_runs_text = StringVar()
self.num_runs_text.set(self.num_of_runs)
self.num_runs_entry = Entry(master, width=15, textvariable=self.num_runs_text)
self.num_runs_entry.grid(column=1, row=3)
self.num_runs_text.trace('w', self.validate_runs)
self.error_run_text = StringVar()
self.error_run_label = Label(master, textvariable=self.error_run_text, foreground="red", width=40)
self.error_run_label.grid(column=2, row=3)
self.prep_button = Button(master, text="Pre-process", command=self.call_preprocess, state='disabled')
self.prep_button.grid(column=0, row=4, pady=20)
self.cluster_button = Button(master, text="Cluster", state='disabled', command=self.call_cluster)
self.cluster_button.grid(column=1, row=4, pady=20)
self.scatter_pic_label = Label(master)
self.scatter_pic_label.grid(column=0, row=5, pady=10)
self.world_map_label= Label(master)
self.world_map_label.grid(column=1, row=5, pady=10)
def validate_runs(self, *args):
"""" Validate the input variable - number of runs - and display messages to the user accordingly """
if (self.num_runs_text.get()):
try:
self.num_of_runs = int(self.num_runs_text.get())
if self.num_of_runs <= 0:
self.error_run_text.set('Enter a number greater than zero')
self.runs_ok = False
self.cluster_button.config(state='disabled')
elif self.num_of_runs >= 50:
self.error_run_text.set('Enter a number smaller than 50')
self.runs_ok = False
self.cluster_button.config(state='disabled')
else:
self.error_run_text.set('')
self.runs_ok = True
self.showClusterButton()
except ValueError: # problem
self.runs_ok = False
self.error_run_text.set('Enter only numbers')
self.cluster_button.config(state='disabled')
else: # empty
self.runs_ok = False
self.error_run_text.set('')
self.cluster_button.config(state='disabled')
def validate_cluster(self, *args):
"""" Validate the input variable - number of clusters - and display messages to the user accordingly """
if self.num_cluster_text.get():
try:
self.num_of_clusters = int(self.num_cluster_text.get())
if self.num_of_clusters <= 1:
self.cluster_ok = False
self.error_cluster_text.set('Enter a number greater than 1')
self.cluster_button.config(state='disabled')
elif self.num_of_clusters > 164:
self.cluster_ok = False
self.error_cluster_text.set('Enter a number smaller than 165')
self.cluster_button.config(state='disabled')
else:
self.cluster_ok = True
self.error_cluster_text.set('')
self.showClusterButton()
except ValueError:
self.cluster_ok = False
self.error_cluster_text.set('Enter only numbers')
self.cluster_button.config(state='disabled')
else:
self.cluster_ok = False
self.error_cluster_text.set('')
self.cluster_button.config(state='disabled')
def fileDialog(self):
"""" Input the data file into a variable and save its path in the file path field. """
file_path = filedialog.askopenfilename(initialdir="/", title="Select A File",
filetype=(("xlsx files", "*.xlsx"), ("all files", "*.*")))
self.file_path.set(file_path)
self.showPreProcessButton()
def showClusterButton(self, *args):
"""" Checking whether to enable "clustering" button-
The number of runs and the number of threads entered by the user is correct"""
if self.runs_ok & self.cluster_ok:
self.cluster_button.config(state='normal')
else:
self.cluster_button.config(state='disabled')
def showPreProcessButton(self, *args):
"""" Checking whether to enable "pre-processing" button-
The file path contains an existing and empty file"""
self.prep_button.config(state='disabled')
if self.file_path.get():
try:
if os.stat(self.file_path.get()).st_size == 0:
self.error_file_path.set('This file is empty')
else:
self.error_file_path.set('')
self.prep_button.config(state='normal')
except FileNotFoundError:
self.error_file_path.set('File not found')
except Exception:
self.error_file_path.set('Please choose a different file')
def call_preprocess(self, *args):
"""" call preProcess function in Cluster class.
Operates a popup if the data cleaning process was successful or not """
if (self.cluster.preProcess(self.file_path.get())):
messagebox.showinfo("K Means Clustering", "Pre-Processing completed successfully!")
else:
messagebox.showerror("K Means Clustering", "There was a problem running the Pre-Processing")
def call_cluster(self, *args):
"""" call clustering function in Cluster class.
Operates a popup if the data clustering was successful or not """
if (self.cluster.clustering(self.num_of_clusters, self.num_of_runs)):
# show plots
scatterImg = PIL.Image.open("scatter.png").resize((350, 300), PIL.Image.ANTIALIAS)
self.scatter_pic = ImageTk.PhotoImage(scatterImg)
self.scatter_pic_label.config(image=self.scatter_pic)
worldImg=PIL.Image.open("map.png").resize((350, 300), PIL.Image.ANTIALIAS)
self.world_pic=ImageTk.PhotoImage(worldImg)
self.world_map_label.config(image=self.world_pic)
response = messagebox.askquestion("K Means Clustering ",
"Clustering completed successfully! Would you like to exit the program?",
icon='warning')
if response == "yes":
self.master.destroy()
else:
messagebox.showerror("K Means Clustering", "There was a problem running the clustering")