-
Notifications
You must be signed in to change notification settings - Fork 0
/
gui.py
271 lines (226 loc) · 11.2 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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
import matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import PySimpleGUI as sg
from json import (load as jsonload, dump as jsondump)
from matplotlib.axes import Axes
from matplotlib.figure import Figure
from matplotlib.widgets import PolygonSelector
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
"""
This file contains all of the gui related functions for the app.
Last Updated: 08/10/2020
Author: Michael Graps
Contributors: Joshua Failla, Andrew Durnford, Nathan Gillbanks
"""
screen_width = 1920*0.9#Get screen width/height from computer settings
screen_height = 1080*0.9 #
# use tkinter
matplotlib.use('TkAgg')
####### Creating the Main Window ################################
# helper text label
def TextLabel(text, justification = 'r', width = 20): #was 30
return sg.Text(text + ':', justification=justification, size=(width, 1))
def create_main_window(parameters, password_attempt, PASSWORD):
sg.theme('PyStat') # sets colour theme of window
radio_choices = [
'1st Harmonic',
'2nd Harmonic',
'3rd Harmonic',
'4th Harmonic',
'5th Harmonic']
# creates layout of the window
layout = [[
sg.Column([
# Row 1: record/load data, parameters, login
[
sg.Column([[
sg.Column([[sg.Button('Record Data',bind_return_key=True)]], element_justification='center',),
sg.Column([[sg.FileBrowse(button_text='Select Data File', key="Select Data File", enable_events=True)]]),
sg.Column([[sg.Button('Parameters', disabled=True, button_color=('white','#adadad'))]]),
sg.Column([[sg.Button('Login', key='Authenticate')]]),
]], justification='center')
],
# hidden: baseline coords
[
sg.Column([
[sg.Input(key="x1")],
[sg.Input(key="y1")],
[sg.Input(key="x2")],
[sg.Input(key="y2")],
], visible=False)
],
# Row 3: graph controls, canvas and results
[
sg.Column([
[
sg.Radio('Harmonics', key='Harmonics', group_id='graph_control_radio', disabled=True, enable_events=True, font='Helvetica 12'),
sg.Radio('Time Domain', key='Time Domain', group_id='graph_control_radio', disabled=True, enable_events=True, font='Helvetica 12'),
sg.Radio('Freq Domain', key='Freq Domain', group_id='graph_control_radio', disabled=True, enable_events=True, font='Helvetica 12'),
sg.Radio('Cumulative Sum', key='Cumulative Sum', group_id='graph_control_radio', disabled=True, enable_events=True, font='Helvetica 12'),
sg.Radio('Envelope', key='Envelope', group_id='graph_control_radio', disabled=True, enable_events=True, font='Helvetica 12')
],
[
sg.Canvas(size=(.5*screen_width, .5*screen_height), key='-CANVAS-'),#
]
], key='Graph Controls', element_justification='center', justification='center'),
],
[
sg.Column([[
#sg.Frame('Results',
# [
# [sg.Text('Conc: 25ppm')],
# [sg.Text('Peak Area: 50')],
# [sg.Text('Peak Height: 10')]
# ])
TextLabel('Results', 'center', None), sg.Input(key='PPM', disabled=True)
]], key='Results', element_justification='center', justification='center')
],
# Row 4: harmonic checkboxes
[
sg.Column([[
sg.Checkbox('1st Harmonic', enable_events=True, key='r1', disabled=True),
sg.Checkbox('2nd Harmonic', enable_events=True, key='r2', disabled=True),
sg.Checkbox('3rd Harmonic', enable_events=True, key='r3', disabled=True),
sg.Checkbox('4th Harmonic', enable_events=True, key='r4', disabled=True),
sg.Checkbox('5th Harmonic', enable_events=True, key='r5', disabled=True)
]]
, key='Harmonic Container', justification='centre')
],
# Ro 5: graph controls
#[
#],
# Row 6: define baseline, calculate result, save data, exit
[
sg.Button('Define Baseline', key='Define baseline', disabled=True, auto_size_button=True),
sg.Button('Copy Area', key='Copy Area', target='Copy Area', auto_size_button=True),
sg.Button('Copy Height', key='Copy Height', target = 'Copy Height', auto_size_button=True),
#sg.FileSaveAs(button_text='Save Raw Data', key='Save Raw Data', target='Save Raw Data', disabled=True, enable_events=True, file_types=(('CSV', '.csv'),('DATA', '.data'), ('BIN', '.bin'), ('All Files', '*.*')), auto_size_button=True, button_color=('white','#adadad')),
sg.FileSaveAs(button_text='Save Processed Data', key='Save Processed Data', disabled=True, target='Save Processed Data', enable_events=True, file_types=(('CSV', '.csv'),('DATA', '.data'), ('BIN', '.bin'), ('All Files', '*.*')), auto_size_button=True),
sg.FileSaveAs(button_text='Save Figure', key='Save Figure', target='Save Figure', enable_events=True, file_types=(('PNG', '.png'), ('PDF', '.pdf'), ('JPG', '.jpg'), ('All Files', '*.*')), auto_size_button=True),
sg.Button('Exit', auto_size_button=True)
],
[
sg.Canvas(size=(.75*screen_width, .75*screen_height), key='-Graph-'),#
]
], element_justification='center', justification='center', scrollable=True, size=(screen_width,screen_height))]] #, size=965, 930
# return window with layout
return sg.Window(
'PyStat - The Python Potentiostat',
layout,
element_justification='center',
font='Helvetica 18',
resizable=True,
icon="favicon.ico")
####### Creating parameters window ##############################
def create_parameters_window(
parameters,
PARAMETER_KEYS_TO_ELEMENT_KEYS):
layout = [[sg.Text('Parameters', justification='center', font='Helvetica 18')],
[TextLabel('Frequency perturbation'), sg.Input(key='-FREQ PERT-')],
[TextLabel('Band-width window'), sg.Input(key='-BW WINDOW-')],
[TextLabel('Env lpf bandwidth'), sg.Input(key='-LPF BW-')],
[TextLabel('Sample Rate'), sg.Input(key='-SAMPLE RATE-')],
[TextLabel('Callibration A'), sg.Input(key='-A-')],
[TextLabel('Callibration B'), sg.Input(key='-B-')],
[TextLabel('Callibration C'), sg.Input(key='-C-')],
[sg.Button('Save',bind_return_key=True), sg.Button('Exit')]]
window = sg.Window(
'Insert Parameters',
layout,
keep_on_top=True,
auto_size_buttons=True,
finalize=True,
grab_anywhere=True,
icon="favicon.ico"
)
for key in PARAMETER_KEYS_TO_ELEMENT_KEYS: # update window with the values read from settings file
try:
window[PARAMETER_KEYS_TO_ELEMENT_KEYS[key]].update(
value=parameters[key])
except Exception as e:
print(
f'Problem updating PySimpleGUI window from parameters. Key = {key}')
return window
def create_excitation_parameters_window(
exc_parameters,
EXCITATION_KEYS_TO_ELEMENT_KEYS):
layout = [[sg.Text('Parameters', justification='center', font='Helvetica 18')],
[TextLabel('amplitude'), sg.Input(key='-AMPLITUDE-')],
[TextLabel('stable'), sg.Input(key='-STABLE-')],
[TextLabel('sample_rate'), sg.Input(key='-EXC SAMPLE RATE-')],
[TextLabel('duration'), sg.Input(key='-DURATION-')],
[TextLabel('frequency'), sg.Input(key='-FREQ-')],
[TextLabel('v1'), sg.Input(key='-V1-')],
[TextLabel('v2'), sg.Input(key='-V2-')],
[TextLabel('v3'), sg.Input(key='-V3-')],
[TextLabel('Conversion Factor'), sg.Input(key='-cfact-')],
#[sg.Radio('Auto Save Name', key='-autosave-', group_id='excitation_radio', disabled=False, enable_events=True)],
# [TextLabel('Save Name'), sg.Input(key='-name-')],
[sg.Button('Record',bind_return_key=True), sg.Button('Cancel')]]
window = sg.Window(
'Excitation Parameters',
layout,
keep_on_top=True,
finalize=True,
icon="favicon.ico")
for key in EXCITATION_KEYS_TO_ELEMENT_KEYS: # update window with the values read from settings file
try:
window[EXCITATION_KEYS_TO_ELEMENT_KEYS[key]].update(
value=exc_parameters[key])
except Exception as e:
print(
f'Problem updating PySimpleGUI window from parameters. Key = {key}')
return window
####### Create Figure In Canvas ##############################
def draw_figure(canvas, figure, toolbar=None):
# create canvas containing passed in figure
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
toolbar = NavigationToolbar2Tk(figure_canvas_agg, canvas) # create toolbar
figure_canvas_agg.get_tk_widget().pack(
side='top', fill='both', expand=1) # pack figure and toolbar into canvas
# return canvas and toolbar
return figure_canvas_agg, toolbar
####### Destroy Figure In Canvas ##############################
def destroy_figure(fig_canvas_agg, toolbar):
fig_canvas_agg.get_tk_widget().forget() # destroys canvas
toolbar.forget() # destroys toolbar
plt.close('all') # destroys figure
###### Load/Save Parameters File ##########################################
def load_parameters(
parameters_file,
default_parameters,
PARAMETER_KEYS_TO_ELEMENT_KEYS):
try:
with open(parameters_file, 'r') as f:
parameters = jsonload(f)
except Exception as e:
sg.popup_quick_message(
f'exception {e}',
'No parameters file found... will create one for you',
keep_on_top=True,
background_color='red',
text_color='white')
parameters = default_parameters
save_parameters(
parameters_file,
parameters,
None,
PARAMETER_KEYS_TO_ELEMENT_KEYS)
return parameters
def save_parameters(
parameters_file,
parameters,
values,
PARAMETER_KEYS_TO_ELEMENT_KEYS):
if values: # if there are stuff specified by another window, fill in those values
for key in PARAMETER_KEYS_TO_ELEMENT_KEYS: # update window with the values read from settings file
try:
parameters[key] = values[PARAMETER_KEYS_TO_ELEMENT_KEYS[key]]
except Exception as e:
print(
f'Problem updating parameters from window values. Key = {key}')
with open(parameters_file, 'w') as f:
jsondump(parameters, f)