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".

/qt_plot.py (379db4a6236832e448f387adb9063ab547e53e1f) (61709 bytes) (mode 100644) (type blob)

#!/usr/bin/env python
# coding: utf-8

import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from pyqtgraph.Qt import QtCore

from pyqtgraph import console

import numpy as np
import pandas as pd # required for estimation graph

from . import estimation as stm

         
def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs):
    """
    This function will start Qt graph window in event loop
    """
    
    return QtGuiPlot2D(sample_box, space, *args, **kwargs)
    

### Define a top-level widget to hold everything
class QtGuiPlot2D(QtGui.QMainWindow):
    #č dublikuje slice_changed
    # do not redraw twice!
    box_runned = QtCore.pyqtSignal()
    space_changed = QtCore.pyqtSignal()
    slice_changed = QtCore.pyqtSignal()
    redraw_called = QtCore.pyqtSignal()
    estimation_added = QtCore.pyqtSignal()
    
    # snad pri vykreslování argy-kvargy nevádí
    def __init__(self, sample_box, space='R', *args, **kwargs):
        
        #E former self.w = QtGui.QMainWindow()
        self.app = pg.mkQApp()
        super().__init__()
        self.setWindowTitle(sample_box.gm_signature + " plot")
        
        self.sample_box = sample_box
        #sample_box.sample_box._log = self.logger
        self.last_shot = None
        self.space = space
        # "zapnuté" prostory
        #self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'aP', 'GK', 'aGK', 'G', 'aG', 'U', 'aU']
        self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'GK', 'G', 'aG', 'U', 'aU']

        # initialize central widget
        self.initialize_central_widget()
        
        # common setup
        self.setup()

        self.plot_setup()
        
        ## Display the widget as a new window
        self.show()

        #
        self.redraw_called.emit()
        
        ## Start the Qt event loop
        self.app.exec_()
        

    def initialize_central_widget(self):
        self.central_widget = pg.PlotWidget()
        self.px_size = 2.5
        self.plot_widget_2d()
        self.redraw_called.connect(self.central_widget.clear)
        
        
        
    def setup(self):    
        
        self.bar = self.menuBar()
        self.view = self.bar.addMenu("View")
        
        
        
        ### Create some widgets to be placed inside
        self.combo_space = pg.ComboBox(items=self.spaces, default=self.space)
        self.combo_space.activated[str].connect(self.change_space)
        
        
        
        
        self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        self.slider.valueChanged.connect(self._slider_chainged)
        self.slider.sliderReleased.connect(lambda:self.slice_changed.emit())
        self.slider.setMaximum(self.sample_box.nsim)
        self.slider.setValue(self.sample_box.nsim)
        
        self.label_nsim = QtGui.QLabel()
        self.label_nsim.setText(str(self.sample_box.nsim))
        
        
        self.btn = QtGui.QPushButton('run box')
        self.btn.clicked.connect(self.run_sb)
        
        self.btn2 = QtGui.QPushButton('connect/disconnect')
        self.btn2.setCheckable(True)
        self.btn2.clicked.connect(self.bx_connect)
        
        self.btn3 = QtGui.QPushButton('redraw')
        self.btn3.clicked.connect(lambda:self.redraw_called.emit())
        
        
        ## Create a grid layout to manage the widgets size and position
        self.layout = pg.LayoutWidget()
        self.setCentralWidget(self.layout)
        #self.w.setLayout(self.layout)

        # 
        self.list_view = QtGui.QListWidget()
        
        ## Add widgets to the layout in their proper positions
        #self.layout.addWidget(self.list_view, 0, 0, 2, 1) 
        self.layout.addWidget(self.combo_space, 0, 0)   
        self.layout.addWidget(self.slider, 0, 1)   
        self.layout.addWidget(self.label_nsim, 0, 2)
        self.layout.addWidget(self.btn, 0, 3) 
        self.layout.addWidget(self.btn2, 0, 4)
        self.layout.addWidget(self.btn3, 0, 5) 
        self.layout.addWidget(self.central_widget, 1, 0, 1, 6)
        


        # status bar, mainly to observe BlackBox
        self.statusBar = QtGui.QStatusBar()
        self.setStatusBar(self.statusBar)
        self.btn_continue = QtGui.QPushButton('continue')
        self.continue_label = QtGui.QLabel()
#        self.continue_layout = QtGui.QHBoxLayout()
#        self.continue_layout.addWidget(self.btn_continue)
#        self.continue_layout.addWidget(self.continue_label)
        self.statusBar.addWidget(self.btn_continue)
        self.statusBar.addWidget(self.continue_label)
        self.btn_continue.hide()
        self.continue_label.hide()
        
        self.statusBar.showMessage("Vitáme vás u nás!")


        
        
        # Dockables, najzajimavejší věc
        self.dockables = []
        
        
        dock = QtGui.QDockWidget("Interactive python console", self)
        dock.setWidget(console.ConsoleWidget(namespace={**locals(), **globals()}))
        self.dockables.append(dock)
        self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, dock)
        

        dock = QtGui.QDockWidget("BlackBox output", self)
        self.output_label = QtGui.QLabel()
        dock.setWidget(self.output_label)
        self.dockables.append(dock)
        self.tabifyDockWidget(self.dockables[0], dock)
        
        
        #č graphy už nemusí jít po stm widgetech
        dock = QtGui.QDockWidget("TRI_current estimation graph", self)
        dock.setWidget(TriEstimationGraph(self, tri_estimation_name='TRI_current_estimations'))
        self.dockables.append(dock)
        self.tabifyDockWidget(self.dockables[0], dock)
        
        dock = QtGui.QDockWidget("TRI_overall estimation graph", self)
        dock.setWidget(TriEstimationGraph(self, tri_estimation_name='TRI_overall_estimations'))
        self.dockables.append(dock)
        self.tabifyDockWidget(self.dockables[0], dock)
        
        dock = QtGui.QDockWidget("Simplex estimation graph", self)
        dock.setWidget(SimpleSimplexEstimationGraph(self.sample_box, self, dock))
        self.dockables.append(dock)
        self.tabifyDockWidget(self.dockables[0], dock)
        
        
        dock = QtGui.QDockWidget("Voronoi estimation graph", self)
        dock.setWidget(VoronoiEstimationGraph(self.sample_box, self, dock))
        self.dockables.append(dock)
        self.tabifyDockWidget(self.dockables[0], dock)




        dock = QtGui.QDockWidget("View", self)
        dock.setWidget(self.list_view)
        self.dockables.append(dock)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
        
        
        for dock in self.dockables:
            self.view.addAction(dock.toggleViewAction())
            #dock.setFloating(True)
      
        #self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
        
        
        


    def plot_setup(self):
        self.graph_menu = self.bar.addMenu("BlackBox")
        self.triangulation_action = QtGui.QAction("Show triangulation", self, checkable=True)
        self.triangulation_action.triggered.connect(self.triangulation_slot)
        self.graph_menu.addAction(self.triangulation_action)

