iam-git / WellMet (public) (License: MIT) (since 2021-08-31) (hash sha1)
WellMet is pure Python framework for spatial structural reliability analysis. Or, more specifically, for "failure probability estimation and detection of failure surfaces by adaptive sequential decomposition of the design domain".
List of commits:
Subject Hash Author Date (UTC)
qt_gui: rearrange functions within qt_gui, add file menu d267357cdbfe805db5ef358e6e1acb24c88b5638 I am 2021-10-30 21:02:17
whitebox: implement run_sample() 576ca55be17e6f14500e70d97536e0b53a57f029 I am 2021-10-30 21:01:07
qt_gui: implement dicebox setup 09a7074b12e46d0554b2c4f73b6a8b672d0b4428 I am 2021-10-30 15:12:33
schemes: small fix 934b2269e5b08930e23fd67df07234251b123153 I am 2021-10-30 15:11:39
qt_gui: prepare setup Goal setup dialog e53197a0b5d5a994dddbcbfb02042c5383f79ec7 Aleksei Gerasimov 2021-10-29 16:47:09
schemes: add conventional functions for tn schemes 9a32048dc342604291f1b7d17efc71be755d3810 Aleksei Gerasimov 2021-10-29 16:45:24
reader: make Reader callable 5cdd55d11ff846f9116fb0e00f54a7830ef3c276 Aleksei Gerasimov 2021-10-27 16:30:05
make WellMet standalone runnable 1fe983d633d7194a64cf6928044082936790ce4d Aleksei Gerasimov 2021-10-27 16:21:51
qt_gui: prepare qt_box_functions module c500fcd20e7b296262a0566d04aabb7bd1ae9cfa Aleksei Gerasimov 2021-10-25 15:39:56
shapeshare: keep empty file to reserve the name b11f17e13dafc3d58db5ad9f101c0126e0bfd871 Aleksei Gerasimov 2021-10-21 14:48:03
delete sball_old :( 792d9d83fde0f38e7396162788ec8aa922b0fd0c Aleksei Gerasimov 2021-10-21 14:47:06
whitebox: add Z_sum, Z_prod, small clean up faec934bb03c20906c9091fc196cc0daf824b54f Aleksei Gerasimov 2021-10-21 13:48:07
g_models: add neverfall, add sign parameter to Z_prod 129abf19da15a5dfcb5a02614d92a233f914d146 Aleksei Gerasimov 2021-10-21 13:45:47
mplot: add one more qhull plot 32e7003aac4887bd83bfff640093f755b4f6cffe I am 2021-09-14 11:42:56
mplot: add ESREL-related figures cba805ba8e7f3c2337027eec6e760aa9234dfdc2 I am 2021-09-12 10:17:21
mplot.mart: allow set up fill keyword cf94410513091b5f96e0e17e8de2f7a3feee1a03 I am 2021-09-12 10:15:55
mplot: add qhull&density figure a36fb606e9f425742925aa4953c0ae07d6b51409 I am 2021-09-10 15:17:58
qt_plot: send sliced sample box to matplotlib fda486b90c56e77bc88b38d0d94d08a751277cfb I am 2021-09-10 15:01:55
mplot: include Axes3d patch 8f5dc7f04b6c804b5ec169ec7b744a8618b3bb69 I am 2021-09-10 11:05:20
rework mplot module considerably 5343602c63032f6f7fd06701b0883eaabb4fc6c1 I am 2021-09-09 13:24:45
Commit d267357cdbfe805db5ef358e6e1acb24c88b5638 - qt_gui: rearrange functions within qt_gui, add file menu
Author: I am
Author date (UTC): 2021-10-30 21:02
Committer name: I am
Committer date (UTC): 2021-10-30 21:02
Parent(s): 576ca55be17e6f14500e70d97536e0b53a57f029
Signer:
Signing key:
Signing status: N
Tree: 332cd2d8e3dfa685787de705b2346357d87d6aa7
File Lines added Lines deleted
qt_gui/gui_startup.py 2 2
qt_gui/qt_graph_widgets.py 911 0
qt_gui/qt_gui.py 170 3194
qt_gui/qt_plot.py 3 1325
File qt_gui/gui_startup.py changed (mode: 100644) (index 5faf82c..2fb294a)
... ... from ..candybox import CandyBox
9 9 #from wellmet import schemes #from wellmet import schemes
10 10
11 11 from . import qt_box_functions as gui from . import qt_box_functions as gui
12 from . import qt_gui
12 from . import qt_plot
13 13
14 14 wt = gui.select_test_case() wt = gui.select_test_case()
15 15
 
... ... gui.read_box(wt)
25 25
26 26 gui.setup_dicebox(wt) gui.setup_dicebox(wt)
27 27
28 qt_gui.QtGuiPlot2D(wt)
28 qt_plot.QtGuiPlot2D(wt)
File qt_gui/qt_graph_widgets.py added (mode: 100644) (index 0000000..669c87a)
1 #!/usr/bin/env python
2 # coding: utf-8
3
4 import pyqtgraph as pg
5 from pyqtgraph.Qt import QtGui
6 from pyqtgraph.Qt import QtCore
7
8 import numpy as np
9 import pandas as pd # required for estimation graph
10
11
12
13 from .. import stm_df
14 """
15 =============
16 График виӝет
17 Grafy
18 Estimation graph widgets
19 ========================
20 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 """
22
23
24 def get_estimation_data(estimations, metric):
25 metric_dict = dict()
26 # new-style: šecko leží dohromady a každý z toho
27 # bere co chce a jak chce
28 # ne že by to bylo nějak šetrný
29 # estimation je slovníkem
30 for estimation in estimations:
31 # nsim musí mäť každej odhad
32 # pokud nemá - je třeba jej prostě opravit
33 nsim = estimation['nsim']
34 try:
35 metric_dict[nsim] = estimation[metric]
36 except KeyError as e:
37 pass #print(self.__class__.__name__ + ":", repr(e))
38
39 # nikdo neslibil, že budou v pořadí
40 x = np.sort(tuple(metric_dict.keys()))
41 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
42 return x, y
43
44
45 class SimplexEstimationData(QtCore.QObject):
46 #š budeme mӓť svůj vlastní signaľčík
47 simplex_estimation_updated = QtCore.pyqtSignal()
48
49 def __init__(self, dice_box, stream=None, *args, **kwargs):
50 super().__init__(stream, *args, **kwargs)
51 self.dice_box = dice_box
52 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
53 #č asi aby nepadalo, když nenajde signaly
54 self.stream = stream
55 if stream is not None:
56 self.stream.box_runned.connect(self.recalculate)
57 self.stream.estimation_added.connect(self.recalculate)
58
59 self.setup_context_menu()
60 self.recalculate()
61
62
63 def setup_context_menu(self):
64 # simplex_data_menu
65 self.TRI_menu = QtGui.QMenu("TRI sources", self.stream)
66
67 self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu)
68 self.TRI_overall_chk.setCheckable(True)
69 self.TRI_overall_chk.setChecked(True)
70 self.TRI_overall_chk.triggered.connect(self.recalculate)
71 self.TRI_menu.addAction(self.TRI_overall_chk)
72
73 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
74 self.simplex_chk.setCheckable(True)
75 self.simplex_chk.setChecked(True)
76 self.simplex_chk.triggered.connect(self.recalculate)
77 self.TRI_menu.addAction(self.simplex_chk)
78
79 # year, it was
80 ## hope, it is temporary
81 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
82 #self.sources_action_group.addAction(self.TRI_overall_chk)
83 #self.sources_action_group.addAction(self.simplex_chk)
84
85 self.TRI_menu.addSeparator()
86
87 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
88 self.proxy_chk.setCheckable(True)
89 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
90 self.proxy_chk.triggered.connect(self.recalculate)
91 self.TRI_menu.addAction(self.proxy_chk)
92
93 self.TRI_menu.addSeparator()
94
95 self.reaction = QtGui.QAction("Update", self.TRI_menu)
96 self.reaction.triggered.connect(self.recalculate)
97 self.TRI_menu.addAction(self.reaction)
98
99 self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
100 self.excelaction.triggered.connect(self.export_to_excel)
101 self.TRI_menu.addAction(self.excelaction)
102
103
104 def export_to_excel(self):
105 #č já bych nechtěl, aby mně export najednou spadl
106 #č z jakéhokoliv důvodu
107 try:
108 proposal_filename = self.dice_box.guessbox.filename
109 if proposal_filename:
110 proposal_filename += '.xlsx'
111 else:
112 proposal_filename = self.dice_box.gm_signature + '.xlsx'
113 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
114 proposal_filename, initialFilter='*.xlsx')
115 self.df.to_excel(filename)
116 except BaseException as e:
117 print(self.__class__.__name__ + ":", repr(e))
118
119
120 def recalculate(self):
121 try:
122 # sources=['box', 'user']
123 sources = list()
124 if self.TRI_overall_chk.isChecked():
125 sources.append('box')
126 if self.simplex_chk.isChecked():
127 sources.append('user')
128
129 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
130 apply_proxy=self.proxy_chk.isChecked())
131 self.simplex_estimation_updated.emit()
132
133 except BaseException as e:
134 print(self.__class__.__name__ + ":", repr(e))
135
136
137
138 class SimplexEstimationGraph(pg.PlotWidget):
139 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
140 super().__init__(parent, *args, **kwargs)
141 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
142 #č asi aby nepadalo, když nenajde signaly
143 self.stream = stream
144 if stream is not None:
145 self.stream.box_runned.connect(self.redraw)
146 self.stream.estimation_added.connect(self.redraw)
147
148 self.dice_box = dice_box
149
150 self.setup_context_menu()
151 self.setup()
152 self.replot()
153
154 def setup_context_menu(self):
155 # creates instance of LegendItem
156 # and saves it into plotItem.legend
157 self.legend = self.addLegend()
158
159 self.plotItem.ctrl.xGridCheck.setChecked(True)
160 self.plotItem.ctrl.yGridCheck.setChecked(True)
161
162 # delete build-in Transforms (with Log_x and Log_y) options,
163 # they can cause uncachable exception (on any zero in data) and crash
164 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
165
166 #č já se bojím. radší to uložím
167 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
168
169 self.plotItem.vb.menu.addMenu(self.stream.simplex_data.TRI_menu)
170
171 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
172 self.legend_chk.setCheckable(True)
173 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
174 self.custom_menu.addAction(self.legend_chk)
175 # apply custom menu option
176 self.legend.setVisible(self.legend_chk.isChecked())
177
178 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
179 self.log_x_chk.setCheckable(True)
180 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
181 self.custom_menu.addAction(self.log_x_chk)
182
183 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
184 self.log_y_chk.setCheckable(True)
185 self.log_y_chk.setChecked(True)
186 self.log_y_chk.triggered.connect(self.replot)
187 self.custom_menu.addAction(self.log_y_chk)
188
189 self.laction = QtGui.QAction("Show labels", self.custom_menu)
190 self.laction.triggered.connect(self.show_labels)
191 self.custom_menu.addAction(self.laction)
192
193
194 def show_labels(self):
195 self.setLabel('left', "Probability measure")
196 self.setLabel('bottom', "Number of simulations")
197
198
199
200 # self.legend.addItem(self.pen_success, "success domain estimation")
201 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
202 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
203 # self.legend.addItem(self.pen_f, "failure domain estimation")
204
205 def setup(self, *args, **kwargs):
206 self.clear()
207 self.setBackground('w')
208 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
209
210 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
211 green = (0, 255, 38, 96)
212 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
213 red = (253, 0, 17, 96)
214 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
215 cream = (255, 221, 0, 96)
216 grey = (196, 196, 196, 96)
217
218 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
219 self.pen_f.setZValue(-100)
220
221 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
222 self.pen_success.setZValue(-100)
223
224 self.pen_outmix = self.plot(x, y)
225
226 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
227 #self.fill_mix.setData(name="mixed simplices measure")
228 self.fill_mix.setBrush(cream)
229 self.fill_mix.setZValue(-100)
230 self.addItem(self.fill_mix)
231
232 #self.pen_outside = self.plot(x, y)
233 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
234 #self.fill_outside.setData(name="out of sampling domain estimation")
235 self.fill_outside.setBrush(grey)
236 self.fill_outside.setZValue(-100)
237 self.addItem(self.fill_outside)
238
239 self.one_ruler = self.addLine(y=1, pen='k')
240 self.zero_ruler = self.addLine(y=0, pen='k')
241
242
243 try:
244 exact_name = self.dice_box.pf_exact_method
245 pen = pg.mkPen(color='b', width=1.5) # blue
246 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
247 #č aby se nám něco zobrazovalo v legendu
248 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
249 except:
250 pass
251
252 pen = pg.mkPen(color='m', width=2)
253 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
254 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
255 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
256
257
258
259
260
261 def replot(self, *args, **kwargs):
262 if self.log_y_chk.isChecked():
263 self.one_ruler.hide()
264 try:
265 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
266 if self.dice_box.pf_exact > 0:
267 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
268 self.pen_exact.show()
269 else:
270 self.pen_exact.hide()
271 except:
272 pass
273 self.setLogMode(y=True)
274 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
275 self.pen_f.setPen(None)
276 self.pen_f.setFillLevel(None)
277 self.pen_success.setFillLevel(0)
278
279 else:
280 self.one_ruler.show()
281 try:
282 self.pen_exact.setPos(self.dice_box.pf_exact)
283 self.pen_exact.show()
284 except:
285 pass
286 self.setLogMode(y=False)
287 self.pen_f.setPen(None)
288 self.pen_f.setFillLevel(0)
289 self.pen_success.setFillLevel(1)
290
291 self.redraw()
292
293
294 #č když se někde objeví nula se zapnutým LogModem -
295 #č qtpygraph hned spadne a není možne ten pad zachytit
296 def zerosafe(self, x, y, fallback_y=None):
297 if self.log_y_chk.isChecked():
298 x = np.array(x)
299 y = np.array(y)
300 if fallback_y is None:
301 fallback_y = y
302 y = np.where(y > 0, y, fallback_y)
303 mask = y > 0
304 return x[mask], y[mask]
305 else:
306 return x, y
307
308 def proxy(self, nsim):
309 if self.proxy_chk.isChecked():
310 proxy = self.dice_box.proxy
311 index = np.array(nsim)-1
312 #č indexy musíme o jedničku změnšit
313 #č výsledek nikoliv. Takže v cajku.
314 return np.cumsum(~proxy)[index]
315 else:
316 return nsim
317
318
319 def _pens_data_update(self):
320 df = self.df
321 nsim = df.nsim.to_numpy()
322 if self.proxy_chk.isChecked():
323 x = self.proxy(nsim)
324 df.insert(loc=0, column='nsim (proxy)', value=x)
325 else:
326 x = nsim
327 # (in case of LogPlot) fallback values also used
328 success_values = df.failure+df.mix+df.out
329 outmix_values = df.failure+df.mix
330 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
331 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
332 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
333 self.pen_success.setData(*self.zerosafe(x, success_values))
334
335
336 def redraw(self):
337 xmin = np.inf
338 xmax = -np.inf
339 tri_estimation = dict()
340 try: # тут всё что угодно может пойти не так
341 # kruci, ještě navic i generovať pokažde znovu...
342
343 # new-style: šecko leží dohromady a každý si z toho
344 # bere co chce a jak chce
345 # ne že by to bylo nějak šetrný
346 # estimation je slovníkem
347 for estimation in self.dice_box.estimations:
348 # nsim musí mäť každej odhad
349 # pokud nemá - je třeba jej prostě opravit
350 nsim = estimation['nsim']
351 try:
352 tri_estimation[nsim] = estimation['TRI_estimation']
353 if nsim > xmax:
354 xmax = nsim
355 if nsim < xmin:
356 xmin = nsim
357
358 except KeyError as e:
359 pass #print(self.__class__.__name__ + ":", repr(e))
360
361 #č neotravuj uživatele chybovejma hlaškama
362 if tri_estimation:
363 # it can be effectively done with pandas
364 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
365 # -1 = 'out', 0=success, 1=failure, 2=mix
366 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
367 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
368 df.sort_values('nsim', inplace=True)
369
370 self._pens_data_update()
371
372 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
373 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
374 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
375
376 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
377 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
378 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
379
380
381 except BaseException as e:
382 print(self.__class__.__name__ + ":", repr(e))
383
384
385
386 class SimplexErrorGraph(pg.PlotWidget):
387 def __init__(self, simplex_data, parent=None, *args, **kwargs):
388 super().__init__(parent, *args, **kwargs)
389 self.simplex_data = simplex_data
390 self.simplex_data.simplex_estimation_updated.connect(self.redraw)
391
392 self.setup_context_menu()
393 self.setup()
394
395 def setup_context_menu(self):
396 # creates instance of LegendItem
397 # and saves it into plotItem.legend
398 self.legend = self.addLegend()
399
400 self.plotItem.ctrl.xGridCheck.setChecked(True)
401 self.plotItem.ctrl.yGridCheck.setChecked(True)
402
403 # menu of SimplexEstimationData
404 self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
405
406 #č já se bojím. radší to uložím
407 self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
408
409 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
410 self.legend_chk.setCheckable(True)
411 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
412 self.custom_menu.addAction(self.legend_chk)
413 # apply custom menu option
414 self.legend.setVisible(self.legend_chk.isChecked())
415
416 self.laction = QtGui.QAction("Show labels", self.custom_menu)
417 self.laction.triggered.connect(self.show_labels)
418 self.custom_menu.addAction(self.laction)
419
420
421 def show_labels(self):
422 self.setLabel('left', "Failure probability estimation error")
423 self.setLabel('bottom', "Number of simulations")
424
425
426 def setup(self, *args, **kwargs):
427 self.clear()
428 self.setBackground('w')
429 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
430
431 # We will use logMode by default
432 self.setLogMode(y=True)
433
434 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
435 #red = (253, 0, 17, 96)
436
437 #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
438 #self.pen_f.setZValue(-100)
439
440
441 pen = pg.mkPen(color='m', width=2)
442 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
443 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
444 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
445
446
447
448 #č když se někde objeví nula se zapnutým LogModem -
449 #č qtpygraph hned spadne a není možne ten pad zachytit
450 def zerosafe(self, x, y, fallback_y=None):
451 x = np.array(x)
452 y = np.array(y)
453 if fallback_y is None:
454 fallback_y = y
455 y = np.where(y > 0, y, fallback_y)
456 mask = y > 0
457 return x[mask], y[mask]
458
459
460 def redraw(self):
461 #č neotravujme uživatele chybovejma hlaškama
462 if hasattr(self.simplex_data.dice_box, 'pf_exact'):
463 try: #ё тут всё что угодно может пойти не так
464 pf_exact = self.simplex_data.dice_box.pf_exact
465
466 df = self.simplex_data.df
467 #č zapíšeme do data rámu, snad nikomu nebude vadit
468 df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
469 df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
470
471 v = df['vertex_estimation_error'].abs()
472 wv = df['weighted_vertex_estimation_error'].abs()
473
474 x, y = self.zerosafe(v.index, v.to_numpy())
475 self.pen_vertex.setData(x, y)
476
477 x, y = self.zerosafe(wv.index, wv.to_numpy())
478 self.pen_weighted_vertex.setData(x, y)
479
480
481 except BaseException as e:
482 print(self.__class__.__name__ + ":", repr(e))
483
484
485
486
487
488
489
490 # DEPRECATED
491 class SimpleSimplexEstimationGraph(pg.PlotWidget):
492 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
493 super().__init__(parent, *args, **kwargs)
494 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
495 #č asi aby nepadalo, když nenajde signaly
496 self.stream = stream
497 if stream is not None:
498 self.stream.box_runned.connect(self.redraw)
499 self.stream.estimation_added.connect(self.redraw)
500
501 self.dice_box = dice_box
502
503 self.setup_context_menu()
504 self.setup()
505 self.replot()
506
507 def setup_context_menu(self):
508 # creates instance of LegendItem
509 # and saves it into plotItem.legend
510 self.legend = self.addLegend()
511
512 self.plotItem.ctrl.xGridCheck.setChecked(True)
513 self.plotItem.ctrl.yGridCheck.setChecked(True)
514
515 # delete build-in Transforms (with Log_x and Log_y) options,
516 # they can cause uncachable exception (on any zero in data) and crash
517 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
518
519 #č já se bojím. radší to uložím
520 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
521
522 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
523 self.legend_chk.setCheckable(True)
524 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
525 self.custom_menu.addAction(self.legend_chk)
526 # apply custom menu option
527 self.legend.setVisible(self.legend_chk.isChecked())
528
529 self.proxy_chk = QtGui.QAction("Proxy", self.custom_menu)
530 self.proxy_chk.setCheckable(True)
531 self.proxy_chk.triggered.connect(self.redraw)
532 self.custom_menu.addAction(self.proxy_chk)
533
534 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
535 self.log_x_chk.setCheckable(True)
536 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
537 self.custom_menu.addAction(self.log_x_chk)
538
539 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
540 self.log_y_chk.setCheckable(True)
541 self.log_y_chk.setChecked(True)
542 self.log_y_chk.triggered.connect(self.replot)
543 self.custom_menu.addAction(self.log_y_chk)
544
545 self.reaction = QtGui.QAction("Redraw", self.custom_menu)
546 self.reaction.triggered.connect(self.redraw)
547 self.custom_menu.addAction(self.reaction)
548
549 self.laction = QtGui.QAction("Show labels", self.custom_menu)
550 self.laction.triggered.connect(self.show_labels)
551 self.custom_menu.addAction(self.laction)
552
553 self.excelaction = QtGui.QAction("Export to Excel", self.custom_menu)
554 self.excelaction.triggered.connect(self.export_to_excel)
555 self.custom_menu.addAction(self.excelaction)
556
557
558 def export_to_excel(self):
559 #č já bych nechtěl, aby mně export najednou spadl
560 #č z jakéhokoliv důvodu
561 try:
562 proposal_filename = self.dice_box.guessbox.filename
563 if proposal_filename:
564 proposal_filename += '.xlsx'
565 else:
566 proposal_filename = self.dice_box.gm_signature + '.xlsx'
567 filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
568 proposal_filename, initialFilter='*.xlsx')
569 self.df.to_excel(filename)
570 except BaseException as e:
571 print(self.__class__.__name__ + ":", repr(e))
572
573 def show_labels(self):
574 self.setLabel('left', "Probability measure")
575 self.setLabel('bottom', "Number of simulations")
576
577
578
579 # self.legend.addItem(self.pen_success, "success domain estimation")
580 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
581 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
582 # self.legend.addItem(self.pen_f, "failure domain estimation")
583
584 def setup(self, *args, **kwargs):
585 self.clear()
586 self.setBackground('w')
587 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
588
589 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
590 green = (0, 255, 38, 96)
591 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
592 red = (253, 0, 17, 96)
593 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
594 cream = (255, 221, 0, 96)
595 grey = (196, 196, 196, 96)
596
597 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
598 self.pen_f.setZValue(-100)
599
600 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
601 self.pen_success.setZValue(-100)
602
603 self.pen_outmix = self.plot(x, y)
604
605 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
606 #self.fill_mix.setData(name="mixed simplices measure")
607 self.fill_mix.setBrush(cream)
608 self.fill_mix.setZValue(-100)
609 self.addItem(self.fill_mix)
610
611 #self.pen_outside = self.plot(x, y)
612 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
613 #self.fill_outside.setData(name="out of sampling domain estimation")
614 self.fill_outside.setBrush(grey)
615 self.fill_outside.setZValue(-100)
616 self.addItem(self.fill_outside)
617
618 self.one_ruler = self.addLine(y=1, pen='k')
619 self.zero_ruler = self.addLine(y=0, pen='k')
620
621
622 try:
623 exact_name = self.dice_box.pf_exact_method
624 pen = pg.mkPen(color='b', width=1.5) # blue
625 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
626 #č aby se nám něco zobrazovalo v legendu
627 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
628 except:
629 pass
630
631 pen = pg.mkPen(color='m', width=2)
632 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
633 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
634 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
635
636
637
638
639
640 def replot(self, *args, **kwargs):
641 if self.log_y_chk.isChecked():
642 self.one_ruler.hide()
643 try:
644 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
645 if self.dice_box.pf_exact > 0:
646 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
647 self.pen_exact.show()
648 else:
649 self.pen_exact.hide()
650 except:
651 pass
652 self.setLogMode(y=True)
653 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
654 self.pen_f.setPen(None)
655 self.pen_f.setFillLevel(None)
656 self.pen_success.setFillLevel(0)
657
658 else:
659 self.one_ruler.show()
660 try:
661 self.pen_exact.setPos(self.dice_box.pf_exact)
662 self.pen_exact.show()
663 except:
664 pass
665 self.setLogMode(y=False)
666 self.pen_f.setPen(None)
667 self.pen_f.setFillLevel(0)
668 self.pen_success.setFillLevel(1)
669
670 self.redraw()
671
672
673 #č když se někde objeví nula se zapnutým LogModem -
674 #č qtpygraph hned spadne a není možne ten pad zachytit
675 def zerosafe(self, x, y, fallback_y=None):
676 if self.log_y_chk.isChecked():
677 x = np.array(x)
678 y = np.array(y)
679 if fallback_y is None:
680 fallback_y = y
681 y = np.where(y > 0, y, fallback_y)
682 mask = y > 0
683 return x[mask], y[mask]
684 else:
685 return x, y
686
687 def proxy(self, nsim):
688 if self.proxy_chk.isChecked():
689 proxy = self.dice_box.proxy
690 index = np.array(nsim)-1
691 #č indexy musíme o jedničku změnšit
692 #č výsledek nikoliv. Takže v cajku.
693 return np.cumsum(~proxy)[index]
694 else:
695 return nsim
696
697
698 def _pens_data_update(self):
699 df = self.df
700 nsim = df.nsim.to_numpy()
701 if self.proxy_chk.isChecked():
702 x = self.proxy(nsim)
703 df.insert(loc=0, column='nsim (proxy)', value=x)
704 else:
705 x = nsim
706 # (in case of LogPlot) fallback values also used
707 success_values = df.failure+df.mix+df.out
708 outmix_values = df.failure+df.mix
709 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
710 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
711 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
712 self.pen_success.setData(*self.zerosafe(x, success_values))
713
714
715 def redraw(self):
716 xmin = np.inf
717 xmax = -np.inf
718 tri_estimation = dict()
719 try: # тут всё что угодно может пойти не так
720 # kruci, ještě navic i generovať pokažde znovu...
721
722 # new-style: šecko leží dohromady a každý si z toho
723 # bere co chce a jak chce
724 # ne že by to bylo nějak šetrný
725 # estimation je slovníkem
726 for estimation in self.dice_box.estimations:
727 # nsim musí mäť každej odhad
728 # pokud nemá - je třeba jej prostě opravit
729 nsim = estimation['nsim']
730 try:
731 tri_estimation[nsim] = estimation['TRI_estimation']
732 if nsim > xmax:
733 xmax = nsim
734 if nsim < xmin:
735 xmin = nsim
736
737 except KeyError as e:
738 pass #print(self.__class__.__name__ + ":", repr(e))
739
740 #č neotravuj uživatele chybovejma hlaškama
741 if tri_estimation:
742 # it can be effectively done with pandas
743 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
744 # -1 = 'out', 0=success, 1=failure, 2=mix
745 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
746 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
747 df.sort_values('nsim', inplace=True)
748
749 self._pens_data_update()
750
751 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
752 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
753 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
754
755 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
756 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
757 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
758
759
760 except BaseException as e:
761 print(self.__class__.__name__ + ":", repr(e))
762
763
764 # DEPRECATED
765 class TriEstimationGraph(SimpleSimplexEstimationGraph):
766 def __init__(self, dice_box, tri_estimation_name='TRI_overall_estimations', stream=None, parent=None, *args, **kwargs):
767 self.tri_estimation_name = tri_estimation_name
768 super().__init__(dice_box, stream, parent, *args, **kwargs)
769
770
771
772 def redraw(self):
773 try: # тут всё что угодно может пойти не так
774 data = self.dice_box.guessbox.estimations[self.tri_estimation_name]
775 nsim, tri_data = data
776 # it can be effectively done with pandas
777 self.df = df = pd.DataFrame(tri_data)
778 # -1 = 'out', 0=success, 1=failure, 2=mix
779 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
780 df.insert(loc=0, column='nsim', value=nsim)
781
782 # Update the data
783 self._pens_data_update()
784
785 if 'vertex_estimation' in self.dice_box.guessbox.estimations:
786 data = self.dice_box.guessbox.estimations['vertex_estimation']
787 nsim, y = data
788 # Update the data
789 #č spolehám na konzistenci blackboxu, ne však úplně
790 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
791 df['vertex_estimation'] = y
792
793 if 'weighted_vertex_estimation' in self.dice_box.guessbox.estimations:
794 data = self.dice_box.guessbox.estimations['weighted_vertex_estimation']
795 nsim, y = data
796 # Update the data
797 #č spolehám na konzistenci blackboxu, ne však úplně
798 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
799 df['weighted_vertex_estimation'] = y
800
801
802 # BaseException
803 except BaseException as e:
804 print(self.__class__.__name__ + ":", repr(e))
805
806
807
808
809
810
811
812 class VoronoiEstimationGraph(pg.PlotWidget):
813 def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
814 super().__init__(parent)
815 self.sb_item = samplebox_item
816 self.sb_item.box_runned.connect(self.redraw)
817 self.sb_item.estimation_added.connect(self.redraw)
818
819 self.black_box = black_box
820 self.setBackground('w')
821
822
823 self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
824 self.reaction.triggered.connect(self.redraw)
825 self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
826
827
828
829 # implicitně Y je v logaritmickem měřítku
830 self.setLogMode(False, True)
831
832 x = y = () # zde jen vytvoříme kostru, nakrmíme daty v .redraw()
833
834
835 # nechapu, proč těm Itemům ríkám "propíska"
836 # propíska? Их есть у нас!
837
838 self.Voronoi_2_point_upper_bound = self.plot(x, y, pen='y')
839 self.Voronoi_2_point_lower_bound = self.plot(x, y, pen='y')
840
841 fill_color = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
842 self.fill = pg.FillBetweenItem(self.Voronoi_2_point_upper_bound, self.Voronoi_2_point_lower_bound, fill_color)
843 self.addItem(self.fill)
844
845 self.Voronoi_2_point_failure_rate = self.plot(x, y, pen=(195,46,212))
846 self.Voronoi_2_point_pure_failure_rate = self.plot(x, y, pen='m')
847 self.Voronoi_failure_rate = self.plot(x, y, pen='r')
848
849 self.pen_exact = self.plot(x, y, pen='b') # blue
850 self.pen_one = self.plot(x, y, pen='k') # black
851
852 self.redraw()
853
854
855 def redraw(self):
856 # kruci, ještě navic i generovať pokažde znovu...
857 metrics = {'Voronoi_2_point_upper_bound':{},\
858 'Voronoi_2_point_lower_bound':{},\
859 'Voronoi_2_point_failure_rate':{},\
860 'Voronoi_2_point_pure_failure_rate':{},\
861 'Voronoi_failure_rate':{},}
862 xmin = np.inf
863 xmax = -np.inf
864 try: # тут всё что угодно может пойти не так
865 # new-style: šecko leží dohromady a každý z toho
866 # bere co chce a jak chce
867 # ne že by to bylo nějak šetrný
868 # estimation je slovníkem
869 for estimation in self.black_box.estimations:
870 # nsim musí mäť každej odhad
871 # pokud nemá - je třeba jej prostě opravit
872 nsim = estimation['nsim']
873
874
875 for metric, metric_dict in metrics.items():
876 try:
877 if estimation[metric] > 0:
878 metric_dict[nsim] = estimation[metric]
879 if nsim > xmax:
880 xmax = nsim
881 if nsim < xmin:
882 xmin = nsim
883 except KeyError as e:
884 pass #print(self.__class__.__name__ + ":", repr(e))
885
886 for metric, metric_dict in metrics.items():
887 pen = getattr(self, metric)
888 # nikdo neslibil, že budou v pořadí
889 x = np.sort(tuple(metric_dict.keys()))
890 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
891 pen.setData(x, y)
892
893 if (xmax - xmin) > 0:
894 self.pen_one.setData((xmin,xmax), (1, 1))
895 if hasattr(self.black_box, 'pf_exact'):
896 # poslední. I když spadne, tak už nikomu moc nevadí
897 self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
898
899 except BaseException as e:
900 print(self.__class__.__name__ + ":", repr(e))
901
902
903 # pen_f.opts['logMode']
904 # pen_outside.setLogMode(False, False)
905 #setLogMode(False, False)
906 #f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
907 #win.addItem(f)
908
909
910
911
File qt_gui/qt_gui.py changed (mode: 100644) (index 8aa7ad5..6de39b3)
... ... from pyqtgraph.Qt import QtCore
8 8 from pyqtgraph import console from pyqtgraph import console
9 9
10 10 import numpy as np import numpy as np
11 import pandas as pd # required for estimation graph
11 from . import qt_graph_widgets
12 from .. import reader
12 13
13 #č vzdávám se.
14 #č quadpy tak se stavá povinnou závislostí
15 #č potrebuju pro HullEstimation widget
16 import quadpy
17
18
19 from .. import estimation as stm
20 from .. import misc
21 from .. import stm_df
22 from .. import sball
23 from .. import schemes
24 from .. import convex_hull as khull
25 #č pro mě je zvykem jako ghull označovat objekt třídy Ghull
26 #č nikoliv čerstvě oddelený modul
27 from ..ghull import Ghull, Shell_MC, Shell_IS, Shell_1DS
28
29
30 14
31 15 ### Define a top-level widget to hold everything ### Define a top-level widget to hold everything
32 class QtGuiPlot2D(QtGui.QMainWindow):
16 class QtGuiWindow(QtGui.QMainWindow):
33 17 #č box_runned dublikuje slice_changed #č box_runned dublikuje slice_changed
34 18 # do not redraw twice! # do not redraw twice!
35 19 box_runned = QtCore.pyqtSignal() box_runned = QtCore.pyqtSignal()
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
84 68
85 69 ## Start the Qt event loop ## Start the Qt event loop
86 70 self.app.exec_() self.app.exec_()
71
72 def setup_menubar(self):
73 self.bar = self.menuBar()
74 self.file_menu = self.bar.addMenu("File")
75 #č kontejner jen aby Python mně Cečkové objekty nevymazal
76 self.file_actions = []
77 load_coordinates_action = QtGui.QAction("Load coordinates", self)
78 load_coordinates_action.triggered.connect(self.load_coordinates)
79 self.file_menu.addAction(load_coordinates_action)
80 self.file_actions.append(load_coordinates_action)
81
82 export_coordinates_action = QtGui.QAction("Export coordinates", self)
83 export_coordinates_action.triggered.connect(self.export_coordinates)
84 self.file_menu.addAction(export_coordinates_action)
85 self.file_actions.append(export_coordinates_action)
86
87 import_samples_action = QtGui.QAction("Import samples", self)
88 import_samples_action.triggered.connect(self.import_samples)
89 self.file_menu.addAction(import_samples_action)
90 self.file_actions.append(import_samples_action)
91
92 export_samples_action = QtGui.QAction("Export samples", self)
93 export_samples_action.triggered.connect(self.export_samples)
94 self.file_menu.addAction(export_samples_action)
95 self.file_actions.append(export_samples_action)
87 96
88
89 def initialize_central_widget(self):
90 self.central_widget = pg.PlotWidget()
91 self.central_widget.setBackground('w')
92 self.px_size = 3.5
93 self.ncircles = 5
94 self.redraw_called.connect(self.central_widget.clear)
97 self.view = self.bar.addMenu("View")
98
99 self.graph_menu = self.bar.addMenu("Box")
100 self.batch_run_action = QtGui.QAction("Batch run", self)
101 self.batch_run_action.triggered.connect(self.batch_run)
102 self.graph_menu.addAction(self.batch_run_action)
103
104 # optional feature
105 self.initialize_matplotlib_menu()
95 106
96 107 # should be INHERITED by gl_plot # should be INHERITED by gl_plot
97 108 def initialize_matplotlib_menu(self): def initialize_matplotlib_menu(self):
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
154 165 # intended as a common setup function # intended as a common setup function
155 166 def setup(self): def setup(self):
156 167
157 self.bar = self.menuBar()
158 self.view = self.bar.addMenu("View")
159
160 self.graph_menu = self.bar.addMenu("Box")
161 self.batch_run_action = QtGui.QAction("Batch run", self)
162 self.batch_run_action.triggered.connect(self.batch_run)
163 self.graph_menu.addAction(self.batch_run_action)
164 168
165 # optional feature
166 self.initialize_matplotlib_menu()
169 self.setup_menubar()
167 170
168 171 ### Create some widgets to be placed inside ### Create some widgets to be placed inside
169 172 self.combo_space = pg.ComboBox(items=self.spaces, default=self.space) self.combo_space = pg.ComboBox(items=self.spaces, default=self.space)
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
180 183 self.slider.setValue(self.sample_box.nsim) self.slider.setValue(self.sample_box.nsim)
181 184
182 185 #č jen aby se slider probral, když uživatel ručně přídá bodíky #č jen aby se slider probral, když uživatel ručně přídá bodíky
183 self.redraw_called.connect(lambda:self.slider.setMaximum(self.sample_box.nsim))
186 self.redraw_called.connect(self.wake_up_slider)
187 self.box_runned.connect(self.wake_up_slider)
184 188
185 189 self.btn = QtGui.QPushButton('run box') self.btn = QtGui.QPushButton('run box')
186 190 self.btn.clicked.connect(self.run_sb) self.btn.clicked.connect(self.run_sb)
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
247 251 self.dockables.append(dock) self.dockables.append(dock)
248 252 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
249 253
250 self.simplex_data = SimplexEstimationData(self.sample_box, self)
254 self.simplex_data = qt_graph_widgets.SimplexEstimationData(self.sample_box, self)
251 255 #č graphy už nemusí jít po stm widgetech #č graphy už nemusí jít po stm widgetech
252 256 dock = QtGui.QDockWidget("TRI_overall estimation graph", self) dock = QtGui.QDockWidget("TRI_overall estimation graph", self)
253 dock.setWidget(TriEstimationGraph(self.sample_box, 'TRI_overall_estimations', self, dock))
257 dock.setWidget(qt_graph_widgets.TriEstimationGraph(self.sample_box, 'TRI_overall_estimations', self, dock))
254 258 self.dockables.append(dock) self.dockables.append(dock)
255 259 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
256 260
257 261 dock = QtGui.QDockWidget("Simplex estimation graph", self) dock = QtGui.QDockWidget("Simplex estimation graph", self)
258 dock.setWidget(SimpleSimplexEstimationGraph(self.sample_box, self, dock))
262 dock.setWidget(qt_graph_widgets.SimpleSimplexEstimationGraph(self.sample_box, self, dock))
259 263 self.dockables.append(dock) self.dockables.append(dock)
260 264 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
261 265
262 266 dock = QtGui.QDockWidget("Simplex error graph", self) dock = QtGui.QDockWidget("Simplex error graph", self)
263 dock.setWidget(SimplexErrorGraph(self.simplex_data, dock))
267 dock.setWidget(qt_graph_widgets.SimplexErrorGraph(self.simplex_data, dock))
264 268 self.dockables.append(dock) self.dockables.append(dock)
265 269 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
266 270
267 271
268 272 dock = QtGui.QDockWidget("Voronoi estimation graph", self) dock = QtGui.QDockWidget("Voronoi estimation graph", self)
269 dock.setWidget(VoronoiEstimationGraph(self.sample_box, self, dock))
273 dock.setWidget(qt_graph_widgets.VoronoiEstimationGraph(self.sample_box, self, dock))
270 274 self.dockables.append(dock) self.dockables.append(dock)
271 275 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
272 276
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
293 297 #dock.setFloating(True) #dock.setFloating(True)
294 298
295 299 #self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items) #self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
300
301
302
303
304 csv_filter = "CSV files (*.csv)"
305 npy_filter = "NumPy binary files (*.npy)"
306 txt_filter = "Text files (*.txt)"
307 gz_filter = "Compressed text files (*.gz)"
308
309 def load_coordinates(self):
310 """
311 Loads numpy data and adds them to the sample_box
312 """
313 nodes = None
314 filter = self.npy_filter + ';;' + self.txt_filter + ';;' + self.gz_filter
315 wt = self.sample_box
296 316
317 try:
318 filename, filter = pg.FileDialog.getOpenFileName(
319 parent=self,
320 caption="Load coordinates",
321 directory="store/%s_%sD.npy" % (wt.gm_signature, wt.nvar),
322 filter=filter,
323 initialFilter=self.npy_filter,
324 #options=pg.FileDialog.Option.DontConfirmOverwrite
325 )
326 if filename:
327 if filter == self.npy_filter:
328 raw_nodes = np.load(filename)
329 else:
330 raw_nodes = np.loadtxt(filename)
331
332 # create sample
333 nodes = wt.f_model.new_sample(sample=raw_nodes, \
334 space=self.space, extend=False)
335
336 except BaseException as e:
337 print(self.__class__.__name__ + ":", \
338 " coordinates loading failed", repr(e))
339
340 #č zde jíž nemá cenu chytat chyby. Sbohem!
341 if nodes is not None:
342 # run!
343 wt.run_sample(nodes)
344 self.box_runned.emit()
297 345
298 346
347 def export_coordinates(self):
348 """
349 Exports current sample box coordinates
350 """
351 filter = self.npy_filter + ';;' + self.txt_filter + ';;' + self.gz_filter
352 wt = self.sample_box
353
354 filename, filter = pg.FileDialog.getSaveFileName(
355 parent=self,
356 caption="Export coordinates",
357 directory="store/%s_%sD.npy" % (wt.gm_signature, wt.nvar),
358 #filter=csv_filter,
359 filter=filter,
360 initialFilter=self.npy_filter,
361 #options=pg.FileDialog.Option.DontConfirmOverwrite
362 )
363 if filename:
364 nsim = self.slider.value()
365 nodes = self.sample_box.f_model[:nsim]
366 raw_nodes = getattr(nodes, self.space)
367 try:
368 if filter == self.npy_filter:
369 np.save(filename, raw_nodes, allow_pickle=False)
370 else:
371 np.savetxt(filename, raw_nodes)
372 except BaseException as e:
373 print(self.__class__.__name__ + ":", \
374 " coordinates export failed", repr(e))
375
376
377
378 def import_samples(self):
379 wt = self.sample_box
380
381 filename, __filter = pg.FileDialog.getOpenFileName(
382 parent=self,
383 caption="Import samples",
384 directory="store/%s_%sD.csv" % (wt.gm_signature, wt.nvar),
385 #filter=csv_filter,
386 filter=self.csv_filter, # + ";;All files(*)",
387 initialFilter=self.csv_filter,
388 #options=pg.FileDialog.Option.DontConfirmOverwrite
389 )
390 if filename and (filename[-4:]=='.csv'):
391 #č Reader vždy dopíše '.csv' na konci souboru
392 #č nechcu to teď měnit
393 filename = filename[:-4]
394
395 #č nechcu chytat žádné chyby. Sbohem!
396 sample_box = reader.reader(filename, f_model=wt.f_model)
397 wt.add_sample(sample_box)
398 self.box_runned.emit()
299 399
300
301 def plot_setup(self):
302 self.view_items = []
303 self.view_items.append(BasePlotting(self))
304 self.view_items.append(UnitCube(self))
305 self.view_items.append(AspectLock(self))
306 self.view_items.append(LastShot(self))
307 self.view_items.append(Circles(self))
308 self.view_items.append(Isocurves(self))
309 self.view_items.append(Boundaries(self))
310 self.view_items.append(ConvexHull2D(self))
311 self.view_items.append(Triangulation(self))
312
313
314
315
316 dock = dock_r = QtGui.QDockWidget("Simplex-based pf estimation", self)
317 dock.setWidget(FastSimplexEstimationWidget(self, dock))
318 self.view.addAction(dock.toggleViewAction())
319 self.dockables.append(dock)
320 self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
321
322
323 dock = QtGui.QDockWidget("Tesselation-based pf estimation", self)
324 dock.setWidget(VoronoiEstimationWidget(self, dock))
325 self.view.addAction(dock.toggleViewAction())
326 self.dockables.append(dock)
327 #self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
328 self.tabifyDockWidget(dock_r, dock)
329
330
331 dock = QtGui.QDockWidget("Ghull", self)
332 dock.setWidget(HullEstimationWidget(self, dock))
333 self.view.addAction(dock.toggleViewAction())
334 self.dockables.append(dock)
335 self.tabifyDockWidget(dock_r, dock)
336
337 dock = QtGui.QDockWidget("Blackbox's candidates", self)
338 dock.setWidget(CandidatesWidget(self, dock))
339 self.view.addAction(dock.toggleViewAction())
340 self.dockables.append(dock)
341 self.tabifyDockWidget(dock_r, dock)
400 def export_samples(self):
401 wt = self.sample_box
402
403 filename, __filter = pg.FileDialog.getSaveFileName(
404 parent=self,
405 caption="Export samples",
406 directory="store/%s_%sD.csv" % (wt.gm_signature, wt.nvar),
407 #filter=csv_filter,
408 filter=self.csv_filter, # + ";;All files(*)",
409 initialFilter=self.csv_filter,
410 #options=pg.FileDialog.Option.DontConfirmOverwrite
411 )
412 if filename:
413 #č Reader vždy dopíše '.csv' na konci souboru
414 #č nechcu to teď měnit
415 if filename[-4:]=='.csv':
416 filename = filename[:-4]
417 nsim = self.slider.value()
418 reader.export(filename, wt[:nsim])
342 419
343 420
344 421 # #
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
364 441 def run_sb(self): def run_sb(self):
365 442 with pg.BusyCursor(): with pg.BusyCursor():
366 443 self.last_shot = self.sample_box() self.last_shot = self.sample_box()
367
368 # slider
369 #č zpusobí slice_changed
370 self.slider.setMaximum(self.sample_box.nsim)
371 self.slider.setValue(self.sample_box.nsim)
372
373 444 self.box_runned.emit() self.box_runned.emit()
374 445
375
446 def wake_up_slider(self):
447 # slider
448 #č zpusobí slice_changed
449 self.slider.setMaximum(self.sample_box.nsim)
450 self.slider.setValue(self.sample_box.nsim)
376 451
377 452 # INHERITED by gl_plot # INHERITED by gl_plot
378 453 def bx_connect(self): def bx_connect(self):
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
434 509
435 510
436 511
437
438 """
439 ==============
440 оӵ Суред люкет
441 č Kreslicí prvky
442 E Drawing items
443 =================
444 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
445 """
446
447
448 class Series:
449 def __init__(self, w, autoredraw=True):
450 self.w = w
451 self.w.space_changed.connect(self.space_update)
452 self.w.redraw_called.connect(self._redraw)
453 # redraw policy
454 self.autoredraw = autoredraw
455 self.items = {}
456
457
458 def add_serie(self, sample, index=None, **plot_kwargs):
459 plot_item = self._draw(sample, plot_kwargs)
460
461 if index is None:
462 index = len(self.items)
463 elif index in self.items:
464 # kind of update, then
465 #č musíme korektně odebrat předchozí kresbu
466 self.remove_item(index)
467
468 self.items[index] = [sample, plot_item, plot_kwargs]
469 return plot_item
470
471
472 def _draw(self, sample, plot_dict):
473 pos = getattr(sample, self.w.space)[:,:2]
474 mask = np.all(np.isfinite(pos), axis=1)
475 return self.w.central_widget.plot(pos[mask], **plot_dict)
476
477
478 def clear(self):
479 for item in self.items.values():
480 __sample, plot_item, __plot_dict = item
481 self.w.central_widget.removeItem(plot_item)
482 self.items.clear()
483
484 def remove_item(self, index):
485 __sample, plot_item, __plot_dict = self.items.pop(index)
486 self.w.central_widget.removeItem(plot_item)
487
488
489 def hide(self, index=None):
490 if index is None:
491 for item in self.items.values():
492 __sample, plot_item, __plot_dict = item
493 plot_item.hide()
494 else:
495 __sample, plot_item, __plot_dict = self.items[index]
496 plot_item.hide()
497
498 def show(self, index=None):
499 if index is None:
500 for item in self.items.values():
501 __sample, plot_item, __plot_dict = item
502 plot_item.show()
503 else:
504 __sample, plot_item, __plot_dict = self.items[index]
505 plot_item.show()
506
507
508 def _redraw(self):
509 if self.autoredraw:
510 for item in self.items.values():
511 sample, _invalid_plot_item, plot_dict = item
512 item[1] = self._draw(sample, plot_dict)
513 else:
514 self.items.clear()
515
516
517 def space_update(self):
518 for item in self.items.values():
519 sample, plot_item, __plot_dict = item
520
521 pos = getattr(sample, self.w.space)[:,:2]
522 mask = np.all(np.isfinite(pos), axis=1)
523 plot_item.setData(pos[mask])
524
525
526
527 #č Kružničky chcete?
528 #ё Кружочки ннада?
529 #оӵ Гаусслэн котыресез
530 class Giracles(Series):
531 def __init__(self, w, autoredraw=True, nrod=200):
532 super().__init__(w, autoredraw)
533
534 self.setup(nrod)
535
536 def setup(self, nrod):
537 phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
538 cos_phi = np.cos(phi)
539 sin_phi = np.sin(phi)
540
541 self.prebound = np.array((cos_phi, sin_phi)).T
542
543
544 def add_circle(self, r=1, index=None, **plot_kwargs):
545 f_model = self.w.sample_box.f_model
546 sample_G = self.prebound * r
547 sample = f_model.new_sample(sample_G, space='G', extend=True)
548 return self.add_serie(sample, index=index, **plot_kwargs)
549 512
550 513
551 514
552 515
553 class InfiniteLines(Series):
554 516
555 def add_line(self, space='G', index=None, **plot_kwargs):
556 plot_item = self.w.central_widget.addLine(**plot_kwargs)
557 if space == self.w.space:
558 plot_item.show()
559 else:
560 plot_item.hide()
561
562 if index is None:
563 index = len(self.items)
564 elif index in self.items:
565 # kind of update, then
566 #č musíme korektně odebrat předchozí kresbu
567 self.remove_item(index)
568
569 self.items[index] = [space, plot_item, plot_kwargs]
570 return plot_item
571
572 def _redraw(self):
573 if self.autoredraw:
574 for item in self.items.values():
575 space, _invalid_plot_item, plot_dict = item
576 item[1] = self.w.central_widget.addLine(**plot_dict)
577 else:
578 self.items.clear()
579
580
581 def space_update(self):
582 for item in self.items.values():
583 space, plot_item, __plot_dict = item
584 if space == self.w.space:
585 plot_item.show()
586 else:
587 plot_item.hide()
588 517
589 518
590 519 """ """
591 ==============
592 у График люкет
593 č Grafické prvky
594 E Drawing modules
595 =================
520 ===========
521 ♥ Чыры-пыры
522 č Jiné
523 E Miscellaneous
524 ===============
596 525 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
597 526 """ """
598 527
599 528
600 class BasePlotting:
601 def __init__(self, w):
602 self.w = w
603 #self.w.box_runned.connect(self.redraw) #č dublikuje slice_changed
604 self.w.space_changed.connect(self.plot)
605 self.w.slice_changed.connect(self.plot)
606 self.w.redraw_called.connect(self.redraw)
607
608
609 def redraw(self):
610 plot_widget = self.w.central_widget
611 #size=self.w.px_size*1.5
612 pos = () #np.empty((nsim, 4))
613 size = self.w.px_size * 2
614 self.failures = plot_widget.plot(pos, pen=None, symbol='x', symbolPen='r',\
615 symbolSize=size*1.5, name='Failures') # symbolBrush=0.2,
616 self.failures.setZValue(100)
617
618 self.proxy_failures = plot_widget.plot(pos, pen=None, symbol='p', symbolPen=0.5,\
619 symbolSize=size, symbolBrush=(217,83,25), name='Proxy failures')
620 self.proxy_failures.setZValue(95)
621
622 self.successes = plot_widget.plot(pos, pen=None, symbol='+', \
623 symbolSize=size*1.5, symbolPen='g', name='Successes')
624 self.successes.setZValue(90)
625
626 self.proxy_successes = plot_widget.plot(pos, pen=None, symbol='p', symbolPen=0.5, \
627 symbolSize=size, symbolBrush=(119,172,48), name='Proxy successes')
628 self.proxy_successes.setZValue(85)
629
630
631 self.nodes = plot_widget.plot(pos, pen=None, symbol='o', symbolPen=0.5, \
632 symbolSize=size, name='Nodes')
633 self.nodes.setZValue(80)
634
635 self.plot()
636
637 def plot(self):
638 nsim = self.w.slider.value()
639
640 sample_box = self.w.sample_box[:nsim]
641
642 pos = getattr(sample_box, self.w.space)[:,:2]
643 if hasattr(sample_box, 'failsi'): #č to je normálně sample_box
644 failsi = sample_box.failsi
645
646 try: # proxy denotes to implicitly-known values
647 proxy = sample_box.proxy
648 except AttributeError:
649 proxy = np.full(nsim, False, dtype=np.bool)
650
651 mask = np.all((failsi, ~proxy), axis=0)
652 self.draw(self.failures, pos[mask])
653
654 mask = np.all((~failsi, ~proxy), axis=0)
655 self.draw(self.successes, pos[mask])
656
657 mask = np.all((failsi, proxy), axis=0)
658 self.draw(self.proxy_failures, pos[mask])
659
660 mask = np.all((~failsi, proxy), axis=0)
661 self.draw(self.proxy_successes, pos[mask])
662
663 else: #č není to teda sample_box...
664 #č snad se nám povede nakreslit aspoň tečky?
665 self.draw(self.nodes, pos)
666
667
668 @staticmethod
669 def draw(plot_item, data):
670 #č musím to udělat takhle
671 #č jinač to zlobí při posunutích slajderu
672 if len(data):
673 plot_item.setData(data)
674 plot_item.show()
675 else:
676 plot_item.hide()
677
678
679 class UnitCube:
680 def __init__(self, w):
681 self.w = w
682 self.w.space_changed.connect(self.plot)
683 self.w.redraw_called.connect(self.redraw)
684
685
686 def redraw(self):
687 plot_widget = self.w.central_widget
688 self.frame = plot_widget.plot(pos=(), pen='k')
689 self.plot()
690
691
692 def plot(self):
693 if self.w.space in ('P', 'U'):
694 self.frame.setData((0,0,1,1,0), (0,1,1,0,0))
695 self.frame.show()
696 elif self.w.space in ('aP', 'aU'):
697 x, y, *__ = (*self.w.sample_box.alpha,)
698 self.frame.setData((0,0,x,x,0), (0,y,y,0,0))
699 self.frame.show()
700 else:
701 self.frame.hide()
702
703
704
705
706
707
708 class AspectLock:
709 def __init__(self, w):
710 self.w = w
711
712 self.item = QtGui.QListWidgetItem('Equal aspect')
713 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
714 self.item.setCheckState(QtCore.Qt.Unchecked)
715 self.w.list_view.addItem(self.item)
716 self.w.list_view.itemChanged.connect(self.set_aspect)
717
718 def set_aspect(self):
719 plot_widget = self.w.central_widget
720 if self.item.checkState():
721 plot_widget.setAspectLocked(lock=True, ratio=1)
722 else:
723 plot_widget.setAspectLocked(lock=False, ratio=1)
724
725
726
727
728 class LastShot:
729 def __init__(self, w):
730 self.w = w
731 self.w.box_runned.connect(self.plot)
732 self.w.space_changed.connect(self.plot)
733 self.w.redraw_called.connect(self.redraw)
734
735 self.item = QtGui.QListWidgetItem('Last shot')
736 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
737 self.item.setCheckState(QtCore.Qt.Checked)
738 self.w.list_view.addItem(self.item)
739 self.w.list_view.itemChanged.connect(self.show_slot)
740
741 def show_slot(self, item):
742 if item is self.item:
743 self.plot()
744
745 def redraw(self):
746 pos = ()
747 plot_widget = self.w.central_widget
748 self.last = plot_widget.plot(pos, pen=None, symbol='o', symbolPen='c', name='Last shot', symbolBrush=None)
749 self.shot = plot_widget.plot(pos, pen=None, symbol='+', symbolPen='c', name='Last shot')
750 self.last.setZValue(110)
751 self.shot.setZValue(110)
752
753 self.plot()
754
755 def plot(self):
756 if self.item.checkState() and (self.w.last_shot is not None):
757 pos = getattr(self.w.last_shot, self.w.space)[:,:2]
758 self.last.setData(pos)
759 self.shot.setData(pos)
760 self.last.show()
761 self.shot.show()
762 else:
763 self.last.hide()
764 self.shot.hide()
765
766
767
768 #č Kružničky chcete?
769 #ё Кружочки ннада?
770 class Circles:
771 def __init__(self, w):
772 self.w = w
773 self.w.space_changed.connect(self.plot)
774 self.w.redraw_called.connect(self.redraw)
775
776 self.name = 'Circles'
777 self.item = QtGui.QListWidgetItem(self.name)
778 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
779 self.item.setCheckState(QtCore.Qt.Checked)
780 self.w.list_view.addItem(self.item)
781 self.w.list_view.itemChanged.connect(self.show_slot)
782
783 self.color = 'k'
784 self.z_value = -1
785
786 def redraw(self):
787 pos = ()
788 plot_widget = self.w.central_widget
789
790 self.circles = []
791 ncircles = self.w.ncircles
792 for r in range(ncircles):
793 pen = pg.mkPen(color=self.color, width=self.w.px_size*(1-r/ncircles))
794 circle = plot_widget.plot(pos=pos, pen=pen, name=self.name)
795 circle.setZValue(self.z_value)
796 self.circles.append(circle)
797
798 self.plot()
799
800 def show_slot(self, item):
801 if item is self.item:
802 self.plot()
803
804 def plot(self):
805 if self.item.checkState():
806
807 f_model = self.w.sample_box.f_model
808
809 nrod = 200
810 phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
811 cos_phi = np.cos(phi)
812 sin_phi = np.sin(phi)
813 for r in range(len(self.circles)):
814 bound_x = r * cos_phi
815 bound_y = r * sin_phi
816
817
818 #оӵ малы транспонировать кароно? Озьы кулэ!
819 bound = np.array((bound_x, bound_y)).T
820 f = f_model.new_sample(bound, space='G', extend=True)
821 pos = getattr(f, self.w.space)[:,:2]
822 self.circles[r].setData(pos)
823 self.circles[r].show()
824
825 else:
826 for circle in self.circles:
827 circle.hide()
828
829
830 class Isocurves:
831 def __init__(self, w):
832 self.w = w
833 self.w.space_changed.connect(self.on_space_changed)
834 self.w.redraw_called.connect(self.redraw)
835
836 self.contour_item = QtGui.QListWidgetItem('Isolevels') # Density contours
837 self.contour_item.setFlags(self.contour_item.flags() | QtCore.Qt.ItemIsUserCheckable)
838 self.contour_item.setCheckState(QtCore.Qt.Unchecked)
839 self.w.list_view.addItem(self.contour_item)
840
841 self.isocurve_item = QtGui.QListWidgetItem('Isocurves')
842 self.isocurve_item.setFlags(self.isocurve_item.flags() | QtCore.Qt.ItemIsUserCheckable)
843 self.isocurve_item.setCheckState(QtCore.Qt.Unchecked)
844 self.w.list_view.addItem(self.isocurve_item)
845
846 self.w.list_view.itemChanged.connect(self.show_slot)
847
848 self.z_value = 1
849 self.ngrid = 300
850
851 def redraw(self):
852 self.curves = []
853 if self.contour_item.checkState() or self.isocurve_item.checkState():
854 #č nejdřív data
855 f_model = self.w.sample_box.f_model
856
857 ns = 100 #č levný IS
858 sample = np.random.randn(ns, 2)*3
859 self.f = f_model.new_sample(sample, space='G', extend=True)
860
861 self.on_space_changed()
862
863 def on_space_changed(self):
864 if self.contour_item.checkState() or self.isocurve_item.checkState():
865 points = getattr(self.f, self.w.space)
866
867 #č valčím s nekoněčno
868 mask = np.all(np.isfinite(points), axis=1)
869
870 self.max = np.max(points[mask], axis=0)
871 self.min = np.min(points[mask], axis=0)
872
873 ngrid = self.ngrid
874 grid = np.mgrid[0:ngrid,0:ngrid].T.reshape(-1, 2)
875 # scale
876 grid = self.grid_scale(grid)
877
878 f_model = self.w.sample_box.f_model
879 self.pdf = f_model.sample_pdf(grid, space=self.w.space)
880 #č pokud tam budou nanka, pak nikdo nic nedostane
881 #č u současných f_modelů však nemají být
882 self.pdf = np.nan_to_num(self.pdf, copy=False)
883 #č reshape, flip a rot90 dle dokumentaci vracej view
884 #č povede-li to numpy, data nebudou žrat další místo v paměti
885 self.data = self.pdf.reshape((ngrid, ngrid))
886 #č bůhví co ta pomocná funkce očekává za vstup
887 #č a co je zvykem u těch borců co pracujou s obrázky
888 #č zkrátka, empiricky - buď zde flipnout a pootočit
889 #č nebo tam dále prohodit souřadnice
890 self.data = np.flip(self.data, axis=0)
891 self.data = np.rot90(self.data, k=-1)
892
893
894 self.plot()
895
896
897 def show_slot(self, item):
898 #č ne že by to bylo úplně ideální, ale ponechám dva druhy isočár sdruženými
899 #č společný plot, společný redraw a společné self.curves
900 if (item is self.contour_item) or (item is self.isocurve_item):
901 if 'f' in self.__dict__:
902 self.plot()
903 else:
904 self.redraw()
905
906 def grid_scale(self, grid):
907 # scale
908 _grid = grid * (self.max - self.min) / (self.ngrid-1)
909 # loc
910 _grid = _grid + self.min
911 return _grid
912
913 def plot(self):
914 #č zejmena tady je to nepříjemný
915 #č třeba bude překreslovat jednu položky
916 #č když jen odcvaknutá druhá
917 for curve in self.curves:
918 self.w.central_widget.removeItem(curve)
919
920 ncurves = self.w.ncircles
921 if self.contour_item.checkState():
922 levels = np.linspace(self.pdf.max(), 0, ncurves+1, endpoint=False)[1:]
923 self._draw_curves(levels, 'Isolevels', (170, 85, 0))
924
925 if self.isocurve_item.checkState():
926 const = 1 / np.prod(self.max - self.min)
927 r_levels = np.arange(ncurves) + 1
928 #č P prostor doopravdy zlobí, takže nějak tak
929 levels = misc.isolevels_2d(self.pdf, const, r_levels, from_top=False)
930 self._draw_curves(levels, 'Isocurves', (100, 45, 0))
931
932 def _draw_curves(self, levels, name, color):
933 ncurves = self.w.ncircles
934 plot_widget = self.w.central_widget
935 for r in range(ncurves):
936 pen = pg.mkPen(color=color, width=self.w.px_size*(1-r/ncurves))
937
938 v = levels[r]
939
940 #č vrací souřadnice v prostoru "gridu"
941 lines = pg.functions.isocurve(self.data, v, connected=True)
942 for line in lines:
943 grid = np.array(line)
944 #grid = np.flip(grid, axis=1)
945
946 #č tady mám výsledek dvouletého výzkumu
947 grid = grid - 0.5
948
949 # scale
950 grid = self.grid_scale(grid)
951 curve = plot_widget.plot(grid, pen=pen, name=name)
952 curve.setZValue(self.z_value)
953 self.curves.append(curve)
954
955
956
957 class Boundaries:
958 def __init__(self, w):
959 self.w = w
960 self.w.space_changed.connect(self.plot)
961 self.w.redraw_called.connect(self.redraw)
962
963 self.item = QtGui.QListWidgetItem('Boundaries')
964 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
965 self.item.setCheckState(QtCore.Qt.Checked)
966 self.w.list_view.addItem(self.item)
967 self.w.list_view.itemChanged.connect(self.show_slot)
968
969
970 def redraw(self):
971 pos = ()
972 plot_widget = self.w.central_widget
973
974 self.bounds = []
975 # ne všichni majó definované hranice
976 try:
977 for bound in self.w.sample_box.get_2D_boundary(nrod=1000):
978 item = plot_widget.plot(pos=pos, pen='b', name='Boundaries')
979 item.setZValue(70)
980 self.bounds.append((bound, item))
981 except AttributeError:
982 pass #print("čo sa děje?")
983
984 self.plot()
985
986 def show_slot(self, item):
987 if item is self.item:
988 self.plot()
989
990 def plot(self):
991 if self.item.checkState():
992 for bound, item in self.bounds:
993 pos = getattr(bound, self.w.space)[:,:2]
994 mask = np.all(np.isfinite(pos), axis=1)
995 item.setData(pos[mask])
996 item.show()
997
998 else:
999 for bound, item in self.bounds:
1000 item.hide()
1001
1002
1003
1004
1005 class Triangulation:
1006 def __init__(self, w):
1007
1008 self.w = w
1009 if self.w.sample_box.nvar == 2:
1010 self.w.box_runned.connect(self.update)
1011 self.w.space_changed.connect(self.replot)
1012 self.w.redraw_called.connect(self.redraw)
1013
1014 self.item = QtGui.QListWidgetItem('Triangulation')
1015 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
1016 self.item.setCheckState(QtCore.Qt.Unchecked)
1017 self.w.list_view.addItem(self.item)
1018
1019
1020 self.w.list_view.itemChanged.connect(self.show_slot)
1021
1022 self.spatial = 'tri'
1023
1024
1025
1026 def redraw(self):
1027 self.simplices = np.empty((0,3), dtype=np.int)
1028 self.plot_items = []
1029 self.replot()
1030
1031
1032 def show_slot(self, item):
1033 if item is self.item:
1034 if (self.w.sample_box.nvar==2) and self.item.checkState():
1035 #for item in self.plot_items:
1036 # item.show()
1037
1038 #оӵ Мед сюредалоз!
1039 self.replot()
1040
1041 else: #оӵ Медам сюреда!
1042 for item in self.plot_items:
1043 item.hide()
1044
1045
1046
1047 def replot(self):
1048 """
1049 on space_chainged
1050 or something like this
1051 when we need to completely
1052 redraw the triangulation
1053 """
1054 if self.item.checkState():
1055 try:
1056 spatial = getattr(self.w.sample_box, self.spatial)
1057 self.simplices = spatial.simplices
1058 for item in self.plot_items:
1059 item.hide()
1060 self.draw_simplices(range(len(self.simplices)))
1061
1062 except BaseException as e:
1063 msg = "error during replot"
1064 print(self.__class__.__name__ + ":",msg, repr(e))
1065
1066
1067
1068 def update(self):
1069 # update triangulation
1070 if self.item.checkState():
1071 try: #оӵ Мед сюредалоз!
1072 former_simplices = self.simplices
1073 spatial = getattr(self.w.sample_box, self.spatial)
1074 self.simplices = spatial.simplices
1075
1076 #č počet simplexů může se přidaním bodů změnšit
1077 #č (hlavně u ConvexHull, ale coplanar taky může vyskočit)
1078 if len(self.simplices) < len(former_simplices):
1079 self.replot()
1080 else:
1081 #č zkontrolujeme co se změnilo
1082 equal_mask = former_simplices == self.simplices[:len(former_simplices)]
1083 changed_simplices_ids = np.argwhere(~equal_mask.all(axis=1)).flatten()
1084 self.draw_simplices(changed_simplices_ids)
1085
1086 #č teď nové simplexy
1087 #ё simplexy свежего разлива
1088 self.draw_simplices(range(len(former_simplices), len(self.simplices)))
1089
1090 except BaseException as e:
1091 msg = "error during update"
1092 print(self.__class__.__name__ + ":",msg, repr(e))
1093
1094
1095
1096
1097 def set_plot_data(self, pos, simplex_id):
1098 if simplex_id < len(self.plot_items):
1099 # Update the data
1100 plot_item = self.plot_items[simplex_id]
1101 plot_item.setData(pos)
1102 plot_item.show()
1103 else: #č spolehám na korektnost volajícího kódu
1104 #оӵ Суредасько
1105 plot_widget = self.w.central_widget
1106 plot_item = plot_widget.plot(pos, pen=0.7)
1107 self.plot_items.append(plot_item)
1108
1109
1110 #č já jsem tu všecko překopal protože .plot() a .setData() jsou nejžravejší na čas
1111 #č a nemá žádnou cenu je provadet hned vedle sebe (spouští totéž dvakrát)
1112 def draw_simplices(self, simplex_ids):
1113 # take coordinates in the space, where triangulation has been performed
1114 sampled_plan_tri = getattr(self.w.sample_box, self.w.sample_box.tri_space)
1115
1116 if self.w.space == self.w.sample_box.tri_space:
1117 for simplex_id in simplex_ids:
1118 triangle = self.simplices[simplex_id]
1119 pos = sampled_plan_tri[triangle[[0,1,2,0]]]
1120
1121 self.set_plot_data(pos, simplex_id)
1122
1123 else:
1124 ns = 100
1125 with pg.BusyCursor():
1126 for simplex_id in simplex_ids:
1127 triangle = self.simplices[simplex_id]
1128 # keep the GUI responsive :)
1129 # it was quite slow on my target machine
1130 self.w.app.processEvents()
1131
1132 x_tri_1 = np.linspace(sampled_plan_tri[triangle[0],0], sampled_plan_tri[triangle[1],0], ns, endpoint=False)
1133 y_tri_1 = np.linspace(sampled_plan_tri[triangle[0],1], sampled_plan_tri[triangle[1],1], ns, endpoint=False)
1134 x_tri_2 = np.linspace(sampled_plan_tri[triangle[1],0], sampled_plan_tri[triangle[2],0], ns, endpoint=False)
1135 y_tri_2 = np.linspace(sampled_plan_tri[triangle[1],1], sampled_plan_tri[triangle[2],1], ns, endpoint=False)
1136 x_tri_3 = np.linspace(sampled_plan_tri[triangle[2],0], sampled_plan_tri[triangle[0],0], ns, endpoint=True)
1137 y_tri_3 = np.linspace(sampled_plan_tri[triangle[2],1], sampled_plan_tri[triangle[0],1], ns, endpoint=True)
1138
1139 tri_bound_tri = np.concatenate(((x_tri_1, y_tri_1), (x_tri_2, y_tri_2), (x_tri_3, y_tri_3)), axis=1).T
1140 #č vytvořme sample
1141 tri_bound = self.w.sample_box.f_model.new_sample(tri_bound_tri, space=self.w.sample_box.tri_space)
1142 pos = getattr(tri_bound, self.w.space)
1143
1144 self.set_plot_data(pos, simplex_id)
1145
1146
1147
1148
1149 class ConvexHull2D(Triangulation):
1150 def __init__(self, w):
1151
1152 self.w = w
1153 if self.w.sample_box.nvar == 2:
1154 self.w.box_runned.connect(self.update)
1155 self.w.space_changed.connect(self.replot)
1156 self.w.redraw_called.connect(self.redraw)
1157
1158 self.item = QtGui.QListWidgetItem('Convex hull')
1159 self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
1160 self.item.setCheckState(QtCore.Qt.Checked)
1161 self.w.list_view.addItem(self.item)
1162
1163
1164 self.w.list_view.itemChanged.connect(self.show_slot)
1165
1166 self.spatial = 'convex_hull'
1167
1168
1169
1170 def redraw(self):
1171 self.simplices = np.empty((0,2), dtype=np.int)
1172 self.plot_items = []
1173 self.replot()
1174
1175
1176
1177
1178
1179 #č já jsem tu všecko překopal protože .plot() a .setData() jsou nejžravejší na čas
1180 #č a nemá žádnou cenu je provadet hned vedle sebe (spouští totéž dvakrát)
1181 def draw_simplices(self, simplex_ids):
1182
1183 # convex hull should be made in the same space as triangulation, I guess
1184 # take coordinates in the triangulation space
1185 sampled_plan_tri = getattr(self.w.sample_box, self.w.sample_box.tri_space)
1186
1187 plot_widget = self.w.central_widget
1188
1189 if self.w.space == self.w.sample_box.tri_space:
1190 for simplex_id in simplex_ids:
1191 pos = sampled_plan_tri[self.simplices[simplex_id]]
1192
1193 self.set_plot_data(pos, simplex_id)
1194
1195 else:
1196 ns = 100
1197 #оӵ кулэ ӧвӧл обновлять экран карыны
1198 for simplex_id in simplex_ids:
1199 start_id, end_id = self.simplices[simplex_id]
1200
1201 x_bound = np.linspace(sampled_plan_tri[start_id,0], sampled_plan_tri[end_id,0], ns, endpoint=True)
1202 y_bound = np.linspace(sampled_plan_tri[start_id,1], sampled_plan_tri[end_id,1], ns, endpoint=True)
1203
1204 # sample compatible
1205 #оӵ малы транспонировать кароно? Озьы кулэ!
1206 bound_tri = np.vstack((x_bound, y_bound)).T
1207 #č vytvořme sample
1208 bound = self.w.sample_box.f_model.new_sample(bound_tri, space=self.w.sample_box.tri_space)
1209 pos = getattr(bound, self.w.space)
1210
1211 self.set_plot_data(pos, simplex_id)
1212
1213
1214
1215
1216
1217 """
1218 =============
1219 График виӝет
1220 Grafy
1221 Estimation graph widgets
1222 ========================
1223 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1224 """
1225
1226
1227 def get_estimation_data(estimations, metric):
1228 metric_dict = dict()
1229 # new-style: šecko leží dohromady a každý z toho
1230 # bere co chce a jak chce
1231 # ne že by to bylo nějak šetrný
1232 # estimation je slovníkem
1233 for estimation in estimations:
1234 # nsim musí mäť každej odhad
1235 # pokud nemá - je třeba jej prostě opravit
1236 nsim = estimation['nsim']
1237 try:
1238 metric_dict[nsim] = estimation[metric]
1239 except KeyError as e:
1240 pass #print(self.__class__.__name__ + ":", repr(e))
1241
1242 # nikdo neslibil, že budou v pořadí
1243 x = np.sort(tuple(metric_dict.keys()))
1244 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
1245 return x, y
1246
1247
1248 class SimplexEstimationData(QtCore.QObject):
1249 #š budeme mӓť svůj vlastní signaľčík
1250 simplex_estimation_updated = QtCore.pyqtSignal()
1251
1252 def __init__(self, dice_box, stream=None, *args, **kwargs):
1253 super().__init__(stream, *args, **kwargs)
1254 self.dice_box = dice_box
1255 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1256 #č asi aby nepadalo, když nenajde signaly
1257 self.stream = stream
1258 if stream is not None:
1259 self.stream.box_runned.connect(self.recalculate)
1260 self.stream.estimation_added.connect(self.recalculate)
1261
1262 self.setup_context_menu()
1263 self.recalculate()
1264
1265
1266 def setup_context_menu(self):
1267 # simplex_data_menu
1268 self.TRI_menu = QtGui.QMenu("TRI sources", self.stream)
1269
1270 self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu)
1271 self.TRI_overall_chk.setCheckable(True)
1272 self.TRI_overall_chk.setChecked(True)
1273 self.TRI_overall_chk.triggered.connect(self.recalculate)
1274 self.TRI_menu.addAction(self.TRI_overall_chk)
1275
1276 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
1277 self.simplex_chk.setCheckable(True)
1278 self.simplex_chk.setChecked(True)
1279 self.simplex_chk.triggered.connect(self.recalculate)
1280 self.TRI_menu.addAction(self.simplex_chk)
1281
1282 # year, it was
1283 ## hope, it is temporary
1284 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
1285 #self.sources_action_group.addAction(self.TRI_overall_chk)
1286 #self.sources_action_group.addAction(self.simplex_chk)
1287
1288 self.TRI_menu.addSeparator()
1289
1290 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
1291 self.proxy_chk.setCheckable(True)
1292 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
1293 self.proxy_chk.triggered.connect(self.recalculate)
1294 self.TRI_menu.addAction(self.proxy_chk)
1295
1296 self.TRI_menu.addSeparator()
1297
1298 self.reaction = QtGui.QAction("Update", self.TRI_menu)
1299 self.reaction.triggered.connect(self.recalculate)
1300 self.TRI_menu.addAction(self.reaction)
1301
1302 self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
1303 self.excelaction.triggered.connect(self.export_to_excel)
1304 self.TRI_menu.addAction(self.excelaction)
1305
1306
1307 def export_to_excel(self):
1308 #č já bych nechtěl, aby mně export najednou spadl
1309 #č z jakéhokoliv důvodu
1310 try:
1311 proposal_filename = self.dice_box.guessbox.filename
1312 if proposal_filename:
1313 proposal_filename += '.xlsx'
1314 else:
1315 proposal_filename = self.dice_box.gm_signature + '.xlsx'
1316 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
1317 proposal_filename, initialFilter='*.xlsx')
1318 self.df.to_excel(filename)
1319 except BaseException as e:
1320 print(self.__class__.__name__ + ":", repr(e))
1321
1322
1323 def recalculate(self):
1324 try:
1325 # sources=['box', 'user']
1326 sources = list()
1327 if self.TRI_overall_chk.isChecked():
1328 sources.append('box')
1329 if self.simplex_chk.isChecked():
1330 sources.append('user')
1331
1332 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
1333 apply_proxy=self.proxy_chk.isChecked())
1334 self.simplex_estimation_updated.emit()
1335
1336 except BaseException as e:
1337 print(self.__class__.__name__ + ":", repr(e))
1338
1339
1340
1341 class SimplexEstimationGraph(pg.PlotWidget):
1342 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
1343 super().__init__(parent, *args, **kwargs)
1344 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1345 #č asi aby nepadalo, když nenajde signaly
1346 self.stream = stream
1347 if stream is not None:
1348 self.stream.box_runned.connect(self.redraw)
1349 self.stream.estimation_added.connect(self.redraw)
1350
1351 self.dice_box = dice_box
1352
1353 self.setup_context_menu()
1354 self.setup()
1355 self.replot()
1356
1357 def setup_context_menu(self):
1358 # creates instance of LegendItem
1359 # and saves it into plotItem.legend
1360 self.legend = self.addLegend()
1361
1362 self.plotItem.ctrl.xGridCheck.setChecked(True)
1363 self.plotItem.ctrl.yGridCheck.setChecked(True)
1364
1365 # delete build-in Transforms (with Log_x and Log_y) options,
1366 # they can cause uncachable exception (on any zero in data) and crash
1367 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
1368
1369 #č já se bojím. radší to uložím
1370 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
1371
1372 self.plotItem.vb.menu.addMenu(self.stream.simplex_data.TRI_menu)
1373
1374 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1375 self.legend_chk.setCheckable(True)
1376 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1377 self.custom_menu.addAction(self.legend_chk)
1378 # apply custom menu option
1379 self.legend.setVisible(self.legend_chk.isChecked())
1380
1381 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
1382 self.log_x_chk.setCheckable(True)
1383 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
1384 self.custom_menu.addAction(self.log_x_chk)
1385
1386 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
1387 self.log_y_chk.setCheckable(True)
1388 self.log_y_chk.setChecked(True)
1389 self.log_y_chk.triggered.connect(self.replot)
1390 self.custom_menu.addAction(self.log_y_chk)
1391
1392 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1393 self.laction.triggered.connect(self.show_labels)
1394 self.custom_menu.addAction(self.laction)
1395
1396
1397 def show_labels(self):
1398 self.setLabel('left', "Probability measure")
1399 self.setLabel('bottom', "Number of simulations")
1400
1401
1402
1403 # self.legend.addItem(self.pen_success, "success domain estimation")
1404 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
1405 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
1406 # self.legend.addItem(self.pen_f, "failure domain estimation")
1407
1408 def setup(self, *args, **kwargs):
1409 self.clear()
1410 self.setBackground('w')
1411 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1412
1413 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
1414 green = (0, 255, 38, 96)
1415 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1416 red = (253, 0, 17, 96)
1417 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
1418 cream = (255, 221, 0, 96)
1419 grey = (196, 196, 196, 96)
1420
1421 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1422 self.pen_f.setZValue(-100)
1423
1424 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
1425 self.pen_success.setZValue(-100)
1426
1427 self.pen_outmix = self.plot(x, y)
1428
1429 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
1430 #self.fill_mix.setData(name="mixed simplices measure")
1431 self.fill_mix.setBrush(cream)
1432 self.fill_mix.setZValue(-100)
1433 self.addItem(self.fill_mix)
1434
1435 #self.pen_outside = self.plot(x, y)
1436 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
1437 #self.fill_outside.setData(name="out of sampling domain estimation")
1438 self.fill_outside.setBrush(grey)
1439 self.fill_outside.setZValue(-100)
1440 self.addItem(self.fill_outside)
1441
1442 self.one_ruler = self.addLine(y=1, pen='k')
1443 self.zero_ruler = self.addLine(y=0, pen='k')
1444
1445
1446 try:
1447 exact_name = self.dice_box.pf_exact_method
1448 pen = pg.mkPen(color='b', width=1.5) # blue
1449 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
1450 #č aby se nám něco zobrazovalo v legendu
1451 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
1452 except:
1453 pass
1454
1455 pen = pg.mkPen(color='m', width=2)
1456 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1457 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1458 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1459
1460
1461
1462
1463
1464 def replot(self, *args, **kwargs):
1465 if self.log_y_chk.isChecked():
1466 self.one_ruler.hide()
1467 try:
1468 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
1469 if self.dice_box.pf_exact > 0:
1470 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
1471 self.pen_exact.show()
1472 else:
1473 self.pen_exact.hide()
1474 except:
1475 pass
1476 self.setLogMode(y=True)
1477 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
1478 self.pen_f.setPen(None)
1479 self.pen_f.setFillLevel(None)
1480 self.pen_success.setFillLevel(0)
1481
1482 else:
1483 self.one_ruler.show()
1484 try:
1485 self.pen_exact.setPos(self.dice_box.pf_exact)
1486 self.pen_exact.show()
1487 except:
1488 pass
1489 self.setLogMode(y=False)
1490 self.pen_f.setPen(None)
1491 self.pen_f.setFillLevel(0)
1492 self.pen_success.setFillLevel(1)
1493
1494 self.redraw()
1495
1496
1497 #č když se někde objeví nula se zapnutým LogModem -
1498 #č qtpygraph hned spadne a není možne ten pad zachytit
1499 def zerosafe(self, x, y, fallback_y=None):
1500 if self.log_y_chk.isChecked():
1501 x = np.array(x)
1502 y = np.array(y)
1503 if fallback_y is None:
1504 fallback_y = y
1505 y = np.where(y > 0, y, fallback_y)
1506 mask = y > 0
1507 return x[mask], y[mask]
1508 else:
1509 return x, y
1510
1511 def proxy(self, nsim):
1512 if self.proxy_chk.isChecked():
1513 proxy = self.dice_box.proxy
1514 index = np.array(nsim)-1
1515 #č indexy musíme o jedničku změnšit
1516 #č výsledek nikoliv. Takže v cajku.
1517 return np.cumsum(~proxy)[index]
1518 else:
1519 return nsim
1520
1521
1522 def _pens_data_update(self):
1523 df = self.df
1524 nsim = df.nsim.to_numpy()
1525 if self.proxy_chk.isChecked():
1526 x = self.proxy(nsim)
1527 df.insert(loc=0, column='nsim (proxy)', value=x)
1528 else:
1529 x = nsim
1530 # (in case of LogPlot) fallback values also used
1531 success_values = df.failure+df.mix+df.out
1532 outmix_values = df.failure+df.mix
1533 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
1534 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
1535 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
1536 self.pen_success.setData(*self.zerosafe(x, success_values))
1537
1538
1539 def redraw(self):
1540 xmin = np.inf
1541 xmax = -np.inf
1542 tri_estimation = dict()
1543 try: # тут всё что угодно может пойти не так
1544 # kruci, ještě navic i generovať pokažde znovu...
1545
1546 # new-style: šecko leží dohromady a každý si z toho
1547 # bere co chce a jak chce
1548 # ne že by to bylo nějak šetrný
1549 # estimation je slovníkem
1550 for estimation in self.dice_box.estimations:
1551 # nsim musí mäť každej odhad
1552 # pokud nemá - je třeba jej prostě opravit
1553 nsim = estimation['nsim']
1554 try:
1555 tri_estimation[nsim] = estimation['TRI_estimation']
1556 if nsim > xmax:
1557 xmax = nsim
1558 if nsim < xmin:
1559 xmin = nsim
1560
1561 except KeyError as e:
1562 pass #print(self.__class__.__name__ + ":", repr(e))
1563
1564 #č neotravuj uživatele chybovejma hlaškama
1565 if tri_estimation:
1566 # it can be effectively done with pandas
1567 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1568 # -1 = 'out', 0=success, 1=failure, 2=mix
1569 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1570 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1571 df.sort_values('nsim', inplace=True)
1572
1573 self._pens_data_update()
1574
1575 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1576 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1577 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1578
1579 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1580 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1581 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1582
1583
1584 except BaseException as e:
1585 print(self.__class__.__name__ + ":", repr(e))
1586
1587
1588
1589 class SimplexErrorGraph(pg.PlotWidget):
1590 def __init__(self, simplex_data, parent=None, *args, **kwargs):
1591 super().__init__(parent, *args, **kwargs)
1592 self.simplex_data = simplex_data
1593 self.simplex_data.simplex_estimation_updated.connect(self.redraw)
1594
1595 self.setup_context_menu()
1596 self.setup()
1597
1598 def setup_context_menu(self):
1599 # creates instance of LegendItem
1600 # and saves it into plotItem.legend
1601 self.legend = self.addLegend()
1602
1603 self.plotItem.ctrl.xGridCheck.setChecked(True)
1604 self.plotItem.ctrl.yGridCheck.setChecked(True)
1605
1606 # menu of SimplexEstimationData
1607 self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
1608
1609 #č já se bojím. radší to uložím
1610 self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
1611
1612 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1613 self.legend_chk.setCheckable(True)
1614 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1615 self.custom_menu.addAction(self.legend_chk)
1616 # apply custom menu option
1617 self.legend.setVisible(self.legend_chk.isChecked())
1618
1619 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1620 self.laction.triggered.connect(self.show_labels)
1621 self.custom_menu.addAction(self.laction)
1622
1623
1624 def show_labels(self):
1625 self.setLabel('left', "Failure probability estimation error")
1626 self.setLabel('bottom', "Number of simulations")
1627
1628
1629 def setup(self, *args, **kwargs):
1630 self.clear()
1631 self.setBackground('w')
1632 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1633
1634 # We will use logMode by default
1635 self.setLogMode(y=True)
1636
1637 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1638 #red = (253, 0, 17, 96)
1639
1640 #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1641 #self.pen_f.setZValue(-100)
1642
1643
1644 pen = pg.mkPen(color='m', width=2)
1645 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1646 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1647 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1648
1649
1650
1651 #č když se někde objeví nula se zapnutým LogModem -
1652 #č qtpygraph hned spadne a není možne ten pad zachytit
1653 def zerosafe(self, x, y, fallback_y=None):
1654 x = np.array(x)
1655 y = np.array(y)
1656 if fallback_y is None:
1657 fallback_y = y
1658 y = np.where(y > 0, y, fallback_y)
1659 mask = y > 0
1660 return x[mask], y[mask]
1661
1662
1663 def redraw(self):
1664 #č neotravujme uživatele chybovejma hlaškama
1665 if hasattr(self.simplex_data.dice_box, 'pf_exact'):
1666 try: #ё тут всё что угодно может пойти не так
1667 pf_exact = self.simplex_data.dice_box.pf_exact
1668
1669 df = self.simplex_data.df
1670 #č zapíšeme do data rámu, snad nikomu nebude vadit
1671 df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
1672 df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
1673
1674 v = df['vertex_estimation_error'].abs()
1675 wv = df['weighted_vertex_estimation_error'].abs()
1676
1677 x, y = self.zerosafe(v.index, v.to_numpy())
1678 self.pen_vertex.setData(x, y)
1679
1680 x, y = self.zerosafe(wv.index, wv.to_numpy())
1681 self.pen_weighted_vertex.setData(x, y)
1682
1683
1684 except BaseException as e:
1685 print(self.__class__.__name__ + ":", repr(e))
1686
1687
1688
1689
1690
1691
1692
1693 # DEPRECATED
1694 class SimpleSimplexEstimationGraph(pg.PlotWidget):
1695 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
1696 super().__init__(parent, *args, **kwargs)
1697 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1698 #č asi aby nepadalo, když nenajde signaly
1699 self.stream = stream
1700 if stream is not None:
1701 self.stream.box_runned.connect(self.redraw)
1702 self.stream.estimation_added.connect(self.redraw)
1703
1704 self.dice_box = dice_box
1705
1706 self.setup_context_menu()
1707 self.setup()
1708 self.replot()
1709
1710 def setup_context_menu(self):
1711 # creates instance of LegendItem
1712 # and saves it into plotItem.legend
1713 self.legend = self.addLegend()
1714
1715 self.plotItem.ctrl.xGridCheck.setChecked(True)
1716 self.plotItem.ctrl.yGridCheck.setChecked(True)
1717
1718 # delete build-in Transforms (with Log_x and Log_y) options,
1719 # they can cause uncachable exception (on any zero in data) and crash
1720 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
1721
1722 #č já se bojím. radší to uložím
1723 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
1724
1725 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1726 self.legend_chk.setCheckable(True)
1727 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1728 self.custom_menu.addAction(self.legend_chk)
1729 # apply custom menu option
1730 self.legend.setVisible(self.legend_chk.isChecked())
1731
1732 self.proxy_chk = QtGui.QAction("Proxy", self.custom_menu)
1733 self.proxy_chk.setCheckable(True)
1734 self.proxy_chk.triggered.connect(self.redraw)
1735 self.custom_menu.addAction(self.proxy_chk)
1736
1737 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
1738 self.log_x_chk.setCheckable(True)
1739 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
1740 self.custom_menu.addAction(self.log_x_chk)
1741
1742 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
1743 self.log_y_chk.setCheckable(True)
1744 self.log_y_chk.setChecked(True)
1745 self.log_y_chk.triggered.connect(self.replot)
1746 self.custom_menu.addAction(self.log_y_chk)
1747
1748 self.reaction = QtGui.QAction("Redraw", self.custom_menu)
1749 self.reaction.triggered.connect(self.redraw)
1750 self.custom_menu.addAction(self.reaction)
1751
1752 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1753 self.laction.triggered.connect(self.show_labels)
1754 self.custom_menu.addAction(self.laction)
1755
1756 self.excelaction = QtGui.QAction("Export to Excel", self.custom_menu)
1757 self.excelaction.triggered.connect(self.export_to_excel)
1758 self.custom_menu.addAction(self.excelaction)
1759
1760
1761 def export_to_excel(self):
1762 #č já bych nechtěl, aby mně export najednou spadl
1763 #č z jakéhokoliv důvodu
1764 try:
1765 proposal_filename = self.dice_box.guessbox.filename
1766 if proposal_filename:
1767 proposal_filename += '.xlsx'
1768 else:
1769 proposal_filename = self.dice_box.gm_signature + '.xlsx'
1770 filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
1771 proposal_filename, initialFilter='*.xlsx')
1772 self.df.to_excel(filename)
1773 except BaseException as e:
1774 print(self.__class__.__name__ + ":", repr(e))
1775
1776 def show_labels(self):
1777 self.setLabel('left', "Probability measure")
1778 self.setLabel('bottom', "Number of simulations")
1779
1780
1781
1782 # self.legend.addItem(self.pen_success, "success domain estimation")
1783 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
1784 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
1785 # self.legend.addItem(self.pen_f, "failure domain estimation")
1786
1787 def setup(self, *args, **kwargs):
1788 self.clear()
1789 self.setBackground('w')
1790 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1791
1792 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
1793 green = (0, 255, 38, 96)
1794 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1795 red = (253, 0, 17, 96)
1796 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
1797 cream = (255, 221, 0, 96)
1798 grey = (196, 196, 196, 96)
1799
1800 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1801 self.pen_f.setZValue(-100)
1802
1803 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
1804 self.pen_success.setZValue(-100)
1805
1806 self.pen_outmix = self.plot(x, y)
1807
1808 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
1809 #self.fill_mix.setData(name="mixed simplices measure")
1810 self.fill_mix.setBrush(cream)
1811 self.fill_mix.setZValue(-100)
1812 self.addItem(self.fill_mix)
1813
1814 #self.pen_outside = self.plot(x, y)
1815 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
1816 #self.fill_outside.setData(name="out of sampling domain estimation")
1817 self.fill_outside.setBrush(grey)
1818 self.fill_outside.setZValue(-100)
1819 self.addItem(self.fill_outside)
1820
1821 self.one_ruler = self.addLine(y=1, pen='k')
1822 self.zero_ruler = self.addLine(y=0, pen='k')
1823
1824
1825 try:
1826 exact_name = self.dice_box.pf_exact_method
1827 pen = pg.mkPen(color='b', width=1.5) # blue
1828 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
1829 #č aby se nám něco zobrazovalo v legendu
1830 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
1831 except:
1832 pass
1833
1834 pen = pg.mkPen(color='m', width=2)
1835 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1836 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1837 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1838
1839
1840
1841
1842
1843 def replot(self, *args, **kwargs):
1844 if self.log_y_chk.isChecked():
1845 self.one_ruler.hide()
1846 try:
1847 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
1848 if self.dice_box.pf_exact > 0:
1849 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
1850 self.pen_exact.show()
1851 else:
1852 self.pen_exact.hide()
1853 except:
1854 pass
1855 self.setLogMode(y=True)
1856 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
1857 self.pen_f.setPen(None)
1858 self.pen_f.setFillLevel(None)
1859 self.pen_success.setFillLevel(0)
1860
1861 else:
1862 self.one_ruler.show()
1863 try:
1864 self.pen_exact.setPos(self.dice_box.pf_exact)
1865 self.pen_exact.show()
1866 except:
1867 pass
1868 self.setLogMode(y=False)
1869 self.pen_f.setPen(None)
1870 self.pen_f.setFillLevel(0)
1871 self.pen_success.setFillLevel(1)
1872
1873 self.redraw()
1874
1875
1876 #č když se někde objeví nula se zapnutým LogModem -
1877 #č qtpygraph hned spadne a není možne ten pad zachytit
1878 def zerosafe(self, x, y, fallback_y=None):
1879 if self.log_y_chk.isChecked():
1880 x = np.array(x)
1881 y = np.array(y)
1882 if fallback_y is None:
1883 fallback_y = y
1884 y = np.where(y > 0, y, fallback_y)
1885 mask = y > 0
1886 return x[mask], y[mask]
1887 else:
1888 return x, y
1889
1890 def proxy(self, nsim):
1891 if self.proxy_chk.isChecked():
1892 proxy = self.dice_box.proxy
1893 index = np.array(nsim)-1
1894 #č indexy musíme o jedničku změnšit
1895 #č výsledek nikoliv. Takže v cajku.
1896 return np.cumsum(~proxy)[index]
1897 else:
1898 return nsim
1899
1900
1901 def _pens_data_update(self):
1902 df = self.df
1903 nsim = df.nsim.to_numpy()
1904 if self.proxy_chk.isChecked():
1905 x = self.proxy(nsim)
1906 df.insert(loc=0, column='nsim (proxy)', value=x)
1907 else:
1908 x = nsim
1909 # (in case of LogPlot) fallback values also used
1910 success_values = df.failure+df.mix+df.out
1911 outmix_values = df.failure+df.mix
1912 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
1913 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
1914 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
1915 self.pen_success.setData(*self.zerosafe(x, success_values))
1916
1917
1918 def redraw(self):
1919 xmin = np.inf
1920 xmax = -np.inf
1921 tri_estimation = dict()
1922 try: # тут всё что угодно может пойти не так
1923 # kruci, ještě navic i generovať pokažde znovu...
1924
1925 # new-style: šecko leží dohromady a každý si z toho
1926 # bere co chce a jak chce
1927 # ne že by to bylo nějak šetrný
1928 # estimation je slovníkem
1929 for estimation in self.dice_box.estimations:
1930 # nsim musí mäť každej odhad
1931 # pokud nemá - je třeba jej prostě opravit
1932 nsim = estimation['nsim']
1933 try:
1934 tri_estimation[nsim] = estimation['TRI_estimation']
1935 if nsim > xmax:
1936 xmax = nsim
1937 if nsim < xmin:
1938 xmin = nsim
1939
1940 except KeyError as e:
1941 pass #print(self.__class__.__name__ + ":", repr(e))
1942
1943 #č neotravuj uživatele chybovejma hlaškama
1944 if tri_estimation:
1945 # it can be effectively done with pandas
1946 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1947 # -1 = 'out', 0=success, 1=failure, 2=mix
1948 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1949 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1950 df.sort_values('nsim', inplace=True)
1951
1952 self._pens_data_update()
1953
1954 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1955 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1956 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1957
1958 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1959 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1960 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1961
1962
1963 except BaseException as e:
1964 print(self.__class__.__name__ + ":", repr(e))
1965
1966
1967 # DEPRECATED
1968 class TriEstimationGraph(SimpleSimplexEstimationGraph):
1969 def __init__(self, dice_box, tri_estimation_name='TRI_overall_estimations', stream=None, parent=None, *args, **kwargs):
1970 self.tri_estimation_name = tri_estimation_name
1971 super().__init__(dice_box, stream, parent, *args, **kwargs)
1972
1973
1974
1975 def redraw(self):
1976 try: # тут всё что угодно может пойти не так
1977 data = self.dice_box.guessbox.estimations[self.tri_estimation_name]
1978 nsim, tri_data = data
1979 # it can be effectively done with pandas
1980 self.df = df = pd.DataFrame(tri_data)
1981 # -1 = 'out', 0=success, 1=failure, 2=mix
1982 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1983 df.insert(loc=0, column='nsim', value=nsim)
1984
1985 # Update the data
1986 self._pens_data_update()
1987
1988 if 'vertex_estimation' in self.dice_box.guessbox.estimations:
1989 data = self.dice_box.guessbox.estimations['vertex_estimation']
1990 nsim, y = data
1991 # Update the data
1992 #č spolehám na konzistenci blackboxu, ne však úplně
1993 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
1994 df['vertex_estimation'] = y
1995
1996 if 'weighted_vertex_estimation' in self.dice_box.guessbox.estimations:
1997 data = self.dice_box.guessbox.estimations['weighted_vertex_estimation']
1998 nsim, y = data
1999 # Update the data
2000 #č spolehám na konzistenci blackboxu, ne však úplně
2001 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
2002 df['weighted_vertex_estimation'] = y
2003
2004
2005 # BaseException
2006 except BaseException as e:
2007 print(self.__class__.__name__ + ":", repr(e))
2008
2009
2010
2011
2012
2013
2014
2015 class VoronoiEstimationGraph(pg.PlotWidget):
2016 def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
2017 super().__init__(parent)
2018 self.sb_item = samplebox_item
2019 self.sb_item.box_runned.connect(self.redraw)
2020 self.sb_item.estimation_added.connect(self.redraw)
2021
2022 self.black_box = black_box
2023 self.setBackground('w')
2024
2025
2026 self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
2027 self.reaction.triggered.connect(self.redraw)
2028 self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
2029
2030
2031
2032 # implicitně Y je v logaritmickem měřítku
2033 self.setLogMode(False, True)
2034
2035 x = y = () # zde jen vytvoříme kostru, nakrmíme daty v .redraw()
2036
2037
2038 # nechapu, proč těm Itemům ríkám "propíska"
2039 # propíska? Их есть у нас!
2040
2041 self.Voronoi_2_point_upper_bound = self.plot(x, y, pen='y')
2042 self.Voronoi_2_point_lower_bound = self.plot(x, y, pen='y')
2043
2044 fill_color = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
2045 self.fill = pg.FillBetweenItem(self.Voronoi_2_point_upper_bound, self.Voronoi_2_point_lower_bound, fill_color)
2046 self.addItem(self.fill)
2047
2048 self.Voronoi_2_point_failure_rate = self.plot(x, y, pen=(195,46,212))
2049 self.Voronoi_2_point_pure_failure_rate = self.plot(x, y, pen='m')
2050 self.Voronoi_failure_rate = self.plot(x, y, pen='r')
2051
2052 self.pen_exact = self.plot(x, y, pen='b') # blue
2053 self.pen_one = self.plot(x, y, pen='k') # black
2054
2055 self.redraw()
2056
2057
2058 def redraw(self):
2059 # kruci, ještě navic i generovať pokažde znovu...
2060 metrics = {'Voronoi_2_point_upper_bound':{},\
2061 'Voronoi_2_point_lower_bound':{},\
2062 'Voronoi_2_point_failure_rate':{},\
2063 'Voronoi_2_point_pure_failure_rate':{},\
2064 'Voronoi_failure_rate':{},}
2065 xmin = np.inf
2066 xmax = -np.inf
2067 try: # тут всё что угодно может пойти не так
2068 # new-style: šecko leží dohromady a každý z toho
2069 # bere co chce a jak chce
2070 # ne že by to bylo nějak šetrný
2071 # estimation je slovníkem
2072 for estimation in self.black_box.estimations:
2073 # nsim musí mäť každej odhad
2074 # pokud nemá - je třeba jej prostě opravit
2075 nsim = estimation['nsim']
2076
2077
2078 for metric, metric_dict in metrics.items():
2079 try:
2080 if estimation[metric] > 0:
2081 metric_dict[nsim] = estimation[metric]
2082 if nsim > xmax:
2083 xmax = nsim
2084 if nsim < xmin:
2085 xmin = nsim
2086 except KeyError as e:
2087 pass #print(self.__class__.__name__ + ":", repr(e))
2088
2089 for metric, metric_dict in metrics.items():
2090 pen = getattr(self, metric)
2091 # nikdo neslibil, že budou v pořadí
2092 x = np.sort(tuple(metric_dict.keys()))
2093 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
2094 pen.setData(x, y)
2095
2096 if (xmax - xmin) > 0:
2097 self.pen_one.setData((xmin,xmax), (1, 1))
2098 if hasattr(self.black_box, 'pf_exact'):
2099 # poslední. I když spadne, tak už nikomu moc nevadí
2100 self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
2101
2102 except BaseException as e:
2103 print(self.__class__.__name__ + ":", repr(e))
2104
2105
2106 # pen_f.opts['logMode']
2107 # pen_outside.setLogMode(False, False)
2108 #setLogMode(False, False)
2109 #f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
2110 #win.addItem(f)
2111
2112
2113
2114
2115
2116
2117
2118 """
2119 =============
2120 Эскерон виӝет
2121 Widgety odhadů
2122 Estimation widgets
2123 ===================
2124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2125 """
2126
2127 class FastSimplexEstimationWidget(QtGui.QSplitter):
2128 # I'd like to get access to the samplebox stuff via the container's reference,
2129 def __init__(self, samplebox_item, parent=None, *args, **kwargs):
2130 super().__init__(parent)
2131 # sb like samplebox, of course
2132 self.sb_item = samplebox_item
2133
2134 self.sb_item.box_runned.connect(self.on_box_run)
2135 self.sb_item.slice_changed.connect(self.self_clear)
2136 self.sb_item.space_changed.connect(self.on_space_changed)
2137 self.sb_item.redraw_called.connect(self.redraw)
2138 #☺ na internetu všichni tak dělaj
2139 self.setup()
2140
2141 def setup(self):
2142 self.setOrientation(QtCore.Qt.Vertical)
2143 self.layout = pg.LayoutWidget(self)
2144 params = list()
2145 params.append({'name': 'method', 'type': 'list', \
2146 'values': ['fast_sampling', 'full_sampling',\
2147 'fast_cubature', 'full_cubature'], 'value': 'fast_sampling'})
2148 params.append({'name': 'model space', 'type': 'list', \
2149 'values': self.sb_item.spaces, 'value': 'Rn'})
2150 params.append({'name': 'sampling space', 'type': 'list',\
2151 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
2152 params.append({'name': 'weighting space', 'type': 'list',\
2153 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
2154 designs = ['None']
2155 if 'designs' in self.sb_item.kwargs:
2156 designs.extend(self.sb_item.kwargs['designs'].keys())
2157 params.append({'name': 'design', 'type': 'list', \
2158 'values': designs, 'value': 'None'})
2159 params.append({'name': 'outside budget', 'type': 'int', \
2160 'limits': (1, float('inf')), 'value': 1000, 'default': 1000})
2161 params.append({'name': 'nodes per simplex', 'type': 'int', \
2162 'limits': (1, float('inf')), 'value': 100, 'default': 100})
2163
2164 if 'schemes' in self.sb_item.kwargs:
2165 schemes = list(self.sb_item.kwargs['schemes'].keys())
2166 else:
2167 schemes = ['None']
2168
2169 params.append({'name': 'scheme', 'type': 'list', \
2170 'values': schemes, 'value': schemes[0]})
2171 params.append({'name': 'node (pixel) size', 'type': 'float',\
2172 'limits': (0, float('inf')), 'value': 3.5, 'default': self.sb_item.px_size})
2173 xkcd_green = (167, 255, 181, 255) # xkcd:light seafoam green #a7ffb5
2174 xkcd_red = (253, 193, 197, 255) # xkcd: pale rose (#fdc1c5)
2175 xkcd_cream = (255, 243, 154, 255) # let's try xkcd: dark cream (#fff39a)
2176 params.append({'name': 'failure', 'type': 'colormap', \
2177 'value': pg.colormap.ColorMap((0,1), [xkcd_red, xkcd_red])})
2178 params.append({'name': 'success', 'type': 'colormap', \
2179 'value': pg.colormap.ColorMap((0,1), [xkcd_green, xkcd_green])})
2180 params.append({'name': 'mix', 'type': 'colormap', \
2181 'value': pg.colormap.ColorMap((0,1), [xkcd_cream, xkcd_cream])})
2182 params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
2183
2184 ### Create tree of Parameter objects
2185 self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
2186 # I don't know why that signals do not work for me
2187 # Only sigTreeStateChanged works, but I don't want to struggle with it
2188 # May be I'll report the issue
2189 #self.param.sigValueChanged.connect(self.param_changed)
2190 #self.param.sigValueChanging.connect(self.param_changing)
2191
2192 ### Create ParameterTree widget
2193 self.ptree = pg.parametertree.ParameterTree()
2194 self.ptree.setParameters(self.param, showTop=False)
2195
2196 self.layout.addWidget(self.ptree, row=0, col=0, colspan=4)
2197
2198
2199
2200 self.btn0 = QtGui.QPushButton('(no graphics)') # 'estimate \n (no graphics)'
2201 self.layout.addWidget(self.btn0, row=1, col=0)
2202 self.btn0.clicked.connect(self.run_stm)
2203
2204 self.btn = QtGui.QPushButton('estimate')
2205 self.layout.addWidget(self.btn, row=1, col=1)
2206 self.btn.clicked.connect(self.go_stm)
2207
2208 self.btn2 = QtGui.QPushButton('redraw')
2209 self.layout.addWidget(self.btn2, row=1, col=2)
2210 self.btn2.clicked.connect(self.recolor)
2211
2212 self.btn3 = QtGui.QPushButton('hide')
2213 self.layout.addWidget(self.btn3, row=1, col=3)
2214 self.btn3.clicked.connect(self.hide)
2215
2216 self.addWidget(self.layout)
2217
2218 self.table = pg.TableWidget(sortable=False)
2219 self.addWidget(self.table)
2220
2221
2222
2223 # pro začatek postačí
2224 # triangulaci kreslím jen v 2D
2225 self.triangulation = []
2226 self.simplices = []
2227 self.max_simplices = {'success':0, 'failure':0, 'mix':0}
2228
2229
2230 def hide(self):
2231 #č nejdřív triangulace
2232 for tri_bound, plot_item in self.triangulation:
2233 plot_item.hide()
2234 # keep the GUI responsive :)
2235 #self.sb_item.app.processEvents()
2236
2237 #č teď tečičky
2238 for nodes, plot_item, cell_stats in self.simplices:
2239 plot_item.hide()
2240 # keep the GUI responsive :)
2241 #self.sb_item.app.processEvents()
2242
2243
2244 def recolor(self):
2245 with pg.BusyCursor():
2246 # keep the GUI responsive :)
2247 self.sb_item.app.processEvents()
2248 #č nejdřív triangulace
2249 for tri_bound, plot_item in self.triangulation:
2250 plot_item.show()
2251
2252
2253 #č teď tečičky
2254 for nodes, plot_item, cell_stats in self.simplices:
2255 event = cell_stats['event']
2256 if event in self.max_simplices:
2257 cell_probability = cell_stats['cell_probability']
2258 cm = self.param.getValues()[event][0] #č očekávám tam kolor mapu
2259 blue_intensity = cell_probability / self.max_simplices[event]
2260 color = cm.mapToQColor(blue_intensity)
2261 else: # outside
2262 color = 0.6
2263 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2264 size = self.param.getValues()['node (pixel) size'][0]
2265 plot_item.setSymbolBrush(color)
2266 plot_item.setSymbolSize(size)
2267 plot_item.show()
2268 # keep the GUI responsive :)
2269 #self.sb_item.app.processEvents()
2270
2271
2272
2273 def on_space_changed(self, *args, **kwargs):
2274 #with pg.BusyCursor():
2275 #self.hide()
2276 # keep the GUI responsive :)
2277 #self.sb_item.app.processEvents()
2278 #č nejdřív triangulace
2279 for tri_bound, plot_item in self.triangulation:
2280 pos = getattr(tri_bound, self.sb_item.space)
2281 plot_item.setData(pos)
2282 #plot_item.show()
2283 # keep the GUI responsive :)
2284 #self.sb_item.app.processEvents()
2285
2286 #č teď tečičky
2287 for nodes, plot_item, cell_stats in self.simplices:
2288 pos = getattr(nodes, self.sb_item.space)[:,:2]
2289 plot_item.setData(pos)
2290 #plot_item.show()
2291 # keep the GUI responsive :)
2292 #self.sb_item.app.processEvents()
2293
2294
2295 #č ten hlavní modul se dočkal na překopávání
2296 def on_box_run(self, *args, **kwargs):
2297 #č je třeba zkontrolovat autorun a restartovat výpočet
2298 if self.param.getValues()['Run with the box'][0]:
2299 self.run_stm()
2300 #else:
2301 # self.self_clear()
2302
2303
2304 def redraw(self, *args, **kwargs):
2305 self.triangulation.clear()
2306 self.simplices.clear()
2307 self.max_simplices['success'] = 0
2308 self.max_simplices['failure'] = 0
2309 self.max_simplices['mix'] = 0
2310
2311
2312 def self_clear(self):
2313 # odebereme prvky-propísky z hlavního plotu
2314 for tri_bound, plot_item in self.triangulation:
2315 self.sb_item.central_widget.removeItem(plot_item)
2316 for nodes, plot_item, cell_stats in self.simplices:
2317 self.sb_item.central_widget.removeItem(plot_item)
2318
2319 self.redraw()
2320
2321 def go_stm(self): self.start_stm(callback=self.callback)
2322 def run_stm(self): self.start_stm()
2323 def start_stm(self, callback=None):
2324 # indikace
2325 #self.setDisabled(True)
2326 with pg.BusyCursor():
2327 nsim = self.sb_item.slider.value()
2328 sample_box = self.sb_item.sample_box[:nsim]
2329 #☺ Krucinal, kdo ten OrderedDict vymyslel?
2330 params = self.param.getValues()
2331 model_space = params['model space'][0]
2332 sampling_space = params['sampling space'][0]
2333 if sampling_space == 'None':
2334 sampling_space = None
2335 weighting_space = params['weighting space'][0]
2336 if weighting_space == 'None':
2337 weighting_space = None
2338 outside_budget = params['outside budget'][0]
2339 simplex_budget = params['nodes per simplex'][0]
2340
2341 design = params['design'][0]
2342 if design == 'None':
2343 design = None
2344 else:
2345 design = self.sb_item.kwargs['designs'][design]
2346
2347 scheme = params['scheme'][0]
2348 if scheme == 'None':
2349 scheme = None
2350 else:
2351 scheme = self.sb_item.kwargs['schemes'][scheme]
2352
2353 #č je třeba skrýt prvky z minula
2354 self.self_clear()
2355
2356 try:
2357
2358 if params['method'][0] == 'fast_cubature':
2359 method = stm.fast_simplex_cubature
2360 data = method(sample_box, scheme, model_space=model_space,\
2361 sampling_space=sampling_space,\
2362 weighting_space=weighting_space,\
2363 outside_budget=outside_budget, \
2364 callback=callback, design=design)
2365
2366 elif params['method'][0] == 'full_cubature':
2367 method = stm.full_simplex_cubature
2368 data = method(sample_box, scheme, model_space=model_space,\
2369 weighting_space=weighting_space,\
2370 callback=callback)
2371 else:
2372 if params['method'][0] == 'full_sampling':
2373 method = stm.full_simplex_estimation
2374 else: # 'fast_sampling'
2375 method = stm.fast_simplex_estimation
2376 data = method(sample_box, model_space=model_space,\
2377 sampling_space=sampling_space, \
2378 weighting_space=weighting_space,\
2379 outside_budget=outside_budget, \
2380 simplex_budget=simplex_budget,\
2381 callback=callback, design=design)
2382
2383 if hasattr(self.sb_item.sample_box, 'estimations'):
2384 self.sb_item.sample_box.estimations.append(data)
2385 self.sb_item.estimation_added.emit()
2386 self.table.setData(data)
2387 except BaseException as e:
2388 msg = "error during estimation "
2389 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
2390 print(error_msg)
2391 # indikace
2392 #self.setEnabled(True)
2393
2394
2395
2396
2397
2398 def callback(self, sx=None, nodes=None, cell_stats=None, simplex=None, *args, **kwargs):
2399 plot_widget = self.sb_item.central_widget
2400 #č stm trianguľaciju pokažde provadí znovu, proto skoro nemá cenu drbat se s její znovupoužitím
2401 if (simplex is not None) and (simplex.nvar==2):
2402
2403 ns = 100
2404 # take coordinates in the space, where triangulation has been performed
2405 simplex_tri = getattr(simplex, sx.tri_space)
2406 x_tri_1 = np.linspace(simplex_tri[0,0], simplex_tri[1,0], ns, endpoint=False)
2407 y_tri_1 = np.linspace(simplex_tri[0,1], simplex_tri[1,1], ns, endpoint=False)
2408 x_tri_2 = np.linspace(simplex_tri[1,0], simplex_tri[2,0], ns, endpoint=False)
2409 y_tri_2 = np.linspace(simplex_tri[1,1], simplex_tri[2,1], ns, endpoint=False)
2410 x_tri_3 = np.linspace(simplex_tri[2,0], simplex_tri[0,0], ns, endpoint=True)
2411 y_tri_3 = np.linspace(simplex_tri[2,1], simplex_tri[0,1], ns, endpoint=True)
2412
2413 tri_bound_tri = np.concatenate(((x_tri_1, y_tri_1), (x_tri_2, y_tri_2),\
2414 (x_tri_3, y_tri_3)), axis=1).T
2415 # vytvořme sample
2416 tri_bound = self.sb_item.sample_box.f_model.new_sample(tri_bound_tri, space=sx.tri_space)
2417
2418 # draw
2419 pos = getattr(tri_bound, self.sb_item.space)
2420 plot_item = plot_widget.plot(pos, pen='k')
2421 plot_item.setZValue(50)
2422
2423 # uložíme data
2424 self.triangulation.append((tri_bound, plot_item))
2425
2426 #plot_item.show()
2427
2428
2429 #
2430 # tečičky
2431 #
2432 pos = getattr(nodes, self.sb_item.space)[:,:2]
2433 event = cell_stats['event']
2434 cell_probability = cell_stats['cell_probability']
2435 if event in self.max_simplices:
2436 cm = self.param.getValues()[event][0] #č očekávám tam kolor mapu
2437
2438 #č chcu ještě na konci prekreslit s různejma barvičkama, podle obsahu pravděpodobnosti
2439 # zkontrolujeme probability
2440 if self.max_simplices[event] < cell_probability:
2441 self.max_simplices[event] = cell_probability
2442 # a hned všecko dotyčné přebarvíme podle obsahu pravděpodobnosti
2443 for self_simplex in self.simplices:
2444 if event == self_simplex[2]['event']:
2445 # zde cell_probability se rovná self.p_cell_max[event]
2446 # ale bacha! Nesplet se jinde!
2447 #č nechť zůstane starý nazev
2448 blue_intensity = self_simplex[2]['cell_probability'] / cell_probability
2449 color = cm.mapToQColor(blue_intensity)
2450 self_simplex[1].setSymbolBrush(color)
2451
2452
2453 intensity = cell_probability / self.max_simplices[event]
2454 #č tam prostě MUSÍ být tuple
2455 color = cm.mapToQColor(intensity)
2456
2457
2458 else: # outside
2459 color = 0.6
2460
2461
2462 # draw tečičky
2463 #
2464
2465 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2466 size = self.param.getValues()['node (pixel) size'][0]
2467 #brush = pg.mkBrush(color)
2468 plot_item = plot_widget.plot(pos, pen=None, symbol='o', symbolPen=pg.mkPen(None), symbolBrush=color,\
2469 symbolSize=size, name='IS localized nodes')
2470 plot_item.setZValue(40)
2471
2472 # uložíme data
2473 self.simplices.append((nodes, plot_item, cell_stats))
2474
2475
2476 # keep the GUI responsive :)
2477 self.sb_item.app.processEvents()
2478
2479
2480
2481
2482
2483
2484 class VoronoiEstimationWidget(QtGui.QSplitter):
2485 """
2486 addLabel(text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs)
2487 """
2488 # I'd like to get access to the samplebox stuff via the container's reference,
2489 # INHERETED by gl_plot
2490 def __init__(self, samplebox_item, parent=None, *args, **kwargs):
2491 super().__init__(parent)
2492 # sb like samplebox, of course
2493 self.sb_item = samplebox_item
2494
2495 self.sb_item.box_runned.connect(self.on_box_run)
2496 self.sb_item.slice_changed.connect(self.self_clear)
2497 self.sb_item.space_changed.connect(self.on_space_changed)
2498 self.sb_item.redraw_called.connect(self.redraw)
2499 #☺ na internetu všichni tak dělaj
2500 self.setup()
2501
2502 # INHERETED by gl_plot
2503 def setup(self):
2504 self.setOrientation(QtCore.Qt.Vertical)
2505 self.layout = pg.LayoutWidget(self)
2506 # model_space='Rn', sampling_space=None, p_norm=1, budget=20000
2507 params = [{'name': 'method', 'type': 'list', 'values': ['Voronoi_tesselation','Voronoi_2_point_estimation'], 'value': 'Voronoi_2_point_estimation'}]
2508 params.append({'name': 'model space', 'type': 'list', 'values': self.sb_item.spaces, 'value': 'Rn'})
2509 params.append({'name': 'sampling space', 'type': 'list', 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
2510 params.append({'name': 'p-norm', 'type': 'float', 'limits': (1, float('inf')), 'value': 1, 'default': np.inf})
2511 params.append({'name': 'budget', 'type': 'float', 'limits': (1, float('inf')), 'value': 20000, 'default': 20000})
2512 self.coloring_modes = ['simple_coloring', 'cell_probability_coloring','node_pf_coloring']
2513 params.append({'name': 'coloring', 'type': 'list', 'values': self.coloring_modes, 'value': self.coloring_modes[1]})
2514 params.append({'name': 'node (pixel) size', 'type': 'float', 'limits': (0, float('inf')), 'value': 3, 'default': 1})
2515 params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
2516
2517 ### Create tree of Parameter objects
2518 self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
2519 # I don't know why that signals do not work for me
2520 # Only sigTreeStateChanged works, but I don't want to struggle with it
2521 # May be I'll report the issue
2522 #self.param.sigValueChanged.connect(self.param_changed)
2523 #self.param.sigValueChanging.connect(self.param_changing)
2524
2525 ### Create ParameterTree widget
2526 self.ptree = pg.parametertree.ParameterTree()
2527 self.ptree.setParameters(self.param, showTop=False)
2528
2529 self.layout.addWidget(self.ptree, row=0, col=0, colspan=3)
2530
2531
2532 self.btn = QtGui.QPushButton('estimate')
2533 self.layout.addWidget(self.btn, row=1, col=0)
2534 self.btn.clicked.connect(self.run_stm)
2535
2536 self.btn2 = QtGui.QPushButton('redraw')
2537 self.layout.addWidget(self.btn2, row=1, col=1)
2538 self.btn2.clicked.connect(self.recolor)
2539
2540 self.btn3 = QtGui.QPushButton('hide')
2541 self.layout.addWidget(self.btn3, row=1, col=2)
2542 self.btn3.clicked.connect(self.hide)
2543
2544 self.addWidget(self.layout)
2545
2546 self.table = pg.TableWidget(sortable=False)
2547 self.addWidget(self.table)
2548
2549 # pro začatek postačí
2550 self.cells = []
2551 # probability of the biggest cell
2552 # used for coloring
2553 self.p_cell_max = {'success':0, 'failure':0}
2554
2555
2556 # INHERETED by gl_plot
2557 def on_box_run(self, *args, **kwargs):
2558 # je třeba zkontrolovat autorun a restartovat výpočet
2559 if self.param.getValues()['Run with the box'][0]:
2560 self.run_stm()
2561 #else:
2562 #self.self_clear()
2563
2564 # INHERETED by gl_plot
2565 def hide(self):
2566 for nodes, plot_item, cell_stats in self.cells:
2567 plot_item.hide()
2568 # keep the GUI responsive :)
2569 #self.sb_item.app.processEvents()
2570
2571 # INHERETED by gl_plot
2572 def redraw(self, *args, **kwargs):
2573 self.cells.clear()
2574 self.p_cell_max['success'] = 0
2575 self.p_cell_max['failure'] = 0
2576
2577 ## I'll rename after main widget refactoring
2578 # refactoring already done, why I should rename?
2579 # INHERETED by gl_plot
2580 def recolor(self):
2581 # indikace
2582 #self.setDisabled(True)
2583 with pg.BusyCursor():
2584 # Krucinal, kdo ten OrderedDict vymyslel?
2585 params = self.param.getValues()
2586 coloring = params['coloring'][0]
2587
2588 # přebarvíme nějak tečičky
2589 # callback vybírám ze svého kódu, ten musí bejt v pořádku
2590 # ne že by to bylo dokonalé bezpečný,
2591 # ale na lokálním počítači asi to není až tak zavadný
2592 coloring_function = getattr(self, coloring)
2593
2594 # hura! Jedeme!
2595 coloring_function()
2596
2597
2598 # indikace
2599 #self.setEnabled(True)
2600
2601
2602 def on_space_changed(self, *args, **kwargs):
2603 # teď tečičky
2604 for nodes, plot_item, cell_stats in self.cells:
2605 pos = getattr(nodes, self.sb_item.space)[:,:2]
2606 plot_item.setData(pos)
2607
2608
2609 # INHERETED by gl_plot
2610 def self_clear(self):
2611 # odebereme prvky-propísky z hlavního plotu
2612 for nodes, plot_item, cell_stats in self.cells:
2613 self.sb_item.central_widget.removeItem(plot_item)
2614
2615 self.redraw()
2616
2617
2618
2619 # INHERETED by gl_plot
2620 def run_stm(self):
2621 # indikace
2622 #self.setDisabled(True)
2623 with pg.BusyCursor():
2624 nsim = self.sb_item.slider.value()
2625 sample_box = self.sb_item.sample_box[:nsim]
2626 # Krucinal, kdo ten OrderedDict vymyslel?
2627 params = self.param.getValues()
2628 method = params['method'][0]
2629 model_space = params['model space'][0]
2630 sampling_space = params['sampling space'][0]
2631 if sampling_space == 'None':
2632 sampling_space = None
2633 p_norm = params['p-norm'][0]
2634 budget = params['budget'][0]
2635 coloring = params['coloring'][0]
2636
2637 # je třeba skrýt prvky z minula
2638 self.self_clear()
2639
2640
2641 # přebarvíme nějak tečičky
2642 # callback vybírám ze svého kódu, ten musí bejt v pořádku
2643 # ne že by to bylo dokonalé bezpečný,
2644 # ale na lokálním počítači asi to není až tak zavadný
2645 coloring_function = getattr(self, coloring)
2646
2647
2648 try:
2649 stm_function = getattr(stm, method)
2650 # model_space='Rn', sampling_space=None, p_norm=1, budget=20000
2651 data = stm_function(sample_box, model_space=model_space, sampling_space=sampling_space,\
2652 p_norm=p_norm, budget=budget, callback=coloring_function)
2653
2654 if hasattr(self.sb_item.sample_box, 'estimations'):
2655 self.sb_item.sample_box.estimations.append(data)
2656 self.sb_item.estimation_added.emit()
2657 self.table.setData(data)
2658
2659 except BaseException as e:
2660 msg = "error during estimation "
2661 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
2662 print(error_msg)
2663
2664
2665
2666 # indikace
2667 #self.setEnabled(True)
2668
2669
2670
2671
2672
2673 def node_pf_coloring(self, estimation=None, nodes=None, cell_stats=None, out_nodes=None, *args, **kwargs):
2674 """
2675 if nodes and cell_stats provided we will add them to self.cells
2676 otherwise function redraw items in self.cells
2677 """
2678 plot_widget = self.sb_item.central_widget
2679 if nodes is None:
2680 for cell in self.cells:
2681 nodes, plot_item, cell_stats = cell
2682 # odebereme prvky z hlavního plotu
2683 # zde je třeba prvky vygenerovat znovu
2684 # protože nikdo neví co tam bylo před tím
2685 # takhle, nechce se mi drbat s tím, co tam bylo před tím
2686 # komplikace ze strany pyqtgraph
2687 plot_widget.removeItem(plot_item)
2688
2689 # bacha, potřebuji prvek uložiť in-place
2690 cell[1] = self.node_pf_scatter_plot(nodes, cell_stats)
2691
2692 # máme nodes, tj. jedeme poprvé
2693 else:
2694 plot_item = self.node_pf_scatter_plot(nodes, cell_stats)
2695
2696 # uložíme data
2697 self.cells.append([nodes, plot_item, cell_stats])
2698
2699 # keep the GUI responsive :)
2700 self.sb_item.app.processEvents()
2701
2702
2703
2704
2705 def node_pf_scatter_plot(self, nodes, cell_stats):
2706 pos = getattr(nodes, self.sb_item.space)[:,:2]
2707 symbol_size = self.param.getValues()['node (pixel) size'][0]
2708 plot_widget = self.sb_item.central_widget
2709 # zas, нет ножек - нет мультиков
2710 # node_pf_estimations nemusejí bejt
2711 try:
2712 # zkusmě pro jednoduchost
2713 # čírou RGB hračku
2714 npf = nodes.node_pf_estimations
2715 colors = tuple((npf[i]*255, (1-npf[i])*255, 0) for i in range(len(pos)))
2716 # sice dokumentace popisuje víc možností zadávání,
2717 # ale toto zadávání různejch barviček je pro mě jediné fungujicí. Drbal jsem s tím do znechucení
2718 # je v podstatě opsané z příkladu
2719 # rovnou přes PlotDataItem mi nefunguje
2720 # žádné jiné možností zadávání já jsem v zdrojacích
2721 # pyqtgraph (konkretně v PlotDataItem a v ScatterPlotItem) neuviděl
2722 # tuším, že je to neunosně drahý
2723 list_of_dicts = list({'pos': pos[i], 'size':symbol_size, 'pen': colors[i], 'brush':colors[i], 'symbol':'o'} for i in range(len(pos)))
2724 plot_item = pg.ScatterPlotItem(list_of_dicts)
2725 plot_widget.addItem(plot_item)
2726 return plot_item
2727
2728 except BaseException as e:
2729 msg = "node_pf_coloring has problems "
2730 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
2731 print(error_msg)
2732 #self.error.emit(error_msg)
2733 # simple coloring
2734 event = cell_stats['event']
2735 color = self.get_color(event)
2736 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2737 return plot_widget.plot(pos, pen=None, symbol='o', symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
2738
2739
2740
2741
2742
2743 def simple_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
2744 """
2745 if nodes and cell_stats provided we will add them to self.cells
2746 otherwise function redraw items in self.cells
2747 """
2748 symbol_size = self.param.getValues()['node (pixel) size'][0]
2749 plot_widget = self.sb_item.central_widget
2750 if nodes is None:
2751 for cell in self.cells:
2752 nodes, plot_item, cell_stats = cell
2753 # odebereme prvky z hlavního plotu
2754 # zde je třeba prvky vygenerovat znovu
2755 # protože nikdo neví co tam bylo před tím
2756 # takhle, nechce se mi drbat s tím, co tam bylo před tím
2757 # komplikace ze strany pyqtgraph
2758 plot_widget.removeItem(plot_item)
2759
2760 # draw
2761 pos = getattr(nodes, self.sb_item.space)[:,:2]
2762 #x, y = (*getattr(nodes, self.sb_item.space).T,)
2763
2764 event = cell_stats['event']
2765 color = self.get_color(event)
2766 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2767 # bacha, potřebuji prvek uložiť in-place
2768 cell[1] = plot_widget.plot(pos, pen=None, symbol='o',\
2769 symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
2770
2771 # máme nodes, tj. jedeme poprvé
2772 else:
2773 # draw tečičky
2774 #
2775 pos = getattr(nodes, self.sb_item.space)[:,:2]
2776
2777 event = cell_stats['event']
2778 color = self.get_color(event)
2779 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2780 plot_item = plot_widget.plot(pos, pen=None, symbol='o',\
2781 symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
2782
2783 # uložíme data
2784 self.cells.append([nodes, plot_item, cell_stats])
2785
2786 # keep the GUI responsive :)
2787 self.sb_item.app.processEvents()
2788
2789
2790
2791 def cell_probability_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
2792 """
2793 if nodes and cell_stats provided we will add them to self.cells
2794 otherwise function redraw items in self.cells
2795 """
2796 symbol_size = self.param.getValues()['node (pixel) size'][0]
2797 plot_widget = self.sb_item.central_widget
2798 if nodes is None:
2799 # odebereme prvky z hlavního plotu
2800 # zde je třeba prvky vygenerovat znovu
2801 # protože nikdo neví co tam bylo před tím
2802 # takhle, nechce se mi drbat s tím, co tam bylo před tím
2803 # komplikace ze strany pyqtgraph
2804 for nodes, plot_item, cell_stats in self.cells:
2805 plot_widget.removeItem(plot_item)
2806
2807 event = cell_stats['event']
2808 cell_probability = cell_stats['cell_probability']
2809 if self.p_cell_max[event] < cell_probability:
2810 self.p_cell_max[event] = cell_probability
2811
2812 # přebarvíme tečičky podle obsahu pravděpodobnosti
2813 for cell in self.cells:
2814 nodes, plot_item, cell_stats = cell
2815 # draw
2816 pos = getattr(nodes, self.sb_item.space)[:,:2]
2817 #x, y = (*getattr(nodes, self.sb_item.space).T,)
2818
2819 event = cell_stats['event']
2820 cell_probability = cell_stats['cell_probability']
2821 # bez modrého - maximální intenzita
2822 blue_intensity = 1 - cell_probability / self.p_cell_max[event]
2823 color = self.get_color(event, blue_intensity)
2824 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2825 # bacha, potřebuji prvek vložit zpätky
2826 cell[1] = plot_widget.plot(pos, pen=None, symbol='o',\
2827 symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
2828
2829 # máme nodes, tj. jedeme poprvé
2830 else:
2831 event = cell_stats['event']
2832 cell_probability = cell_stats['cell_probability']
2833 # zkontrolujeme probability
2834 if self.p_cell_max[event] < cell_probability:
2835 self.p_cell_max[event] = cell_probability
2836 # a hned všecko dotyčné přebarvíme podle obsahu pravděpodobnosti
2837 for cell in self.cells:
2838 if event == cell[2]['event']:
2839 # bez modrého - maximální intenzita
2840 # zde cell_probability se rovná self.p_cell_max[event]
2841 # ale bacha! Nesplet se jinde!
2842 blue_intensity = 1 - cell[2]['cell_probability'] / cell_probability
2843 color = self.get_color(event, blue_intensity)
2844 # bacha, potřebuji prvek vložit zpätky
2845 cell[1].setSymbolBrush(color)
2846 cell[1].setSymbolPen(color)
2847
2848 # bez modrého - maximální intenzita
2849 blue_intensity = 1 - cell_probability / self.p_cell_max[event]
2850 color = self.get_color(event, blue_intensity)
2851
2852
2853 # draw tečičky
2854 #
2855 pos = getattr(nodes, self.sb_item.space)[:,:2]
2856 #x, y = (*getattr(nodes, self.sb_item.space).T,)
2857
2858 #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
2859 plot_item = plot_widget.plot(pos, pen=None, symbol='o',\
2860 symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
2861
2862 # uložíme data
2863 self.cells.append([nodes, plot_item, cell_stats])
2864
2865 # keep the GUI responsive :)
2866 self.sb_item.app.processEvents()
2867
2868
2869
2870 def get_color(self, event, blue_intensity=None):
2871 """
2872 get color for 'simple_coloring' or 'cell_probability_coloring'
2873 """
2874 # generally
2875 if event == 'success':
2876 color = [167, 255, 181]# xkcd:light seafoam green #a7ffb5
2877 elif event == 'failure':
2878 color = [253, 193, 197] # xkcd: pale rose (#fdc1c5)
2879 # já vím, že Voronoi nemá 'mix', эн но юа
2880 else:# 'mix'
2881 color = [255, 243, 154] # let's try xkcd: dark cream (#fff39a)
2882
2883 if blue_intensity is not None:
2884 # let's play with blue a little bit
2885 # chcu mít korektní výstup
2886 # aspoň v něčem chcu být jistý
2887 if blue_intensity > 1:
2888 color[2] = 255
2889 elif blue_intensity < 0:
2890 color[2] = 0
2891 else:
2892 # pyqtgraph žere barvy i s čarkou
2893 # ale my je mu davat nebudeme
2894 color[2] = int(blue_intensity*255)
2895
2896 return tuple(color)
2897
2898
2899
2900
2901
2902
2903
2904
2905 class HullEstimationWidget(pg.LayoutWidget):
2906 # I'd like to get access to the samplebox stuff via the container's reference,
2907 def __init__(self, samplebox_item, parent=None, *args, **kwargs):
2908 super().__init__(parent)
2909 # sb like samplebox, of course
2910 self.sb_item = samplebox_item
2911
2912 self.giracle = Giracles(w=samplebox_item, autoredraw=False, nrod=200)
2913 #č Ghull se zkomplikoval. Musím integraci řešit zvlášť
2914 # Serie for integration nodes
2915 self.serint = Series(w=samplebox_item, autoredraw=False)
2916 #ё hyperplanes? Кого ты обманываешь, Alexi?
2917 #č tak. už je to equation_planes :)
2918 self.equation_planes = InfiniteLines(w=samplebox_item, autoredraw=False)
2919
2920 # signals handling:
2921 # box_runned - handled by .on_box_run() method
2922 # space_changed - handled automatically by smart items
2923 # slice_changed - setted up clear() on smart items
2924 # redraw_called - handled automatically by smart items
2925 # estimation_added - class does not handle the signal
2926 # nor emits the signal itself
2927 # (as does not save estimations anywhere for now)
2928
2929 # todo: design estimation record
2930
2931 self.sb_item.box_runned.connect(self.on_box_run)
2932 #č Alexi, ten signal může té funkce posilát bůhví co navíc.
2933 #č (ano. clear() nebere žádné argumenty, takže v cajku)
2934 self.sb_item.slice_changed.connect(self.giracle.clear)
2935 self.sb_item.slice_changed.connect(self.equation_planes.clear)
2936 #č ty naše chytré prvky giracle a equation_planes
2937 #č hlídají space_changed a redraw_called sami.
2938
2939 self.schemes = dict()
2940 self.ndim = self.sb_item.sample_box.nvar
2941 #☺ na internetu všichni tak dělaj
2942 self.setup()
2943
2944 def setup(self):
2945 #č já teďkom dědím ne QSplitter, ale LayoutWidget
2946 #оӵ Кужым кариськы, Олёш!
2947
2948 #č zkusíme nový (pro WellMet) UI, uživatelské rozhraní
2949 #оӵ кнопка вылын
2950 #self.layout = self.addLayout(row=0, col=0)
2951 #self.tool_layout = QtGui.QHBoxLayout()
2952 #self.layout.addLayout(self.tool_layout, 0, 0)
2953 #self.addWidget(self.layout, row=0, col=0)
2954
2955 #č toolbar je obecně super věc, ale mě zlobí umístění v layoutu
2956 self.toolbar = QtGui.QToolBar(self)
2957 #č jmenovitě, roztažení mě nefunguje vůbec
2958 #size_policy = self.toolbar.sizePolicy()
2959 #size_policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding)
2960 #self.toolbar.setSizePolicy(size_policy)
2961
2962 #č draw_convex_hull ja navržena tak, aby brala jíž hotový hull
2963 # if self.ndim == 2:
2964 # action = self.toolbar.addAction("draw convex hull", self.draw_convex_hull)
2965 # btn = self.toolbar.widgetForAction(action)
2966 # btn.setAutoRaise(False)
2967
2968 action = self.toolbar.addAction("shell out!", self.get_shell_estimation)
2969 btn = self.toolbar.widgetForAction(action)
2970 btn.setAutoRaise(False)
2971 btn.setToolTip("Creates Ghull object")
2972 #btn.setSizePolicy(size_policy)
2973
2974 action = self.toolbar.addAction("integrate", self.integrate)
2975 btn = self.toolbar.widgetForAction(action)
2976 btn.setAutoRaise(False)
2977 btn.setToolTip("Only uses Ghull object created before")
2978 #btn.setSizePolicy(size_policy)
2979
2980 action = self.toolbar.addAction("shot!", self.shot)
2981 btn = self.toolbar.widgetForAction(action)
2982 btn.setAutoRaise(False)
2983
2984 action = self.toolbar.addAction("fire!", self.fire)
2985 btn = self.toolbar.widgetForAction(action)
2986 btn.setAutoRaise(False)
2987 #btn.setSizePolicy(size_policy)
2988
2989 action = self.toolbar.addAction("boom!", self.boom)
2990 btn = self.toolbar.widgetForAction(action)
2991 btn.setAutoRaise(False)
2992
2993 action = self.toolbar.addAction("hide", self.hide)
2994 btn = self.toolbar.widgetForAction(action)
2995 btn.setAutoRaise(False)
2996 #btn.setSizePolicy(size_policy)
2997
2998 action = self.toolbar.addAction("show", self.show)
2999 btn = self.toolbar.widgetForAction(action)
3000 btn.setAutoRaise(False)
3001
3002 action = self.toolbar.addAction("clear", self.clear)
3003 btn = self.toolbar.widgetForAction(action)
3004 btn.setAutoRaise(False)
3005
3006 #self.tool_layout.addWidget(self.toolbar)
3007 self.addWidget(self.toolbar, row=0, col=0)
3008
3009
3010 #оӵ остальной (люкет) уллапала
3011
3012 ### Create ParameterTree widget
3013 self.ptree = pg.parametertree.ParameterTree()
3014 self._set_param()
3015 self.ptree.setParameters(self.param, showTop=False)
3016
3017 self.splitter = QtGui.QSplitter(self)
3018 self.splitter.setOrientation(QtCore.Qt.Vertical)
3019 self.splitter.addWidget(self.ptree)
3020
3021 self.table = pg.TableWidget(sortable=False)
3022 self.splitter.addWidget(self.table)
3023
3024 #self.addWidget(self.splitter, row=1, col=0, colspan=5)
3025 self.addWidget(self.splitter, row=1, col=0)
3026
3027 def hide(self):
3028 self.serint.hide()
3029 self.giracle.hide()
3030 self.equation_planes.hide()
3031
3032 def show(self):
3033 self.serint.show()
3034 self.giracle.show()
3035 self.equation_planes.show()
3036
3037 def clear(self):
3038 self.serint.clear()
3039 self.giracle.clear()
3040 self.equation_planes.clear()
3041
3042 #оӵ DirectHull понна гинэ
3043 #č pouze pro DirectHull
3044 def get_scheme(self):
3045 scheme = self.param.getValues()['scheme'][0]
3046 if scheme == 'random':
3047 ndir = self.param.getValues()['ndir'][0]
3048 return sball.get_random_directions(ndir, self.ndim)
3049 elif scheme in self.schemes:
3050 return self.schemes[scheme].points
3051 else:
3052 Scheme = getattr(quadpy.un, scheme)
3053 self.schemes[scheme] = Scheme(self.ndim)
3054 return self.schemes[scheme].points
3055
3056
3057 def _set_param(self):
3058 params = list()
3059 params.append({'name': 'method', 'type': 'list', 'value': 'DirectHull', \
3060 'values': ['SBall', 'BrickHull', 'DirectHull', 'CompleteHull', 'QHull']})
3061 params.append({'name': 'space', 'type': 'list', 'tip': "Not used for SBall", \
3062 'values': self.sb_item.spaces, 'value': 'G'})
3063
3064 schemes_list = schemes.un_spheres + ['random']
3065 params.append({'name': 'scheme', 'type': 'list', \
3066 'values': schemes_list, 'value': schemes_list[0], \
3067 'tip': "Used only for DirectHull and CompleteHull. Generation can take for a while"})
3068 params.append({'name': 'ndir', 'type': 'int', \
3069 'limits': (1, float('inf')), 'value': 1000, 'default': 1000, \
3070 'title': "number of random directions", \
3071 'tip': "Used only for random scheme in DirectHull (or CompleteHull)"})
3072
3073 params.append({'name': 'integrator', 'title': "integrator", 'type': 'list', \
3074 'values': ['MC', 'IS', '1DS'], 'value': '1DS' })
3075 params.append({'name': 'nonG_reduction', 'type': 'float', \
3076 'title': "non Gaussian reduction", \
3077 'limits': (0, 1), 'value': 0.9, 'default': 0.9,\
3078 'tip': "Applied when Ghull integrates non Gaussian convex hulls"})
3079
3080 params.append({'name': 'use_MC', 'title': "use MC", 'type': 'bool', 'value': False, \
3081 'tip': "Used for shot(), fire() and boom() functions"})
3082
3083 params.append({'name': 'budget', 'type': 'int', \
3084 'limits': (1, float('inf')), 'value': 1000, 'default': 1000,\
3085 'tip': "Number of simulations for optimal importance sampling"})
3086
3087 params.append({'name': 'node (pixel) size', 'type': 'float',\
3088 'limits': (0, float('inf')), 'value': 3.5, 'default': self.sb_item.px_size})
3089 #ё больше калорий богу калорий!
3090 params.append({'name': 'r', 'type': 'color', 'value': (189, 204, 0, 255) })
3091 params.append({'name': 'inside', 'type': 'color', 'value': (133, 172, 102, 255) })
3092 params.append({'name': 'convex_hull', 'type': 'color', 'value': (85, 170, 255, 255) }) # (186, 109, 0, 255)
3093 params.append({'name': 'fire', 'type': 'color', 'value': (245, 117, 0, 255) })
3094 params.append({'name': 'orth', 'type': 'color', 'value': (255, 0, 0, 255) })
3095 params.append({'name': 'outside', 'type': 'color', 'value': 0.6})
3096 params.append({'name': 'R', 'type': 'color', 'value': (85, 85, 255, 255) })
3097 params.append({'name': 'Update as the box runned', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
3098 params.append({'name': 'index', 'title': "replace previous", 'type': 'bool', 'value': True })
3099
3100 ### Create tree of Parameter objects
3101 # I don't know why that signals do not work for me
3102 # Only sigTreeStateChanged works, but I don't want to struggle with it
3103 # May be I'll report the issue
3104 #self.param.sigValueChanged.connect(self.param_changed)
3105 #self.param.sigValueChanging.connect(self.param_changing)
3106 self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
3107
3108 def get_ghull(self):
3109 integrator = self.param.getValues()['integrator'][0]
3110 if integrator == 'MC':
3111 Integrator = Shell_MC
3112 elif integrator == 'IS':
3113 Integrator = Shell_IS
3114 elif integrator == '1DS':
3115 Integrator = Shell_1DS
3116 nonG_reduction = self.param.getValues()['nonG_reduction'][0]
3117 hull = self.get_hull()
3118 self.ghull = Ghull(hull, Integrator=Integrator, non_Gaussian_reduction=nonG_reduction)
3119 return self.ghull
3120
3121
3122 #č jistě potřebuji něco, co zpracuje parameter_tree
3123 #č a vratí platný hull pro Ghull
3124 def get_hull(self):
3125 #č bez semplu se neobejde
3126 nsim = self.sb_item.slider.value()
3127 sample = self.sb_item.sample_box.f_model[:nsim]
3128
3129 # ['SBall', 'BrickHull', 'DirectHull', 'QHull']
3130 hull_model = self.param.getValues()['method'][0]
3131 if hull_model == 'SBall':
3132 return khull.GBall(sample)
3133 elif hull_model == 'BrickHull':
3134 space = self.param.getValues()['space'][0]
3135 return khull.BrickHull(sample, space)
3136 elif hull_model == 'DirectHull':
3137 space = self.param.getValues()['space'][0]
3138 direct_plan = self.get_scheme()
3139 return khull.DirectHull(sample, direct_plan, space)
3140 elif hull_model == 'CompleteHull':
3141 space = self.param.getValues()['space'][0]
3142 direct_plan = self.get_scheme()
3143 return khull.CompleteHull(sample, direct_plan, space)
3144 elif hull_model == 'QHull':
3145 space = self.param.getValues()['space'][0]
3146 #č tento widget pokažde generuje obálku znovu
3147 return khull.QHull(sample, space, incremental=False)
3148 else:
3149 raise ValueError("HullEstimationWidget: co to je za obálku?")
3150
3151 #č ten hlavní modul se dočkal na překopávání
3152 def on_box_run(self, *args, **kwargs):
3153 self.clear()
3154 #č je třeba zkontrolovat autorun a restartovat výpočet
3155 if self.param.getValues()['Update as the box runned'][0]:
3156 self.get_shell_estimation()
3157
3158 def index(self, index):
3159 if self.param.getValues()['index'][0]: # replace previous
3160 return index
3161 else:
3162 return None
3163
3164 def draw_planes(self, equations, space, **kwargs):
3165 if self.ndim == 2:
3166 #č musíme něco zavolat na self.equation_planes
3167 #č equation_planes má funkci add_line()
3168 #č add_line(self, space='G', index=None, **plot_kwargs)
3169 #č která pak plot_kwargs přeposilá funkci addLine()
3170 #č na central widgetu.
3171 #č To vše skončí ve pyqtgrafové InfiniteLine třidě.
3172 #č ta moje třida InfiniteLines sama se stará o shodování prostorů
3173 #č indexy posilat nebudeme (s nimi je to trošku komplikovanější)
3174
3175 #pos = list() #č navrhové body nakreslíme všechny dohromady
3176 for equation in equations:
3177 #č ve 2D bych očekával v rovnici pouze 3 hodnoty (já potřebuji směry)
3178 x, y, offset = equation
3179 design_point = [-x*offset, -y*offset]
3180 #self.sb_item.central_widget.plot(np.array([pos, pos]), symbol='o')
3181 # if y < 0: #č tak to aspoň kreslí
3182 # angle = np.rad2deg(np.arcsin(x))
3183 # else:
3184 # angle = np.rad2deg(np.arccos(y))
3185
3186 if (x*y) < 0: #č tak to aspoň kreslí
3187 angle = np.rad2deg(np.arccos(np.abs(y)))
3188 else:
3189 angle = np.rad2deg(np.arccos(-np.abs(y)))
3190 self.equation_planes.add_line(space=space, pos=design_point, angle=angle, **kwargs)
3191
3192
3193
3194 def draw_convex_hull(self, hull):
3195 try:
3196 if self.param.getValues()['index'][0]: # replace previous
3197 self.equation_planes.clear()
3198
3199 #č zatím uděláme jen pro 2D infinite lajny
3200 design_points = hull.get_design_points()
3201
3202 size = self.param.getValues()['node (pixel) size'][0]
3203 color = self.param.getValues()['convex_hull'][0] #č tam bude barva
3204
3205 self.giracle.add_serie(design_points, z=31, index=self.index('design points'),\
3206 pen=None, symbol='o', symbolPen=pg.mkPen(None), \
3207 symbolBrush=color, symbolSize=size, name='design points')
3208 self.draw_planes(hull.equations, space=hull.space, z=29, pen=color)
3209
3210
3211 # orth
3212 color = self.param.getValues()['orth'][0] #č tam bude barva
3213 #self.giracle.add_serie(FORM_points, z=32, index=self.index('2FORM points'),\
3214 # pen=None, symbol='o', symbolPen=pg.mkPen(None), \
3215 # symbolBrush=color, symbolSize=size, name='2FORM points')
3216 self.draw_planes(hull.get_orth_equations(), space=hull.space, z=30, pen=color)
3217
3218
3219 # 2FORM
3220 color = self.param.getValues()['fire'][0] #č tam bude barva
3221 #self.giracle.add_serie(FORM_points, z=32, index=self.index('2FORM points'),\
3222 # pen=None, symbol='o', symbolPen=pg.mkPen(None), \
3223 # symbolBrush=color, symbolSize=size, name='2FORM points')
3224 self.draw_planes(hull.get_2FORM_equations(), space=hull.space, z=30, pen=color)
3225
3226
3227 except BaseException as e:
3228 msg = "draw_convex_hull error "
3229 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3230 print(error_msg)
3231 self.sb_item.errors.append(e)
3232
3233 def draw_ghull(self, r, R):
3234 # r-circle
3235 if r < 0:
3236 r = 0
3237 color = self.param.getValues()['r'][0] #č tam bude barva
3238 #č krucí, nevím co mám dělat s indexama.
3239 #č co mám dělat s předchozí kresbou? Nechame
3240 self.giracle.add_circle(r=r, index=self.index('r'),z=32, pen=color, name='r')
3241
3242 # R-circle. #č Při kreslení nahradíme předchozí.
3243 color = self.param.getValues()['R'][0] #č tam bude barva
3244 self.giracle.add_circle(R, z=32, index=self.index('R'), pen=color, name='R')
3245
3246
3247
3248
3249 def get_shell_estimation(self):
3250 ghull = self.get_ghull()
3251 self.draw_convex_hull(ghull.hull)
3252
3253 try:
3254 shell_estimation, global_stats = ghull.get_shell_estimation()
3255
3256 # if hasattr(self.sb_item.sample_box, 'estimations'):
3257 # self.sb_item.sample_box.estimations.append(data)
3258 # self.sb_item.estimation_added.emit()
3259 self.table.setData({**global_stats, 'shell_estimation':shell_estimation})
3260
3261 self.draw_ghull(global_stats['r'], global_stats['R'])
3262
3263 except BaseException as e:
3264 msg = "error during estimation "
3265 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3266 print(error_msg)
3267 self.sb_item.errors.append(e)
3268
3269
3270 def shot(self):
3271 ghull = self.get_ghull()
3272 self.draw_candidates(ghull.hull.shot)
3273
3274 def fire(self):
3275 ghull = self.get_ghull()
3276 self.draw_candidates(ghull.hull.fire)
3277
3278 def boom(self):
3279 ghull = self.get_ghull()
3280 self.draw_candidates(ghull.boom)
3281
3282 def draw_candidates(self, source_function):
3283 #č špatně rozumím, co tím bylo mysleno
3284 #č že jsem chtěl kreslit náhodné směry?
3285 ##č zatím máme issue s náhodným planem
3286 ##č kdyby něco - vyřeším přes ukladání
3287 ##č náhodných plánů v parameter_tree
3288
3289 self.draw_convex_hull(self.ghull.hull)
3290
3291 #☺ Krucinal, kdo ten OrderedDict vymyslel?
3292 params = self.param.getValues()
3293 ns = params['budget'][0]
3294 use_MC = params['use_MC'][0]
3295 try:
3296 fire = source_function(ns, use_MC=use_MC)
3297 # draw tečičky
3298 color = self.param.getValues()['fire'][0] #č tam bude barva
3299 size = self.param.getValues()['node (pixel) size'][0]
3300 #brush = pg.mkBrush(color)
3301 self.giracle.add_serie(fire, z=30, index=self.index('fire'),\
3302 pen=None, symbol='o', symbolPen=pg.mkPen(None), \
3303 symbolBrush=color, symbolSize=size, name='fire')
3304
3305 except BaseException as e:
3306 msg = "error "
3307 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3308 print(error_msg)
3309 self.sb_item.errors.append(e)
3310
3311 def integration_callback(self, nodes):
3312 #č draw tečičky
3313 size = self.param.getValues()['node (pixel) size'][0]
3314 plot_params = {'pen':None, 'symbol':'o', 'symbolSize':size, \
3315 'symbolPen':pg.mkPen(None)}
3316 #brush = pg.mkBrush(color)
3317 mask = nodes.is_outside
3318
3319 index = 'inside'
3320 color = self.param.getValues()[index][0] #č tam bude barva
3321 self.serint.add_serie(nodes[~mask], z=30,\
3322 symbolBrush=color, name=index, **plot_params)
3323
3324 index = 'outside'
3325 color = self.param.getValues()[index][0] #č tam bude barva
3326 self.serint.add_serie(nodes[mask], z=30, \
3327 symbolBrush=color, name=index, **plot_params)
3328
3329 # keep the GUI responsive :)
3330 self.sb_item.app.processEvents()
3331
3332
3333
3334 def integrate(self):
3335 #č integrace se stala stateful
3336 #č a musím jú taky testovat
3337 if 'ghull' not in self.__dict__:
3338 ghull = self.get_ghull()
3339 else:
3340 ghull = self.ghull
3341 nsim = self.sb_item.slider.value()
3342 sample = self.sb_item.sample_box.f_model[:nsim]
3343 #č teď - saháme do vnitřku naších obliběných tříd
3344 ghull.hull.sample = sample
3345 ghull.sample = sample
3346
3347 self.draw_convex_hull(ghull.hull)
3348
3349
3350 #☺ Krucinal, kdo ten OrderedDict vymyslel?
3351 params = self.param.getValues()
3352 budget = params['budget'][0]
3353
3354 if self.param.getValues()['index'][0]: # replace previous
3355 self.serint.clear()
3356
3357 try:
3358 data = ghull.integrate(budget, callback_all=self.integration_callback)
3359 ghull_estimation, convex_hull_estimation, global_stats = data
3360
3361 #if hasattr(self.sb_item.sample_box, 'estimations'):
3362 #self.sb_item.sample_box.estimations.append(data)
3363 #self.sb_item.estimation_added.emit()
3364 self.table.setData({**global_stats, "ghull_estimation":ghull_estimation,\
3365 "convex_hull_estimation": convex_hull_estimation})
3366
3367 self.draw_ghull(global_stats['r'], global_stats['R'])
3368
3369
3370 except ValueError as e: #BaseException
3371 msg = "error during estimation "
3372 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3373 print(error_msg)
3374 self.sb_item.errors.append(e)
3375
3376 # draw DP
3377 if ghull.hull.space != 'G':
3378 size = self.param.getValues()['node (pixel) size'][0] + 3
3379 plot_params = {'pen':None, 'symbol':'t2', 'symbolSize':size, \
3380 'symbolPen':pg.mkPen(None)}
3381
3382 #color = self.param.getValues()[index][0] #č tam bude barva
3383 self.serint.add_serie(ghull.gint.DP, z=35, index='DP', name='DP', **plot_params)
3384
3385
3386
3387
3388
3389 """
3390 ===========
3391 ♥ Чыры-пыры
3392 č Jiné
3393 E Miscellaneous
3394 ===============
3395 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3396 """
3397
3398
3399
3400 class CandidatesWidget(pg.LayoutWidget):
3401 """
3402 """
3403 # I'd like to get access to the samplebox stuff via the container's reference,
3404 # but relying to Qt's parent mechanism makes me worry.
3405 def __init__(self, samplebox_item, parent=None, *args, **kwargs):
3406 super().__init__(parent)
3407 # sb like samplebox, of course
3408 self.sb_item = samplebox_item
3409
3410 #self.sb_item.box_runned.connect(self.on_box_run)
3411 self.sb_item.slice_changed.connect(self.rerun)
3412 self.sb_item.space_changed.connect(self.rerun)
3413 self.sb_item.redraw_called.connect(self.redraw)
3414 #☺ na internetu všichni tak dělaj
3415 self.setup()
3416
3417 def setup(self):
3418 # 1
3419 #
3420 self.autorun = QtGui.QCheckBox('Show')
3421 self.autorun.stateChanged.connect(self.rerun)
3422 self.addWidget(self.autorun)
3423
3424 self.btn = QtGui.QPushButton('redraw')
3425 self.addWidget(self.btn, row=0, col=1)
3426 self.btn.clicked.connect(self.rerun)
3427
3428 # 2
3429 #
3430 #č predpokladam pandas verzi CandyBox'u
3431 #items = list(self.sb_item.sample_box.candidates_index[-1].df.columns)
3432 try:
3433 #č načíst sloupce prostě z libovolného vzorku
3434 df = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
3435 items = df.columns
3436 except:
3437 #♥ мыным дунне
3438 items = []
3439
3440 self.attr = pg.ComboBox(items=items)
3441 #self.attr.activated.connect(self.redraw)
3442 self.addWidget(self.attr, row=1, col=0, colspan=2)
3443
3444 # 3
3445 #
3446 self.gradient = pg.GradientWidget(self, orientation='right')
3447 self.gradient.setColorMap(pg.colormap.ColorMap((0,1),\
3448 [(255, 255, 255, 255), (67, 0, 81, 255)]))
3449 self.addWidget(self.gradient, row=2, col=1)
3450
3451
3452
3453 #E pens, i.e. handles of PlotItem
3454 self.pens = []
3455
3456
3457 def run_stm(self):
3458 #č indikace
3459 #self.setDisabled(True)
3460 plot_widget = self.sb_item.central_widget
3461 with pg.BusyCursor():
3462
3463 color_map = self.gradient.colorMap()
3464
3465 try:#č může se tu stat cokoliv
3466 #č načíst sloupce prostě z libovolného vzorku
3467 cb = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
3468 #č je třeba mít seznam aktualní
3469 self.attr.setItems(list(cb.df.columns))
3470
3471 #č neplest s self.attr!
3472 attr = self.attr.currentText()
3473
3474 #č kruci, nejdřív je třeba najít maxvalue, minvalue je implicitně nula
3475 maxvalue = -np.inf
3476 minvalue = np.inf
3477 for id, cb in self.sb_item.sample_box.candidates_index.items():
3478 array = getattr(cb, attr)
3479 if len(array):
3480 maxcb = np.nanmax(array)
3481 mincb = np.nanmin(array)
3482 if maxcb > maxvalue:
3483 maxvalue = maxcb
3484 maxitem = cb[np.nanargmax(array)]
3485 if mincb < minvalue:
3486 minvalue = mincb
3487
3488 #č zvlášť nakreslím maximální hodnotu
3489 pos = getattr(maxitem, self.sb_item.space)[:,:2]
3490 max_item = plot_widget.plot(pos, data=maxvalue, pen=None, symbol='t1',\
3491 symbolBrush=color_map.mapToQColor(1))
3492 max_item.setZValue(130)
3493 self.pens.append(max_item)
3494
3495 #č a teď jdeme!
3496 for id, cb in self.sb_item.sample_box.candidates_index.items():
3497 array = getattr(cb, attr)
3498 if np.isnan(array).any():
3499 msg = "%s candidates has nans in %s attribute"%(id, attr)
3500 error_msg = self.__class__.__name__ + ": " + msg
3501 print(error_msg)
3502 mask = np.isfinite(array)
3503 values = array[mask]
3504 norm_values = (values - minvalue) / (maxvalue - minvalue)
3505
3506 pos = getattr(cb, self.sb_item.space)[mask][:,:2]
3507
3508 #č sehnal jsem toto ze zdrojaků pyqtgraph
3509 style = dict(pen=None, symbol='o', symbolSize=self.sb_item.px_size, symbolPen=pg.mkPen(None))
3510 style['symbolBrush'] = np.array([pg.functions.mkBrush(*x) for x in color_map.map(norm_values)])
3511 pen = plot_widget.plot(pos, data=values, **style)
3512 pen.setZValue(-1)
3513 self.pens.append(pen)
3514
3515 except BaseException as e:
3516 msg = ""
3517 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3518 print(error_msg)
3519
3520
3521
3522 # indikace
3523 #self.setEnabled(True)
3524
3525
3526
3527 #č současně ten hlavní modul se pokusí zavolat redraw při zpouštění boxu
3528 #č ten hlavní modul se těší na překopávání
3529 def rerun(self, *args, **kwargs):
3530 #č uklizení budu chtit jednoznačně
3531 self.self_clear()
3532 #č a teď řešíme, zda je třeba restartovat výpočet
3533 if self.autorun.isChecked():
3534 self.run_stm()
3535
3536 def redraw(self, *args, **kwargs):
3537 self.pens.clear()
3538
3539
3540 def self_clear(self):
3541 #č odebereme prvky-propísky z hlavního plotu
3542 for plot_item in self.pens:
3543 self.sb_item.central_widget.removeItem(plot_item)
3544
3545 self.pens.clear()
3546
3547
3548 #E not implementeed yet on the main window side
3549 # def on_space_changed(self, *args, **kwargs):
3550 # pass
3551
3552
3553 529
3554 530 class BoxTreeWidget(pg.LayoutWidget): class BoxTreeWidget(pg.LayoutWidget):
3555 531 """ """
File qt_gui/qt_plot.py changed (mode: 100644) (index 2a088a1..b211600)
... ... import pyqtgraph as pg
5 5 from pyqtgraph.Qt import QtGui from pyqtgraph.Qt import QtGui
6 6 from pyqtgraph.Qt import QtCore from pyqtgraph.Qt import QtCore
7 7
8 from pyqtgraph import console
9 8
10 9 import numpy as np import numpy as np
11 import pandas as pd # required for estimation graph
12 10
13 11 #č vzdávám se. #č vzdávám se.
14 12 #č quadpy tak se stavá povinnou závislostí #č quadpy tak se stavá povinnou závislostí
 
... ... import quadpy
18 16
19 17 from .. import estimation as stm from .. import estimation as stm
20 18 from .. import misc from .. import misc
21 from .. import stm_df
22 19 from .. import sball from .. import sball
23 20 from .. import schemes from .. import schemes
24 21 from .. import convex_hull as khull from .. import convex_hull as khull
25 22 #č pro mě je zvykem jako ghull označovat objekt třídy Ghull #č pro mě je zvykem jako ghull označovat objekt třídy Ghull
26 23 #č nikoliv čerstvě oddelený modul #č nikoliv čerstvě oddelený modul
27 from .ghull import Ghull, Shell_MC, Shell_IS, Shell_1DS
24 from ..ghull import Ghull, Shell_MC, Shell_IS, Shell_1DS
25 from . import qt_gui
28 26
29
30 def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs):
31 """
32 This function will start Qt graph window in event loop
33 """
34
35 return QtGuiPlot2D(sample_box, space, *args, **kwargs)
36 27
37 28
38 ### Define a top-level widget to hold everything
39 class QtGuiPlot2D(QtGui.QMainWindow):
40 #č box_runned dublikuje slice_changed
41 # do not redraw twice!
42 box_runned = QtCore.pyqtSignal()
43 space_changed = QtCore.pyqtSignal()
44 slice_changed = QtCore.pyqtSignal()
45 redraw_called = QtCore.pyqtSignal()
46 estimation_added = QtCore.pyqtSignal()
47
48 # INHERITED by gl_plot
49 # snad pri vykreslování argy-kvargy nevádí
50 def __init__(self, sample_box, space='R', *args, **kwargs):
51
52 #E former self.w = QtGui.QMainWindow()
53 self.app = pg.mkQApp()
54 super().__init__()
55 try:
56 self.setWindowTitle("%sD: %s" %(sample_box.nvar, sample_box.gm_signature))
57 except:
58 self.setWindowTitle("%sD nodes" % sample_box.nvar)
59
60 # for debug
61 # container for errors
62 # to trace errors
63 self.errors = []
64
65 self.kwargs = kwargs
66 self.sample_box = sample_box
67 #sample_box.sample_box._log = self.logger
68 self.last_shot = None
69 try:
70 self.space = self.sample_box.tri_space
71 except AttributeError:
72 self.space = space
73
74 # "zapnuté" prostory
75 #self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'aP', 'GK', 'aGK', 'G', 'aG', 'U', 'aU']
76 self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'GK', 'G', 'aG', 'U', 'aU']
77
78 # initialize central widget
79 self.initialize_central_widget()
80
81 # common setup
82 self.setup()
83
84 self.plot_setup()
85
86 ## Display the widget as a new window
87 self.show()
88
89 #
90 self.redraw_called.emit()
91
92 ## Start the Qt event loop
93 self.app.exec_()
94
95
29 class QtGuiPlot2D(qt_gui.QtGuiWindow):
96 30 def initialize_central_widget(self): def initialize_central_widget(self):
97 31 self.central_widget = pg.PlotWidget() self.central_widget = pg.PlotWidget()
98 32 self.central_widget.setBackground('w') self.central_widget.setBackground('w')
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
100 34 self.ncircles = 5 self.ncircles = 5
101 35 self.redraw_called.connect(self.central_widget.clear) self.redraw_called.connect(self.central_widget.clear)
102 36
103 # should be INHERITED by gl_plot
104 def initialize_matplotlib_menu(self):
105 try: # entire optional functionality
106 from .mplot import show_ax, show_ax3d, show_fig
107 from .mplot import maxes
108 from .mplot import maxes3d
109 from .mplot import mfigs
110 from .mplot import misc as mmisc
111 self.matplotlib_menu = self.bar.addMenu("Matplotlib")
112 self.matplotlib_actions = []
113
114 self.matplotlib_2D_menu = self.matplotlib_menu.addMenu("2D plots")
115 self._setup_mpl_submenu(self.matplotlib_2D_menu, maxes, show_ax)
116
117 self.matplotlib_3D_menu = self.matplotlib_menu.addMenu("3D plots")
118 self._setup_mpl_submenu(self.matplotlib_3D_menu, maxes3d, show_ax3d)
119
120 self.matplotlib_figs_menu = self.matplotlib_menu.addMenu("Complex plots")
121 self._setup_mpl_submenu(self.matplotlib_figs_menu, mfigs, show_fig)
122
123 self.matplotlib_misc_menu = self.matplotlib_menu.addMenu("Others")
124 for smthng in mmisc.__all__:
125 mpl_action = QtGui.QAction(smthng, self)
126 show_mpl = self._mpl_prepare_fn(getattr(mmisc, smthng))
127 mpl_action.triggered.connect(show_mpl)
128 self.matplotlib_misc_menu.addAction(mpl_action)
129 # prevent GC from wiping out both Qt object and our function
130 self.matplotlib_actions.append((mpl_action, show_mpl))
131
132 except ImportError as e:
133 msg = "Matplotlib related features are unavailiable"
134 print(self.__class__.__name__ + ":", msg, repr(e))
135
136 def _setup_mpl_submenu(self, menu, module, handler):
137 for drawing in module.__all__:
138 mpl_action = QtGui.QAction(drawing, self)
139 # do not really understand what I am doing :(
140 # try to show_mpl remember its actual drawing string
141 show_mpl = self._mpl_prepare_show_fn(handler, getattr(module, drawing))
142 mpl_action.triggered.connect(show_mpl)
143 menu.addAction(mpl_action)
144 # prevent GC from wiping out both Qt object and our function
145 self.matplotlib_actions.append((mpl_action, show_mpl))
146
147 def _mpl_prepare_show_fn(self, show, to_draw):
148 return lambda: show(to_draw, self.get_sample_box(), space=self.space)
149
150 def _mpl_prepare_fn(self, fn):
151 return lambda: fn(sample_box=self.get_sample_box(), space=self.space)
152
153 def get_sample_box(self):
154 nsim = self.slider.value()
155 if nsim == self.sample_box.nsim:
156 return self.sample_box
157 else:
158 return self.sample_box[:nsim]
159
160 # INHERITED by gl_plot
161 # intended as a common setup function
162 def setup(self):
163
164 self.bar = self.menuBar()
165 self.view = self.bar.addMenu("View")
166
167 self.graph_menu = self.bar.addMenu("Box")
168 self.batch_run_action = QtGui.QAction("Batch run", self)
169 self.batch_run_action.triggered.connect(self.batch_run)
170 self.graph_menu.addAction(self.batch_run_action)
171
172 # optional feature
173 self.initialize_matplotlib_menu()
174
175 ### Create some widgets to be placed inside
176 self.combo_space = pg.ComboBox(items=self.spaces, default=self.space)
177 self.combo_space.activated[str].connect(self.change_space)
178
179
180 self.label_nsim = QtGui.QLabel()
181 self.label_nsim.setText(str(self.sample_box.nsim))
182
183 self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
184 self.slider.valueChanged.connect(self._slider_chainged)
185 self.slider.sliderReleased.connect(lambda:self.slice_changed.emit())
186 self.slider.setMaximum(self.sample_box.nsim)
187 self.slider.setValue(self.sample_box.nsim)
188
189 #č jen aby se slider probral, když uživatel ručně přídá bodíky
190 self.redraw_called.connect(lambda:self.slider.setMaximum(self.sample_box.nsim))
191
192 self.btn = QtGui.QPushButton('run box')
193 self.btn.clicked.connect(self.run_sb)
194
195 self.btn2 = QtGui.QPushButton('connect/disconnect')
196 self.btn2.setCheckable(True)
197 self.btn2.clicked.connect(self.bx_connect)
198
199 self.btn3 = QtGui.QPushButton('redraw')
200 self.btn3.clicked.connect(lambda:self.redraw_called.emit())
201
202
203 ## Create a grid layout to manage the widgets size and position
204 self.layout = pg.LayoutWidget()
205 self.setCentralWidget(self.layout)
206 #self.w.setLayout(self.layout)
207
208 #
209 self.list_view = QtGui.QListWidget()
210
211 ## Add widgets to the layout in their proper positions
212 #self.layout.addWidget(self.list_view, 0, 0, 2, 1)
213 self.layout.addWidget(self.combo_space, 0, 0)
214 self.layout.addWidget(self.slider, 0, 1)
215 self.layout.addWidget(self.label_nsim, 0, 2)
216 self.layout.addWidget(self.btn, 0, 3)
217 self.layout.addWidget(self.btn2, 0, 4)
218 self.layout.addWidget(self.btn3, 0, 5)
219 self.layout.addWidget(self.central_widget, 1, 0, 1, 6)
220
221
222
223 # status bar, mainly to observe BlackBox
224 self.statusBar = QtGui.QStatusBar()
225 self.setStatusBar(self.statusBar)
226 self.btn_continue = QtGui.QPushButton('continue')
227 self.continue_label = QtGui.QLabel()
228 # self.continue_layout = QtGui.QHBoxLayout()
229 # self.continue_layout.addWidget(self.btn_continue)
230 # self.continue_layout.addWidget(self.continue_label)
231 self.statusBar.addWidget(self.btn_continue)
232 self.statusBar.addWidget(self.continue_label)
233 self.btn_continue.hide()
234 self.continue_label.hide()
235
236 self.statusBar.showMessage("Vitáme vás u nás!")
237
238
239
240
241 # Dockables, najzajimavejší věc
242 self.dockables = []
243
244
245 dock = QtGui.QDockWidget("Interactive python console", self)
246 dock.setWidget(console.ConsoleWidget(namespace={**locals(), **globals()}))
247 self.dockables.append(dock)
248 self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, dock)
249
250
251 dock = QtGui.QDockWidget("BlackBox output", self)
252 self.output_label = QtGui.QLabel()
253 dock.setWidget(self.output_label)
254 self.dockables.append(dock)
255 self.tabifyDockWidget(self.dockables[0], dock)
256
257 self.simplex_data = SimplexEstimationData(self.sample_box, self)
258 #č graphy už nemusí jít po stm widgetech
259 dock = QtGui.QDockWidget("TRI_overall estimation graph", self)
260 dock.setWidget(TriEstimationGraph(self.sample_box, 'TRI_overall_estimations', self, dock))
261 self.dockables.append(dock)
262 self.tabifyDockWidget(self.dockables[0], dock)
263
264 dock = QtGui.QDockWidget("Simplex estimation graph", self)
265 dock.setWidget(SimpleSimplexEstimationGraph(self.sample_box, self, dock))
266 self.dockables.append(dock)
267 self.tabifyDockWidget(self.dockables[0], dock)
268
269 dock = QtGui.QDockWidget("Simplex error graph", self)
270 dock.setWidget(SimplexErrorGraph(self.simplex_data, dock))
271 self.dockables.append(dock)
272 self.tabifyDockWidget(self.dockables[0], dock)
273
274
275 dock = QtGui.QDockWidget("Voronoi estimation graph", self)
276 dock.setWidget(VoronoiEstimationGraph(self.sample_box, self, dock))
277 self.dockables.append(dock)
278 self.tabifyDockWidget(self.dockables[0], dock)
279
280
281
282
283 dock = dock_l = QtGui.QDockWidget("Box tree", self)
284 dock.setWidget(BoxTreeWidget(self, dock))
285 self.dockables.append(dock)
286 self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
287
288
289
290 dock = QtGui.QDockWidget("View", self)
291 dock.setWidget(self.list_view)
292 self.dockables.append(dock)
293 self.tabifyDockWidget(dock_l, dock)
294
295
296
297
298 for dock in self.dockables:
299 self.view.addAction(dock.toggleViewAction())
300 #dock.setFloating(True)
301
302 #self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
303
304
305
306 37
307 38
308 39 def plot_setup(self): def plot_setup(self):
 
... ... class QtGuiPlot2D(QtGui.QMainWindow):
348 79 self.tabifyDockWidget(dock_r, dock) self.tabifyDockWidget(dock_r, dock)
349 80
350 81
351 #
352 #č Tlačítka!
353 #
354
355 # INHERITED by gl_plot
356 def _slider_chainged(self, value):
357 #č .setMaximum() nezpůsobuje emitování slice_changed, jsem zkontroloval
358 self.slider.setMaximum(self.sample_box.nsim)
359 self.label_nsim.setText(str(value))
360 if not self.slider.isSliderDown(): # co to vůbec děla?
361 self.slice_changed.emit()
362
363 # INHERITED by gl_plot
364 def change_space(self, space):
365 self.space = space
366 self.space_changed.emit()
367 #self.plot_widget_2d()
368 #self.slice_plot_data()
369
370 # INHERITED by gl_plot
371 def run_sb(self):
372 with pg.BusyCursor():
373 self.last_shot = self.sample_box()
374
375 # slider
376 #č zpusobí slice_changed
377 self.slider.setMaximum(self.sample_box.nsim)
378 self.slider.setValue(self.sample_box.nsim)
379
380 self.box_runned.emit()
381
382
383
384 # INHERITED by gl_plot
385 def bx_connect(self):
386 if self.btn2.isChecked():
387 try:
388 self.sample_box.connect(self.logger)
389 except BaseException as e:
390 print(self.__class__.__name__ + ":", "connection to BlackBox failed", repr(e))
391 else:
392 try:
393 self.sample_box.disconnect()
394 except BaseException as e:
395 print(self.__class__.__name__ + ":", "error while disconnecting of BlackBox", repr(e))
396
397 # INHERITED by gl_plot
398 def logger(self, *args, msg="", indent=0, **kwargs):
399 self.continue_label.setText("BlackBox: " + msg)
400 self.output_label.setText(str(args) + str(kwargs))
401
402 loop = QtCore.QEventLoop()
403 self.btn_continue.clicked.connect(loop.quit)
404 self.btn_continue.show()
405 self.continue_label.show()
406 # i want to clear status bar temporaly
407 status = self.statusBar.currentMessage()
408 self.statusBar.clearMessage()
409
410 loop.exec_() # Execution stops here until finished called
411
412 self.btn_continue.hide()
413 self.continue_label.hide()
414 self.statusBar.showMessage(status)
415
416
417 def batch_run(self):
418 #pg.QtGui.QInputDialog.getInt(
419 runs, ok = QtGui.QInputDialog.getInt(self,"Batch run","runs")
420
421 if ok:
422 with pg.ProgressDialog("Running..", 0, runs, cancelText='Stop', busyCursor=True) as dlg:
423 for i in range(runs):
424 # keep the GUI responsive :)
425 self.app.processEvents()
426
427 self.last_shot = self.sample_box()
428
429 # slider
430 #č zpusobí slice_changed
431 self.slider.setMaximum(self.sample_box.nsim)
432 self.slider.setValue(self.sample_box.nsim)
433
434 self.box_runned.emit()
435
436 dlg += 1
437 if dlg.wasCanceled():
438 break
439
440
441
442 82
443 83
444 84
 
... ... class ConvexHull2D(Triangulation):
1220 860
1221 861
1222 862
1223
1224 """
1225 =============
1226 График виӝет
1227 Grafy
1228 Estimation graph widgets
1229 ========================
1230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1231 """
1232
1233
1234 def get_estimation_data(estimations, metric):
1235 metric_dict = dict()
1236 # new-style: šecko leží dohromady a každý z toho
1237 # bere co chce a jak chce
1238 # ne že by to bylo nějak šetrný
1239 # estimation je slovníkem
1240 for estimation in estimations:
1241 # nsim musí mäť každej odhad
1242 # pokud nemá - je třeba jej prostě opravit
1243 nsim = estimation['nsim']
1244 try:
1245 metric_dict[nsim] = estimation[metric]
1246 except KeyError as e:
1247 pass #print(self.__class__.__name__ + ":", repr(e))
1248
1249 # nikdo neslibil, že budou v pořadí
1250 x = np.sort(tuple(metric_dict.keys()))
1251 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
1252 return x, y
1253
1254
1255 class SimplexEstimationData(QtCore.QObject):
1256 #š budeme mӓť svůj vlastní signaľčík
1257 simplex_estimation_updated = QtCore.pyqtSignal()
1258
1259 def __init__(self, dice_box, stream=None, *args, **kwargs):
1260 super().__init__(stream, *args, **kwargs)
1261 self.dice_box = dice_box
1262 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1263 #č asi aby nepadalo, když nenajde signaly
1264 self.stream = stream
1265 if stream is not None:
1266 self.stream.box_runned.connect(self.recalculate)
1267 self.stream.estimation_added.connect(self.recalculate)
1268
1269 self.setup_context_menu()
1270 self.recalculate()
1271
1272
1273 def setup_context_menu(self):
1274 # simplex_data_menu
1275 self.TRI_menu = QtGui.QMenu("TRI sources", self.stream)
1276
1277 self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu)
1278 self.TRI_overall_chk.setCheckable(True)
1279 self.TRI_overall_chk.setChecked(True)
1280 self.TRI_overall_chk.triggered.connect(self.recalculate)
1281 self.TRI_menu.addAction(self.TRI_overall_chk)
1282
1283 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
1284 self.simplex_chk.setCheckable(True)
1285 self.simplex_chk.setChecked(True)
1286 self.simplex_chk.triggered.connect(self.recalculate)
1287 self.TRI_menu.addAction(self.simplex_chk)
1288
1289 # year, it was
1290 ## hope, it is temporary
1291 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
1292 #self.sources_action_group.addAction(self.TRI_overall_chk)
1293 #self.sources_action_group.addAction(self.simplex_chk)
1294
1295 self.TRI_menu.addSeparator()
1296
1297 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
1298 self.proxy_chk.setCheckable(True)
1299 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
1300 self.proxy_chk.triggered.connect(self.recalculate)
1301 self.TRI_menu.addAction(self.proxy_chk)
1302
1303 self.TRI_menu.addSeparator()
1304
1305 self.reaction = QtGui.QAction("Update", self.TRI_menu)
1306 self.reaction.triggered.connect(self.recalculate)
1307 self.TRI_menu.addAction(self.reaction)
1308
1309 self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
1310 self.excelaction.triggered.connect(self.export_to_excel)
1311 self.TRI_menu.addAction(self.excelaction)
1312
1313
1314 def export_to_excel(self):
1315 #č já bych nechtěl, aby mně export najednou spadl
1316 #č z jakéhokoliv důvodu
1317 try:
1318 proposal_filename = self.dice_box.guessbox.filename
1319 if proposal_filename:
1320 proposal_filename += '.xlsx'
1321 else:
1322 proposal_filename = self.dice_box.gm_signature + '.xlsx'
1323 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
1324 proposal_filename, initialFilter='*.xlsx')
1325 self.df.to_excel(filename)
1326 except BaseException as e:
1327 print(self.__class__.__name__ + ":", repr(e))
1328
1329
1330 def recalculate(self):
1331 try:
1332 # sources=['box', 'user']
1333 sources = list()
1334 if self.TRI_overall_chk.isChecked():
1335 sources.append('box')
1336 if self.simplex_chk.isChecked():
1337 sources.append('user')
1338
1339 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
1340 apply_proxy=self.proxy_chk.isChecked())
1341 self.simplex_estimation_updated.emit()
1342
1343 except BaseException as e:
1344 print(self.__class__.__name__ + ":", repr(e))
1345
1346
1347
1348 class SimplexEstimationGraph(pg.PlotWidget):
1349 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
1350 super().__init__(parent, *args, **kwargs)
1351 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1352 #č asi aby nepadalo, když nenajde signaly
1353 self.stream = stream
1354 if stream is not None:
1355 self.stream.box_runned.connect(self.redraw)
1356 self.stream.estimation_added.connect(self.redraw)
1357
1358 self.dice_box = dice_box
1359
1360 self.setup_context_menu()
1361 self.setup()
1362 self.replot()
1363
1364 def setup_context_menu(self):
1365 # creates instance of LegendItem
1366 # and saves it into plotItem.legend
1367 self.legend = self.addLegend()
1368
1369 self.plotItem.ctrl.xGridCheck.setChecked(True)
1370 self.plotItem.ctrl.yGridCheck.setChecked(True)
1371
1372 # delete build-in Transforms (with Log_x and Log_y) options,
1373 # they can cause uncachable exception (on any zero in data) and crash
1374 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
1375
1376 #č já se bojím. radší to uložím
1377 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
1378
1379 self.plotItem.vb.menu.addMenu(self.stream.simplex_data.TRI_menu)
1380
1381 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1382 self.legend_chk.setCheckable(True)
1383 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1384 self.custom_menu.addAction(self.legend_chk)
1385 # apply custom menu option
1386 self.legend.setVisible(self.legend_chk.isChecked())
1387
1388 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
1389 self.log_x_chk.setCheckable(True)
1390 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
1391 self.custom_menu.addAction(self.log_x_chk)
1392
1393 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
1394 self.log_y_chk.setCheckable(True)
1395 self.log_y_chk.setChecked(True)
1396 self.log_y_chk.triggered.connect(self.replot)
1397 self.custom_menu.addAction(self.log_y_chk)
1398
1399 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1400 self.laction.triggered.connect(self.show_labels)
1401 self.custom_menu.addAction(self.laction)
1402
1403
1404 def show_labels(self):
1405 self.setLabel('left', "Probability measure")
1406 self.setLabel('bottom', "Number of simulations")
1407
1408
1409
1410 # self.legend.addItem(self.pen_success, "success domain estimation")
1411 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
1412 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
1413 # self.legend.addItem(self.pen_f, "failure domain estimation")
1414
1415 def setup(self, *args, **kwargs):
1416 self.clear()
1417 self.setBackground('w')
1418 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1419
1420 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
1421 green = (0, 255, 38, 96)
1422 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1423 red = (253, 0, 17, 96)
1424 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
1425 cream = (255, 221, 0, 96)
1426 grey = (196, 196, 196, 96)
1427
1428 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1429 self.pen_f.setZValue(-100)
1430
1431 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
1432 self.pen_success.setZValue(-100)
1433
1434 self.pen_outmix = self.plot(x, y)
1435
1436 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
1437 #self.fill_mix.setData(name="mixed simplices measure")
1438 self.fill_mix.setBrush(cream)
1439 self.fill_mix.setZValue(-100)
1440 self.addItem(self.fill_mix)
1441
1442 #self.pen_outside = self.plot(x, y)
1443 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
1444 #self.fill_outside.setData(name="out of sampling domain estimation")
1445 self.fill_outside.setBrush(grey)
1446 self.fill_outside.setZValue(-100)
1447 self.addItem(self.fill_outside)
1448
1449 self.one_ruler = self.addLine(y=1, pen='k')
1450 self.zero_ruler = self.addLine(y=0, pen='k')
1451
1452
1453 try:
1454 exact_name = self.dice_box.pf_exact_method
1455 pen = pg.mkPen(color='b', width=1.5) # blue
1456 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
1457 #č aby se nám něco zobrazovalo v legendu
1458 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
1459 except:
1460 pass
1461
1462 pen = pg.mkPen(color='m', width=2)
1463 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1464 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1465 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1466
1467
1468
1469
1470
1471 def replot(self, *args, **kwargs):
1472 if self.log_y_chk.isChecked():
1473 self.one_ruler.hide()
1474 try:
1475 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
1476 if self.dice_box.pf_exact > 0:
1477 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
1478 self.pen_exact.show()
1479 else:
1480 self.pen_exact.hide()
1481 except:
1482 pass
1483 self.setLogMode(y=True)
1484 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
1485 self.pen_f.setPen(None)
1486 self.pen_f.setFillLevel(None)
1487 self.pen_success.setFillLevel(0)
1488
1489 else:
1490 self.one_ruler.show()
1491 try:
1492 self.pen_exact.setPos(self.dice_box.pf_exact)
1493 self.pen_exact.show()
1494 except:
1495 pass
1496 self.setLogMode(y=False)
1497 self.pen_f.setPen(None)
1498 self.pen_f.setFillLevel(0)
1499 self.pen_success.setFillLevel(1)
1500
1501 self.redraw()
1502
1503
1504 #č když se někde objeví nula se zapnutým LogModem -
1505 #č qtpygraph hned spadne a není možne ten pad zachytit
1506 def zerosafe(self, x, y, fallback_y=None):
1507 if self.log_y_chk.isChecked():
1508 x = np.array(x)
1509 y = np.array(y)
1510 if fallback_y is None:
1511 fallback_y = y
1512 y = np.where(y > 0, y, fallback_y)
1513 mask = y > 0
1514 return x[mask], y[mask]
1515 else:
1516 return x, y
1517
1518 def proxy(self, nsim):
1519 if self.proxy_chk.isChecked():
1520 proxy = self.dice_box.proxy
1521 index = np.array(nsim)-1
1522 #č indexy musíme o jedničku změnšit
1523 #č výsledek nikoliv. Takže v cajku.
1524 return np.cumsum(~proxy)[index]
1525 else:
1526 return nsim
1527
1528
1529 def _pens_data_update(self):
1530 df = self.df
1531 nsim = df.nsim.to_numpy()
1532 if self.proxy_chk.isChecked():
1533 x = self.proxy(nsim)
1534 df.insert(loc=0, column='nsim (proxy)', value=x)
1535 else:
1536 x = nsim
1537 # (in case of LogPlot) fallback values also used
1538 success_values = df.failure+df.mix+df.out
1539 outmix_values = df.failure+df.mix
1540 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
1541 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
1542 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
1543 self.pen_success.setData(*self.zerosafe(x, success_values))
1544
1545
1546 def redraw(self):
1547 xmin = np.inf
1548 xmax = -np.inf
1549 tri_estimation = dict()
1550 try: # тут всё что угодно может пойти не так
1551 # kruci, ještě navic i generovať pokažde znovu...
1552
1553 # new-style: šecko leží dohromady a každý si z toho
1554 # bere co chce a jak chce
1555 # ne že by to bylo nějak šetrný
1556 # estimation je slovníkem
1557 for estimation in self.dice_box.estimations:
1558 # nsim musí mäť každej odhad
1559 # pokud nemá - je třeba jej prostě opravit
1560 nsim = estimation['nsim']
1561 try:
1562 tri_estimation[nsim] = estimation['TRI_estimation']
1563 if nsim > xmax:
1564 xmax = nsim
1565 if nsim < xmin:
1566 xmin = nsim
1567
1568 except KeyError as e:
1569 pass #print(self.__class__.__name__ + ":", repr(e))
1570
1571 #č neotravuj uživatele chybovejma hlaškama
1572 if tri_estimation:
1573 # it can be effectively done with pandas
1574 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1575 # -1 = 'out', 0=success, 1=failure, 2=mix
1576 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1577 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1578 df.sort_values('nsim', inplace=True)
1579
1580 self._pens_data_update()
1581
1582 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1583 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1584 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1585
1586 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1587 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1588 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1589
1590
1591 except BaseException as e:
1592 print(self.__class__.__name__ + ":", repr(e))
1593
1594
1595
1596 class SimplexErrorGraph(pg.PlotWidget):
1597 def __init__(self, simplex_data, parent=None, *args, **kwargs):
1598 super().__init__(parent, *args, **kwargs)
1599 self.simplex_data = simplex_data
1600 self.simplex_data.simplex_estimation_updated.connect(self.redraw)
1601
1602 self.setup_context_menu()
1603 self.setup()
1604
1605 def setup_context_menu(self):
1606 # creates instance of LegendItem
1607 # and saves it into plotItem.legend
1608 self.legend = self.addLegend()
1609
1610 self.plotItem.ctrl.xGridCheck.setChecked(True)
1611 self.plotItem.ctrl.yGridCheck.setChecked(True)
1612
1613 # menu of SimplexEstimationData
1614 self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
1615
1616 #č já se bojím. radší to uložím
1617 self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
1618
1619 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1620 self.legend_chk.setCheckable(True)
1621 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1622 self.custom_menu.addAction(self.legend_chk)
1623 # apply custom menu option
1624 self.legend.setVisible(self.legend_chk.isChecked())
1625
1626 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1627 self.laction.triggered.connect(self.show_labels)
1628 self.custom_menu.addAction(self.laction)
1629
1630
1631 def show_labels(self):
1632 self.setLabel('left', "Failure probability estimation error")
1633 self.setLabel('bottom', "Number of simulations")
1634
1635
1636 def setup(self, *args, **kwargs):
1637 self.clear()
1638 self.setBackground('w')
1639 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1640
1641 # We will use logMode by default
1642 self.setLogMode(y=True)
1643
1644 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1645 #red = (253, 0, 17, 96)
1646
1647 #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1648 #self.pen_f.setZValue(-100)
1649
1650
1651 pen = pg.mkPen(color='m', width=2)
1652 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1653 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1654 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1655
1656
1657
1658 #č když se někde objeví nula se zapnutým LogModem -
1659 #č qtpygraph hned spadne a není možne ten pad zachytit
1660 def zerosafe(self, x, y, fallback_y=None):
1661 x = np.array(x)
1662 y = np.array(y)
1663 if fallback_y is None:
1664 fallback_y = y
1665 y = np.where(y > 0, y, fallback_y)
1666 mask = y > 0
1667 return x[mask], y[mask]
1668
1669
1670 def redraw(self):
1671 #č neotravujme uživatele chybovejma hlaškama
1672 if hasattr(self.simplex_data.dice_box, 'pf_exact'):
1673 try: #ё тут всё что угодно может пойти не так
1674 pf_exact = self.simplex_data.dice_box.pf_exact
1675
1676 df = self.simplex_data.df
1677 #č zapíšeme do data rámu, snad nikomu nebude vadit
1678 df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
1679 df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
1680
1681 v = df['vertex_estimation_error'].abs()
1682 wv = df['weighted_vertex_estimation_error'].abs()
1683
1684 x, y = self.zerosafe(v.index, v.to_numpy())
1685 self.pen_vertex.setData(x, y)
1686
1687 x, y = self.zerosafe(wv.index, wv.to_numpy())
1688 self.pen_weighted_vertex.setData(x, y)
1689
1690
1691 except BaseException as e:
1692 print(self.__class__.__name__ + ":", repr(e))
1693
1694
1695
1696
1697
1698
1699
1700 # DEPRECATED
1701 class SimpleSimplexEstimationGraph(pg.PlotWidget):
1702 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
1703 super().__init__(parent, *args, **kwargs)
1704 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
1705 #č asi aby nepadalo, když nenajde signaly
1706 self.stream = stream
1707 if stream is not None:
1708 self.stream.box_runned.connect(self.redraw)
1709 self.stream.estimation_added.connect(self.redraw)
1710
1711 self.dice_box = dice_box
1712
1713 self.setup_context_menu()
1714 self.setup()
1715 self.replot()
1716
1717 def setup_context_menu(self):
1718 # creates instance of LegendItem
1719 # and saves it into plotItem.legend
1720 self.legend = self.addLegend()
1721
1722 self.plotItem.ctrl.xGridCheck.setChecked(True)
1723 self.plotItem.ctrl.yGridCheck.setChecked(True)
1724
1725 # delete build-in Transforms (with Log_x and Log_y) options,
1726 # they can cause uncachable exception (on any zero in data) and crash
1727 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
1728
1729 #č já se bojím. radší to uložím
1730 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
1731
1732 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
1733 self.legend_chk.setCheckable(True)
1734 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
1735 self.custom_menu.addAction(self.legend_chk)
1736 # apply custom menu option
1737 self.legend.setVisible(self.legend_chk.isChecked())
1738
1739 self.proxy_chk = QtGui.QAction("Proxy", self.custom_menu)
1740 self.proxy_chk.setCheckable(True)
1741 self.proxy_chk.triggered.connect(self.redraw)
1742 self.custom_menu.addAction(self.proxy_chk)
1743
1744 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
1745 self.log_x_chk.setCheckable(True)
1746 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
1747 self.custom_menu.addAction(self.log_x_chk)
1748
1749 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
1750 self.log_y_chk.setCheckable(True)
1751 self.log_y_chk.setChecked(True)
1752 self.log_y_chk.triggered.connect(self.replot)
1753 self.custom_menu.addAction(self.log_y_chk)
1754
1755 self.reaction = QtGui.QAction("Redraw", self.custom_menu)
1756 self.reaction.triggered.connect(self.redraw)
1757 self.custom_menu.addAction(self.reaction)
1758
1759 self.laction = QtGui.QAction("Show labels", self.custom_menu)
1760 self.laction.triggered.connect(self.show_labels)
1761 self.custom_menu.addAction(self.laction)
1762
1763 self.excelaction = QtGui.QAction("Export to Excel", self.custom_menu)
1764 self.excelaction.triggered.connect(self.export_to_excel)
1765 self.custom_menu.addAction(self.excelaction)
1766
1767
1768 def export_to_excel(self):
1769 #č já bych nechtěl, aby mně export najednou spadl
1770 #č z jakéhokoliv důvodu
1771 try:
1772 proposal_filename = self.dice_box.guessbox.filename
1773 if proposal_filename:
1774 proposal_filename += '.xlsx'
1775 else:
1776 proposal_filename = self.dice_box.gm_signature + '.xlsx'
1777 filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
1778 proposal_filename, initialFilter='*.xlsx')
1779 self.df.to_excel(filename)
1780 except BaseException as e:
1781 print(self.__class__.__name__ + ":", repr(e))
1782
1783 def show_labels(self):
1784 self.setLabel('left', "Probability measure")
1785 self.setLabel('bottom', "Number of simulations")
1786
1787
1788
1789 # self.legend.addItem(self.pen_success, "success domain estimation")
1790 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
1791 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
1792 # self.legend.addItem(self.pen_f, "failure domain estimation")
1793
1794 def setup(self, *args, **kwargs):
1795 self.clear()
1796 self.setBackground('w')
1797 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
1798
1799 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
1800 green = (0, 255, 38, 96)
1801 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
1802 red = (253, 0, 17, 96)
1803 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
1804 cream = (255, 221, 0, 96)
1805 grey = (196, 196, 196, 96)
1806
1807 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
1808 self.pen_f.setZValue(-100)
1809
1810 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
1811 self.pen_success.setZValue(-100)
1812
1813 self.pen_outmix = self.plot(x, y)
1814
1815 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
1816 #self.fill_mix.setData(name="mixed simplices measure")
1817 self.fill_mix.setBrush(cream)
1818 self.fill_mix.setZValue(-100)
1819 self.addItem(self.fill_mix)
1820
1821 #self.pen_outside = self.plot(x, y)
1822 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
1823 #self.fill_outside.setData(name="out of sampling domain estimation")
1824 self.fill_outside.setBrush(grey)
1825 self.fill_outside.setZValue(-100)
1826 self.addItem(self.fill_outside)
1827
1828 self.one_ruler = self.addLine(y=1, pen='k')
1829 self.zero_ruler = self.addLine(y=0, pen='k')
1830
1831
1832 try:
1833 exact_name = self.dice_box.pf_exact_method
1834 pen = pg.mkPen(color='b', width=1.5) # blue
1835 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
1836 #č aby se nám něco zobrazovalo v legendu
1837 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
1838 except:
1839 pass
1840
1841 pen = pg.mkPen(color='m', width=2)
1842 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
1843 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
1844 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
1845
1846
1847
1848
1849
1850 def replot(self, *args, **kwargs):
1851 if self.log_y_chk.isChecked():
1852 self.one_ruler.hide()
1853 try:
1854 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
1855 if self.dice_box.pf_exact > 0:
1856 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
1857 self.pen_exact.show()
1858 else:
1859 self.pen_exact.hide()
1860 except:
1861 pass
1862 self.setLogMode(y=True)
1863 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
1864 self.pen_f.setPen(None)
1865 self.pen_f.setFillLevel(None)
1866 self.pen_success.setFillLevel(0)
1867
1868 else:
1869 self.one_ruler.show()
1870 try:
1871 self.pen_exact.setPos(self.dice_box.pf_exact)
1872 self.pen_exact.show()
1873 except:
1874 pass
1875 self.setLogMode(y=False)
1876 self.pen_f.setPen(None)
1877 self.pen_f.setFillLevel(0)
1878 self.pen_success.setFillLevel(1)
1879
1880 self.redraw()
1881
1882
1883 #č když se někde objeví nula se zapnutým LogModem -
1884 #č qtpygraph hned spadne a není možne ten pad zachytit
1885 def zerosafe(self, x, y, fallback_y=None):
1886 if self.log_y_chk.isChecked():
1887 x = np.array(x)
1888 y = np.array(y)
1889 if fallback_y is None:
1890 fallback_y = y
1891 y = np.where(y > 0, y, fallback_y)
1892 mask = y > 0
1893 return x[mask], y[mask]
1894 else:
1895 return x, y
1896
1897 def proxy(self, nsim):
1898 if self.proxy_chk.isChecked():
1899 proxy = self.dice_box.proxy
1900 index = np.array(nsim)-1
1901 #č indexy musíme o jedničku změnšit
1902 #č výsledek nikoliv. Takže v cajku.
1903 return np.cumsum(~proxy)[index]
1904 else:
1905 return nsim
1906
1907
1908 def _pens_data_update(self):
1909 df = self.df
1910 nsim = df.nsim.to_numpy()
1911 if self.proxy_chk.isChecked():
1912 x = self.proxy(nsim)
1913 df.insert(loc=0, column='nsim (proxy)', value=x)
1914 else:
1915 x = nsim
1916 # (in case of LogPlot) fallback values also used
1917 success_values = df.failure+df.mix+df.out
1918 outmix_values = df.failure+df.mix
1919 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
1920 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
1921 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
1922 self.pen_success.setData(*self.zerosafe(x, success_values))
1923
1924
1925 def redraw(self):
1926 xmin = np.inf
1927 xmax = -np.inf
1928 tri_estimation = dict()
1929 try: # тут всё что угодно может пойти не так
1930 # kruci, ještě navic i generovať pokažde znovu...
1931
1932 # new-style: šecko leží dohromady a každý si z toho
1933 # bere co chce a jak chce
1934 # ne že by to bylo nějak šetrný
1935 # estimation je slovníkem
1936 for estimation in self.dice_box.estimations:
1937 # nsim musí mäť každej odhad
1938 # pokud nemá - je třeba jej prostě opravit
1939 nsim = estimation['nsim']
1940 try:
1941 tri_estimation[nsim] = estimation['TRI_estimation']
1942 if nsim > xmax:
1943 xmax = nsim
1944 if nsim < xmin:
1945 xmin = nsim
1946
1947 except KeyError as e:
1948 pass #print(self.__class__.__name__ + ":", repr(e))
1949
1950 #č neotravuj uživatele chybovejma hlaškama
1951 if tri_estimation:
1952 # it can be effectively done with pandas
1953 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1954 # -1 = 'out', 0=success, 1=failure, 2=mix
1955 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1956 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1957 df.sort_values('nsim', inplace=True)
1958
1959 self._pens_data_update()
1960
1961 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1962 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1963 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1964
1965 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1966 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1967 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1968
1969
1970 except BaseException as e:
1971 print(self.__class__.__name__ + ":", repr(e))
1972
1973
1974 # DEPRECATED
1975 class TriEstimationGraph(SimpleSimplexEstimationGraph):
1976 def __init__(self, dice_box, tri_estimation_name='TRI_overall_estimations', stream=None, parent=None, *args, **kwargs):
1977 self.tri_estimation_name = tri_estimation_name
1978 super().__init__(dice_box, stream, parent, *args, **kwargs)
1979
1980
1981
1982 def redraw(self):
1983 try: # тут всё что угодно может пойти не так
1984 data = self.dice_box.guessbox.estimations[self.tri_estimation_name]
1985 nsim, tri_data = data
1986 # it can be effectively done with pandas
1987 self.df = df = pd.DataFrame(tri_data)
1988 # -1 = 'out', 0=success, 1=failure, 2=mix
1989 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1990 df.insert(loc=0, column='nsim', value=nsim)
1991
1992 # Update the data
1993 self._pens_data_update()
1994
1995 if 'vertex_estimation' in self.dice_box.guessbox.estimations:
1996 data = self.dice_box.guessbox.estimations['vertex_estimation']
1997 nsim, y = data
1998 # Update the data
1999 #č spolehám na konzistenci blackboxu, ne však úplně
2000 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
2001 df['vertex_estimation'] = y
2002
2003 if 'weighted_vertex_estimation' in self.dice_box.guessbox.estimations:
2004 data = self.dice_box.guessbox.estimations['weighted_vertex_estimation']
2005 nsim, y = data
2006 # Update the data
2007 #č spolehám na konzistenci blackboxu, ne však úplně
2008 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
2009 df['weighted_vertex_estimation'] = y
2010
2011
2012 # BaseException
2013 except BaseException as e:
2014 print(self.__class__.__name__ + ":", repr(e))
2015
2016
2017
2018
2019
2020
2021
2022 class VoronoiEstimationGraph(pg.PlotWidget):
2023 def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
2024 super().__init__(parent)
2025 self.sb_item = samplebox_item
2026 self.sb_item.box_runned.connect(self.redraw)
2027 self.sb_item.estimation_added.connect(self.redraw)
2028
2029 self.black_box = black_box
2030 self.setBackground('w')
2031
2032
2033 self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
2034 self.reaction.triggered.connect(self.redraw)
2035 self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
2036
2037
2038
2039 # implicitně Y je v logaritmickem měřítku
2040 self.setLogMode(False, True)
2041
2042 x = y = () # zde jen vytvoříme kostru, nakrmíme daty v .redraw()
2043
2044
2045 # nechapu, proč těm Itemům ríkám "propíska"
2046 # propíska? Их есть у нас!
2047
2048 self.Voronoi_2_point_upper_bound = self.plot(x, y, pen='y')
2049 self.Voronoi_2_point_lower_bound = self.plot(x, y, pen='y')
2050
2051 fill_color = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
2052 self.fill = pg.FillBetweenItem(self.Voronoi_2_point_upper_bound, self.Voronoi_2_point_lower_bound, fill_color)
2053 self.addItem(self.fill)
2054
2055 self.Voronoi_2_point_failure_rate = self.plot(x, y, pen=(195,46,212))
2056 self.Voronoi_2_point_pure_failure_rate = self.plot(x, y, pen='m')
2057 self.Voronoi_failure_rate = self.plot(x, y, pen='r')
2058
2059 self.pen_exact = self.plot(x, y, pen='b') # blue
2060 self.pen_one = self.plot(x, y, pen='k') # black
2061
2062 self.redraw()
2063
2064
2065 def redraw(self):
2066 # kruci, ještě navic i generovať pokažde znovu...
2067 metrics = {'Voronoi_2_point_upper_bound':{},\
2068 'Voronoi_2_point_lower_bound':{},\
2069 'Voronoi_2_point_failure_rate':{},\
2070 'Voronoi_2_point_pure_failure_rate':{},\
2071 'Voronoi_failure_rate':{},}
2072 xmin = np.inf
2073 xmax = -np.inf
2074 try: # тут всё что угодно может пойти не так
2075 # new-style: šecko leží dohromady a každý z toho
2076 # bere co chce a jak chce
2077 # ne že by to bylo nějak šetrný
2078 # estimation je slovníkem
2079 for estimation in self.black_box.estimations:
2080 # nsim musí mäť každej odhad
2081 # pokud nemá - je třeba jej prostě opravit
2082 nsim = estimation['nsim']
2083
2084
2085 for metric, metric_dict in metrics.items():
2086 try:
2087 if estimation[metric] > 0:
2088 metric_dict[nsim] = estimation[metric]
2089 if nsim > xmax:
2090 xmax = nsim
2091 if nsim < xmin:
2092 xmin = nsim
2093 except KeyError as e:
2094 pass #print(self.__class__.__name__ + ":", repr(e))
2095
2096 for metric, metric_dict in metrics.items():
2097 pen = getattr(self, metric)
2098 # nikdo neslibil, že budou v pořadí
2099 x = np.sort(tuple(metric_dict.keys()))
2100 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
2101 pen.setData(x, y)
2102
2103 if (xmax - xmin) > 0:
2104 self.pen_one.setData((xmin,xmax), (1, 1))
2105 if hasattr(self.black_box, 'pf_exact'):
2106 # poslední. I když spadne, tak už nikomu moc nevadí
2107 self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
2108
2109 except BaseException as e:
2110 print(self.__class__.__name__ + ":", repr(e))
2111
2112
2113 # pen_f.opts['logMode']
2114 # pen_outside.setLogMode(False, False)
2115 #setLogMode(False, False)
2116 #f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
2117 #win.addItem(f)
2118
2119
2120
2121
2122
2123
2124
2125 863 """ """
2126 864 ============= =============
2127 865 Эскерон виӝет Эскерон виӝет
 
... ... class CandidatesWidget(pg.LayoutWidget):
3557 2295 # pass # pass
3558 2296
3559 2297
3560
3561 class BoxTreeWidget(pg.LayoutWidget):
3562 """
3563 """
3564 # I'd like to get access to the samplebox stuff via the container's reference,
3565 # but relying to Qt's parent mechanism makes me worry.
3566 def __init__(self, samplebox_item, parent=None, *args, **kwargs):
3567 super().__init__(parent)
3568 # sb like samplebox, of course
3569 self.sb_item = samplebox_item
3570
3571
3572 self.btn = QtGui.QPushButton('update')
3573 self.addWidget(self.btn, row=0, col=0)
3574 self.btn.clicked.connect(self.update)
3575
3576 #self.tree = pg.DataTreeWidget(self, data=self.get_data(samplebox_item))
3577 self.tree = pg.DataTreeWidget(self, data=dict())
3578 self.addWidget(self.tree, row=1, col=0)
3579
3580 def update(self, *args, **kwargs):
3581 try:
3582 self.tree.setData(self.get_data(self.sb_item), hideRoot=True)
3583 except BaseException as e:
3584 msg = ""
3585 error_msg = self.__class__.__name__ + ": " + msg + repr(e)
3586 print(error_msg)
3587
3588 @staticmethod
3589 def get_data(self): #č nenechej si splest tím "self", je to prostě reference na QtGuiPlot2D
3590 data_tree = dict()
3591 data_tree['self.sample_box'] = self.sample_box.__dict__
3592 try: # shapeshare
3593 data_tree['self.sample_box.shapeshare'] = self.sample_box.shapeshare.__dict__
3594 except AttributeError:
3595 pass
3596 try:
3597 data_tree['self.sample_box.dicebox'] = self.sample_box.dicebox.__dict__
3598 except AttributeError:
3599 pass
3600 try:
3601 data_tree['self.sample_box.reader'] = self.sample_box.reader.__dict__
3602 except AttributeError:
3603 pass
3604 try:
3605 data_tree['self.sample_box.samplebox'] = self.sample_box.samplebox.__dict__
3606 except AttributeError:
3607 pass
3608 try:
3609 data_tree['self.sample_box.candybox'] = self.sample_box.candybox.__dict__
3610 except AttributeError:
3611 pass
3612 try:
3613 data_tree['self.sample_box.f_model'] = self.sample_box.f_model.__dict__
3614 except AttributeError:
3615 pass
3616
3617 return data_tree
3618
3619
3620 2298
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/iam-git/WellMet

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/iam-git/WellMet

Clone this repository using git:
git clone git://git.rocketgit.com/user/iam-git/WellMet

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main