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: replace old copypaste by cleaned up EstimationGraph 515d0d8a892984f8a7667da874972daff3318d74 I am 2022-12-12 05:36:43
qt_gui: prepare new BoxEstimationData class; rework ErrorGraph 37387100715f980771a8a37f99eec3e723759cd3 I am 2022-12-11 23:17:06
dicebox.circumtri: replace ndim by nvar to make TriEstimation pandas-friendly 0824222ae4c9c1f3fede971481816ed9ded9707a I am 2022-12-11 23:14:05
step back: introduce box_estimations, keep "estimations" for user ones dde983d57423e28083980cbae05f0a81fc8311e6 I am 2022-12-10 03:54:09
simplex.BetterCubatureIntegration: hotfix f8a607e5d60c591eb81037010717519c1fe6e993 I am 2022-12-08 00:29:57
qt_gui.qt_gui: add EstimationTableWidget bb44fc8a056ed90906c217cfc95f7cabc6ef71eb I am 2022-12-07 23:17:42
remove deprecated never used Plotly code d42ebb3535e4736a1e9fdb84c8d6dae633c83a33 I am 2022-12-07 15:03:51
dicebox.circumtri.CircumTri: enable estimations 4fe25ad47d71b1fd19fe00ad03d9b320b8c8614c I am 2022-12-07 14:30:46
dicebox: introduce new clean experimental CircumTri box aca3e971212590a59e9d07a3ff1aa952d02a848b I am 2022-12-07 04:19:55
simplex.Triangulation: keep locally pdfs and failsi, send tuple on simplex invalidation d2885ce44585e22294f9940159d6313642164f4c I am 2022-12-07 04:14:05
convex_hull.QHull: manual update() fix 5ccff702b9920c7525c88d306f2300cd43b2e76b I am 2022-12-07 04:02:39
simplex: implement BetterCubatureIntegration 88b14adc4423f0587bd51bed06e74ce6d0d60bd1 I am 2022-12-05 22:20:31
convex_hull.BrickHull: add get_hyperplane_distances() method a use it as fallback for the Qhull 48d35c953a5cbbf739e5e838709bc00fe2f047d4 I am 2022-12-05 03:30:12
convex_hull.Qhull: add get_hyperplane_distances() method, add auto_update parameter 28aada4b79b52f58c4ad43d270be997ec6359166 I am 2022-12-04 22:49:41
move diceboxes to the dedicated drawer 31c7d30ed43f04b9469df843f909814c062adf5e I am 2022-12-04 21:27:37
reader: finally, add new Store class for the estimations 673b7daa8213807d0217089b3317674595156f6d I am 2022-12-03 17:46:22
f_models.SNorm: hotfix 5f364d1770e18d18fb810760b6207c905b551762 I am 2022-12-02 21:33:48
f_models: rewrite SNorm in lazy way. Old SNorm class renamed to SNormClassic 3b6805b2a1d0bce88960bc016bbe74bb5274810b I am 2022-12-02 21:11:37
simplex: implement CircumCenter class 0a1a67122854cfb331f696163f22cfc67331f3e8 I am 2022-12-01 01:40:38
voronoi.ContactVoronoi: add explore_couple() method 72f4dffa5e8e7ee3165df4648f6a35d75d6678a3 I am 2022-11-29 11:59:07
Commit 515d0d8a892984f8a7667da874972daff3318d74 - qt_gui: replace old copypaste by cleaned up EstimationGraph
Author: I am
Author date (UTC): 2022-12-12 05:36
Committer name: I am
Committer date (UTC): 2022-12-12 05:36
Parent(s): 37387100715f980771a8a37f99eec3e723759cd3
Signer:
Signing key:
Signing status: N
Tree: 719d4a7b5c36ed69c03ea9c6d88008dd88053932
File Lines added Lines deleted
wellmet/qt_gui/qt_graph_widgets.py 132 629
wellmet/qt_gui/qt_gui.py 21 21
File wellmet/qt_gui/qt_graph_widgets.py changed (mode: 100644) (index 6d8e689..505aa7b)
... ... class BoxEstimationData(QtCore.QObject):
191 191 #č z jakéhokoliv důvodu #č z jakéhokoliv důvodu
192 192 try: try:
193 193 proposal_filename = '.xlsx' proposal_filename = '.xlsx'
194 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
194 filename, *__ = pg.FileDialog.getSaveFileName(None, 'Export to Excel',\
195 195 proposal_filename, initialFilter='*.xlsx') proposal_filename, initialFilter='*.xlsx')
196 196 if filename: if filename:
197 197 self.df.to_excel(filename) self.df.to_excel(filename)
 
... ... class BoxEstimationData(QtCore.QObject):
214 214
215 215
216 216 class ErrorGraph(pg.PlotWidget): class ErrorGraph(pg.PlotWidget):
217 def __init__(self, pf_exact, signal, menu, parent=None, *args, **kwargs):
217 def __init__(self, pf_exact, box_data, parent=None, *args, **kwargs):
218 218 super().__init__(parent, *args, **kwargs) super().__init__(parent, *args, **kwargs)
219 219
220 220 self.pf_exact = pf_exact self.pf_exact = pf_exact
221 221
222 signal.connect(self.redraw)
222 self.box_data = box_data
223 box_data.estimations_updated.connect(self.redraw)
223 224
224 self.setup_context_menu(menu)
225 self.setup_context_menu(box_data.TRI_menu)
225 226 self.setup() self.setup()
227 self.redraw(box_data.df)
226 228
227 229 def setup_context_menu(self, menu): def setup_context_menu(self, menu):
228 230 # creates instance of LegendItem # creates instance of LegendItem
 