##        dock = dock_r = QtGui.QDockWidget("Simplex-based pf estimation", self.w)
##        dock.setWidget(SimplexEstimationWidget(self, dock))
        #self.view.addAction(dock.toggleViewAction())
##        self.dockables.append(dock)
##        self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        
        #!
        dock = dock_r = QtGui.QDockWidget("Tesselation-based pf estimation", self)
        dock.setWidget(VoronoiEstimationWidget(self, dock))
        self.view.addAction(dock.toggleViewAction())
        self.dockables.append(dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        #self.w.tabifyDockWidget(dock_r, dock)
        
        
        dock = QtGui.QDockWidget("Blackbox's candidates", self)
        dock.setWidget(CandidatesWidget(self, dock))
        self.view.addAction(dock.toggleViewAction())
        self.dockables.append(dock)
        self.tabifyDockWidget(dock_r, dock)


    #
    #č Tlačítka!
    #


    def _slider_chainged(self, value):
        self.label_nsim.setText(str(value))
        if not self.slider.isSliderDown(): # co to vůbec děla?
            self.slice_changed.emit()

    def change_space(self, space):
        self.space = space
        self.space_changed.emit()
        #self.plot_widget_2d()
        #self.slice_plot_data()
        
    def run_sb(self):
        with pg.BusyCursor():
            self.last_shot = self.sample_box()
            
            # slider
            #č zpusobí slice_changed
            self.slider.setMaximum(self.sample_box.nsim)
            self.slider.setValue(self.sample_box.nsim)
            
            self.box_runned.emit()


        
        
    def bx_connect(self):
        if self.btn2.isChecked():
            try:
                self.sample_box.connect(self.logger)
            except BaseException as e:
                print(self.__class__.__name__ + ":", "connection to BlackBox failed", repr(e))
        else:
            try:
                self.sample_box.disconnect()
            except BaseException as e:
                print(self.__class__.__name__ + ":", "error while disconnecting of BlackBox", repr(e))
        
        
    def logger(self, *args, msg="", indent=0, **kwargs):
        self.continue_label.setText("BlackBox: " + msg)
        self.output_label.setText(str(args) + str(kwargs))
        
        loop = QtCore.QEventLoop()
        self.btn_continue.clicked.connect(loop.quit)
        self.btn_continue.show()
        self.continue_label.show()
        # i want to clear status bar temporaly
        status = self.statusBar.currentMessage()
        self.statusBar.clearMessage()
        
        loop.exec_()  # Execution stops here until finished called  
        
        self.btn_continue.hide()
        self.continue_label.hide()
        self.statusBar.showMessage(status)
        
    

    def plot_widget_2d(self):
        self.plotWidget.clear()
        # Kružničky chcete?
        # Кружочки ннада?
        if self.space in ('Rn', 'G'):
            nrod = 200
            phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
            for r in range(5):
                bound_x = r * np.cos(phi)
                bound_y = r * np.sin(phi)
                pen = pg.mkPen(color='k', width=6-r)
                self.plotWidget.plot(bound_x, bound_y, pen=pen)
        elif self.space in ('P', 'U'):
            self.plotWidget.plot((0,0,1,1,0), (0,1,1,0,0), pen='k')
        
        x, y, z, *__ = (*getattr(self.sample_box.failure_samples, self.space).T,)
        self.failures = self.plotWidget.plot(x, y, pen=None, symbol='x', symbolPen='r',  name='Failures') # symbolBrush=0.2,
        
        x, y, z, *__ = (*getattr(self.sample_box.success_samples, self.space).T,)
        self.successes = self.plotWidget.plot(x, y, pen=None, symbol='+', symbolPen='g',  name='Successes')
        
        x = y = ()
        self.last = self.plotWidget.plot(x, y, pen=None, symbol='o', symbolPen='c',  name='Last shot', symbolBrush=None)
        self.shot = self.plotWidget.plot(x, y, pen=None, symbol='+', symbolPen='c',  name='Last shot')
        
            
            # pro začatek postačí
        self.triangulation = []
        
        # slider
        self.slider.setMaximum(self.sample_box.nsim)
        self.slider.setValue(self.sample_box.nsim)
        
        # малы со кулэ?
        return self.plotWidget
        
        
    def slice_plot_data(self, sample=None):
        if sample:
            x, y = (*getattr(sample, self.space).T,)
            self.last.setData(x, y)
            self.shot.setData(x, y)
    
        nsim = self.slider.value()
        
        # Update the data
        x, y = (*getattr(self.sample_box[:nsim].failure_samples, self.space).T,)
        self.failures.setData(x, y)
        
        x, y = (*getattr(self.sample_box[:nsim].success_samples, self.space).T,)
        self.successes.setData(x, y)
        
        
        
        # update triangulation
        #print("Суредасько", (self.sample_box.nvar==2), self.triangulation_action.isChecked())
        if (self.sample_box.nvar==2) and self.triangulation_action.isChecked():
            try:
                # take coordinates in the space, where triangulation has been performed
                sampled_plan_tri = getattr(self.sample_box, self.sample_box.tri_space)
                ns = 100
                
                if len(self.triangulation) < len(self.sample_box.tri.simplices):
                    x = y = ()
                    gap = len(self.sample_box.tri.simplices) - len(self.triangulation)
                    for __ in range(gap):
                        self.triangulation.append(self.plotWidget.plot(x, y, pen=0.7))
                
                for triangle, plot_item in zip(self.sample_box.tri.simplices, self.triangulation):
                    x_tri = np.linspace(sampled_plan_tri[triangle[0],0], sampled_plan_tri[triangle[1],0], ns, endpoint=False)
                    y_tri = np.linspace(sampled_plan_tri[triangle[0],1], sampled_plan_tri[triangle[1],1], ns, endpoint=False)
                    x_tri = np.append(x_tri, np.linspace(sampled_plan_tri[triangle[1],0], sampled_plan_tri[triangle[2],0], ns, endpoint=False))
                    y_tri = np.append(y_tri, np.linspace(sampled_plan_tri[triangle[1],1], sampled_plan_tri[triangle[2],1], ns, endpoint=False))
                    x_tri = np.append(x_tri, np.linspace(sampled_plan_tri[triangle[2],0], sampled_plan_tri[triangle[0],0], ns, endpoint=True))
                    y_tri = np.append(y_tri, np.linspace(sampled_plan_tri[triangle[2],1], sampled_plan_tri[triangle[0],1], ns, endpoint=True))
                    
                    tri_bound_tri = np.array((x_tri, y_tri)).T
                    # vytvořme sample
                    tri_bound = self.sample_box.sampled_plan.new_sample(tri_bound_tri, space=self.sample_box.tri_space)
                    
                    # Update the data
                    #print("Суредасько", tri_bound)
                    plot_item.setData(*getattr(tri_bound, self.space).T)
                    
            except BaseException as e:
                msg = "error during triangulation drawing"
                print(self.__class__.__name__ + ":",msg, repr(e))
                
                
        
    
        
        
    def triangulation_slot(self):
        if self.triangulation_action.isChecked():
            #print("Мед сюредалоз!")
            for plot_item in self.triangulation:
                plot_item.show()
            self.slice_plot_data()
        else:
            #print("Медам сюреда!")
            for plot_item in self.triangulation:
                plot_item.hide()





class PlotViewWidget(QtGui.QListWidget):
    def __init__(self):
        super().__init__()
        print(self.addItem("Item 1"))
        
        item = QtGui.QListWidgetItem('testcase_name')
        item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
        item.setCheckState(QtCore.Qt.Checked)
        self.addItem(item)
    
        self.addItem("Item 3")
        self.addItem("Item 4")
        
##from PyQt5 import QtWidgets, QtCore
##
##self.listWidgetTestCases = QtWidgets.QListWidget()
##
##for testcases in root.iter('testcase'):
##    testcase_name = str(testcases.attrib)
##
##    item = QtWidgets.QListWidgetItem(testcase_name)
##    item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
##    item.setCheckState(QtCore.Qt.Unchecked)
##    self.listWidgetTestCases.addItem(item)


"""
=============
График виӝет 
Grafy
Estimation graph widgets
========================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
        



class TriEstimationGraph(pg.PlotWidget):
    def __init__(self, samplebox_item, tri_estimation_name='TRI_current_estimations',   parent=None, *args, **kwargs):
        super().__init__(parent)
        self.sb_item = samplebox_item
        self.sb_item.box_runned.connect(self.redraw)
        self.sb_item.estimation_added.connect(self.redraw)
        
        self.black_box = samplebox_item.sample_box
        self.tri_estimation_name = tri_estimation_name
        self.setBackground('w')
        x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
        
        #self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
        pen = pg.mkPen(color=(255, 0, 0), width=3)#, style=QtCore.Qt.DashLine)
        self.pen_f = self.plot(x, y, pen=pen) # red
        self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
        self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
        self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
        self.pen_exact = self.plot(x, y, pen='b') # blue
        
        self.setLogMode(False, True)
        
        self.redraw()
        
   
    def redraw(self):
        try: # тут всё что угодно может пойти не так
            data = self.black_box.guessbox.estimations[self.tri_estimation_name]
            x = data[0]
            # it can be effectively done with pandas
            df = pd.DataFrame(data[1])
            # -1 = 'out', 0=success, 1=failure, 2=mix
            df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
           
            # Update the data
            # když se někde objeví nula se zapnutým LogModem - qtpygraph hned spadne a není možne ten pad zachytit
            def nonzero(data): return np.where(data > 0, data, 1) 
            self.pen_f.setData(np.array(x)[df.failure.to_numpy() > 0], df.failure.to_numpy()[df.failure.to_numpy() > 0])
            self.pen_mix.setData(x, nonzero(df.failure))
            self.pen_outside.setData(x, nonzero(df.failure+df.mix))
            self.pen_success.setData(x, nonzero(df.failure+df.mix+df.out)) # kontrolu, zda je to 1, nechame uživateli
            
            self.pen_exact.setData((min(x),max(x)), (self.black_box.pf_exact, self.black_box.pf_exact))
        
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        
        
        # pen_f.opts['logMode']
        # pen_outside.setLogMode(False, False)
        #setLogMode(False, False)
        




class SimpleSimplexEstimationGraph(pg.PlotWidget):
    def __init__(self, black_box, samplebox_item,   parent=None, *args, **kwargs):
        super().__init__(parent)
        self.sb_item = samplebox_item
        self.sb_item.box_runned.connect(self.redraw)
        self.sb_item.estimation_added.connect(self.redraw)
        
        self.black_box = black_box
        
    
        self.log_x_chk = QtGui.QAction("Log X", self.plotItem.ctrlMenu)
        self.log_x_chk.setCheckable(True)
        self.log_y_chk = QtGui.QAction("Log Y", self.plotItem.ctrlMenu)
        self.log_y_chk.setCheckable(True)
        # setLogMode(self, x=None, y=None)
        self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
        self.log_y_chk.triggered.connect(self.setup)
        
        self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
        self.reaction.triggered.connect(self.redraw)
        
        #pw.plotItem.ctrlMenu.actions()
        self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
        
        self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.log_y_chk)
        self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.log_x_chk)
        self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
        
        
        self.setup()
        
        
    def setup(self, *args, **kwargs):
        self.clear()
        self.setBackground('w')
        x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
        
        if self.log_y_chk.isChecked():
            self.setLogMode(y=True)
            #self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
            pen = pg.mkPen(color=(255, 0, 0), width=3)#, style=QtCore.Qt.DashLine)
            self.pen_f = self.plot(x, y, pen=pen) # red
            self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
            self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
            self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
            self.pen_exact = self.plot(x, y, pen='b') # blue
            
            
        else:
            self.setLogMode(y=False)
            self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
            self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
            self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
            self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
            self.pen_exact = self.plot(x, y, pen='b') # blue
        
        
        self.redraw()
        
   
    def redraw(self):
        xmin = np.inf
        xmax = -np.inf
        tri_estimation = dict()
        try: # тут всё что угодно может пойти не так
            # kruci, ještě navic i generovať pokažde znovu...
        
            # new-style: šecko leží dohromady a každý si z toho
            # bere co chce a jak chce
            # ne že by to bylo nějak šetrný
            # estimation je slovníkem
            for estimation in self.black_box.estimations:
                # nsim musí mäť každej odhad
                # pokud nemá - je třeba jej prostě opravit
                nsim = estimation['nsim']
                try: 
                    tri_estimation[nsim] = estimation['TRI_estimation']
                    if nsim > xmax:
                        xmax = nsim
                    if nsim < xmin:
                        xmin = nsim
                except KeyError as e:
                    pass #print(self.__class__.__name__ + ":", repr(e))
            
                
            # it can be effectively done with pandas
            df = pd.DataFrame(tuple(tri_estimation.values()))
            # -1 = 'out', 0=success, 1=failure, 2=mix
            df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
            df.insert(loc=0, column='x', value=tuple(tri_estimation.keys()), allow_duplicates=False)
            df.sort_values('x', inplace=True)
            x = df.x.to_numpy()
            
            if self.log_y_chk.isChecked():
                # Update the data
                # když se někde objeví nula se zapnutým LogModem - qtpygraph hned spadne a není možne ten pad zachytit
                def nonzero(data): return np.where(data > 0, data, 1) 
                self.pen_f.setData(x[df.failure.to_numpy() > 0], df.failure.to_numpy()[df.failure.to_numpy() > 0])
                self.pen_mix.setData(x, nonzero(df.failure))
                self.pen_outside.setData(x, nonzero(df.failure+df.mix))
                self.pen_success.setData(x, nonzero(df.failure+df.mix+df.out)) # kontrolu, zda je to 1, nechame uživateli
                
                
                
            else:
                # Update the data
                self.pen_f.setData(x, df.failure)
                self.pen_mix.setData(x, df.failure+df.mix)
                self.pen_outside.setData(x, df.failure+df.mix+df.out)
                self.pen_success.setData(x, df.failure+df.mix+df.out+df.success) # kontrolu, zda je to 1, nechame uivateli
                
           
           
            if (xmax - xmin) > 0:
                if hasattr(self.black_box, 'pf_exact'):
                    # poslední. I když spadne, tak už nikomu moc nevadí
                    self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
        
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        
        
        # pen_f.opts['logMode']
        # pen_outside.setLogMode(False, False)
        #setLogMode(False, False)
        #f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
        #win.addItem(f)
        
        







class VoronoiEstimationGraph(pg.PlotWidget):
    def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
        super().__init__(parent)
        self.sb_item = samplebox_item
        self.sb_item.box_runned.connect(self.redraw)
        self.sb_item.estimation_added.connect(self.redraw)
        
        self.black_box = black_box
        self.setBackground('w')
        
        
        self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
        self.reaction.triggered.connect(self.redraw)
        self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
        
        
        
        # implicitně Y je v logaritmickem měřítku
        self.setLogMode(False, True)

        x = y = () # zde jen vytvoříme kostru, nakrmíme daty v .redraw()
        
        
        # nechapu, proč těm Itemům ríkám "propíska" 
        # propíska? Их есть у нас!
        
        self.Voronoi_2_point_upper_bound = self.plot(x, y, pen='y')
        self.Voronoi_2_point_lower_bound = self.plot(x, y, pen='y')
        
        fill_color = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
        self.fill = pg.FillBetweenItem(self.Voronoi_2_point_upper_bound, self.Voronoi_2_point_lower_bound, fill_color)
        self.addItem(self.fill)
        
        self.Voronoi_2_point_failure_rate = self.plot(x, y, pen=(195,46,212))
        self.Voronoi_2_point_pure_failure_rate = self.plot(x, y, pen='m')
        self.Voronoi_failure_rate = self.plot(x, y, pen='r')
        
        self.pen_exact = self.plot(x, y, pen='b') # blue
        self.pen_one = self.plot(x, y, pen='k') # black
        
        self.redraw()
    
   
    def redraw(self):
        # kruci, ještě navic i generovať pokažde znovu...
        metrics = {'Voronoi_2_point_upper_bound':{},\
                    'Voronoi_2_point_lower_bound':{},\
                    'Voronoi_2_point_failure_rate':{},\
                    'Voronoi_2_point_pure_failure_rate':{},\
                    'Voronoi_failure_rate':{},}
        xmin = np.inf
        xmax = -np.inf
        try: # тут всё что угодно может пойти не так
            # new-style: šecko leží dohromady a každý z toho
            # bere co chce a jak chce
            # ne že by to bylo nějak šetrný
            # estimation je slovníkem
            for estimation in self.black_box.estimations:
                # nsim musí mäť každej odhad
                # pokud nemá - je třeba jej prostě opravit
                nsim = estimation['nsim']
                
                
                for metric, metric_dict in metrics.items():
                    try: 
                        if estimation[metric] > 0:
                            metric_dict[nsim] = estimation[metric]
                            if nsim > xmax:
                                xmax = nsim
                            if nsim < xmin:
                                xmin = nsim
                    except KeyError as e:
                        pass #print(self.__class__.__name__ + ":", repr(e))
            
            for metric, metric_dict in metrics.items():
                pen = getattr(self, metric)
                # nikdo neslibil, že budou v pořadí
                x = np.sort(tuple(metric_dict.keys()))
                y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
                pen.setData(x, y)
                
            if (xmax - xmin) > 0:
                self.pen_one.setData((xmin,xmax), (1, 1))
                if hasattr(self.black_box, 'pf_exact'):
                    # poslední. I když spadne, tak už nikomu moc nevadí
                    self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
        
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        
        
        # pen_f.opts['logMode']
        # pen_outside.setLogMode(False, False)
        #setLogMode(False, False)
        #f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
        #win.addItem(f)







"""
=============
Эскерон виӝет 
Widgety odhadů
Estimation widgets
===================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""

        
        
class SimplexEstimationWidget(pg.LayoutWidget):
    """
    addLabel(text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs)
    """
    # I'd like to get access to the samplebox stuff via the container's reference, 
    # but relying to Qt's parent mechanism makes me worry.
    def __init__(self, samplebox_item,  parent=None, *args, **kwargs):
        super().__init__(parent)
        # sb like samplebox, of course
        self.sb_item = samplebox_item
        
        self.sb_item.box_runned.connect(self.on_box_run)
        self.sb_item.slice_changed.connect(self.self_clear)
        self.sb_item.space_changed.connect(self.on_space_changed)
        self.sb_item.redraw_called.connect(self.redraw)
        #☺ na internetu všichni tak dělaj
        self.setup()
        
    def setup(self):
        params = list()
        params.append({'name': 'model space', 'type': 'list', 'values': self.sb_item.spaces, 'value': 'Rn'})
        params.append({'name': 'sampling space', 'type': 'list', 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
        params.append({'name': 'nodes per simplex', 'type': 'int', 'limits': (1, float('inf')), 'value': 1000, 'default': 1000})    
        params.append({'name': 'node (pixel) size', 'type': 'float', 'limits': (0, float('inf')), 'value': 3.5, 'default': self.sb_item.px_size})
        xkcd_green = (167, 255, 181, 255) # xkcd:light seafoam green #a7ffb5
        xkcd_red   = (253, 193, 197, 255) # xkcd: pale rose (#fdc1c5)
        xkcd_cream = (255, 243, 154, 255) # let's try xkcd: dark cream (#fff39a)
        params.append({'name': 'failure', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_red, xkcd_red])})
        params.append({'name': 'success', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_green, xkcd_green])})
        params.append({'name': 'mix', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_cream, xkcd_cream])})
        params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
        
        ### Create tree of Parameter objects
        self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
        # I don't know why that signals do not work for me
        # Only sigTreeStateChanged works, but I don't want to struggle with it
        # May be I'll report the issue 
        #self.param.sigValueChanged.connect(self.param_changed)
        #self.param.sigValueChanging.connect(self.param_changing)
        
        ### Create ParameterTree widget
        self.ptree = pg.parametertree.ParameterTree()
        self.ptree.setParameters(self.param, showTop=False)
        
        self.addWidget(self.ptree, row=0, col=0, colspan=2)
        
        
        
        self.btn = QtGui.QPushButton('estimate')
        self.addWidget(self.btn, row=1, col=0)
        self.btn.clicked.connect(self.run_stm)
        
        self.btn2 = QtGui.QPushButton('redraw')
        self.addWidget(self.btn2, row=1, col=1)
        self.btn2.clicked.connect(self.recolor)
        
        
        self.table = pg.TableWidget(sortable=False)
        self.addWidget(self.table, row=2, col=0, colspan=2)
        

        
        # pro začatek postačí
        # triangulaci kreslím jen v 2D
        self.triangulation = [] 
        self.simplices = []
        self.max_simplices = {'success':0, 'failure':0, 'mix':0}



        
    def recolor(self):
        # indikace
        #self.setDisabled(True)
        with pg.BusyCursor():
            #☺ Krucinal, kdo ten OrderedDict vymyslel?
            params = self.param.getValues()
            coloring = params['coloring'][0]
            
            # přebarvíme nějak tečičky 
            # callback vybírám ze svého kódu, ten musí bejt v pořádku
            # ne že by to bylo dokonalé bezpečný, 
            # ale na lokálním počítači asi to není až tak zavadný
            coloring_function = getattr(self, coloring)
            
            # hura! Jedeme!
            coloring_function()
            
            
        # indikace
        #self.setEnabled(True)

    def on_space_changed(self, *args, **kwargs):
        # asi stači překreslit propísky z tri_bound'ov
        pass


    # ten hlavní modul se dočkal na překopávání
    def on_box_run(self, *args, **kwargs):
        # je třeba zkontrolovat autorun a restartovat výpočet
        if self.param.getValues()['Run with the box'][0]:
            self.run_stm()
        #else:
        #    self.self_clear()
    
        
    def redraw(self, *args, **kwargs):
        self.triangulation.clear()
        self.simplices.clear()
        self.max_simplices['success'] = 0
        self.max_simplices['failure'] = 0
        self.max_simplices['mix'] = 0
            
        
    def self_clear(self):
        # odebereme prvky-propísky z hlavního plotu
        for tri_bound, plot_item in self.triangulation:
            self.sb_item.central_widget.removeItem(plot_item)
        for nodes, plot_item, cell_stats in self.simplices:
            self.sb_item.central_widget.removeItem(plot_item)
        
        self.redraw()
    

    def run_stm(self):
        # indikace
        #self.setDisabled(True)
        with pg.BusyCursor():
            nsim = self.sb_item.slider.value()
            sample_box = self.sb_item.sample_box[:nsim]
            #☺ Krucinal, kdo ten OrderedDict vymyslel?
            params = self.param.getValues()
            model_space = params['model space'][0]
            sampling_space = params['sampling space'][0]
            if sampling_space == 'None':
                sampling_space = None
            nis = params['nodes per simplex'][0]
            
            #č je třeba skrýt prvky z minula
            self.self_clear()

            
            try:
                data = stm.simple_simplex_estimation(sample_box, model_space=model_space,\
                                         sampling_space=sampling_space, nis=nis, callback=self.callback)
                
                if hasattr(self.sb_item.sample_box, 'estimations'):
                    self.sb_item.sample_box.estimations.append(data)
                    self.sb_item.estimation_added.emit()
                self.table.setData(data)
            except BaseException as e:
                msg = "error during estimation "
                error_msg = self.__class__.__name__ + ": " + msg + repr(e)
                print(error_msg)
            
                
              
            
        # indikace
        #self.setEnabled(True)
        
        
    def callback(self, estimation, simplex, nodes, cell_stats, out_nodes, *args, **kwargs):
        # stm trianguľaciju pokažde provadí znovu, proto skoro nemá cenu drbat se s její znovupoužitím
        if (simplex.nvar==2):
            ns = 100
            
            
            simplex_tri = getattr(simplex, estimation['model_space'])
            x_tri = np.linspace(simplex_tri[0,0], simplex_tri[1,0], ns, endpoint=False)
            y_tri = np.linspace(simplex_tri[0,1], simplex_tri[1,1], ns, endpoint=False)
            x_tri = np.append(x_tri, np.linspace(simplex_tri[1,0], simplex_tri[2,0], ns, endpoint=False))
            y_tri = np.append(y_tri, np.linspace(simplex_tri[1,1], simplex_tri[2,1], ns, endpoint=False))
            x_tri = np.append(x_tri, np.linspace(simplex_tri[2,0], simplex_tri[0,0], ns, endpoint=True))
            y_tri = np.append(y_tri, np.linspace(simplex_tri[2,1], simplex_tri[0,1], ns, endpoint=True))
                
            tri_bound_tri = np.array((x_tri, y_tri)).T
            # vytvořme sample
            tri_bound = self.sb_item.sample_box.sampled_plan.new_sample(tri_bound_tri, space=estimation['model_space'])
            
            # draw 
            x, y = (*getattr(tri_bound, self.sb_item.space).T,)
            plot_item = self.sb_item.plotWidget.plot(x, y, pen='c')
            
            # uložíme data
            self.triangulation.append((tri_bound, plot_item))
            
            #plot_item.show()
        
        
        #    
        # tečičky
        #
        
        
        # draw 
        x, y = (*getattr(nodes, self.sb_item.space).T,)
        
        color = self.get_color(cell_stats)
        #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
        plot_item = self.sb_item.plotWidget.plot(x, y, pen=None, symbol='o', symbolPen=None,\
                                     symbolBrush=(color), symbolSize=self.sb_item.px_size, name='IS localized nodes')
        


        # ToDO
        # přebarvíme tečičky podle obsahu pravděpodobnosti
