azapyGUI 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. azapyGUI/AppSettingsPage.py +213 -0
  2. azapyGUI/AppSettingsPageMisc.py +101 -0
  3. azapyGUI/AppSettingsWindow.py +52 -0
  4. azapyGUI/BacktestComputation.py +166 -0
  5. azapyGUI/BacktestEntryWindow.py +307 -0
  6. azapyGUI/BacktestMenuPortfolioWindow.py +20 -0
  7. azapyGUI/CloneMenuPortfolioWindow.py +93 -0
  8. azapyGUI/CrossHairBCursor.py +80 -0
  9. azapyGUI/DF_Window.py +63 -0
  10. azapyGUI/DF_table.py +282 -0
  11. azapyGUI/EditMenuPortfolioWindow.py +16 -0
  12. azapyGUI/EditPortfolioWindow.py +475 -0
  13. azapyGUI/EntryClonePortfolioWindow.py +35 -0
  14. azapyGUI/EntryNameWindow.py +55 -0
  15. azapyGUI/EntryRenamePortfolioWindow.py +33 -0
  16. azapyGUI/GetMktData.py +85 -0
  17. azapyGUI/MenuApp.py +194 -0
  18. azapyGUI/MktDataFrame.py +129 -0
  19. azapyGUI/MktDataNode.py +34 -0
  20. azapyGUI/ModelParamEditWindow.py +143 -0
  21. azapyGUI/NrShares_table.py +54 -0
  22. azapyGUI/PortAnalyseWindow.py +179 -0
  23. azapyGUI/PortDataNode.py +180 -0
  24. azapyGUI/PortfolioFrame.py +197 -0
  25. azapyGUI/RebalanceMenuPortfolioWindow.py +21 -0
  26. azapyGUI/RemoveMenuPortfolioWindow.py +33 -0
  27. azapyGUI/SaveMenuPortfolioWindow.py +36 -0
  28. azapyGUI/Scrollable.py +60 -0
  29. azapyGUI/SelectOneWindow.py +65 -0
  30. azapyGUI/SymbAnalyseWindow.py +21 -0
  31. azapyGUI/SymbExtractWindow.py +129 -0
  32. azapyGUI/SymbTableEntry.py +109 -0
  33. azapyGUI/TimeSeriesViewWindow.py +480 -0
  34. azapyGUI/ViewTip.py +72 -0
  35. azapyGUI/WeightsWindow.py +352 -0
  36. azapyGUI/__init__.py +6 -0
  37. azapyGUI/azHelper.py +27 -0
  38. azapyGUI/azapyApp.py +89 -0
  39. azapyGUI/config.py +35 -0
  40. azapyGUI/configHelps.py +84 -0
  41. azapyGUI/configMSG.py +194 -0
  42. azapyGUI/configModels.py +519 -0
  43. azapyGUI/configPlot.py +70 -0
  44. azapyGUI/configSettings.py +138 -0
  45. azapyGUI/configTips.py +240 -0
  46. azapyGUI/mktDataValidation.py +42 -0
  47. azapyGUI/modelParametersValidation.py +442 -0
  48. azapyGUI/serviceMasterUserConfig.py +28 -0
  49. azapyGUI/tkHelper.py +18 -0
  50. azapyGUI-0.0.1.dist-info/LICENSE +674 -0
  51. azapyGUI-0.0.1.dist-info/METADATA +126 -0
  52. azapyGUI-0.0.1.dist-info/RECORD +54 -0
  53. azapyGUI-0.0.1.dist-info/WHEEL +5 -0
  54. azapyGUI-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,307 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ import time