... ... class ErrorGraph(pg.PlotWidget):
276 278 # df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact # df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
277 279 # df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact # df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
278 280
279 v = (df['vertex_estimation'] - self.pf_exact).abs()
280 wv = (df['weighted_vertex_estimation'] - self.pf_exact).abs()
281 if len(v) > 1: #č nevím proč hazí chyby. Asi kvůli zadané širce.
281 if len(df) < 2: #č nevím proč hazí chyby. Asi kvůli zadané širce.
282 return
283
284 if 'vertex_estimation' in df:
285 v = (df['vertex_estimation'] - self.pf_exact).abs()
282 286 self.pen_vertex.setData(v.index.to_numpy(), v.to_numpy()) self.pen_vertex.setData(v.index.to_numpy(), v.to_numpy())
287 if 'weighted_vertex_estimation' in df:
288 wv = (df['weighted_vertex_estimation'] - self.pf_exact).abs()
283 289 self.pen_weighted_vertex.setData(wv.index.to_numpy(), wv.to_numpy()) self.pen_weighted_vertex.setData(wv.index.to_numpy(), wv.to_numpy())
284 290
285 291
 
... ... class ErrorGraph(pg.PlotWidget):
290 296
291 297
292 298
293
294
295
296
297
298
299 #
300 # DEPRECATED
301 #
302
303
304 def get_estimation_data(estimations, metric):
305 metric_dict = dict()
306 # new-style: šecko leží dohromady a každý z toho
307 # bere co chce a jak chce
308 # ne že by to bylo nějak šetrný
309 # estimation je slovníkem
310 for estimation in estimations:
311 # nsim musí mäť každej odhad
312 # pokud nemá - je třeba jej prostě opravit
313 nsim = estimation['nsim']
314 try:
315 metric_dict[nsim] = estimation[metric]
316 except KeyError as e:
317 pass #print(self.__class__.__name__ + ":", repr(e))
318
319 # nikdo neslibil, že budou v pořadí
320 x = np.sort(tuple(metric_dict.keys()))
321 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
322 return x, y
323
324
325 class SimplexEstimationData(QtCore.QObject):
326 #š budeme mӓť svůj vlastní signaľčík
327 estimations_updated = QtCore.pyqtSignal(pd.DataFrame)
328
329 def __init__(self, dice_box, stream=None, *args, **kwargs):
330 super().__init__(stream, *args, **kwargs)
331 self.dice_box = dice_box
332 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
333 #č asi aby nepadalo, když nenajde signaly
334 self.stream = stream
335 if stream is not None:
336 self.stream.box_runned.connect(self.recalculate)
337 self.stream.estimation_added.connect(self.recalculate)
338
339 self.setup_context_menu()
340 self.recalculate()
341
342
343 def setup_context_menu(self):
344 # simplex_data_menu
345 self.TRI_menu = QtWidgets.QMenu("TRI sources", self.stream)
346
347 self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu)
348 self.TRI_overall_chk.setCheckable(True)
349 self.TRI_overall_chk.setChecked(True)
350 self.TRI_overall_chk.triggered.connect(self.recalculate)
351 self.TRI_menu.addAction(self.TRI_overall_chk)
352
353 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
354 self.simplex_chk.setCheckable(True)
355 self.simplex_chk.setChecked(True)
356 self.simplex_chk.triggered.connect(self.recalculate)
357 self.TRI_menu.addAction(self.simplex_chk)
358
359 # year, it was
360 ## hope, it is temporary
361 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
362 #self.sources_action_group.addAction(self.TRI_overall_chk)
363 #self.sources_action_group.addAction(self.simplex_chk)
364
365 self.TRI_menu.addSeparator()
366
367 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
368 self.proxy_chk.setCheckable(True)
369 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
370 self.proxy_chk.triggered.connect(self.recalculate)
371 self.TRI_menu.addAction(self.proxy_chk)
372
373 self.TRI_menu.addSeparator()
374
375 self.reaction = QtGui.QAction("Update", self.TRI_menu)
376 self.reaction.triggered.connect(self.recalculate)
377 self.TRI_menu.addAction(self.reaction)
378
379 self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
380 self.excelaction.triggered.connect(self.export_to_excel)
381 self.TRI_menu.addAction(self.excelaction)
382
383
384 def export_to_excel(self):
385 #č já bych nechtěl, aby mně export najednou spadl
386 #č z jakéhokoliv důvodu
387 try:
388 proposal_filename = self.dice_box.guessbox.filename
389 if proposal_filename:
390 proposal_filename += '.xlsx'
391 else:
392 proposal_filename = self.dice_box.gm_signature + '.xlsx'
393 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
394 proposal_filename, initialFilter='*.xlsx')
395 self.df.to_excel(filename)
396 except BaseException as e:
397 print(self.__class__.__name__ + ":", repr(e))
398
399
400 def recalculate(self):
401 try:
402 # sources=['box', 'user']
403 sources = list()
404 if self.TRI_overall_chk.isChecked():
405 sources.append('box')
406 if self.simplex_chk.isChecked():
407 sources.append('user')
408
409 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
410 apply_proxy=self.proxy_chk.isChecked())
411 self.estimations_updated.emit(self.df)
412
413 except BaseException as e:
414 print(self.__class__.__name__ + ":", repr(e))
415
416
417
418 class SimplexEstimationGraph(pg.PlotWidget):
419 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
299 class EstimationGraph(pg.PlotWidget):
300 def __init__(self, pf_exact, box_data, parent=None, *args, **kwargs):
420 301 super().__init__(parent, *args, **kwargs) super().__init__(parent, *args, **kwargs)
421 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
422 #č asi aby nepadalo, když nenajde signaly
423 self.stream = stream
424 if stream is not None:
425 self.stream.box_runned.connect(self.redraw)
426 self.stream.estimation_added.connect(self.redraw)
427 302
428 self.dice_box = dice_box
303 self.pf_exact = pf_exact
429 304
430 self.setup_context_menu()
305 self.box_data = box_data
306 box_data.estimations_updated.connect(self.redraw)
307
308 self.setup_context_menu(box_data.TRI_menu)
431 309 self.setup() self.setup()
432 310 self.replot() self.replot()
433 311
434 def setup_context_menu(self):
312 def setup_context_menu(self, menu):
435 313 # creates instance of LegendItem # creates instance of LegendItem
436 314 # and saves it into plotItem.legend # and saves it into plotItem.legend
437 315 self.legend = self.addLegend() self.legend = self.addLegend()
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
446 324 #č já se bojím. radší to uložím #č já se bojím. radší to uložím
447 325 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options") self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
448 326
449 self.plotItem.vb.menu.addMenu(self.stream.simplex_data.TRI_menu)
327 self.plotItem.vb.menu.addMenu(menu)
450 328
451 329 self.legend_chk = QtGui.QAction("Legend", self.custom_menu) self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
452 330 self.legend_chk.setCheckable(True) self.legend_chk.setCheckable(True)
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
481 359 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation") # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
482 360 # self.legend.addItem(self.pen_mix, "mixed simplices measure") # self.legend.addItem(self.pen_mix, "mixed simplices measure")
483 361 # self.legend.addItem(self.pen_f, "failure domain estimation") # self.legend.addItem(self.pen_f, "failure domain estimation")
484
485 362 def setup(self, *args, **kwargs): def setup(self, *args, **kwargs):
486 363 self.clear() self.clear()
487 364 self.setBackground('w') self.setBackground('w')
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
520 397 self.one_ruler = self.addLine(y=1, pen='k') self.one_ruler = self.addLine(y=1, pen='k')
521 398 self.zero_ruler = self.addLine(y=0, pen='k') self.zero_ruler = self.addLine(y=0, pen='k')
522 399
523
524 try:
525 exact_name = self.dice_box.pf_exact_method
400 if self.pf_exact > 0:
401 exact_name = "exact solution"
526 402 pen = pg.mkPen(color='b', width=1.5) # blue pen = pg.mkPen(color='b', width=1.5) # blue
527 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
403 self.pen_exact = self.addLine(y=self.pf_exact, pen=pen, name=exact_name)
528 404 #č aby se nám něco zobrazovalo v legendu #č aby se nám něco zobrazovalo v legendu
529 405 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name) self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
530 except:
531 pass
532 406
533 407 pen = pg.mkPen(color='m', width=2) pen = pg.mkPen(color='m', width=2)
534 408 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation") self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
536 410 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation") self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
537 411
538 412
539
540
541
542 413 def replot(self, *args, **kwargs): def replot(self, *args, **kwargs):
543 414 if self.log_y_chk.isChecked(): if self.log_y_chk.isChecked():
544 415 self.one_ruler.hide() self.one_ruler.hide()
545 try:
546 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
547 if self.dice_box.pf_exact > 0:
548 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
549 self.pen_exact.show()
550 else:
551 self.pen_exact.hide()
552 except:
553 pass
416
417 if self.pf_exact > 0:
418 self.pen_exact.setPos(np.log10(self.pf_exact))
419
420
554 421 self.setLogMode(y=True) self.setLogMode(y=True)
555 422 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine) #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
556 423 self.pen_f.setPen(None) self.pen_f.setPen(None)
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
559 426
560 427 else: else:
561 428 self.one_ruler.show() self.one_ruler.show()
562 try:
563 self.pen_exact.setPos(self.dice_box.pf_exact)
564 self.pen_exact.show()
565 except:
566 pass
429
430 if self.pf_exact > 0:
431 self.pen_exact.setPos(self.pf_exact)
432
433
567 434 self.setLogMode(y=False) self.setLogMode(y=False)
568 435 self.pen_f.setPen(None) self.pen_f.setPen(None)
569 436 self.pen_f.setFillLevel(0) self.pen_f.setFillLevel(0)
570 437 self.pen_success.setFillLevel(1) self.pen_success.setFillLevel(1)
571 438
572 self.redraw()
573
574
575 #č když se někde objeví nula se zapnutým LogModem -
576 #č qtpygraph hned spadne a není možne ten pad zachytit
577 def zerosafe(self, x, y, fallback_y=None):
578 if self.log_y_chk.isChecked():
579 x = np.array(x)
580 y = np.array(y)
581 if fallback_y is None:
582 fallback_y = y
583 y = np.where(y > 0, y, fallback_y)
584 mask = y > 0
585 return x[mask], y[mask]
586 else:
587 return x, y
588
589 def proxy(self, nsim):
590 if self.proxy_chk.isChecked():
591 proxy = self.dice_box.proxy
592 index = np.array(nsim)-1
593 #č indexy musíme o jedničku změnšit
594 #č výsledek nikoliv. Takže v cajku.
595 return np.cumsum(~proxy)[index]
596 else:
597 return nsim
598
439 self.redraw(self.box_data.df)
440
441 @staticmethod
442 def _set_data(plot_item, serie):
443 plot_item.setData(serie.index.to_numpy(), serie.to_numpy())
599 444
600 def _pens_data_update(self):
601 df = self.df
602 nsim = df.nsim.to_numpy()
603 if self.proxy_chk.isChecked():
604 x = self.proxy(nsim)
605 df.insert(loc=0, column='nsim (proxy)', value=x)
606 else:
607 x = nsim
608 # (in case of LogPlot) fallback values also used
609 success_values = df.failure+df.mix+df.out
610 outmix_values = df.failure+df.mix
611 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
612 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
613 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
614 self.pen_success.setData(*self.zerosafe(x, success_values))
615
445
446
447 def redraw(self, df):
616 448
617 def redraw(self):
618 xmin = np.inf
619 xmax = -np.inf
620 tri_estimation = dict()
621 try: # тут всё что угодно может пойти не так
622 # kruci, ještě navic i generovať pokažde znovu...
449 if len(df) < 2: #č nevím proč hazí chyby. Asi kvůli zadané širce.
450 return
623 451
624 # new-style: šecko leží dohromady a každý si z toho
625 # bere co chce a jak chce
626 # ne že by to bylo nějak šetrný
627 # estimation je slovníkem
628 for estimation in self.dice_box.estimations:
629 # nsim musí mäť každej odhad
630 # pokud nemá - je třeba jej prostě opravit
631 nsim = estimation['nsim']
632 try:
633 tri_estimation[nsim] = estimation['TRI_estimation']
634 if nsim > xmax:
635 xmax = nsim
636 if nsim < xmin:
637 xmin = nsim
638
639 except KeyError as e:
640 pass #print(self.__class__.__name__ + ":", repr(e))
641
642 #č neotravuj uživatele chybovejma hlaškama
643 if tri_estimation:
644 # it can be effectively done with pandas
645 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
646 # -1 = 'out', 0=success, 1=failure, 2=mix
647 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
648 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
649 df.sort_values('nsim', inplace=True)
650
651 self._pens_data_update()
652
653 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
654 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
655 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
656
657 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
658 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
659 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
452 if 'vertex_estimation' in df:
453 self._set_data(self.pen_vertex, df['vertex_estimation'])
660 454
661
662 except BaseException as e:
663 print(self.__class__.__name__ + ":", repr(e))
455 if 'weighted_vertex_estimation' in df:
456 self._set_data(self.pen_weighted_vertex, df['weighted_vertex_estimation'])
457
458 self._set_data(self.pen_f, df.failure)
459 self._set_data(self.pen_outmix, df.failure + df.mix)
460 self._set_data(self.pen_success, df.failure + df.mix + df.outside)
461
664 462
665 463
666 #
667 #class SimplexErrorGraph(pg.PlotWidget):
668 # def __init__(self, simplex_data, parent=None, *args, **kwargs):
669 # super().__init__(parent, *args, **kwargs)
670 # self.simplex_data = simplex_data
671 # self.simplex_data.simplex_estimation_updated.connect(self.redraw)
672 #
673 # self.setup_context_menu()
674 # self.setup()
675 #
676 # def setup_context_menu(self):
677 # # creates instance of LegendItem
678 # # and saves it into plotItem.legend
679 # self.legend = self.addLegend()
680 #
681 # self.plotItem.ctrl.xGridCheck.setChecked(True)
682 # self.plotItem.ctrl.yGridCheck.setChecked(True)
683 #
684 # # menu of SimplexEstimationData
685 # self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
686 #
687 # #č já se bojím. radší to uložím
688 # self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
689 #
690 # self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
691 # self.legend_chk.setCheckable(True)
692 # self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
693 # self.custom_menu.addAction(self.legend_chk)
694 # # apply custom menu option
695 # self.legend.setVisible(self.legend_chk.isChecked())
696 #
697 # self.laction = QtGui.QAction("Show labels", self.custom_menu)
698 # self.laction.triggered.connect(self.show_labels)
699 # self.custom_menu.addAction(self.laction)
700 #
701 #
702 # def show_labels(self):
703 # self.setLabel('left', "Failure probability estimation error")
704 # self.setLabel('bottom', "Number of simulations")
705 #
706 #
707 # def setup(self, *args, **kwargs):
708 # self.clear()
709 # self.setBackground('w')
710 # self.setLimits(xMin=-0.45)
711 # x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
712 #
713 # # We will use logMode by default
714 # self.setLogMode(y=True)
715 #
716 # #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
717 # #red = (253, 0, 17, 96)
718 #
719 # #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
720 # #self.pen_f.setZValue(-100)
721 #
722 #
723 # pen = pg.mkPen(color='m', width=2)
724 # self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
725 # pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
726 # self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
727 #
728 #
729 #
730 # #č když se někde objeví nula se zapnutým LogModem -
731 # #č qtpygraph hned spadne a není možne ten pad zachytit
732 # def zerosafe(self, x, y, fallback_y=None):
733 # x = np.array(x)
734 # y = np.array(y)
735 # if fallback_y is None:
736 # fallback_y = y
737 # y = np.where(y > 0, y, fallback_y)
738 # mask = y > 0
739 # return x[mask], y[mask]
740 #
741 #
742 # def redraw(self):
743 # #č neotravujme uživatele chybovejma hlaškama
744 # if hasattr(self.simplex_data.dice_box, 'pf_exact'):
745 # try: #ё тут всё что угодно может пойти не так
746 # pf_exact = self.simplex_data.dice_box.pf_exact
747 #
748 # df = self.simplex_data.df
749 # #č zapíšeme do data rámu, snad nikomu nebude vadit
750 # df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
751 # df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
752 #
753 # v = df['vertex_estimation_error'].abs()
754 # wv = df['weighted_vertex_estimation_error'].abs()
755 #
756 # x, y = self.zerosafe(v.index, v.to_numpy())
757 # self.pen_vertex.setData(x, y)
758 #
759 # x, y = self.zerosafe(wv.index, wv.to_numpy())
760 # self.pen_weighted_vertex.setData(x, y)
761 #
762 #
763 # except BaseException as e:
764 # print(self.__class__.__name__ + ":", repr(e))
765 464
766 465
767 466
 