##            for nodes, plot_item, cell_stats in self.simplices:
##                plot_item.setSymbolBrush(self.get_color(cell_stats))


        # uložíme data
        self.simplices.append((nodes, plot_item, cell_stats))
        
        
        
        # keep the GUI responsive :)
        self.sb_item.app.processEvents()
        
            
    
        
    def get_color(self, cell_stats):
        event = cell_stats['event']
        cell_probability = cell_stats['cell_probability']
        # generally
        if event == 'success':
            color = [167, 255, 181]# xkcd:light seafoam green #a7ffb5
        elif event == 'failure':
            color = [253, 193, 197] # xkcd: pale rose (#fdc1c5)
        else:# 'mix'
            color = [255, 243, 154] # let's try xkcd: dark cream (#fff39a)
            
        # let's play with blue a little bit
        # chcu ještě na konci prekreslit s různejma barvičkama, podle obsahu pravděpodobnosti
        if self.max_simplices[event] < cell_probability:
            self.max_simplices[event] = cell_probability
            # bez modrého - maximální intenzita
            color[2] = 0
        else:
            ratio = cell_probability / self.max_simplices[event]
            color[2] = 255 - int(ratio*255) 
        
        return tuple(color)
            
            
            







class VoronoiEstimationWidget(pg.LayoutWidget):
    """
    addLabel(text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs)
    """
    # I'd like to get access to the samplebox stuff via the container's reference, 
    # but relying to Qt's parent mechanism makes me worry.
    def __init__(self, samplebox_item,  parent=None, *args, **kwargs):
        super().__init__(parent)
        # sb like samplebox, of course
        self.sb_item = samplebox_item
        
        self.sb_item.box_runned.connect(self.on_box_run)
        self.sb_item.slice_changed.connect(self.self_clear)
        self.sb_item.space_changed.connect(self.on_space_changed)
        self.sb_item.redraw_called.connect(self.redraw)
        #☺ na internetu všichni tak dělaj
        self.setup()
        
    def setup(self):
        # model_space='Rn', sampling_space=None, p_norm=1, budget=20000
        params = [{'name': 'method', 'type': 'list', 'values': ['Voronoi_tesselation','Voronoi_2_point_estimation'], 'value': 'Voronoi_2_point_estimation'}]
        params.append({'name': 'model space', 'type': 'list', 'values': self.sb_item.spaces, 'value': 'Rn'})
        params.append({'name': 'sampling space', 'type': 'list', 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
        params.append({'name': 'p-norm', 'type': 'float', 'limits': (1, float('inf')), 'value': 1, 'default': np.inf})
        params.append({'name': 'budget', 'type': 'float', 'limits': (1, float('inf')), 'value': 20000, 'default': 20000})
        self.coloring_modes = ['simple_coloring', 'cell_probability_coloring','node_pf_coloring']
        params.append({'name': 'coloring', 'type': 'list', 'values': self.coloring_modes, 'value': self.coloring_modes[1]})
        params.append({'name': 'node (pixel) size', 'type': 'float', 'limits': (0, float('inf')), 'value': 3, 'default': 1})
        params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
        
        ### Create tree of Parameter objects
        self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
        # I don't know why that signals do not work for me
        # Only sigTreeStateChanged works, but I don't want to struggle with it
        # May be I'll report the issue 
        #self.param.sigValueChanged.connect(self.param_changed)
        #self.param.sigValueChanging.connect(self.param_changing)
        
        ### Create ParameterTree widget
        self.ptree = pg.parametertree.ParameterTree()
        self.ptree.setParameters(self.param, showTop=False)
        
        self.addWidget(self.ptree, row=0, col=0, colspan=2)
        
        
        self.btn = QtGui.QPushButton('estimate')
        self.addWidget(self.btn, row=1, col=0)
        self.btn.clicked.connect(self.run_stm)
        
        self.btn2 = QtGui.QPushButton('redraw')
        self.addWidget(self.btn2, row=1, col=1)
        self.btn2.clicked.connect(self.recolor)
        
#        self.autorun = QtGui.QCheckBox('Run with the box')
#        self.addWidget(self.autorun, row=1, col=1)
        
        self.table = pg.TableWidget(sortable=False)
        self.addWidget(self.table, row=2, col=0, colspan=2)
        
        # pro začatek postačí
        self.cells = []
        # probability of the biggest cell
        # used for coloring
        self.p_cell_max = {'success':0, 'failure':0}
     
     
     
    def on_box_run(self, *args, **kwargs):
        # je třeba zkontrolovat autorun a restartovat výpočet
        if self.param.getValues()['Run with the box'][0]:
            self.run_stm()
        #else:
            #self.self_clear()
    
    def redraw(self, *args, **kwargs):
        self.cells.clear()
        self.p_cell_max['success'] = 0
        self.p_cell_max['failure'] = 0
    
    # I'll rename after main widget refactoring
    def recolor(self):
        # indikace
        #self.setDisabled(True)
        with pg.BusyCursor():
            # Krucinal, kdo ten OrderedDict vymyslel?
            params = self.param.getValues()
            coloring = params['coloring'][0]
            
            # přebarvíme nějak tečičky 
            # callback vybírám ze svého kódu, ten musí bejt v pořádku
            # ne že by to bylo dokonalé bezpečný, 
            # ale na lokálním počítači asi to není až tak zavadný
            coloring_function = getattr(self, coloring)
            
            # hura! Jedeme!
            coloring_function()
            
            
        # indikace
        #self.setEnabled(True)
    
    
    def on_space_changed(self, *args, **kwargs):
        # asi stači překreslit propísky z tri_bound'ov
        pass
        
        
    def self_clear(self):
        # odebereme prvky-propísky z hlavního plotu
        for nodes, plot_item, cell_stats in self.cells:
            self.sb_item.central_widget.removeItem(plot_item)
        
        self.redraw()
        



    def run_stm(self):
        # indikace
        #self.setDisabled(True)
        with pg.BusyCursor():
            nsim = self.sb_item.slider.value()
            sample_box = self.sb_item.sample_box[:nsim]
            # Krucinal, kdo ten OrderedDict vymyslel?
            params = self.param.getValues()
            method = params['method'][0]
            model_space = params['model space'][0]
            sampling_space = params['sampling space'][0]
            if sampling_space == 'None':
                sampling_space = None
            p_norm = params['p-norm'][0]
            budget = params['budget'][0]
            coloring = params['coloring'][0]
            
            # je třeba skrýt prvky z minula
            self.self_clear()
            
            
            # přebarvíme nějak tečičky 
            # callback vybírám ze svého kódu, ten musí bejt v pořádku
            # ne že by to bylo dokonalé bezpečný, 
            # ale na lokálním počítači asi to není až tak zavadný
            coloring_function = getattr(self, coloring)
            
            
            try:
                stm_function = getattr(stm, method)
                # model_space='Rn', sampling_space=None, p_norm=1, budget=20000
                data = stm_function(sample_box, model_space=model_space, sampling_space=sampling_space,\
                                                     p_norm=p_norm, budget=budget, callback=coloring_function)
                
                if hasattr(self.sb_item.sample_box, 'estimations'):
                    self.sb_item.sample_box.estimations.append(data)
                    self.sb_item.estimation_added.emit()
                self.table.setData(data)
                    
            except BaseException as e:
                msg = "error during estimation "
                error_msg = self.__class__.__name__ + ": " + msg + repr(e)
                print(error_msg)
                
            
            
        # indikace
        #self.setEnabled(True)
    
        
        
            
        
    def node_pf_coloring(self, estimation=None, nodes=None, cell_stats=None, out_nodes=None, *args, **kwargs):
        """
        if nodes and cell_stats  provided we will add them to self.cells
        otherwise function redraw items in self.cells
        """
        
        if nodes is None:
            for cell in self.cells:
                nodes, plot_item, cell_stats = cell
                # odebereme prvky z hlavního plotu
                # zde je třeba prvky vygenerovat znovu 
                # protože nikdo neví co tam bylo před tím
                # takhle, nechce se mi drbat s tím, co tam bylo před tím
                # komplikace ze strany pyqtgraph
                self.sb_item.plotWidget.removeItem(plot_item)
                
                # bacha, potřebuji prvek uložiť in-place
                cell[1] = self.node_pf_scatter_plot(nodes, cell_stats)
        
        # máme nodes, tj. jedeme poprvé        
        else:
            plot_item = self.node_pf_scatter_plot(nodes, cell_stats)
            
            # uložíme data
            self.cells.append([nodes, plot_item, cell_stats])
            
            # keep the GUI responsive :)
            self.sb_item.app.processEvents()
            
            
            
            
    def node_pf_scatter_plot(self, nodes, cell_stats):
        pos = getattr(nodes, self.sb_item.space)
        symbol_size = self.param.getValues()['node (pixel) size'][0]
            
        # zas, нет ножек - нет мультиков
        # node_pf_estimations nemusejí bejt
        try:
            # zkusmě pro jednoduchost 
            # čírou RGB hračku
            npf = nodes.node_pf_estimations
            colors = tuple((npf[i]*255, (1-npf[i])*255, 0) for i in range(len(pos))) 
            # sice dokumentace popisuje víc možností zadávání, 
            # ale toto zadávání různejch barviček je pro mě jediné fungujicí. Drbal jsem s tím do znechucení
            # je v podstatě opsané z příkladu
            # rovnou přes PlotDataItem mi nefunguje
            # žádné jiné možností zadávání já jsem v zdrojacích 
            # pyqtgraph (konkretně v PlotDataItem a v ScatterPlotItem) neuviděl
            # tuším, že je to neunosně drahý
            list_of_dicts = list({'pos': pos[i], 'size':symbol_size, 'pen': colors[i], 'brush':colors[i], 'symbol':'o'} for i in range(len(pos)))
            plot_item = pg.ScatterPlotItem(list_of_dicts)
            self.sb_item.plotWidget.addItem(plot_item)
            return plot_item
            
        except BaseException as e:
            msg = "node_pf_coloring has problems "
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)
            self.error.emit(error_msg)
            # simple coloring
            event = cell_stats['event']
            color = self.get_color(event)
            #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
            return self.sb_item.plotWidget.plot(pos, pen=None, symbol='o', symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
        

        
        
    
    def simple_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
        """
        if nodes and cell_stats  provided we will add them to self.cells
        otherwise function redraw items in self.cells
        """
        symbol_size = self.param.getValues()['node (pixel) size'][0]
        
        if nodes is None:
            for cell in self.cells:
                nodes, plot_item, cell_stats = cell
                # odebereme prvky z hlavního plotu
                # zde je třeba prvky vygenerovat znovu 
                # protože nikdo neví co tam bylo před tím
                # takhle, nechce se mi drbat s tím, co tam bylo před tím
                # komplikace ze strany pyqtgraph
                self.sb_item.plotWidget.removeItem(plot_item)
                
                # draw 
                pos = getattr(nodes, self.sb_item.space)
                #x, y = (*getattr(nodes, self.sb_item.space).T,)
                
                event = cell_stats['event']
                color = self.get_color(event)
                #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
                # bacha, potřebuji prvek uložiť in-place
                cell[1] = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
                        symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
        
        # máme nodes, tj. jedeme poprvé        
        else:
            # draw tečičky
            #
            pos = getattr(nodes, self.sb_item.space)
            
            event = cell_stats['event']
            color = self.get_color(event)
            #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
            plot_item = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
                     symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
            
            # uložíme data
            self.cells.append([nodes, plot_item, cell_stats])
            
            # keep the GUI responsive :)
            self.sb_item.app.processEvents()
    
        
            
    def cell_probability_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
        """
        if nodes and cell_stats  provided we will add them to self.cells
        otherwise function redraw items in self.cells
        """
        symbol_size = self.param.getValues()['node (pixel) size'][0]
        
        if nodes is None:
            # odebereme prvky z hlavního plotu
            # zde je třeba prvky vygenerovat znovu 
            # protože nikdo neví co tam bylo před tím
            # takhle, nechce se mi drbat s tím, co tam bylo před tím
            # komplikace ze strany pyqtgraph
            for nodes, plot_item, cell_stats in self.cells:
                self.sb_item.plotWidget.removeItem(plot_item)
                
                event = cell_stats['event']
                cell_probability = cell_stats['cell_probability']
                if self.p_cell_max[event] < cell_probability:
                    self.p_cell_max[event] = cell_probability
                
            # přebarvíme tečičky podle obsahu pravděpodobnosti
            for cell in self.cells:
                nodes, plot_item, cell_stats = cell
                # draw 
                pos = getattr(nodes, self.sb_item.space)
                #x, y = (*getattr(nodes, self.sb_item.space).T,)
                
                event = cell_stats['event']
                cell_probability = cell_stats['cell_probability']
                # bez modrého - maximální intenzita
                blue_intensity = 1 - cell_probability / self.p_cell_max[event]
                color = self.get_color(event, blue_intensity)
                #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
                # bacha, potřebuji prvek vložit zpätky
                cell[1] = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
                            symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
        
        # máme nodes, tj. jedeme poprvé        
        else:
            event = cell_stats['event']
            cell_probability = cell_stats['cell_probability']
            # zkontrolujeme probability
            if self.p_cell_max[event] < cell_probability:
                self.p_cell_max[event] = cell_probability
                # a hned všecko dotyčné přebarvíme podle obsahu pravděpodobnosti
                for cell in self.cells:
                    if event == cell[2]['event']:
                        # bez modrého - maximální intenzita
                        # zde cell_probability se rovná self.p_cell_max[event]
                        # ale bacha! Nesplet se jinde!
                        blue_intensity = 1 - cell[2]['cell_probability'] / cell_probability
                        color = self.get_color(event, blue_intensity)
                        # bacha, potřebuji prvek vložit zpätky
                        cell[1].setSymbolBrush(color)
                        cell[1].setSymbolPen(color)
            
            # bez modrého - maximální intenzita
            blue_intensity = 1 - cell_probability / self.p_cell_max[event]
            color = self.get_color(event, blue_intensity)
            
            
            # draw tečičky
            #
            pos = getattr(nodes, self.sb_item.space)
            #x, y = (*getattr(nodes, self.sb_item.space).T,)
            
            #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
            plot_item = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
                        symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
            
            # uložíme data
            self.cells.append([nodes, plot_item, cell_stats])
            
            # keep the GUI responsive :)
            self.sb_item.app.processEvents()
        
                
                
    def get_color(self, event, blue_intensity=None):
        """
        get color for 'simple_coloring' or 'cell_probability_coloring'
        """
        # generally
        if event == 'success':
            color = [167, 255, 181]# xkcd:light seafoam green #a7ffb5
        elif event == 'failure':
            color = [253, 193, 197] # xkcd: pale rose (#fdc1c5)
        # já vím, že Voronoi nemá 'mix', эн но юа
        else:# 'mix'
            color = [255, 243, 154] # let's try xkcd: dark cream (#fff39a)
            
        if blue_intensity is not None:
            # let's play with blue a little bit
            # chcu mít korektní výstup
            # aspoň v něčem chcu být jistý
            if blue_intensity > 1:
                color[2] = 255
            elif blue_intensity < 0:
                color[2] = 0
            else:
                # pyqtgraph žere barvy i s čarkou
                # ale my je mu davat nebudeme
                color[2] = int(blue_intensity*255) 
            
        return tuple(color)            
                    




"""
===========
♥ Чыры-пыры 
č Jiné
E Miscellaneous
===============
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""

        
        
class CandidatesWidget(pg.LayoutWidget):
    """
    """
    # I'd like to get access to the samplebox stuff via the container's reference, 
    # but relying to Qt's parent mechanism makes me worry.
    def __init__(self, samplebox_item,  parent=None, *args, **kwargs):
        super().__init__(parent)
        # sb like samplebox, of course
        self.sb_item = samplebox_item
        
        #self.sb_item.box_runned.connect(self.on_box_run)
        self.sb_item.slice_changed.connect(self.rerun)
        self.sb_item.space_changed.connect(self.rerun)
        self.sb_item.redraw_called.connect(self.redraw)
        #☺ na internetu všichni tak dělaj
        self.setup()
        
    def setup(self):
        # 1
        #
        self.autorun = QtGui.QCheckBox('Show')
        self.autorun.stateChanged.connect(self.rerun)
        self.addWidget(self.autorun)
        
        self.btn = QtGui.QPushButton('redraw')
        self.addWidget(self.btn, row=0, col=1)
        self.btn.clicked.connect(self.rerun)
        
        # 2
        #
        #č predpokladam pandas verzi CandyBox'u
        #items = list(self.sb_item.sample_box.candidates_index[-1].df.columns)
        try:
            #č načíst sloupce prostě z libovolného vzorku
            df = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
            items = df.columns
        except:
            #♥ мыным дунне
            items = []
            
        self.attr = pg.ComboBox(items=items)
        #self.attr.activated.connect(self.redraw)
        self.addWidget(self.attr, row=1, col=0, colspan=2)
        
        # 3
        #
        self.gradient = pg.GradientWidget(self, orientation='right')
        self.addWidget(self.gradient, row=2, col=1)
        
        #E pens, i.e. handles of PlotItem
        self.pens = []


    def run_stm(self):
        #č indikace
        #self.setDisabled(True)
        with pg.BusyCursor():
            
            color_map = self.gradient.colorMap()
            
            try:#č může se tu stat cokoliv
                #č načíst sloupce prostě z libovolného vzorku
                cb = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
                #č je třeba mít seznam aktualní
                self.attr.setItems(list(cb.df.columns))
                
                #č neplest s self.attr!
                attr = self.attr.currentText()
                
                #č kruci, nejdřív je třeba najít maxvalue, minvalue je implicitně nula
                maxvalue = -np.inf
                minvalue = np.inf
                for id, cb in self.sb_item.sample_box.candidates_index.items():
                    array = getattr(cb, attr)
                    maxcb = np.nanmax(array)
                    mincb = np.nanmin(array)
                    if maxcb > maxvalue:
                        maxvalue = maxcb
                    if mincb < minvalue:
                        minvalue = mincb
                
                
                
                #č a teď jdeme!
                for id, cb in self.sb_item.sample_box.candidates_index.items():
                    array = getattr(cb, attr)
                    if np.isnan(array).any():
                        msg = "%s candidates has nans in %s attribute"%(id, attr)
                        error_msg = self.__class__.__name__ + ": " + msg
                        print(error_msg)
                    mask = np.isfinite(array)
                    values = array[mask]
                    norm_values = (values - minvalue) / (maxvalue - minvalue)
                    
                    pos = getattr(cb, self.sb_item.space)[mask]
                    
                    #č sehnal jsem toto ze zdrojaků pyqtgraph
                    style = dict(pen=None, symbol='o', symbolSize=self.sb_item.px_size, symbolPen=pg.mkPen(None))
                    style['symbolBrush'] = np.array([pg.functions.mkBrush(*x) for x in color_map.map(norm_values)])
                    pen = self.sb_item.plotWidget.plot(pos, data=values, **style)
                    pen.setZValue(-1)
                    self.pens.append(pen)
                
            except BaseException as e:
                msg = ""
                error_msg = self.__class__.__name__ + ": " + msg + repr(e)
                print(error_msg)
                self.error.emit(error_msg)
            
            
            
        # indikace
        #self.setEnabled(True)
        

        
    #č současně ten hlavní modul se pokusí zavolat redraw při zpouštění boxu
    #č ten hlavní modul se těší na překopávání
    def rerun(self, *args, **kwargs):
        #č uklizení budu chtit jednoznačně 
        self.self_clear()
        #č a teď řešíme, zda je třeba restartovat výpočet
        if self.autorun.isChecked():
            self.run_stm()

    def redraw(self, *args, **kwargs):
        self.pens.clear()
            
        
    def self_clear(self):
        #č odebereme prvky-propísky z hlavního plotu
        for plot_item in self.pens:
            self.sb_item.central_widget.removeItem(plot_item)
        
        self.pens.clear()
    
    
        #E not implementeed yet on the main window side        
#    def on_space_changed(self, *args, **kwargs):
#        pass    
        

        


Mode Type Size Ref File
100644 blob 17474 79f2258efa33670c57a70e41eff5d117bf69dcb7 IS_stat.py
100644 blob 6 0916b75b752887809bac2330f3de246c42c245cd __init__.py
100644 blob 63303 4a921c50676e2e8d1fd12a004d8dad7d2bcd1d38 blackbox.py
100644 blob 11078 cd8e7e5ab6fa5edde14878d8fa90bc65012ccc0d candybox.py
100644 blob 31020 1a4e4f3ccbfee2218309ffb33d1cf46bc249d4b9 estimation.py
100644 blob 18660 c1ef0f2dd7e992953ebd0b295de5c5c6721215d6 f_models.py
100644 blob 31025 70bab60405bfe783a2f7a9f2c41b7c1629d3d474 g_models.py
100644 blob 52315 cbecebc34eb21cc476b640b6c95ca9ba5ce745e1 gl_plot.py
100644 blob 2718 5d721d117448dbb96c554ea8f0e4651ffe9ac457 gp_plot.py
100644 blob 29393 96162a5d181b8307507ba2f44bafe984aa939163 lukiskon.py
100644 blob 10489 1f6dd06a036fdc4ba6a7e6d61ac0b84e8ad3a4c1 mplot.py
100644 blob 993 593f0411936cebc2b6ac12775f1b7c62e53e717c plot.py
100644 blob 2807 1feb1d43e90e027f35bbd0a6730ab18501cef63a plotly_plot.py
100644 blob 61709 379db4a6236832e448f387adb9063ab547e53e1f qt_plot.py
100644 blob 57475 645d9c4a2339f5a3997f1f16e61b58d0defba6cc qt_plot_old.py
100644 blob 6304 7fc6ac75e415df43af5b7aa9d6d1848aa5d0963d reader.py
100644 blob 4284 a0e0b4e593204ff6254f23a67652804db07800a6 samplebox.py
100644 blob 5553 bac994ae58f1df80c7f8b3f33955af5402f5a4f3 sball.py
100644 blob 2800 109ef02b48b0e735d9081be69bffd0471675bc98 simplex.py
100644 blob 21623 281aef80556b8d22842b8659f6f0b7dab0ad71af whitebox.py
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