4
+ import webbrowser
5
+
6
+ import azapyGUI.configSettings as configSettings
7
+ import azapyGUI.configMSG as configMSG
8
+ import azapyGUI.config as config
9
+ import azapyGUI.configTips as configTips
10
+ import azapyGUI.configHelps as configHelps
11
+ import azapyGUI.tkHelper as tkHelper
12
+ from azapyGUI.mktDataValidation import sdate_edate_validate
13
+ from azapyGUI.BacktestComputation import BacktestComputation
14
+ from azapyGUI.PortAnalyseWindow import PortAnalyseWindow
15
+ from azapyGUI.modelParametersValidation import _validDateMMDDYYYY, _validInt, _validIntNegative, _list2string
16
+ from azapyGUI.Scrollable import Scrollable
17
+
18
+ class BacktestEntryWindow:
19
+ def __init__(self, master, pnames):
20
+ self._master = master
21
+ self._pnames = pnames
22
+ self._paw = None
23
+
24
+ self._window = tk.Toplevel()
25
+ self._window.title("Backtesting")
26
+ self._window.focus_set()
27
+ self._window.protocol("WM_DELETE_WINDOW", self._btn_cancel_func)
28
+
29
+ menubar = tk.Menu(self._window)
30
+ filemenu = tk.Menu(menubar, tearoff=0)
31
+ filemenu.add_command(label='Help', command=self._menu_help_func)
32
+ menubar.add_cascade(label='Help', menu=filemenu)
33
+ self._window.config(menu=menubar)
34
+
35
+ text = 'Backtesting simulation parameters'
36
+ self._frm_btp = tk.LabelFrame(master=self._window, text=text, font=("Forte", 10))
37
+ self._frm_btp.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
38
+ self._frm_btp.columnconfigure(1, weight=1)
39
+
40
+ row = 0
41
+ self._frm_btp.rowconfigure(row, weight=1)
42
+ text = 'Portfolios: ' + _list2string(self._pnames, 5)
43
+ lbl = tk.Label(master=self._frm_btp, text='Portfolios:', anchor=tk.W)
44
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.NW)
45
+ lbl = tk.Label(master=self._frm_btp, text=_list2string(self._pnames, 5),
46
+ anchor=tk.W, justify=tk.LEFT)
47
+ lbl.grid(row=row, column=1, columnspan=3, padx=5, pady=5, sticky=tk.NW)
48
+
49
+
50
+ row += 1
51
+ self._frm_btp.rowconfigure(row, weight=1)
52
+ lbl = tk.Label(master=self._frm_btp, text='End Date')
53
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
54
+
55
+ self._ent_edate = tk.StringVar(master=self._frm_btp,
56
+ value=configSettings.MasterApplicationSettings['edate'])
57
+ ent_edate = tk.Entry(master=self._frm_btp, width=10, textvariable=self._ent_edate)
58
+ ent_edate['validatecommand'] = (ent_edate.register(_validDateMMDDYYYY),'%S','%d','%P')
59
+ ent_edate.grid(row=row, column=1, pady=5, padx=5, sticky=tk.W)
60
+ config.tiptil.bind(ent_edate, configTips._bkt_edate_tip)
61
+
62
+
63
+ lbl = tk.Label(master=self._frm_btp, text='Bday offset')
64
+ lbl.grid(row=row, column=2, padx=5, pady=5, sticky=tk.W)
65
+
66
+ self._ent_noffset = tk.StringVar(master=self._frm_btp,
67
+ value=configSettings.MasterApplicationSettings['noffset'])
68
+ ent_noffset = tk.Entry(master=self._frm_btp, width=3, textvariable=self._ent_noffset)
69
+ ent_noffset['validatecommand'] = (ent_noffset.register(_validInt),'%S','%d','%P')
70
+ ent_noffset.grid(row=row, column=3, pady=5, padx=5, sticky=tk.W)
71
+ config.tiptil.bind(ent_noffset, configTips._bkt_noffset_tip)
72
+
73
+ row += 1
74
+ self._frm_btp.rowconfigure(row, weight=1)
75
+ lbl = tk.Label(master=self._frm_btp, text='Start Date')
76
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
77
+
78
+ self._ent_sdate = tk.StringVar(master=self._frm_btp,
79
+ value=configSettings.MasterApplicationSettings['sdate'])
80
+ ent_sdate = tk.Entry(master=self._frm_btp, width=10, textvariable=self._ent_sdate)
81
+ ent_sdate['validatecommand'] = (ent_sdate.register(_validDateMMDDYYYY),'%S','%d','%P')
82
+ ent_sdate.grid(row=row, column=1, pady=5, padx=5, sticky=tk.W)
83
+ config.tiptil.bind(ent_sdate, configTips._bkt_sdate_tip)
84
+
85
+ lbl = tk.Label(master=self._frm_btp, text='Fixing offset')
86
+ lbl.grid(row=row, column=2, padx=5, pady=5, sticky=tk.W)
87
+
88
+ self._ent_fixoffset= tk.StringVar(master=self._frm_btp,
89
+ value=configSettings.MasterApplicationSettings['fixoffset'])
90
+ ent_fixoffset = tk.Entry(master=self._frm_btp, width=3, textvariable=self._ent_fixoffset)
91
+ ent_fixoffset['validatecommand'] = (ent_fixoffset.register(_validIntNegative),'%S','%d','%P')
92
+ ent_fixoffset.grid(row=row, column=3, pady=5, padx=5, sticky=tk.W)
93
+ config.tiptil.bind(ent_fixoffset, configTips._bkt_fixoffset_tip)
94
+
95
+ row += 1
96
+ self._frm_btp.rowconfigure(row, weight=1)
97
+ lbl = tk.Label(master=self._frm_btp, text='Capital')
98
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
99
+
100
+ self._ent_capital = tk.StringVar(master=self._frm_btp,
101
+ value=configSettings.MasterApplicationSettings['capital'])
102
+ ent_capital = tk.Entry(master=self._frm_btp, width=10, textvariable=self._ent_capital)
103
+ ent_capital['validatecommand'] = (ent_capital.register(_validInt),'%S','%d','%P')
104
+ ent_capital.grid(row=row, column=1, pady=5, padx=5, sticky=tk.W)
105
+ config.tiptil.bind(ent_capital, configTips._bkt_capital_tip)
106
+
107
+
108
+ lbl = tk.Label(master=self._frm_btp, text='Nr Shares int')
109
+ lbl.grid(row=row, column=2, padx=5, pady=5, sticky=tk.W)
110
+
111
+ self._ent_nsh_round = tk.BooleanVar(master=self._frm_btp,
112
+ value=configSettings.MasterApplicationSettings['nsh_round'])
113
+ ckb_ent_nsh_round = ttk.Checkbutton(master=self._frm_btp, variable=self._ent_nsh_round,
114
+ onvalue=True, offvalue=False)
115
+ ckb_ent_nsh_round.grid(row=row, column=3, pady=5, padx=5, sticky=tk.W)
116
+ config.tiptil.bind(ckb_ent_nsh_round, configTips._bkt_nsh_round_tip)
117
+
118
+ text = "Market Data"
119
+ self._frm_mkt = tk.LabelFrame(master=self._window, text=text, font=("Forte", 10))
120
+ self._frm_mkt.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
121
+ self._frm_mkt.columnconfigure(1, weight=1)
122
+
123
+ row = 0
124
+ self._frm_mkt.rowconfigure(row, weight=1)
125
+ lbl = tk.Label(master=self._frm_mkt, text='Provider')
126
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
127
+
128
+ pval = list(configSettings.MasterApplicationSettings["Provider"].keys())
129
+ self._ent_provider = tk.StringVar(master=self._frm_mkt)
130
+ ent_provider = ttk.Combobox(master=self._frm_mkt, width=12, textvariable=self._ent_provider)
131
+ ent_provider["values"] = pval
132
+ ent_provider.current(0)
133
+ ent_provider.grid(row=row, column=1, pady=5, padx=5, sticky=tk.EW)
134
+ config.tiptil.bind(ent_provider, configTips._bkt_provider_tip)
135
+
136
+ lbl = tk.Label(master=self._frm_mkt, text="force", anchor=tk.W)
137
+ lbl.grid(row=row, column=2, padx=5, pady=5, sticky=tk.W)
138
+
139
+ self._ent_force = tk.BooleanVar(value=configSettings.MasterApplicationSettings['force'])
140
+ chk_force = tk.Checkbutton(master=self._frm_mkt, onvalue=True, offvalue=False, variable=self._ent_force)
141
+ chk_force.grid(row=row, column=3, padx=5, pady=5, sticky=tk.W)
142
+ config.tiptil.bind(chk_force, configTips._bkt_force_tip)
143
+
144
+
145
+ frm_btn = tk.Frame(master=self._window)
146
+ frm_btn.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
147
+
148
+ self._btn_cancel = tk.Button(master=frm_btn, text='Cancel', width=12, command=self._btn_cancel_func)
149
+ self._btn_cancel.pack(side=tk.LEFT, padx=5, pady=5,)
150
+
151
+ self._btn_start = tk.Button(master=frm_btn, text='Start', width=12, command=self._btn_start_func)
152
+ self._btn_start.pack(side=tk.RIGHT, padx=5, pady=5,)
153
+
154
+ # self._frm_progress = tk.LabelFrame(master=self._window, text="Progress", font=("Forte", 10), height=200, width=300)
155
+ # self._frm_progress.pack(fill=tk.X, expand=False, padx=5, pady=5)
156
+
157
+
158
+ def _destroy_all_windows(self):
159
+ for widget in self._window.winfo_children():
160
+ if isinstance(widget, tk.Toplevel):
161
+ widget.destroy()
162
+
163
+
164
+ def _on_exit(self):
165
+ for pname in self._pnames:
166
+ config.PortDataDict[pname].setActive(False)
167
+ config.appPortfolioFrame.refresh()
168
+
169
+ if self._paw is not None: self._paw._btn_quit_func()
170
+ self._destroy_all_windows()
171
+ self._window.grab_release()
172
+ if self._master.winfo_exists():
173
+ self._master.focus_set()
174
+ self._master.lift()
175
+ self._window.destroy()
176
+
177
+
178
+ def _btn_cancel_func(self):
179
+ self.status = False
180
+ self._on_exit()
181
+
182
+
183
+ def _validate_entries(self):
184
+ # get inputs
185
+ s_sdate = self._ent_sdate.get()
186
+ s_edate = self._ent_edate.get()
187
+ s_noffset = self._ent_noffset.get()
188
+ s_fixoffset = self._ent_fixoffset.get()
189
+ s_capital = self._ent_capital.get()
190
+ self._nsh_round = self._ent_nsh_round.get()
191
+ self._provider = self._ent_provider.get()
192
+ self._force = self._ent_force.get()
193
+
194
+ # validate sdate and edate
195
+ state, self.sdate, self.edate = sdate_edate_validate(s_sdate, s_edate)
196
+ if not state:
197
+ tk.messagebox.showwarning("Warning", message=self.sdate,
198
+ parent=self._window)
199
+ return False
200
+
201
+ # validate noffset
202
+ try:
203
+ self.noffset = int(s_noffset)
204
+ except:
205
+ tk.messagebox.showwarning("Warning", message=configMSG._validate_noffset_msg,
206
+ parent=self._window)
207
+ return False
208
+
209
+ # validate fixoffset
210
+ try:
211
+ self.fixoffset = int(s_fixoffset)
212
+ except:
213
+ tk.messagebox.showwarning("Warning", message=configMSG._validate_fixoffset_msg,
214
+ parent=self._window)
215
+ return False
216
+ if self.fixoffset > 0:
217
+ tk.messagebox.showwarning("Warning", message=configMSG._validate_fixoffset_msg,
218
+ parent=self._window)
219
+ return False
220
+
221
+ # capital
222
+ try:
223
+ self._capital = float(s_capital)
224
+ except:
225
+ tk.messagebox.showerror("Warning", message=configMSG._validate_capital_msg,
226
+ parent=self._window)
227
+ return False
228
+ if self._capital < 10000:
229
+ tk.messagebox.showerror("Warning", message=configMSG._validate_capital_msg,
230
+ parent=self._window)
231
+ return False
232
+
233
+
234
+ return True
235
+
236
+
237
+ def _buid_frm_progress(self):
238
+ self._frm_progress = tk.LabelFrame(master=self._window, text="Progress", font=("Forte", 10))
239
+ self._frm_progress.pack(fill=tk.X, expand=False, padx=5, pady=5, ipadx=5, ipady=5)
240
+
241
+ onfrm = self._frm_progress if len(self._pnames) <= 5 else Scrollable(self._frm_progress)
242
+
243
+ row = 0
244
+ lbl = tk.Label(master=onfrm, text='Collect Mkt Data')
245
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
246
+
247
+ self._time_mktdata = tk.StringVar(master=onfrm, value='-')
248
+ lbl = tk.Label(master=onfrm, textvariable=self._time_mktdata, width=10)
249
+ lbl.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
250
+
251
+ self._time_port = {}
252
+ for pname in self._pnames:
253
+ row += 1
254
+ lbl = tk.Label(master=onfrm, text=f'Portfolio {pname}')
255
+ lbl.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
256
+
257
+ self._time_port[pname] = tk.StringVar(master=onfrm, value='-')
258
+ lbl = tk.Label(master=onfrm, textvariable=self._time_port[pname], width=10)
259
+ lbl.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
260
+
261
+ onfrm.update()
262
+ self._window.update()
263
+
264
+
265
+ def _btn_start_func(self):
266
+ if not self._validate_entries(): return
267
+
268
+ tkHelper.enable_widget(self._frm_btp, enabled=False)
269
+ tkHelper.enable_widget(self._frm_mkt, enabled=False)
270
+ self._btn_start.config(state=tk.DISABLED)
271
+ self._btn_cancel.config(text="Close")
272
+ self._window.update()
273
+
274
+ self.status = True
275
+
276
+ self._buid_frm_progress()
277
+
278
+ btc = BacktestComputation(master=self._window,
279
+ pnames=self._pnames,
280
+ sdate=self.sdate,
281
+ edate=self.edate,
282
+ noffset=self.noffset,
283
+ fixoffset=self.fixoffset,
284
+ capital=self._capital,
285
+ nsh_round=self._nsh_round,
286
+ provider=self._provider,
287
+ force=self._force,
288
+ )
289
+
290
+ tic = time.perf_counter()
291
+ btc.collectMktData()
292
+ toc = time.perf_counter()
293
+ self._time_mktdata.set(str(round(toc-tic, 4)) + 's')
294
+ self._window.update()
295
+ config.appMktDataFrame.refresh()
296
+
297
+ btc.compute(self._time_port)
298
+
299
+ ports = btc.backtest
300
+ if len(ports) < 1: return
301
+
302
+ self._paw = PortAnalyseWindow(master=self._window, ports=ports)
303
+
304
+
305
+ def _menu_help_func(self):
306
+ webbrowser.open_new_tab(configHelps._Backtest_panel_help)
307
+
@@ -0,0 +1,20 @@
1
+ import azapyGUI.config as config
2
+ from azapyGUI.SelectOneWindow import SelectOneWindow
3
+
4
+ class BacktestMenuPortfolioWindow(SelectOneWindow):
5
+ def __init__(self, master=None):
6
+ values = [kk for kk, vv in config.PortDataDict.items() if vv.status != 'Edit']
7
+ if len(values) == 0:
8
+ self.selection = None
9
+ return
10
+ title = "Backtesting Portfolio"
11
+ text = "Choose portfolio"
12
+ tip_text = "Only portfolios with status=Set or Active can be backtested."
13
+ btn_text = "Backtest"
14
+ super().__init__(master=master, title=title, text=text, values=values,
15
+ tip_text=tip_text, btn_text=btn_text)
16
+
17
+
18
+ def _btn_action(self):
19
+ self.selection = self._ent.get()
20
+ self._btn_cancel()
@@ -0,0 +1,93 @@
1
+ import tkinter as tk
2
+ from tkinter import ttk
3
+ import string
4
+ from copy import deepcopy
5
+
6
+ import azapyGUI.config as config
7
+ import azapyGUI.configMSG as configMSG
8
+
9
+ class CloneMenuPortfolioWindow:
10
+ def __init__(self, master=None):
11
+ self._master = master
12
+ values = list(config.PortDataDict.keys())
13
+ if len(values) == 0: return
14
+
15
+ btn_text = "Save"
16
+ self._end_values = False
17
+ title = "Clone Portfolio"
18
+ self._window = tk.Toplevel()
19
+ self._window.title(title)
20
+ self._window.geometry("230x130")
21
+ self._window.protocol("WM_DELETE_WINDOW", self._btn_cancel)
22
+
23
+ frm = tk.LabelFrame(master=self._window, text=title, font=("Forte", 10) )
24
+ frm.pack(expand=True, fill=tk.BOTH, padx=5, pady=5)
25
+ frm.columnconfigure(0, weight=1)
26
+ frm.columnconfigure(1, weight=1)
27
+
28
+ row = 0
29
+ frm.rowconfigure(row, weight=1)
30
+ lbl_text = "Target Portfolio:"
31
+ lbl = tk.Label(master=frm, text=lbl_text)
32
+ lbl.grid(row=row, column=0, pady=5, padx=5, sticky=tk.W)
33
+
34
+ self._cbx = ttk.Combobox(master=frm, width=12, state='readonly')
35
+ self._cbx['values'] = values
36
+ self._cbx.current(0)
37
+ self._cbx.grid(row=row, column=1, padx=5, pady=5, sticky=tk.W)
38
+
39
+ row += 1
40
+ frm.rowconfigure(row, weight=1)
41
+ lbl_text = "New name:"
42
+ lbl = tk.Label(master=frm, text=lbl_text)
43
+ lbl.grid(row=row, column=0, pady=5, padx=5, sticky=tk.W)
44
+
45
+ self._ent = tk.Entry(master=frm, width=12,)
46
+ self._ent.grid(row=row, column=1, pady=5, padx=5, sticky=tk.W)
47
+ self._ent.bind('<Return>', lambda event: self._btn_action())
48
+ self._ent.focus()
49
+
50
+ row += 1
51
+ frm.rowconfigure(row, weight=1)
52
+ btn_cancel = tk.Button(master=frm, text="Cancel", width=8, command=self._btn_cancel)
53
+ btn_cancel.grid(row=row, column=0, pady=5, padx=5, sticky=tk.W)
54
+
55
+ btn_action = tk.Button(master=frm, text=btn_text, width=8, command=self._btn_action)
56
+ btn_action.grid(row=row, column=1, pady=5, padx=5, sticky=tk.E)
57
+
58
+ self._window.update()
59
+ if (self._master is not None) and self._master.winfo_exists():
60
+ self._master.wait_window(self._window)
61
+
62
+
63
+ def _btn_cancel(self):
64
+ self._window.grab_release()
65
+ if (self._master is not None) and self._master.winfo_exists():
66
+ self._master.focus_set()
67
+ self._window.destroy()
68
+
69
+
70
+ def _btn_action(self):
71
+ if self._end_values:
72
+ self._btn_cancel()
73
+ return
74
+
75
+ tname = self._cbx.get()
76
+ nname = self._ent.get().strip(string.whitespace)
77
+ allowed_char = set(string.ascii_letters + string.digits + ".-_")
78
+ if (len(nname) > 0) and (set(nname) < allowed_char):
79
+ if nname in config.PortDataDict.keys():
80
+ tk.messagebox.showwarning("Warning", configMSG._validate_portfolio_name_exist_msg,
81
+ parent=self._window)
82
+ return
83
+ port = deepcopy((config.PortDataDict[tname]))
84
+ port.name = nname
85
+ port.status = 'Set'
86
+ port.saved = False
87
+ config.PortDataDict[nname] = port
88
+ self._btn_cancel()
89
+ config.appPortfolioFrame.refresh()
90
+ return
91
+ tk.messagebox.showwarning("Warning", configMSG._validate_portfolio_name_msg,
92
+ parent=self._window)
93
+
@@ -0,0 +1,80 @@
1
+ class CrossHairBCursor:
2
+ def __init__(self, ax, varx=None, vary=None,
3
+ transformx = lambda x: x, transformy = lambda y: y,
4
+ show_label=False):
5
+ self._show_label = show_label
6
+ self.varx = varx
7
+ self.vary = vary
8
+ self.transformx = transformx
9
+ self.transformy = transformy
10
+ self.set_ax(ax)
11
+
12
+
13
+ def on_draw(self, event):
14
+ self.create_new_background()
15
+
16
+
17
+ def set_ax(self, ax):
18
+ self.ax = ax
19
+ x = ax.get_xlim()[1]
20
+ y = ax.get_ylim()[1]
21
+ if self.varx is not None:
22
+ self.varx.set(self.transformx(x))
23
+ if self.vary is not None:
24
+ self.vary.set(self.transformy(y))
25
+
26
+ self.background = None
27
+ self.horizontal_line = ax.axhline(y, color='k', lw=0.8, ls='--')
28
+ self.vertical_line = ax.axvline(x, color='k', lw=0.8, ls='--')
29
+ if self._show_label:
30
+ self.text = ax.text(0.72, 0.9, '', transform=ax.transAxes)
31
+ self._creating_background = False
32
+ ax.figure.canvas.mpl_connect('draw_event', self.on_draw)
33
+
34
+
35
+ def set_cross_hair_visible(self, visible):
36
+ need_redraw = self.horizontal_line.get_visible() != visible
37
+ self.horizontal_line.set_visible(visible)
38
+ self.vertical_line.set_visible(visible)
39
+ if self._show_label:
40
+ self.text.set_visible(visible)
41
+ return need_redraw
42
+
43
+
44
+ def create_new_background(self):
45
+ if self._creating_background:
46
+ return
47
+ self._creating_background = True
48
+ self.set_cross_hair_visible(False)
49
+ self.ax.figure.canvas.draw()
50
+ self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)
51
+ self.set_cross_hair_visible(True)
52
+ self._creating_background = False
53
+
54
+
55
+ def on_mouse_move(self, event):
56
+ if self.background is None:
57
+ self.create_new_background()
58
+ if not event.inaxes:
59
+ need_redraw = self.set_cross_hair_visible(False)
60
+ if need_redraw:
61
+ self.ax.figure.canvas.restore_region(self.background)
62
+ self.ax.figure.canvas.blit(self.ax.bbox)
63
+ else:
64
+ self.set_cross_hair_visible(True)
65
+ x, y = event.xdata, event.ydata
66
+ if self.varx is not None:
67
+ self.varx.set(self.transformx(x))
68
+ if self.vary is not None:
69
+ self.vary.set(self.transformy(y))
70
+ self.horizontal_line.set_ydata([y])
71
+ self.vertical_line.set_xdata([x])
72
+ if self._show_label:
73
+ self.text.set_text(f'x={self._transformx(x)}, y={self._transformy(y)}')
74
+
75
+ self.ax.figure.canvas.restore_region(self.background)
76
+ self.ax.draw_artist(self.horizontal_line)
77
+ self.ax.draw_artist(self.vertical_line)
78
+ if self._show_label:
79
+ self.ax.draw_artist(self.text)
80
+ self.ax.figure.canvas.blit(self.ax.bbox)
azapyGUI/DF_Window.py ADDED
@@ -0,0 +1,63 @@
1
+ import tkinter as tk
2
+ import pandas as pd
3
+ import os
4
+
5
+ import azapyGUI.configSettings as configSettings
6
+ from azapyGUI.DF_table import DF_table
7
+
8
+ class DF_Window(tk.Toplevel):
9
+ def __init__(self, master, df, title, geometry, fname):
10
+ self._master = master
11
+ self._fname = fname
12
+
13
+ super().__init__()
14
+ self._window = self
15
+ self._window.geometry(geometry)
16
+ self._window.title(title)
17
+ self._window.protocol("WM_DELETE_WINDOW", self.destroy)
18
+
19
+ menubar = tk.Menu(self._window)
20
+ filemenu = tk.Menu(menubar, tearoff=0)
21
+ filemenu.add_command(label='To csv', command=self._save_df)
22
+ filemenu.add_command(label='To Excel', command=self._to_excel_df)
23
+ menubar.add_cascade(label="Save", menu=filemenu)
24
+ self._window.config(menu=menubar)
25
+
26
+ self._dft = DF_table(df, master=self._window)
27
+ self._dft.pack(fill=tk.BOTH, expand=True, ipadx=5, ipady=5)
28
+
29
+
30
+ def _save_df(self):
31
+ port_path = configSettings.MasterApplicationSettings["UserOutputDirectory"]
32
+ path = tk.filedialog.asksaveasfilename(
33
+ defaultextension=".csv",
34
+ filetypes=[("Excel Files", "*.csv")],
35
+ initialdir=port_path,
36
+ initialfile=str(self._fname) + '.csv',
37
+ parent=self._window
38
+ )
39
+ if path:
40
+ self._dft.get_df().to_csv(path)
41
+
42
+
43
+ def _to_excel_df(self):
44
+ port_path = configSettings.MasterApplicationSettings["UserOutputDirectory"]
45
+ path = tk.filedialog.asksaveasfilename(
46
+ defaultextension=".xlsx",
47
+ filetypes=[("Excel Files", "*.xlsx")],
48
+ initialdir=port_path,
49
+ initialfile=str(self._fname) + '.xlsx',
50
+ parent=self._window
51
+ )
52
+ if path:
53
+ with pd.ExcelWriter(path, mode='w', engine='xlsxwriter',
54
+ date_format="YYYY-MM-DD",
55
+ datetime_format="YYYY-MM-DD") as writer:
56
+ #self._dft.get_df().reset_index().to_excel(writer, index=False)
57
+ self._dft.get_df().to_excel(writer)
58
+ if configSettings.MasterApplicationSettings["OpenExcel"]:
59
+ try:
60
+ os.system('start EXCEL.EXE ' + path)
61
+ except:
62
+ pass
63
+