... ... class SimplexEstimationGraph(pg.PlotWidget):
769 468
770 469
771 470
471 #
772 472 # DEPRECATED # DEPRECATED
773 class SimpleSimplexEstimationGraph(pg.PlotWidget):
774 def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
775 super().__init__(parent, *args, **kwargs)
473 #
474
475
476 def get_estimation_data(estimations, metric):
477 metric_dict = dict()
478 # new-style: šecko leží dohromady a každý z toho
479 # bere co chce a jak chce
480 # ne že by to bylo nějak šetrný
481 # estimation je slovníkem
482 for estimation in estimations:
483 # nsim musí mäť každej odhad
484 # pokud nemá - je třeba jej prostě opravit
485 nsim = estimation['nsim']
486 try:
487 metric_dict[nsim] = estimation[metric]
488 except KeyError as e:
489 pass #print(self.__class__.__name__ + ":", repr(e))
490
491 # nikdo neslibil, že budou v pořadí
492 x = np.sort(tuple(metric_dict.keys()))
493 y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
494 return x, y
495
496
497 class SimplexEstimationData(QtCore.QObject):
498 #š budeme mӓť svůj vlastní signaľčík
499 estimations_updated = QtCore.pyqtSignal(pd.DataFrame)
500
501 def __init__(self, dice_box, stream=None, *args, **kwargs):
502 super().__init__(stream, *args, **kwargs)
503 self.dice_box = dice_box
776 504 #č je zřejmě, že tím potokem bylo myšleno hlavní okínko #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
777 505 #č asi aby nepadalo, když nenajde signaly #č asi aby nepadalo, když nenajde signaly
778 506 self.stream = stream self.stream = stream
779 507 if stream is not None: if stream is not None:
780 self.stream.box_runned.connect(self.redraw)
781 self.stream.estimation_added.connect(self.redraw)
782
783 self.dice_box = dice_box
508 self.stream.box_runned.connect(self.recalculate)
509 self.stream.estimation_added.connect(self.recalculate)
784 510
785 511 self.setup_context_menu() self.setup_context_menu()
786 self.setup()
787 self.replot()
512 self.recalculate()
513
788 514
789 515 def setup_context_menu(self): def setup_context_menu(self):
790 # creates instance of LegendItem
791 # and saves it into plotItem.legend
792 self.legend = self.addLegend()
793
794 self.plotItem.ctrl.xGridCheck.setChecked(True)
795 self.plotItem.ctrl.yGridCheck.setChecked(True)
516 # simplex_data_menu
517 self.TRI_menu = QtWidgets.QMenu("TRI sources", self.stream)
796 518
797 # delete build-in Transforms (with Log_x and Log_y) options,
798 # they can cause uncachable exception (on any zero in data) and crash
799 self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
519 self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu)
520 self.TRI_overall_chk.setCheckable(True)
521 self.TRI_overall_chk.setChecked(True)
522 self.TRI_overall_chk.triggered.connect(self.recalculate)
523 self.TRI_menu.addAction(self.TRI_overall_chk)
800 524
801 #č já se bojím. radší to uložím
802 self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
525 self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu)
526 self.simplex_chk.setCheckable(True)
527 self.simplex_chk.setChecked(True)
528 self.simplex_chk.triggered.connect(self.recalculate)
529 self.TRI_menu.addAction(self.simplex_chk)
803 530
804 self.legend_chk = QtGui.QAction("Legend", self.custom_menu)
805 self.legend_chk.setCheckable(True)
806 self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
807 self.custom_menu.addAction(self.legend_chk)
808 # apply custom menu option
809 self.legend.setVisible(self.legend_chk.isChecked())
531 # year, it was
532 ## hope, it is temporary
533 #self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
534 #self.sources_action_group.addAction(self.TRI_overall_chk)
535 #self.sources_action_group.addAction(self.simplex_chk)
810 536
811 self.proxy_chk = QtGui.QAction("Proxy", self.custom_menu)
812 self.proxy_chk.setCheckable(True)
813 self.proxy_chk.triggered.connect(self.redraw)
814 self.custom_menu.addAction(self.proxy_chk)
537 self.TRI_menu.addSeparator()
815 538
816 self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
817 self.log_x_chk.setCheckable(True)
818 self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
819 self.custom_menu.addAction(self.log_x_chk)
539 self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu)
540 self.proxy_chk.setCheckable(True)
541 self.proxy_chk.setChecked(hasattr(self.dice_box, 'proxy'))
542 self.proxy_chk.triggered.connect(self.recalculate)
543 self.TRI_menu.addAction(self.proxy_chk)
820 544
821 self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
822 self.log_y_chk.setCheckable(True)
823 self.log_y_chk.setChecked(True)
824 self.log_y_chk.triggered.connect(self.replot)
825 self.custom_menu.addAction(self.log_y_chk)
545 self.TRI_menu.addSeparator()
826 546
827 self.reaction = QtGui.QAction("Redraw", self.custom_menu)
828 self.reaction.triggered.connect(self.redraw)
829 self.custom_menu.addAction(self.reaction)
830
831 self.laction = QtGui.QAction("Show labels", self.custom_menu)
832 self.laction.triggered.connect(self.show_labels)
833 self.custom_menu.addAction(self.laction)
547 self.reaction = QtGui.QAction("Update", self.TRI_menu)
548 self.reaction.triggered.connect(self.recalculate)
549 self.TRI_menu.addAction(self.reaction)
834 550
835 self.excelaction = QtGui.QAction("Export to Excel", self.custom_menu)
551 self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
836 552 self.excelaction.triggered.connect(self.export_to_excel) self.excelaction.triggered.connect(self.export_to_excel)
837 self.custom_menu.addAction(self.excelaction)
553 self.TRI_menu.addAction(self.excelaction)
838 554
839 555
840 556 def export_to_excel(self): def export_to_excel(self):
 
