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 (f4ef8295edbfd2509cc6026f797536baeb53a8f7) (110138 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
from . import misc

         
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):
    #č box_runned 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()
    
    # INHERITED by gl_plot
    # 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("%sD: %s" %(sample_box.nvar, sample_box.gm_signature))
        
        self.kwargs = kwargs
        self.sample_box = sample_box
        #sample_box.sample_box._log = self.logger
        self.last_shot = None
        try:
            self.space = self.sample_box.tri_space
        except AttributeError:
            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.central_widget.setBackground('w')
        self.px_size = 3.5
        self.ncircles = 5
        self.redraw_called.connect(self.central_widget.clear)
        
        
    # INHERITED by gl_plot
    # intended as a common setup function
    def setup(self):    
        
        self.bar = self.menuBar()
        self.view = self.bar.addMenu("View")
        
        self.graph_menu = self.bar.addMenu("Box")
        self.batch_run_action = QtGui.QAction("Batch run", self)
        self.batch_run_action.triggered.connect(self.batch_run)
        self.graph_menu.addAction(self.batch_run_action)
        
        
        ### 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.label_nsim = QtGui.QLabel()
        self.label_nsim.setText(str(self.sample_box.nsim))
        
        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.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)
        
        self.simplex_data = SimplexEstimationData(self.sample_box, self)
        #č graphy už nemusí jít po stm widgetech
        dock = QtGui.QDockWidget("TRI_overall estimation graph", self)
        dock.setWidget(TriEstimationGraph(self.sample_box, 'TRI_overall_estimations', self, dock))
        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("Simplex error graph", self)
        dock.setWidget(SimplexErrorGraph(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 = dock_l = QtGui.QDockWidget("Box tree", self)
        dock.setWidget(BoxTreeWidget(self, dock))
        self.dockables.append(dock)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
        
        
        
        dock = QtGui.QDockWidget("View", self)
        dock.setWidget(self.list_view)
        self.dockables.append(dock)
        self.tabifyDockWidget(dock_l, 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.view_items = []
        self.view_items.append(BasePlotting(self))
        self.view_items.append(UnitCube(self))
        self.view_items.append(AspectLock(self))
        self.view_items.append(LastShot(self))
        self.view_items.append(Circles(self))
        self.view_items.append(Isocurves(self))
        self.view_items.append(Boundaries(self))
        self.view_items.append(ConvexHull2D(self))
        self.view_items.append(Triangulation(self))
        
        
        

        dock = dock_r = QtGui.QDockWidget("Simplex-based pf estimation", self)
        dock.setWidget(FastSimplexEstimationWidget(self, dock))
        self.view.addAction(dock.toggleViewAction())
        self.dockables.append(dock)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        
        
        dock = 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.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!
    #

    # INHERITED by gl_plot
    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()
            
    # INHERITED by gl_plot
    def change_space(self, space):
        self.space = space
        self.space_changed.emit()
        #self.plot_widget_2d()
        #self.slice_plot_data()
        
    # INHERITED by gl_plot
    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()


        
    # INHERITED by gl_plot
    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))
        
    # INHERITED by gl_plot
    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 batch_run(self):
        #pg.QtGui.QInputDialog.getInt(
        runs, ok = QtGui.QInputDialog.getInt(self,"Batch run","runs")
  
        if ok:
            with pg.ProgressDialog("Running..", 0, runs, cancelText='Stop', busyCursor=True) as dlg:
                for i in range(runs):
                    # keep the GUI responsive :)
                    self.app.processEvents()
                    
                    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()
                    
                    dlg += 1
                    if dlg.wasCanceled():
                        break
                    
         
    




        



"""
==============
у График люкет
č Grafické prvky
E Drawing modules
=================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""


class BasePlotting:
    def __init__(self, w):
        self.w = w
        #self.w.box_runned.connect(self.redraw) #č dublikuje slice_changed
        self.w.space_changed.connect(self.plot)
        self.w.slice_changed.connect(self.plot)
        self.w.redraw_called.connect(self.redraw)
        
    
    def redraw(self):
        plot_widget = self.w.central_widget
        #size=self.w.px_size*1.5
        pos = () #np.empty((nsim, 4))
        size = self.w.px_size * 2
        self.failures = plot_widget.plot(pos, pen=None, symbol='x', symbolPen='r',\
                    symbolSize=size*1.5,  name='Failures') # symbolBrush=0.2,
        self.failures.setZValue(100)
        
        self.proxy_failures = plot_widget.plot(pos, pen=None, symbol='p', symbolPen=0.5,\
                symbolSize=size, symbolBrush=(217,83,25), name='Proxy failures')
        self.proxy_failures.setZValue(95)
        
        self.successes = plot_widget.plot(pos, pen=None, symbol='+', \
                    symbolSize=size*1.5, symbolPen='g',  name='Successes')
        self.successes.setZValue(90)
        
        self.proxy_successes = plot_widget.plot(pos, pen=None, symbol='p', symbolPen=0.5, \
                symbolSize=size, symbolBrush=(119,172,48), name='Proxy successes')
        self.proxy_successes.setZValue(85)
        
        self.plot()
        
    def plot(self):
        nsim = self.w.slider.value()
        
        sample_box = self.w.sample_box[:nsim]
        
        pos = getattr(sample_box, self.w.space)[:,:2]
        failsi = sample_box.failsi
        
        try: # proxy denotes to implicitly-known values
            proxy = sample_box.proxy
        except AttributeError:
            proxy = np.full(nsim, False, dtype=np.bool)
        
        mask = np.all((failsi, ~proxy), axis=0)
        self.draw(self.failures, pos[mask])
        
        mask = np.all((~failsi, ~proxy), axis=0)
        self.draw(self.successes, pos[mask])
        
        mask = np.all((failsi, proxy), axis=0)
        self.draw(self.proxy_failures, pos[mask])
        
        mask = np.all((~failsi, proxy), axis=0)
        self.draw(self.proxy_successes, pos[mask])
        
            
    @staticmethod
    def draw(plot_item, data):
        #č musím to udělat takhle
        #č jinač to zlobí při posunutích slajderu
        if len(data):
            plot_item.setData(data)
            plot_item.show()
        else:
            plot_item.hide()


class UnitCube:
    def __init__(self, w):
        self.w = w
        self.w.space_changed.connect(self.plot)
        self.w.redraw_called.connect(self.redraw)
        

    def redraw(self):
        plot_widget = self.w.central_widget
        self.frame = plot_widget.plot(pos=(), pen='k')
        self.plot()
        

    def plot(self):
        if self.w.space in ('P', 'U'):
            self.frame.setData((0,0,1,1,0), (0,1,1,0,0))
            self.frame.show()
        elif self.w.space in ('aP', 'aU'):
            x, y, *__ = (*self.w.sample_box.alpha,)
            self.frame.setData((0,0,x,x,0), (0,y,y,0,0))
            self.frame.show()
        else:
            self.frame.hide()






class AspectLock:
    def __init__(self, w):
        self.w = w

        self.item = QtGui.QListWidgetItem('Equal aspect')
        self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.item.setCheckState(QtCore.Qt.Unchecked)
        self.w.list_view.addItem(self.item)
        self.w.list_view.itemChanged.connect(self.set_aspect)

    def set_aspect(self):
        plot_widget = self.w.central_widget
        if self.item.checkState():
            plot_widget.setAspectLocked(lock=True, ratio=1)
        else:
            plot_widget.setAspectLocked(lock=False, ratio=1)
            
            


class LastShot:
    def __init__(self, w):
        self.w = w
        self.w.box_runned.connect(self.plot)
        self.w.space_changed.connect(self.plot)
        self.w.redraw_called.connect(self.redraw)

        self.item = QtGui.QListWidgetItem('Last shot')
        self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.item.setCheckState(QtCore.Qt.Checked)
        self.w.list_view.addItem(self.item)
        self.w.list_view.itemChanged.connect(self.show_slot)
        
    def show_slot(self, item):
        if item is self.item:
            self.plot()

    def redraw(self):
        pos = ()
        plot_widget = self.w.central_widget
        self.last = plot_widget.plot(pos, pen=None, symbol='o', symbolPen='c',  name='Last shot', symbolBrush=None)
        self.shot = plot_widget.plot(pos, pen=None, symbol='+', symbolPen='c',  name='Last shot')
        self.last.setZValue(110)
        self.shot.setZValue(110)
        
        self.plot()

    def plot(self):
        if self.item.checkState() and (self.w.last_shot is not None):
            pos = getattr(self.w.last_shot, self.w.space)[:,:2]
            self.last.setData(pos)
            self.shot.setData(pos)
            self.last.show()
            self.shot.show()
        else:
            self.last.hide()
            self.shot.hide()



#č Kružničky chcete?
#ё Кружочки ннада?
class Circles:
    def __init__(self, w):
        self.w = w
        self.w.space_changed.connect(self.plot)
        self.w.redraw_called.connect(self.redraw)
        
        self.name = 'Circles'
        self.item = QtGui.QListWidgetItem(self.name)
        self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.item.setCheckState(QtCore.Qt.Checked)
        self.w.list_view.addItem(self.item)
        self.w.list_view.itemChanged.connect(self.show_slot)
        
        self.color = 'k'
        self.z_value = -1

    def redraw(self):
        pos = ()
        plot_widget = self.w.central_widget
        
        self.circles = []
        ncircles = self.w.ncircles
        for r in range(ncircles):
            pen = pg.mkPen(color=self.color, width=self.w.px_size*(1-r/ncircles))
            circle = plot_widget.plot(pos=pos, pen=pen, name=self.name)
            circle.setZValue(self.z_value)
            self.circles.append(circle)
        
        self.plot()
        
    def show_slot(self, item):
        if item is self.item:
            self.plot()

    def plot(self):
        if self.item.checkState():
            
            f_model = self.w.sample_box.f_model
            
            nrod = 200
            phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
            cos_phi = np.cos(phi)
            sin_phi = np.sin(phi)
            for r in range(len(self.circles)):
                bound_x = r * cos_phi
                bound_y = r * sin_phi
                
                
                #оӵ малы транспонировать кароно? Озьы кулэ!
                bound = np.array((bound_x, bound_y)).T
                f = f_model.new_sample(bound, space='G', extend=True)
                pos = getattr(f, self.w.space)[:,:2]
                self.circles[r].setData(pos)
                self.circles[r].show()
            
        else:
            for circle in self.circles:
                circle.hide()


class Isocurves:
    def __init__(self, w):
        self.w = w
        self.w.space_changed.connect(self.on_space_changed)
        self.w.redraw_called.connect(self.redraw)

        self.contour_item = QtGui.QListWidgetItem('Isolevels') # Density contours
        self.contour_item.setFlags(self.contour_item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.contour_item.setCheckState(QtCore.Qt.Unchecked)
        self.w.list_view.addItem(self.contour_item)
        
        self.isocurve_item = QtGui.QListWidgetItem('Isocurves') 
        self.isocurve_item.setFlags(self.isocurve_item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.isocurve_item.setCheckState(QtCore.Qt.Unchecked)
        self.w.list_view.addItem(self.isocurve_item)
        
        self.w.list_view.itemChanged.connect(self.show_slot)
        
        self.z_value = 1
        self.ngrid = 300

    def redraw(self):
        self.curves = []
        if self.contour_item.checkState() or self.isocurve_item.checkState():
            #č nejdřív data
            f_model = self.w.sample_box.f_model
           
            ns = 100 #č levný IS
            sample = np.random.randn(ns, 2)*3
            self.f = f_model.new_sample(sample, space='G', extend=True)
            
            self.on_space_changed()
           
    def on_space_changed(self):
        points = getattr(self.f, self.w.space)
            
        #č valčím s nekoněčno
        mask = np.all(np.isfinite(points), axis=1)
        
        self.max = np.max(points[mask], axis=0)
        self.min = np.min(points[mask], axis=0)

        ngrid = self.ngrid
        grid = np.mgrid[0:ngrid,0:ngrid].T.reshape(-1, 2)
        # scale
        grid = self.grid_scale(grid)
    
        f_model = self.w.sample_box.f_model
        self.pdf = f_model.sample_pdf(grid, space=self.w.space)
        #č pokud tam budou nanka, pak nikdo nic nedostane
        #č u současných f_modelů však nemají být
        self.pdf = np.nan_to_num(self.pdf, copy=False)
        #č reshape, flip a rot90 dle dokumentaci vracej view
        #č povede-li to numpy, data nebudou žrat další místo v paměti
        self.data = self.pdf.reshape((ngrid, ngrid))
        #č bůhví co ta pomocná funkce očekává za vstup
        #č a co je zvykem u těch borců co pracujou s obrázky 
        #č zkrátka, empiricky - buď zde flipnout a pootočit
        #č nebo tam dále prohodit souřadnice
        self.data = np.flip(self.data, axis=0)
        self.data = np.rot90(self.data, k=-1)
        
            
        self.plot()
            
        
    def show_slot(self, item):
        #č ne že by to bylo úplně ideální, ale ponechám dva druhy isočár sdruženými
        #č společný plot, společný redraw a společné self.curves
        if (item is self.contour_item) or (item is self.isocurve_item):
            if 'f' in self.__dict__:
                self.plot()
            else:
                self.redraw()
    
    def grid_scale(self, grid):
        # scale
        _grid = grid * (self.max - self.min) / (self.ngrid-1)
        # loc
        _grid = _grid + self.min
        return _grid
    
    def plot(self):
        #č zejmena tady je to nepříjemný
        #č třeba bude překreslovat jednu položky
        #č když jen odcvaknutá druhá
        for curve in self.curves:
            self.w.central_widget.removeItem(curve)
        
        ncurves = self.w.ncircles
        if self.contour_item.checkState():
            levels = np.linspace(self.pdf.max(), 0, ncurves+1, endpoint=False)[1:]
            self._draw_curves(levels, 'Isolevels', (170, 85, 0))
            
        if self.isocurve_item.checkState():
            const = 1 / np.prod(self.max - self.min)
            r_levels = np.arange(ncurves) + 1
            #č P prostor doopravdy zlobí, takže nějak tak    
            levels = misc.isolevels_2d(self.pdf, const, r_levels, from_top=False)
            self._draw_curves(levels, 'Isocurves', (100, 45, 0))
            
    def _draw_curves(self, levels, name, color):
        ncurves = self.w.ncircles
        plot_widget = self.w.central_widget
        for r in range(ncurves):
            pen = pg.mkPen(color=color, width=self.w.px_size*(1-r/ncurves))
            
            v = levels[r]
            
            #č vrací souřadnice v prostoru "gridu"
            lines = pg.functions.isocurve(self.data, v, connected=True)
            for line in lines:
                grid = np.array(line) 
                #grid = np.flip(grid, axis=1)
                
                #č tady mám výsledek dvouletého výzkumu
                grid = grid - 0.5
                
                # scale
                grid = self.grid_scale(grid) 
                curve = plot_widget.plot(grid, pen=pen, name=name)
                curve.setZValue(self.z_value)
                self.curves.append(curve)



class Boundaries:
    def __init__(self, w):
        self.w = w
        self.w.space_changed.connect(self.plot)
        self.w.redraw_called.connect(self.redraw)

        self.item = QtGui.QListWidgetItem('Boundaries')
        self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
        self.item.setCheckState(QtCore.Qt.Checked)
        self.w.list_view.addItem(self.item)
        self.w.list_view.itemChanged.connect(self.show_slot)
        

    def redraw(self):
        pos = ()
        plot_widget = self.w.central_widget
        
        self.bounds = []
        # ne všichni majó definované hranice
        try:
            for bound in self.w.sample_box.get_2D_boundary(nrod=1000):
                item = plot_widget.plot(pos=pos, pen='b', name='Boundaries')
                item.setZValue(70)
                self.bounds.append((bound, item))
        except AttributeError:
            pass #print("čo sa děje?")
        
        self.plot()
        
    def show_slot(self, item):
        if item is self.item:
            self.plot()

    def plot(self):
        if self.item.checkState():
            for bound, item in self.bounds:
                pos = getattr(bound, self.w.space)[:,:2]
                mask = np.all(np.isfinite(pos), axis=1)
                item.setData(pos[mask])
                item.show()
            
        else:
            for bound, item in self.bounds:
                item.hide()




class Triangulation:
    def __init__(self, w):
        
        self.w = w
        if self.w.sample_box.nvar == 2:
            self.w.box_runned.connect(self.update)
            self.w.space_changed.connect(self.replot)
            self.w.redraw_called.connect(self.redraw)
    
            self.item = QtGui.QListWidgetItem('Triangulation')
            self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
            self.item.setCheckState(QtCore.Qt.Unchecked)
            self.w.list_view.addItem(self.item)
    
            
            self.w.list_view.itemChanged.connect(self.show_slot)
            
            self.spatial = 'tri'
        
        

    def redraw(self):
        self.simplices = np.empty((0,3), dtype=np.int)
        self.plot_items = []
        self.replot()


    def show_slot(self, item):
        if item is self.item:
            if (self.w.sample_box.nvar==2) and self.item.checkState():
                #for item in self.plot_items:
                #    item.show()
                
                #оӵ Мед сюредалоз!
                self.replot()
                
            else: #оӵ Медам сюреда!
                for item in self.plot_items:
                    item.hide()
            

    
    def replot(self):
        """
        on space_chainged
        or something like this
        when we need to completely
        redraw the triangulation
        """
        if self.item.checkState():
            try:
                spatial = getattr(self.w.sample_box, self.spatial)
                self.simplices = spatial.simplices
                for item in self.plot_items:
                    item.hide()
                self.draw_simplices(range(len(self.simplices)))
                    
            except BaseException as e:
                msg = "error during replot"
                print(self.__class__.__name__ + ":",msg, repr(e))
            


    def update(self):
        # update triangulation
        if self.item.checkState():
            try: #оӵ Мед сюредалоз!
                former_simplices = self.simplices 
                spatial = getattr(self.w.sample_box, self.spatial)
                self.simplices = spatial.simplices
                
                #č počet simplexů může se přidaním bodů změnšit
                #č (hlavně u ConvexHull, ale coplanar taky může vyskočit)
                if len(self.simplices) < len(former_simplices):
                    self.replot()
                else:
                    #č zkontrolujeme co se změnilo
                    equal_mask = former_simplices == self.simplices[:len(former_simplices)]
                    changed_simplices_ids = np.argwhere(~equal_mask.all(axis=1)).flatten()
                    self.draw_simplices(changed_simplices_ids)
                    
                    #č teď nové simplexy
                    #ё simplexy свежего разлива
                    self.draw_simplices(range(len(former_simplices), len(self.simplices)))
                    
            except BaseException as e:
                msg = "error during update"
                print(self.__class__.__name__ + ":",msg, repr(e))
        
    
                
    
    def set_plot_data(self, pos, simplex_id):
        if simplex_id < len(self.plot_items):
            # Update the data
            plot_item = self.plot_items[simplex_id]
            plot_item.setData(pos)
            plot_item.show()
        else: #č spolehám na korektnost volajícího kódu
            #оӵ Суредасько
            plot_widget = self.w.central_widget
            plot_item = plot_widget.plot(pos, pen=0.7)
            self.plot_items.append(plot_item)
                
    
    #č já jsem tu všecko překopal protože .plot() a .setData() jsou nejžravejší na čas
    #č a nemá žádnou cenu je provadet hned vedle sebe (spouští totéž dvakrát)
    def draw_simplices(self, simplex_ids):
        # take coordinates in the space, where triangulation has been performed
        sampled_plan_tri = getattr(self.w.sample_box, self.w.sample_box.tri_space)
        
        if self.w.space == self.w.sample_box.tri_space:
            for simplex_id in simplex_ids:
                triangle = self.simplices[simplex_id]
                pos = sampled_plan_tri[triangle[[0,1,2,0]]]
                
                self.set_plot_data(pos, simplex_id)
                    
        else:
            ns = 100
            with pg.BusyCursor():
                for simplex_id in simplex_ids:
                    triangle = self.simplices[simplex_id]
                    # keep the GUI responsive :)
                    # it was quite slow on my target machine
                    self.w.app.processEvents()
                    
                    x_tri_1 = np.linspace(sampled_plan_tri[triangle[0],0], sampled_plan_tri[triangle[1],0], ns, endpoint=False)
                    y_tri_1 = np.linspace(sampled_plan_tri[triangle[0],1], sampled_plan_tri[triangle[1],1], ns, endpoint=False)
                    x_tri_2 = np.linspace(sampled_plan_tri[triangle[1],0], sampled_plan_tri[triangle[2],0], ns, endpoint=False)
                    y_tri_2 = np.linspace(sampled_plan_tri[triangle[1],1], sampled_plan_tri[triangle[2],1], ns, endpoint=False)
                    x_tri_3 = np.linspace(sampled_plan_tri[triangle[2],0], sampled_plan_tri[triangle[0],0], ns, endpoint=True)
                    y_tri_3 = np.linspace(sampled_plan_tri[triangle[2],1], sampled_plan_tri[triangle[0],1], ns, endpoint=True)
                    
                    tri_bound_tri = np.concatenate(((x_tri_1, y_tri_1), (x_tri_2, y_tri_2), (x_tri_3, y_tri_3)), axis=1).T
                    #č vytvořme sample
                    tri_bound = self.w.sample_box.f_model.new_sample(tri_bound_tri, space=self.w.sample_box.tri_space)
                    pos = getattr(tri_bound, self.w.space)
                    
                    self.set_plot_data(pos, simplex_id)
                



class ConvexHull2D(Triangulation):
    def __init__(self, w):
        
        self.w = w
        if self.w.sample_box.nvar == 2:
            self.w.box_runned.connect(self.update)
            self.w.space_changed.connect(self.replot)
            self.w.redraw_called.connect(self.redraw)
    
            self.item = QtGui.QListWidgetItem('Convex hull')
            self.item.setFlags(self.item.flags() | QtCore.Qt.ItemIsUserCheckable)
            self.item.setCheckState(QtCore.Qt.Checked)
            self.w.list_view.addItem(self.item)
    
            
            self.w.list_view.itemChanged.connect(self.show_slot)
            
            self.spatial = 'convex_hull'
        
        

    def redraw(self):
        self.simplices = np.empty((0,2), dtype=np.int)
        self.plot_items = []
        self.replot()

        
                
                
    
    #č já jsem tu všecko překopal protože .plot() a .setData() jsou nejžravejší na čas
    #č a nemá žádnou cenu je provadet hned vedle sebe (spouští totéž dvakrát)
    def draw_simplices(self, simplex_ids):
        
        # convex hull should be made in the same space as triangulation, I guess
        # take coordinates in the triangulation space
        sampled_plan_tri = getattr(self.w.sample_box, self.w.sample_box.tri_space)
        
        plot_widget = self.w.central_widget
        
        if self.w.space == self.w.sample_box.tri_space:
            for simplex_id in simplex_ids:
                pos = sampled_plan_tri[self.simplices[simplex_id]]
                
                self.set_plot_data(pos, simplex_id)
                    
        else:
            ns = 100
            #оӵ кулэ ӧвӧл обновлять экран карыны
            for simplex_id in simplex_ids:
                start_id, end_id = self.simplices[simplex_id]
                
                x_bound = np.linspace(sampled_plan_tri[start_id,0], sampled_plan_tri[end_id,0], ns, endpoint=True)
                y_bound = np.linspace(sampled_plan_tri[start_id,1], sampled_plan_tri[end_id,1], ns, endpoint=True)
                
                # sample compatible
                #оӵ малы транспонировать кароно? Озьы кулэ!
                bound_tri = np.vstack((x_bound, y_bound)).T
                #č vytvořme sample
                bound = self.w.sample_box.f_model.new_sample(bound_tri, space=self.w.sample_box.tri_space)
                pos = getattr(bound, self.w.space)
                
                self.set_plot_data(pos, simplex_id)


    
        

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

def get_estimation_data(estimations, metric):
    metric_dict = dict()
    # 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 estimations:
        # nsim musí mäť každej odhad
        # pokud nemá - je třeba jej prostě opravit
        nsim = estimation['nsim']
        try: 
            metric_dict[nsim] = estimation[metric]
        except KeyError as e:
            pass #print(self.__class__.__name__ + ":", repr(e))
    
    # 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()))]
    return x, y


class SimplexEstimationData(QtCore.QObject):
    #š budeme mӓť svůj vlastní signaľčík
    simplex_estimation_updated = QtCore.pyqtSignal()
    
    def __init__(self, dice_box, stream=None, *args, **kwargs):
        super().__init__(stream, *args, **kwargs)
        self.dice_box = dice_box
        #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
        #č asi aby nepadalo, když nenajde signaly
        self.stream = stream
        if stream is not None:
            self.stream.box_runned.connect(self.recalculate)
            self.stream.estimation_added.connect(self.recalculate)
        
        self.setup_context_menu()
        self.recalculate()
        
        
    def setup_context_menu(self):
        # simplex_data_menu
        self.TRI_menu = QtGui.QMenu("TRI sources", self.stream)
        
        self.TRI_overall_chk = QtGui.QAction("TRI_overall_estimations", self.TRI_menu) 
        self.TRI_overall_chk.setCheckable(True)
        self.TRI_overall_chk.setChecked(True)
        self.TRI_overall_chk.triggered.connect(self.recalculate)
        self.TRI_menu.addAction(self.TRI_overall_chk)
        
        self.simplex_chk = QtGui.QAction("Simplex estimations", self.TRI_menu) 
        self.simplex_chk.setCheckable(True)
        #self.simplex_chk.setChecked(True)
        self.simplex_chk.triggered.connect(self.recalculate)
        self.TRI_menu.addAction(self.simplex_chk)
        
        # hope, it is temporary
        self.sources_action_group = QtGui.QActionGroup(self.TRI_menu)
        self.sources_action_group.addAction(self.TRI_overall_chk)
        self.sources_action_group.addAction(self.simplex_chk)
        
        self.TRI_menu.addSeparator()
        
        self.proxy_chk = QtGui.QAction("Proxy", self.TRI_menu) 
        self.proxy_chk.setCheckable(True)
        self.proxy_chk.triggered.connect(self.recalculate)
        self.TRI_menu.addAction(self.proxy_chk)
        
        self.TRI_menu.addSeparator()
        
        self.reaction = QtGui.QAction("Update", self.TRI_menu)
        self.reaction.triggered.connect(self.recalculate)
        self.TRI_menu.addAction(self.reaction)
        
        self.excelaction = QtGui.QAction("Export to Excel", self.TRI_menu)
        self.excelaction.triggered.connect(self.export_to_excel)
        self.TRI_menu.addAction(self.excelaction)
        
        
    def export_to_excel(self):
        #č já bych nechtěl, aby mně export najednou spadl 
        #č z jakéhokoliv důvodu
        try:
            proposal_filename = self.dice_box.guessbox.filename
            if proposal_filename:
                proposal_filename += '.xlsx'
            else:
                proposal_filename = self.dice_box.gm_signature + '.xlsx'
            filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
                                         proposal_filename, initialFilter='*.xlsx')
            self.df.to_excel(filename)
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        
        
    def recalculate(self):
        if self.simplex_chk.isChecked():
            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.dice_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']
                    except KeyError as e:
                        pass #print(self.__class__.__name__ + ":", repr(e))
                
                #č neotravuj uživatele chybovejma hlaškama
                if tri_estimation:
                    # it can be effectively done with pandas
                    self.df = 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='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
                    df.sort_values('nsim', inplace=True)
    
                    self._pens_data_update()
                
                    nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
                    df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                    self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
                    
                    nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
                    df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                    self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
            except:
                pass
        self.simplex_estimation_updated.emit()


class SimplexEstimationGraph(pg.PlotWidget):
    def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
        #č asi aby nepadalo, když nenajde signaly
        self.stream = stream
        if stream is not None:
            self.stream.box_runned.connect(self.redraw)
            self.stream.estimation_added.connect(self.redraw)
        
        self.dice_box = dice_box
        
        self.setup_context_menu()
        self.setup()
        self.replot()
        
    def setup_context_menu(self):
        # creates instance of LegendItem 
        # and saves it into plotItem.legend
        self.legend = self.addLegend()
    
        self.plotItem.ctrl.xGridCheck.setChecked(True)
        self.plotItem.ctrl.yGridCheck.setChecked(True)
        
        # delete build-in Transforms (with Log_x and Log_y) options, 
        # they can cause uncachable exception (on any zero in data) and crash
        self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
        
        #č já se bojím. radší to uložím
        self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
        
        self.plotItem.vb.menu.addMenu(self.stream.simplex_data.TRI_menu)
        
        self.legend_chk = QtGui.QAction("Legend", self.custom_menu) 
        self.legend_chk.setCheckable(True)
        self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
        self.custom_menu.addAction(self.legend_chk)
        # apply custom menu option
        self.legend.setVisible(self.legend_chk.isChecked())
        
        self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
        self.log_x_chk.setCheckable(True)
        self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
        self.custom_menu.addAction(self.log_x_chk)
        
        self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
        self.log_y_chk.setCheckable(True)
        self.log_y_chk.setChecked(True)
        self.log_y_chk.triggered.connect(self.replot)
        self.custom_menu.addAction(self.log_y_chk)

        self.laction = QtGui.QAction("Show labels", self.custom_menu)
        self.laction.triggered.connect(self.show_labels)
        self.custom_menu.addAction(self.laction)
        
            
    def show_labels(self):
        self.setLabel('left', "Probability measure")
        self.setLabel('bottom', "Number of simulations")
        
    
    
#       self.legend.addItem(self.pen_success, "success domain estimation")
#        self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
#        self.legend.addItem(self.pen_mix, "mixed simplices measure")
#        self.legend.addItem(self.pen_f, "failure domain estimation")
    
    def setup(self, *args, **kwargs):
        self.clear()
        self.setBackground('w')
        x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
        
        #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
        green = (0, 255, 38, 96) 
        #xkcd_red   = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
        red   = (253, 0, 17, 96)
        #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
        cream = (255, 221, 0, 96)
        grey = (196, 196, 196, 96)
        
        self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
        self.pen_f.setZValue(-100)
        
        self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation") 
        self.pen_success.setZValue(-100)
        
        self.pen_outmix = self.plot(x, y)
        
        self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
        #self.fill_mix.setData(name="mixed simplices measure")
        self.fill_mix.setBrush(cream)
        self.fill_mix.setZValue(-100)
        self.addItem(self.fill_mix)
        
        #self.pen_outside = self.plot(x, y)
        self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
        #self.fill_outside.setData(name="out of sampling domain estimation")
        self.fill_outside.setBrush(grey)
        self.fill_outside.setZValue(-100)
        self.addItem(self.fill_outside)
        
        self.one_ruler = self.addLine(y=1, pen='k') 
        self.zero_ruler = self.addLine(y=0, pen='k') 
            
        
        try:
            exact_name = self.dice_box.pf_exact_method
            pen = pg.mkPen(color='b', width=1.5) # blue
            self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name) 
            #č aby se nám něco zobrazovalo v legendu
            self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
        except:
            pass
            
        pen = pg.mkPen(color='m', width=2)
        self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
        pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
        self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
        
        
        
        
        
    def replot(self, *args, **kwargs):
        if self.log_y_chk.isChecked():
            self.one_ruler.hide()
            try:
                #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
                if self.dice_box.pf_exact > 0:
                    self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
                    self.pen_exact.show()
                else:
                    self.pen_exact.hide()
            except:
                pass
            self.setLogMode(y=True)
            #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
            self.pen_f.setPen(None)
            self.pen_f.setFillLevel(None)
            self.pen_success.setFillLevel(0)
            
        else:
            self.one_ruler.show()
            try:
                self.pen_exact.setPos(self.dice_box.pf_exact)
                self.pen_exact.show()
            except:
                pass
            self.setLogMode(y=False)
            self.pen_f.setPen(None)
            self.pen_f.setFillLevel(0)
            self.pen_success.setFillLevel(1)
        
        self.redraw()
    
    
    #č když se někde objeví nula se zapnutým LogModem - 
    #č qtpygraph hned spadne a není možne ten pad zachytit
    def zerosafe(self, x, y, fallback_y=None): 
        if self.log_y_chk.isChecked():
            x = np.array(x)
            y = np.array(y)
            if fallback_y is None:
                fallback_y = y
            y = np.where(y > 0, y, fallback_y)
            mask = y > 0
            return x[mask], y[mask]
        else:
            return x, y
        
    def proxy(self, nsim):
        if self.proxy_chk.isChecked():
            proxy = self.dice_box.proxy
            index = np.array(nsim)-1
            #č indexy musíme o jedničku změnšit
            #č výsledek nikoliv. Takže v cajku.
            return np.cumsum(~proxy)[index]
        else:
            return nsim
            

    def _pens_data_update(self):
        df = self.df
        nsim = df.nsim.to_numpy()
        if self.proxy_chk.isChecked():
            x = self.proxy(nsim)
            df.insert(loc=0, column='nsim (proxy)', value=x)
        else:
            x = nsim
        # (in case of LogPlot) fallback values also used
        success_values = df.failure+df.mix+df.out
        outmix_values = df.failure+df.mix
        failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
        self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
        self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
        self.pen_success.setData(*self.zerosafe(x, success_values))
    
    
    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.dice_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))
            
            #č neotravuj uživatele chybovejma hlaškama
            if tri_estimation:
                # it can be effectively done with pandas
                self.df = 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='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
                df.sort_values('nsim', inplace=True)

                self._pens_data_update()
            
                nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
                df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
                
                nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
                df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
        
            
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))



class SimplexErrorGraph(SimplexEstimationGraph):
    pass




# DEPRECATED
class SimpleSimplexEstimationGraph(pg.PlotWidget):
    def __init__(self, dice_box, stream=None, parent=None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        #č je zřejmě, že tím potokem bylo myšleno hlavní okínko
        #č asi aby nepadalo, když nenajde signaly
        self.stream = stream
        if stream is not None:
            self.stream.box_runned.connect(self.redraw)
            self.stream.estimation_added.connect(self.redraw)
        
        self.dice_box = dice_box
        
        self.setup_context_menu()
        self.setup()
        self.replot()
        
    def setup_context_menu(self):
        # creates instance of LegendItem 
        # and saves it into plotItem.legend
        self.legend = self.addLegend()
    
        self.plotItem.ctrl.xGridCheck.setChecked(True)
        self.plotItem.ctrl.yGridCheck.setChecked(True)
        
        # delete build-in Transforms (with Log_x and Log_y) options, 
        # they can cause uncachable exception (on any zero in data) and crash
        self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
        
        #č já se bojím. radší to uložím
        self.custom_menu = self.plotItem.vb.menu.addMenu("TRI options")
        
        self.legend_chk = QtGui.QAction("Legend", self.custom_menu) 
        self.legend_chk.setCheckable(True)
        self.legend_chk.triggered.connect(lambda: self.legend.setVisible(self.legend_chk.isChecked()))
        self.custom_menu.addAction(self.legend_chk)
        # apply custom menu option
        self.legend.setVisible(self.legend_chk.isChecked())
        
        self.proxy_chk = QtGui.QAction("Proxy", self.custom_menu) 
        self.proxy_chk.setCheckable(True)
        self.proxy_chk.triggered.connect(self.redraw)
        self.custom_menu.addAction(self.proxy_chk)
        
        self.log_x_chk = QtGui.QAction("Log X", self.custom_menu)
        self.log_x_chk.setCheckable(True)
        self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
        self.custom_menu.addAction(self.log_x_chk)
        
        self.log_y_chk = QtGui.QAction("Log Y", self.custom_menu)
        self.log_y_chk.setCheckable(True)
        self.log_y_chk.setChecked(True)
        self.log_y_chk.triggered.connect(self.replot)
        self.custom_menu.addAction(self.log_y_chk)
        
        self.reaction = QtGui.QAction("Redraw", self.custom_menu)
        self.reaction.triggered.connect(self.redraw)
        self.custom_menu.addAction(self.reaction)

        self.laction = QtGui.QAction("Show labels", self.custom_menu)
        self.laction.triggered.connect(self.show_labels)
        self.custom_menu.addAction(self.laction)
        
        self.excelaction = QtGui.QAction("Export to Excel", self.custom_menu)
        self.excelaction.triggered.connect(self.export_to_excel)
        self.custom_menu.addAction(self.excelaction)
        
        
    def export_to_excel(self):
        #č já bych nechtěl, aby mně export najednou spadl 
        #č z jakéhokoliv důvodu
        try:
            proposal_filename = self.dice_box.guessbox.filename
            if proposal_filename:
                proposal_filename += '.xlsx'
            else:
                proposal_filename = self.dice_box.gm_signature + '.xlsx'
            filename, *__ = pg.FileDialog.getSaveFileName(self, 'Export to Excel',\
                                         proposal_filename, initialFilter='*.xlsx')
            self.df.to_excel(filename)
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
            
    def show_labels(self):
        self.setLabel('left', "Probability measure")
        self.setLabel('bottom', "Number of simulations")
        
    
    
#       self.legend.addItem(self.pen_success, "success domain estimation")
#        self.legend.addItem(self.pen_outside, "out of sampling domain estimation")
#        self.legend.addItem(self.pen_mix, "mixed simplices measure")
#        self.legend.addItem(self.pen_f, "failure domain estimation")
    
    def setup(self, *args, **kwargs):
        self.clear()
        self.setBackground('w')
        x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
        
        #xkcd_green = (167, 255, 181) # xkcd:light seafoam green #a7ffb5
        green = (0, 255, 38, 96) 
        #xkcd_red   = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
        red   = (253, 0, 17, 96)
        #xkcd_cream = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
        cream = (255, 221, 0, 96)
        grey = (196, 196, 196, 96)
        
        self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
        self.pen_f.setZValue(-100)
        
        self.pen_success = self.plot(x, y, brush=green) #, name="success domain estimation") 
        self.pen_success.setZValue(-100)
        
        self.pen_outmix = self.plot(x, y)
        
        self.fill_mix = pg.FillBetweenItem(self.pen_f, self.pen_outmix)
        #self.fill_mix.setData(name="mixed simplices measure")
        self.fill_mix.setBrush(cream)
        self.fill_mix.setZValue(-100)
        self.addItem(self.fill_mix)
        
        #self.pen_outside = self.plot(x, y)
        self.fill_outside = pg.FillBetweenItem(self.pen_outmix, self.pen_success)
        #self.fill_outside.setData(name="out of sampling domain estimation")
        self.fill_outside.setBrush(grey)
        self.fill_outside.setZValue(-100)
        self.addItem(self.fill_outside)
        
        self.one_ruler = self.addLine(y=1, pen='k') 
        self.zero_ruler = self.addLine(y=0, pen='k') 
            
        
        try:
            exact_name = self.dice_box.pf_exact_method
            pen = pg.mkPen(color='b', width=1.5) # blue
            self.pen_exact = self.addLine(y=self.dice_box.pf_exact, pen=pen, name=exact_name) 
            #č aby se nám něco zobrazovalo v legendu
            self.pen_exact_PR = self.plot(x, y, pen=pen, name=exact_name)
        except:
            pass
            
        pen = pg.mkPen(color='m', width=2)
        self.pen_vertex = self.plot(x, y, pen=pen, name="simple pf estimation")
        pen = pg.mkPen(color='r', width=2) #(118, 187, 255)
        self.pen_weighted_vertex = self.plot(x, y, pen=pen, name="weighted pf estimation")
        
        
        
        
        
    def replot(self, *args, **kwargs):
        if self.log_y_chk.isChecked():
            self.one_ruler.hide()
            try:
                #č try nás nezáchraní protí odloženému spádnutí pyqtgraph
                if self.dice_box.pf_exact > 0:
                    self.pen_exact.setPos(np.log10(self.dice_box.pf_exact))
                    self.pen_exact.show()
                else:
                    self.pen_exact.hide()
            except:
                pass
            self.setLogMode(y=True)
            #self.pen_f.setPen(pg.mkPen(color=(255, 0, 0), width=3)) #, style=QtCore.Qt.DashLine)
            self.pen_f.setPen(None)
            self.pen_f.setFillLevel(None)
            self.pen_success.setFillLevel(0)
            
        else:
            self.one_ruler.show()
            try:
                self.pen_exact.setPos(self.dice_box.pf_exact)
                self.pen_exact.show()
            except:
                pass
            self.setLogMode(y=False)
            self.pen_f.setPen(None)
            self.pen_f.setFillLevel(0)
            self.pen_success.setFillLevel(1)
        
        self.redraw()
    
    
    #č když se někde objeví nula se zapnutým LogModem - 
    #č qtpygraph hned spadne a není možne ten pad zachytit
    def zerosafe(self, x, y, fallback_y=None): 
        if self.log_y_chk.isChecked():
            x = np.array(x)
            y = np.array(y)
            if fallback_y is None:
                fallback_y = y
            y = np.where(y > 0, y, fallback_y)
            mask = y > 0
            return x[mask], y[mask]
        else:
            return x, y
        
    def proxy(self, nsim):
        if self.proxy_chk.isChecked():
            proxy = self.dice_box.proxy
            index = np.array(nsim)-1
            #č indexy musíme o jedničku změnšit
            #č výsledek nikoliv. Takže v cajku.
            return np.cumsum(~proxy)[index]
        else:
            return nsim
            

    def _pens_data_update(self):
        df = self.df
        nsim = df.nsim.to_numpy()
        if self.proxy_chk.isChecked():
            x = self.proxy(nsim)
            df.insert(loc=0, column='nsim (proxy)', value=x)
        else:
            x = nsim
        # (in case of LogPlot) fallback values also used
        success_values = df.failure+df.mix+df.out
        outmix_values = df.failure+df.mix
        failure_fallback = np.where(outmix_values > 0, outmix_values, success_values)
        self.pen_f.setData(*self.zerosafe(x, df.failure, failure_fallback))
        self.pen_outmix.setData(*self.zerosafe(x, outmix_values, success_values))
        self.pen_success.setData(*self.zerosafe(x, success_values))
    
    
    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.dice_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))
            
            #č neotravuj uživatele chybovejma hlaškama
            if tri_estimation:
                # it can be effectively done with pandas
                self.df = 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='nsim', value=tuple(tri_estimation.keys()), allow_duplicates=False)
                df.sort_values('nsim', inplace=True)

                self._pens_data_update()
            
                nsim, y = get_estimation_data(self.dice_box.estimations, 'vertex_estimation')
                df['vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
                
                nsim, y = get_estimation_data(self.dice_box.estimations, 'weighted_vertex_estimation')
                df['weighted_vertex_estimation'] = y #č spolehám na konzistenci odhadů (ne úplně)
                self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), y))
        
            
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        

# DEPRECATED
class TriEstimationGraph(SimpleSimplexEstimationGraph):
    def __init__(self, dice_box, tri_estimation_name='TRI_overall_estimations', stream=None, parent=None, *args, **kwargs):
        self.tri_estimation_name = tri_estimation_name
        super().__init__(dice_box, stream, parent, *args, **kwargs)
        
        
   
    def redraw(self):
        try: # тут всё что угодно может пойти не так
            data = self.dice_box.guessbox.estimations[self.tri_estimation_name]
            nsim, tri_data = data
            # it can be effectively done with pandas
            self.df = df = pd.DataFrame(tri_data)
            # -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='nsim', value=nsim)
            
            # Update the data
            self._pens_data_update()
            
            if 'vertex_estimation' in self.dice_box.guessbox.estimations:
                data = self.dice_box.guessbox.estimations['vertex_estimation']
                nsim, y = data
                # Update the data
                #č spolehám na konzistenci blackboxu, ne však úplně
                self.pen_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
                df['vertex_estimation'] = y 
            
            if 'weighted_vertex_estimation' in self.dice_box.guessbox.estimations:
                data = self.dice_box.guessbox.estimations['weighted_vertex_estimation']
                nsim, y = data
                # Update the data
                #č spolehám na konzistenci blackboxu, ne však úplně
                self.pen_weighted_vertex.setData(*self.zerosafe(self.proxy(nsim), np.array(y)))
                df['weighted_vertex_estimation'] = y 
                
            
        # BaseException
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        






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 FastSimplexEstimationWidget(QtGui.QSplitter):
    # I'd like to get access to the samplebox stuff via the container's reference, 
    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):
        self.setOrientation(QtCore.Qt.Vertical)
        self.layout = pg.LayoutWidget(self)
        params = list()
        params.append({'name': 'method', 'type': 'list', \
                     'values': ['fast', 'full', 'cubature'], 'value': 'fast'})
        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': 'weighting space', 'type': 'list',\
                        'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
        designs = ['None']
        if 'designs' in self.sb_item.kwargs:
            designs.extend(self.sb_item.kwargs['designs'].keys())
        params.append({'name': 'design', 'type': 'list', \
                     'values': designs, 'value': 'None'})
        params.append({'name': 'outside budget', 'type': 'int', \
                    'limits': (1, float('inf')), 'value': 1000, 'default': 1000})    
        params.append({'name': 'nodes per simplex', 'type': 'int', \
                    'limits': (1, float('inf')), 'value': 100, 'default': 100})  
                    
        if 'schemes' in self.sb_item.kwargs:
            schemes = list(self.sb_item.kwargs['schemes'].keys())
        else: 
            schemes = ['None']
            
        params.append({'name': 'scheme', 'type': 'list', \
                     'values': schemes, 'value': schemes[0]})
        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.layout.addWidget(self.ptree, row=0, col=0, colspan=3)
        
        
        
        self.btn = QtGui.QPushButton('estimate')
        self.layout.addWidget(self.btn, row=1, col=0)
        self.btn.clicked.connect(self.run_stm)
        
        self.btn2 = QtGui.QPushButton('redraw')
        self.layout.addWidget(self.btn2, row=1, col=1)
        self.btn2.clicked.connect(self.recolor)
        
        self.btn3 = QtGui.QPushButton('hide')
        self.layout.addWidget(self.btn3, row=1, col=2)
        self.btn3.clicked.connect(self.hide)
        
        self.addWidget(self.layout)
        
        self.table = pg.TableWidget(sortable=False)
        self.addWidget(self.table)
        

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


    def hide(self):
        #č nejdřív triangulace
        for tri_bound, plot_item in self.triangulation:
            plot_item.hide()
            # keep the GUI responsive :)
            #self.sb_item.app.processEvents()

        #č teď tečičky
        for nodes, plot_item, cell_stats in self.simplices:
            plot_item.hide()
            # keep the GUI responsive :)
            #self.sb_item.app.processEvents()
        
        
    def recolor(self):
        with pg.BusyCursor():
            # keep the GUI responsive :)
            self.sb_item.app.processEvents()
            #č nejdřív triangulace
            for tri_bound, plot_item in self.triangulation:
                plot_item.show()
                
                
            #č teď tečičky    
            for nodes, plot_item, cell_stats in self.simplices:
                event = cell_stats['event']
                if event in self.max_simplices:
                    cell_probability = cell_stats['cell_probability']
                    cm = self.param.getValues()[event][0] #č očekávám tam kolor mapu
                    blue_intensity = cell_probability / self.max_simplices[event]
                    color = cm.mapToQColor(blue_intensity)
                else: # outside
                    color = 0.6
                #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
                size = self.param.getValues()['node (pixel) size'][0]
                plot_item.setSymbolBrush(color)
                plot_item.setSymbolSize(size)
                plot_item.show()
                # keep the GUI responsive :)
                #self.sb_item.app.processEvents()

        

    def on_space_changed(self, *args, **kwargs):
        #with pg.BusyCursor():
        #self.hide()
        # keep the GUI responsive :)
        #self.sb_item.app.processEvents()
        #č nejdřív triangulace
        for tri_bound, plot_item in self.triangulation:
            pos = getattr(tri_bound, self.sb_item.space)
            plot_item.setData(pos)
            #plot_item.show()
            # keep the GUI responsive :)
            #self.sb_item.app.processEvents()

        #č teď tečičky
        for nodes, plot_item, cell_stats in self.simplices:
            pos = getattr(nodes, self.sb_item.space)[:,:2]
            plot_item.setData(pos)
            #plot_item.show()
            # keep the GUI responsive :)
            #self.sb_item.app.processEvents()


    #č 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
            weighting_space = params['weighting space'][0]
            if weighting_space == 'None':
                weighting_space = None
            outside_budget = params['outside budget'][0]
            simplex_budget = params['nodes per simplex'][0]
            
            design = params['design'][0]
            if design == 'None':
                design = None
            else:
                design = self.sb_item.kwargs['designs'][design]
                
            scheme = params['scheme'][0]
            if scheme == 'None':
                scheme = None
            else:
                scheme = self.sb_item.kwargs['schemes'][scheme]
            
            #č je třeba skrýt prvky z minula
            self.self_clear()

            
            try:
                
                if params['method'][0] == 'cubature':
                    method = stm.fast_simplex_cubature
                    data = method(sample_box, scheme, model_space=model_space,\
                                  sampling_space=sampling_space,\
                                   weighting_space=weighting_space,\
                                    outside_budget=outside_budget, \
                                    callback=self.callback, design=design)
                else:
                    if params['method'][0] == 'full':
                        method = stm.full_simplex_estimation
                    else:
                        method = stm.fast_simplex_estimation
                    data = method(sample_box, model_space=model_space,\
                                  sampling_space=sampling_space, \
                                   weighting_space=weighting_space,\
                                    outside_budget=outside_budget, \
                                     simplex_budget=simplex_budget,\
                                    callback=self.callback, design=design)
                
                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, sx=None, nodes=None, cell_stats=None, simplex=None, *args, **kwargs):
        plot_widget = self.sb_item.central_widget
        #č stm trianguľaciju pokažde provadí znovu, proto skoro nemá cenu drbat se s její znovupoužitím
        if (simplex is not None) and (simplex.nvar==2):
        
            ns = 100
            # take coordinates in the space, where triangulation has been performed
            simplex_tri = getattr(simplex, sx.tri_space)
            x_tri_1 = np.linspace(simplex_tri[0,0], simplex_tri[1,0], ns, endpoint=False)
            y_tri_1 = np.linspace(simplex_tri[0,1], simplex_tri[1,1], ns, endpoint=False)
            x_tri_2 = np.linspace(simplex_tri[1,0], simplex_tri[2,0], ns, endpoint=False)
            y_tri_2 = np.linspace(simplex_tri[1,1], simplex_tri[2,1], ns, endpoint=False)
            x_tri_3 = np.linspace(simplex_tri[2,0], simplex_tri[0,0], ns, endpoint=True)
            y_tri_3 = np.linspace(simplex_tri[2,1], simplex_tri[0,1], ns, endpoint=True)
                
            tri_bound_tri = np.concatenate(((x_tri_1, y_tri_1), (x_tri_2, y_tri_2),\
                                             (x_tri_3, y_tri_3)), axis=1).T
            # vytvořme sample
            tri_bound = self.sb_item.sample_box.f_model.new_sample(tri_bound_tri, space=sx.tri_space)
            
            # draw 
            pos = getattr(tri_bound, self.sb_item.space)
            plot_item = plot_widget.plot(pos, pen='k')
            plot_item.setZValue(50)
            
            # uložíme data
            self.triangulation.append((tri_bound, plot_item))
            
            #plot_item.show()
        
        
        #    
        # tečičky
        #
        pos = getattr(nodes, self.sb_item.space)[:,:2]
        event = cell_stats['event']
        cell_probability = cell_stats['cell_probability']
        if event in self.max_simplices:
            cm = self.param.getValues()[event][0] #č očekávám tam kolor mapu
            
            #č chcu ještě na konci prekreslit s různejma barvičkama, podle obsahu pravděpodobnosti
            # zkontrolujeme probability
            if self.max_simplices[event] < cell_probability:
                self.max_simplices[event] = cell_probability
                # a hned všecko dotyčné přebarvíme podle obsahu pravděpodobnosti
                for self_simplex in self.simplices:
                    if event == self_simplex[2]['event']:
                        # zde cell_probability se rovná self.p_cell_max[event]
                        # ale bacha! Nesplet se jinde!
                        #č nechť zůstane starý nazev
                        blue_intensity = self_simplex[2]['cell_probability'] / cell_probability
                        color = cm.mapToQColor(blue_intensity)
                        self_simplex[1].setSymbolBrush(color)
            
            
            intensity = cell_probability / self.max_simplices[event]
            #č tam prostě MUSÍ být tuple
            color = cm.mapToQColor(intensity)
            
        
        else: # outside
            color = 0.6
        
        
        # draw tečičky
        #
        
        #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
        size = self.param.getValues()['node (pixel) size'][0]
        #brush = pg.mkBrush(color)
        plot_item = plot_widget.plot(pos, pen=None, symbol='o', symbolPen=pg.mkPen(None), symbolBrush=color,\
                                     symbolSize=size, name='IS localized nodes')
        plot_item.setZValue(40)

        # uložíme data
        self.simplices.append((nodes, plot_item, cell_stats))
        
        
        # keep the GUI responsive :)
        self.sb_item.app.processEvents()
        
        




class VoronoiEstimationWidget(QtGui.QSplitter):
    """
    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, 
    # INHERETED by gl_plot
    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()
    
    # INHERETED by gl_plot
    def setup(self):
        self.setOrientation(QtCore.Qt.Vertical)
        self.layout = pg.LayoutWidget(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.layout.addWidget(self.ptree, row=0, col=0, colspan=3)
        
        
        self.btn = QtGui.QPushButton('estimate')
        self.layout.addWidget(self.btn, row=1, col=0)
        self.btn.clicked.connect(self.run_stm)
        
        self.btn2 = QtGui.QPushButton('redraw')
        self.layout.addWidget(self.btn2, row=1, col=1)
        self.btn2.clicked.connect(self.recolor)
        
        self.btn3 = QtGui.QPushButton('hide')
        self.layout.addWidget(self.btn3, row=1, col=2)
        self.btn3.clicked.connect(self.hide)
        
        self.addWidget(self.layout)
        
        self.table = pg.TableWidget(sortable=False)
        self.addWidget(self.table)
        
        # pro začatek postačí
        self.cells = []
        # probability of the biggest cell
        # used for coloring
        self.p_cell_max = {'success':0, 'failure':0}
     
     
    # INHERETED by gl_plot
    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()
    
    # INHERETED by gl_plot
    def hide(self):
        for nodes, plot_item, cell_stats in self.cells:
            plot_item.hide()
            # keep the GUI responsive :)
            #self.sb_item.app.processEvents()
    
    # INHERETED by gl_plot
    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
    # refactoring already done, why I should rename?
    # INHERETED by gl_plot
    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):
        # teď tečičky
        for nodes, plot_item, cell_stats in self.cells:
            pos = getattr(nodes, self.sb_item.space)[:,:2]
            plot_item.setData(pos)
        
        
    # INHERETED by gl_plot
    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()
        


    # INHERETED by gl_plot
    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
        """
        plot_widget = self.sb_item.central_widget
        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
                plot_widget.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)[:,:2]
        symbol_size = self.param.getValues()['node (pixel) size'][0]
        plot_widget = self.sb_item.central_widget
        # 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)
            plot_widget.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 plot_widget.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]
        plot_widget = self.sb_item.central_widget
        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
                plot_widget.removeItem(plot_item)
                
                # draw 
                pos = getattr(nodes, self.sb_item.space)[:,:2]
                #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] = plot_widget.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)[:,:2]
            
            event = cell_stats['event']
            color = self.get_color(event)
            #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
            plot_item = plot_widget.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]
        plot_widget = self.sb_item.central_widget
        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:
                plot_widget.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)[:,:2]
                #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] = plot_widget.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)[:,:2]
            #x, y = (*getattr(nodes, self.sb_item.space).T,)
            
            #symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
            plot_item = plot_widget.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.gradient.setColorMap(pg.colormap.ColorMap((0,1),\
                         [(255, 255, 255, 255), (67, 0, 81, 255)]))
        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)
        plot_widget = self.sb_item.central_widget
        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
                        maxitem = cb[np.nanargmax(array)]
                    if mincb < minvalue:
                        minvalue = mincb
                
                #č zvlášť nakreslím maximální hodnotu
                pos = getattr(maxitem, self.sb_item.space)[:,:2]
                max_item = plot_widget.plot(pos, data=maxvalue, pen=None, symbol='t1',\
                                             symbolBrush=color_map.mapToQColor(1))
                max_item.setZValue(130)
                self.pens.append(max_item)
                    
                #č 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][:,:2]
                    
                    #č 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 = plot_widget.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)
            
            
            
        # 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    
        


class BoxTreeWidget(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.btn = QtGui.QPushButton('update')
        self.addWidget(self.btn, row=0, col=0)
        self.btn.clicked.connect(self.update)
        
        #self.tree = pg.DataTreeWidget(self, data=self.get_data(samplebox_item))
        self.tree = pg.DataTreeWidget(self, data=dict())
        self.addWidget(self.tree, row=1, col=0)

    def update(self, *args, **kwargs):
        try:
            self.tree.setData(self.get_data(self.sb_item), hideRoot=True)
        except BaseException as e:
            msg = ""
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)
            
    @staticmethod
    def get_data(self): #č nenechej si splest tím "self", je to prostě reference na QtGuiPlot2D
        data_tree = dict()
        data_tree['self.sample_box'] = self.sample_box.__dict__
        try: # shapeshare
            data_tree['self.sample_box.shapeshare'] = self.sample_box.shapeshare.__dict__
        except AttributeError:
            pass
        try:
            data_tree['self.sample_box.dicebox'] = self.sample_box.dicebox.__dict__
        except AttributeError:
            pass
        try:
            data_tree['self.sample_box.reader'] = self.sample_box.reader.__dict__
        except AttributeError:
            pass
        try:
            data_tree['self.sample_box.samplebox'] = self.sample_box.samplebox.__dict__
        except AttributeError:
            pass
        try:
            data_tree['self.sample_box.candybox'] = self.sample_box.candybox.__dict__
        except AttributeError:
            pass
        try:
            data_tree['self.sample_box.f_model'] = self.sample_box.f_model.__dict__
        except AttributeError:
            pass
            
        return data_tree


        


Mode Type Size Ref File
100644 blob 19075 e556c1eafdce91cf8d67a5075447eb04a9abe383 IS_stat.py
100644 blob 6 0916b75b752887809bac2330f3de246c42c245cd __init__.py
100644 blob 73368 3d245b8568158ac63c80fa0847631776a140db0f blackbox.py
100644 blob 11243 10c424c2ce5e8cdd0da97a5aba74c54d1ca71e0d candybox.py
100644 blob 53568 5d2342f46163fb2320bde4c42577ad73fb304a96 dicebox.py
100644 blob 35771 e9632b8fb33b7dbd77cef556ec9c4dda0951064f estimation.py
100644 blob 34189 e2b43f8f1a46cfc950347d6106ff3cba9ffe5f0c f_models.py
100644 blob 31025 70bab60405bfe783a2f7a9f2c41b7c1629d3d474 g_models.py
100644 blob 42800 ade48f8103eaf1d2d0e002766535620a85c7c359 gl_plot.py
100644 blob 2718 5d721d117448dbb96c554ea8f0e4651ffe9ac457 gp_plot.py
100644 blob 29393 96162a5d181b8307507ba2f44bafe984aa939163 lukiskon.py
100644 blob 2004 6ea8dc8f50a656c48f786d5a00bd6398276c9741 misc.py
100644 blob 10489 1f6dd06a036fdc4ba6a7e6d61ac0b84e8ad3a4c1 mplot.py
100644 blob 1366 993a88f239b6304e48eb519c20a640f28055d7c9 plot.py
100644 blob 2807 1feb1d43e90e027f35bbd0a6730ab18501cef63a plotly_plot.py
100644 blob 110138 f4ef8295edbfd2509cc6026f797536baeb53a8f7 qt_plot.py
100644 blob 6304 7fc6ac75e415df43af5b7aa9d6d1848aa5d0963d reader.py
100644 blob 4284 a0e0b4e593204ff6254f23a67652804db07800a6 samplebox.py
100644 blob 5553 bac994ae58f1df80c7f8b3f33955af5402f5a4f3 sball.py
100644 blob 21623 281aef80556b8d22842b8659f6f0b7dab0ad71af shapeshare.py
100644 blob 41483 940b5c6b493930ce36f1792b0e3c81a022e8cb90 simplex.py
100644 blob 10317 b1c9dca82c5cc30c7b7aa5da2869c0bd131e409d stm_df.py
100644 blob 3411 526104441da7029c83ff7c5037ae6b0dbc9a118d testcases_2D.py
100644 blob 22048 4a6014ca5255aa96059ff9ed5a7e29df98d26ffc 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