... ... class SimpleSimplexEstimationGraph(pg.PlotWidget):
846 562 proposal_filename += '.xlsx' proposal_filename += '.xlsx'
847 563 else: else:
848 564 proposal_filename = self.dice_box.gm_signature + '.xlsx' proposal_filename = self.dice_box.gm_signature + '.xlsx'
849 filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
565 filename, *__ = pg.FileDialog.getSaveFileName(self.stream, 'Export to Excel',\
850 566 proposal_filename, initialFilter='*.xlsx') proposal_filename, initialFilter='*.xlsx')
851 567 self.df.to_excel(filename) self.df.to_excel(filename)
852 568 except BaseException as e: except BaseException as e:
853 569 print(self.__class__.__name__ + ":", repr(e)) print(self.__class__.__name__ + ":", repr(e))
854
855 def show_labels(self):
856 self.setLabel('left', "Probability measure")
857 self.setLabel('bottom', "Number of simulations")
858 570
859
860
861 # self.legend.addItem(self.pen_success, "success domain estimation")
862 # self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
863 # self.legend.addItem(self.pen_mix, "mixed simplices measure")
864 # self.legend.addItem(self.pen_f, "failure domain estimation")
865
866 def setup(self, *args, **kwargs):
867 self.clear()
868 self.setBackground('w')
869 self.setLimits(xMin=-0.45)
870 x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
871
872 #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
873 green = (0, 255, 38, 96)
874 #xkcd_red = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
875 red = (253, 0, 17, 96)
876 #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
877 cream = (255, 221, 0, 96)
878 grey = (196, 196, 196, 96)
879
880 self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
881 self.pen_f.setZValue(-100)
882
883 self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation")
884 self.pen_success.setZValue(-100)
885
886 self.pen_outmix = self.plot(x, y)
887
888 self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
889 #self.fill_mix.setData(name="mixed simplices measure")
890 self.fill_mix.setBrush(cream)
891 self.fill_mix.setZValue(-100)
892 self.addItem(self.fill_mix)
893
894 #self.pen_outside = self.plot(x, y)
895 self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
896 #self.fill_outside.setData(name="out of sampling domain estimation")
897 self.fill_outside.setBrush(grey)
898 self.fill_outside.setZValue(-100)
899 self.addItem(self.fill_outside)
900
901 self.one_ruler = self.addLine(y=1, pen='k')
902 self.zero_ruler = self.addLine(y=0, pen='k')
903
904 571
572 def recalculate(self):
905 573 try: try:
906 exact_name = self.dice_box.pf_exact_method
907 pen = pg.mkPen(color='b', width=1.5) # blue
908 self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name)
909 #č aby se nám něco zobrazovalo v legendu
910 self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
911 except:
912 pass
913
914 pen = pg.mkPen(color='m', width=2)
915 self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
916 pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
917 self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
918
919
920
921
922
923 def replot(self, *args, **kwargs):
924 if self.log_y_chk.isChecked():
925 self.one_ruler.hide()
926 try:
927 #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
928 if self.dice_box.pf_exact > 0:
929 self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
930 self.pen_exact.show()
931 else:
932 self.pen_exact.hide()
933 except:
934 pass
935 self.setLogMode(y=True)
936 #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
937 self.pen_f.setPen(None)
938 self.pen_f.setFillLevel(None)
939 self.pen_success.setFillLevel(0)
940
941 else:
942 self.one_ruler.show()
943 try:
944 self.pen_exact.setPos(self.dice_box.pf_exact)
945 self.pen_exact.show()
946 except:
947 pass
948 self.setLogMode(y=False)
949 self.pen_f.setPen(None)
950 self.pen_f.setFillLevel(0)
951 self.pen_success.setFillLevel(1)
952
953 self.redraw()
954
955
956 #č když se někde objeví nula se zapnutým LogModem -
957 #č qtpygraph hned spadne a není možne ten pad zachytit
958 def zerosafe(self, x, y, fallback_y=None):
959 if self.log_y_chk.isChecked():
960 x = np.array(x)
961 y = np.array(y)
962 if fallback_y is None:
963 fallback_y = y
964 y = np.where(y > 0, y, fallback_y)
965 mask = y > 0
966 return x[mask], y[mask]
967 else:
968 return x, y
969
970 def proxy(self, nsim):
971 if self.proxy_chk.isChecked():
972 proxy = self.dice_box.proxy
973 index = np.array(nsim)-1
974 #č indexy musíme o jedničku změnšit
975 #č výsledek nikoliv. Takže v cajku.
976 return np.cumsum(~proxy)[index]
977 else:
978 return nsim
979
980
981 def _pens_data_update(self):
982 df = self.df
983 nsim = df.nsim.to_numpy()
984 if self.proxy_chk.isChecked():
985 x = self.proxy(nsim)
986 df.insert(loc=0, column='nsim (proxy)', value=x)
987 else:
988 x = nsim
989 # (in case of LogPlot) fallback values also used
990 success_values = df.failure+df.mix+df.out
991 outmix_values = df.failure+df.mix
992 failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
993 self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
994 self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
995 self.pen_success.setData(*self.zerosafe(x, success_values))
996
997
998 def redraw(self):
999 xmin = np.inf
1000 xmax = -np.inf
1001 tri_estimation = dict()
1002 try: # тут всё что угодно может пойти не так
1003 # kruci, ještě navic i generovať pokažde znovu...
1004
1005 # new-style: šecko leží dohromady a každý si z toho
1006 # bere co chce a jak chce
1007 # ne že by to bylo nějak šetrný
1008 # estimation je slovníkem
1009 for estimation in self.dice_box.estimations:
1010 # nsim musí mäť každej odhad
1011 # pokud nemá - je třeba jej prostě opravit
1012 nsim = estimation['nsim']
1013 try:
1014 tri_estimation[nsim] = estimation['TRI_estimation']
1015 if nsim > xmax:
1016 xmax = nsim
1017 if nsim < xmin:
1018 xmin = nsim
1019
1020 except KeyError as e:
1021 pass #print(self.__class__.__name__ + ":", repr(e))
1022
1023 #č neotravuj uživatele chybovejma hlaškama
1024 if tri_estimation:
1025 # it can be effectively done with pandas
1026 self.df = df = pd.DataFrame(tuple(tri_estimation.values()))
1027 # -1 = 'out', 0=success, 1=failure, 2=mix
1028 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1029 df.insert(loc=0, column='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
1030 df.sort_values('nsim', inplace=True)
1031
1032 self._pens_data_update()
1033
1034 nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
1035 df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1036 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
574 # sources=['box', 'user']
575 sources = list()
576 if self.TRI_overall_chk.isChecked():
577 sources.append('box')
578 if self.simplex_chk.isChecked():
579 sources.append('user')
1037 580
1038 nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
1039 df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
1040 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
1041
581 self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
582 apply_proxy=self.proxy_chk.isChecked())
583 self.estimations_updated.emit(self.df)
1042 584
1043 585 except BaseException as e: except BaseException as e:
1044 586 print(self.__class__.__name__ + ":", repr(e)) print(self.__class__.__name__ + ":", repr(e))
1045 587
1046 588
1047 # DEPRECATED
1048 class TriEstimationGraph(SimpleSimplexEstimationGraph):
1049 def __init__(self, dice_box, tri_estimation_name='TRI_overall_estimations', stream=None, parent=None, *args, **kwargs):
1050 self.tri_estimation_name = tri_estimation_name
1051 super().__init__(dice_box, stream, parent, *args, **kwargs)
1052
1053
1054
1055 def redraw(self):
1056 try: # тут всё что угодно может пойти не так
1057 data = self.dice_box.guessbox.estimations[self.tri_estimation_name]
1058 nsim, tri_data = data
1059 # it can be effectively done with pandas
1060 self.df = df = pd.DataFrame(tri_data)
1061 # -1 = 'out', 0=success, 1=failure, 2=mix
1062 df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
1063 df.insert(loc=0, column='nsim', value=nsim)
1064
1065 # Update the data
1066 self._pens_data_update()
1067
1068 if 'vertex_estimation' in self.dice_box.guessbox.estimations:
1069 data = self.dice_box.guessbox.estimations['vertex_estimation']
1070 nsim, y = data
1071 # Update the data
1072 #č spolehám na konzistenci blackboxu, ne však úplně
1073 self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
1074 df['vertex_estimation'] = y
1075
1076 if 'weighted_vertex_estimation' in self.dice_box.guessbox.estimations:
1077 data = self.dice_box.guessbox.estimations['weighted_vertex_estimation']
1078 nsim, y = data
1079 # Update the data
1080 #č spolehám na konzistenci blackboxu, ne však úplně
1081 self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
1082 df['weighted_vertex_estimation'] = y
1083
1084
1085 # BaseException
1086 except BaseException as e:
1087 print(self.__class__.__name__ + ":", repr(e))
589
590
1088 591
1089 592
1090 593
File wellmet/qt_gui/qt_gui.py changed (mode: 100644) (index 6a2d0b3..9b558e0)
... ... 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 from . import qt_graph_widgets
11 from . import qt_graph_widgets as gw
12 12 from . import qt_pairwise from . import qt_pairwise
13 13 from .. import reader from .. import reader
14 14
 
... ... class QtGuiWindow(QtWidgets.QMainWindow):
261 261 #č graphy už nemusí jít po stm widgetech #č graphy už nemusí jít po stm widgetech
262 262 if hasattr(self.sample_box, 'box_estimations'): if hasattr(self.sample_box, 'box_estimations'):
263 263 dock = QtWidgets.QDockWidget("Estimation data", self) dock = QtWidgets.QDockWidget("Estimation data", self)
264 widget = EstimationTableWidget(self.sample_box.box_estimations, self.box_runned, dock)
264 widget = EstimationTableWidget(self.sample_box.box_estimations,
265 self.box_runned, dock)
265 266 dock.setWidget(widget) dock.setWidget(widget)
266 267 self.dockables.append(dock) self.dockables.append(dock)
267 268 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
268 269
269 self.box_estimation_data = qt_graph_widgets.BoxEstimationData(
270 self.sample_box.box_estimations, self.box_runned, self)
270 self.box_estimation_data = gw.BoxEstimationData(
271 self.sample_box.box_estimations, self.box_runned, self)
271 272 else: else:
272 self.box_estimation_data = qt_graph_widgets.SimplexEstimationData(self.sample_box, self)
273 self.box_estimation_data = \
274 gw.SimplexEstimationData(self.sample_box, self)
273 275
274 #č graphy už nemusí jít po stm widgetech
275 dock = QtWidgets.QDockWidget("TRI_overall estimation graph", self)
276 dock.setWidget(qt_graph_widgets.TriEstimationGraph(self.sample_box, 'TRI_overall_estimations', self, dock))
277 self.dockables.append(dock)
278 self.tabifyDockWidget(self.dockables[0], dock)
279
280 dock = QtWidgets.QDockWidget("Simplex estimation graph", self)
281 dock.setWidget(qt_graph_widgets.SimpleSimplexEstimationGraph(self.sample_box, self, dock))
282 self.dockables.append(dock)
283 self.tabifyDockWidget(self.dockables[0], dock)
284 276
285 277 if hasattr(self.sample_box, 'pf_exact'): if hasattr(self.sample_box, 'pf_exact'):
286 dock = QtWidgets.QDockWidget("Error graph", self)
287 278 pf_exact = self.sample_box.pf_exact pf_exact = self.sample_box.pf_exact
288 menu = self.box_estimation_data.TRI_menu
289 signal = self.box_estimation_data.estimations_updated
290 dock.setWidget(qt_graph_widgets.ErrorGraph(pf_exact, signal, menu, dock))
279
280 dock = QtWidgets.QDockWidget("Error graph", self)
281 dock.setWidget(gw.ErrorGraph(pf_exact, self.box_estimation_data, dock))
291 282 self.dockables.append(dock) self.dockables.append(dock)
292 283 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
284 else:
285 pf_exact = -1
286
287 dock = QtWidgets.QDockWidget("Estimation graph", self)
288 widget = gw.EstimationGraph(pf_exact, self.box_estimation_data, dock)
289 dock.setWidget(widget)
290 self.dockables.append(dock)
291 self.tabifyDockWidget(self.dockables[0], dock)
292
293 293
294 294 dock = QtWidgets.QDockWidget("Voronoi estimation graph", self) dock = QtWidgets.QDockWidget("Voronoi estimation graph", self)
295 dock.setWidget(qt_graph_widgets.VoronoiEstimationGraph(self.sample_box, self, dock))
295 dock.setWidget(gw.VoronoiEstimationGraph(self.sample_box, self, dock))
296 296 self.dockables.append(dock) self.dockables.append(dock)
297 297 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
298 298
299 299 dock = QtWidgets.QDockWidget("GRaph", self) dock = QtWidgets.QDockWidget("GRaph", self)
300 dock.setWidget(qt_graph_widgets.GRaph(self, dock))
300 dock.setWidget(gw.GRaph(self, dock))
301 301 self.dockables.append(dock) self.dockables.append(dock)
302 302 self.tabifyDockWidget(self.dockables[0], dock) self.tabifyDockWidget(self.dockables[0], dock)
303 303
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