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 (2dd1eb8becf89c34b1243d424b9cae855b128e12) (142508 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

#č vzdávám se.
#č quadpy tak se stavá povinnou závislostí
#č potrebuju pro HullEstimation widget
import quadpy 


from . import estimation as stm
from . import misc
from . import stm_df
from . import sball
from . import schemes
from . import convex_hull as khull
#č pro mě je zvykem jako ghull označovat objekt třídy Ghull
#č nikoliv čerstvě oddelený modul
from .ghull import Ghull, Shell_MC, Shell_IS, Shell_1DS

         
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__()
        try:
            self.setWindowTitle("%sD: %s" %(sample_box.nvar, sample_box.gm_signature))
        except:
            self.setWindowTitle("%sD nodes" % sample_box.nvar)
        
        # for debug
        # container for errors
        # to trace errors
        self.errors = []
        
        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)
        
    # should be INHERITED by gl_plot
    def initialize_matplotlib_menu(self):
        try: # entire optional functionality
            from .mplot import show2D
            from . import maxes
            self.matplotlib_menu = self.bar.addMenu("Matplotlib")
            self.matplotlib_actions = []
            for drawing in maxes.__all__:
                mpl_action = QtGui.QAction(drawing, self)
                # do not really understand what I am doing :(
                # try to show_mpl remember its actual drawing string
                show_mpl = self._get_mpl_function(show2D, drawing)
                mpl_action.triggered.connect(show_mpl)
                self.matplotlib_menu.addAction(mpl_action)
                # prevent GC from wiping out both Qt object and our function
                self.matplotlib_actions.append((mpl_action, show_mpl))
                
        except ImportError as e:
            msg = "Matplotlib related features are unavailiable"
            print(self.__class__.__name__ + ":", msg, repr(e))
    
    def _get_mpl_function(self, show, drawing):
        return lambda: show(self.sample_box, space=self.space, drawing=drawing)
    
    # 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)
        
        # optional feature
        self.initialize_matplotlib_menu()
        
        ### 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)
        
        #č jen aby se slider probral, když uživatel ručně přídá bodíky
        self.redraw_called.connect(lambda:self.slider.setMaximum(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.simplex_data, 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("Ghull", self)
        dock.setWidget(HullEstimationWidget(self, dock))
        self.view.addAction(dock.toggleViewAction())
        self.dockables.append(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):
        #č .setMaximum() nezpůsobuje emitování slice_changed, jsem zkontroloval
        self.slider.setMaximum(self.sample_box.nsim)
        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
                    
         
    



"""
==============
оӵ Суред люкет
č Kreslicí prvky
E Drawing items
=================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
        

class Series:
    def __init__(self, w, autoredraw=True):
        self.w = w
        self.w.space_changed.connect(self.space_update)
        self.w.redraw_called.connect(self._redraw)
        # redraw policy
        self.autoredraw = autoredraw
        self.items = {}


    def add_serie(self, sample, index=None, **plot_kwargs):
        plot_item = self._draw(sample, plot_kwargs)
        
        if index is None:
            index = len(self.items)
        elif index in self.items:
            # kind of update, then
            #č musíme korektně odebrat předchozí kresbu
            self.remove_item(index)
            
        self.items[index] = [sample, plot_item, plot_kwargs]
        return plot_item
    
    
    def _draw(self, sample, plot_dict):
        pos = getattr(sample, self.w.space)[:,:2]
        mask = np.all(np.isfinite(pos), axis=1)
        return self.w.central_widget.plot(pos[mask], **plot_dict)
        
        
    def clear(self):
        for item in self.items.values():
            __sample, plot_item, __plot_dict = item
            self.w.central_widget.removeItem(plot_item)
        self.items.clear()
     
    def remove_item(self, index):
        __sample, plot_item, __plot_dict = self.items.pop(index)
        self.w.central_widget.removeItem(plot_item)
            
            
    def hide(self, index=None):
        if index is None:
            for item in self.items.values():
                __sample, plot_item, __plot_dict = item
                plot_item.hide()
        else:
            __sample, plot_item, __plot_dict = self.items[index]
            plot_item.hide()
        
    def show(self, index=None):
        if index is None:
            for item in self.items.values():
                __sample, plot_item, __plot_dict = item
                plot_item.show()
        else:
            __sample, plot_item, __plot_dict = self.items[index]
            plot_item.show()
        
        
    def _redraw(self):
        if self.autoredraw:
            for item in self.items.values():
                sample, _invalid_plot_item, plot_dict = item
                item[1] = self._draw(sample, plot_dict)
        else:
            self.items.clear()
    
    
    def space_update(self):
        for item in self.items.values():
            sample, plot_item, __plot_dict = item
            
            pos = getattr(sample, self.w.space)[:,:2]
            mask = np.all(np.isfinite(pos), axis=1)
            plot_item.setData(pos[mask])
    
    

#č Kružničky chcete?
#ё Кружочки ннада?
#оӵ Гаусслэн котыресез
class Giracles(Series):
    def __init__(self, w, autoredraw=True, nrod=200):
        super().__init__(w, autoredraw)
        
        self.setup(nrod)

    def setup(self, nrod):
        phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
        cos_phi = np.cos(phi)
        sin_phi = np.sin(phi)
        
        self.prebound = np.array((cos_phi, sin_phi)).T

    
    def add_circle(self, r=1, index=None, **plot_kwargs):
        f_model = self.w.sample_box.f_model
        sample_G = self.prebound * r
        sample = f_model.new_sample(sample_G, space='G', extend=True)
        return self.add_serie(sample, index=index, **plot_kwargs)
        



class InfiniteLines(Series):

    def add_line(self, space='G', index=None, **plot_kwargs):
        plot_item = self.w.central_widget.addLine(**plot_kwargs)
        if space == self.w.space:
            plot_item.show()
        else:
            plot_item.hide()
                
        if index is None:
            index = len(self.items)
        elif index in self.items:
            # kind of update, then
            #č musíme korektně odebrat předchozí kresbu
            self.remove_item(index)
            
        self.items[index] = [space, plot_item, plot_kwargs]
        return plot_item
    
    def _redraw(self):
        if self.autoredraw:
            for item in self.items.values():
                space, _invalid_plot_item, plot_dict = item
                item[1] = self.w.central_widget.addLine(**plot_dict)
        else:
            self.items.clear()
    
    
    def space_update(self):
        for item in self.items.values():
            space, plot_item, __plot_dict = item
            if space == self.w.space:
                plot_item.show()
            else:
                plot_item.hide()


"""
==============
у График люкет
č 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.nodes = plot_widget.plot(pos, pen=None, symbol='o', symbolPen=0.5, \
                symbolSize=size, name='Nodes')
        self.nodes.setZValue(80)
        
        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]
        if hasattr(sample_box, 'failsi'): #č to je normálně sample_box
            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])
            
        else: #č není to teda sample_box... 
            #č snad se nám povede nakreslit aspoň tečky?
            self.draw(self.nodes, pos)
        
            
    @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):
        if self.contour_item.checkState() or self.isocurve_item.checkState():
            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)
        
        # year, it was
        ## 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.setChecked(hasattr(self.dice_box, 'proxy'))
        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.stream, '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):
        try:
            # sources=['box', 'user']
            sources = list()
            if self.TRI_overall_chk.isChecked():
                sources.append('box')
            if self.simplex_chk.isChecked():
                sources.append('user')
                
            self.df = stm_df.get_tri_data_frame(self.dice_box, sources=sources,\
                                        apply_proxy=self.proxy_chk.isChecked())
            self.simplex_estimation_updated.emit()
            
        except BaseException as e:
            print(self.__class__.__name__ + ":", repr(e))
        


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(pg.PlotWidget):
    def __init__(self, simplex_data, parent=None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.simplex_data = simplex_data
        self.simplex_data.simplex_estimation_updated.connect(self.redraw)
        
        self.setup_context_menu()
        self.setup()
        
    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)
        
        # menu of SimplexEstimationData
        self.plotItem.vb.menu.addMenu(self.simplex_data.TRI_menu)
        
        #č já se bojím. radší to uložím
        self.custom_menu = self.plotItem.vb.menu.addMenu("Error graph")
        
        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.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', "Failure probability estimation error")
        self.setLabel('bottom', "Number of simulations")
        
    
    def setup(self, *args, **kwargs):
        self.clear()
        self.setBackground('w')
        x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
        
        # We will use logMode by default
        self.setLogMode(y=True)
        
        #xkcd_red   = (253, 193, 197) # xkcd: pale rose (#fdc1c5)
        #red   = (253, 0, 17, 96)
        
        #self.pen_f = self.plot(x, y, brush=red)#, name="failure domain estimation")
        #self.pen_f.setZValue(-100)
        
        
        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")
        
        
    
    #č 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): 
        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]
        
    
    def redraw(self):
        #č neotravujme uživatele chybovejma hlaškama
        if hasattr(self.simplex_data.dice_box, 'pf_exact'):
            try: #ё тут всё что угодно может пойти не так
                pf_exact = self.simplex_data.dice_box.pf_exact
                
                df = self.simplex_data.df
                #č zapíšeme do data rámu, snad nikomu nebude vadit
                df['vertex_estimation_error'] = df['vertex_estimation'] - pf_exact
                df['weighted_vertex_estimation_error'] = df['weighted_vertex_estimation'] - pf_exact
                
                v = df['vertex_estimation_error'].abs()
                wv = df['weighted_vertex_estimation_error'].abs()
                
                x, y = self.zerosafe(v.index, v.to_numpy())
                self.pen_vertex.setData(x, y)
                
                x, y = self.zerosafe(wv.index, wv.to_numpy())
                self.pen_weighted_vertex.setData(x, y)
            
                
            except BaseException as e:
                print(self.__class__.__name__ + ":", repr(e))







# 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_sampling', 'full_sampling',\
                      'fast_cubature', 'full_cubature'], 'value': 'fast_sampling'})
        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=4)
        
        
        
        self.btn0 = QtGui.QPushButton('(no graphics)') # 'estimate \n (no graphics)'
        self.layout.addWidget(self.btn0, row=1, col=0)
        self.btn0.clicked.connect(self.run_stm)
        
        self.btn = QtGui.QPushButton('estimate')
        self.layout.addWidget(self.btn, row=1, col=1)
        self.btn.clicked.connect(self.go_stm)
        
        self.btn2 = QtGui.QPushButton('redraw')
        self.layout.addWidget(self.btn2, row=1, col=2)
        self.btn2.clicked.connect(self.recolor)
        
        self.btn3 = QtGui.QPushButton('hide')
        self.layout.addWidget(self.btn3, row=1, col=3)
        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 go_stm(self): self.start_stm(callback=self.callback)
    def run_stm(self): self.start_stm()
    def start_stm(self, callback=None):
        # 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] == 'fast_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=callback, design=design)
                                    
                elif params['method'][0] == 'full_cubature':
                    method = stm.full_simplex_cubature
                    data = method(sample_box, scheme, model_space=model_space,\
                                   weighting_space=weighting_space,\
                                    callback=callback)
                else:
                    if params['method'][0] == 'full_sampling':
                        method = stm.full_simplex_estimation
                    else: # 'fast_sampling'
                        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=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)            
                    







class HullEstimationWidget(pg.LayoutWidget):
    # 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.giracle = Giracles(w=samplebox_item, autoredraw=False, nrod=200)
        #č Ghull se zkomplikoval. Musím integraci řešit zvlášť
        # Serie for integration nodes
        self.serint = Series(w=samplebox_item, autoredraw=False)
        #ё hyperplanes? Кого ты обманываешь, Alexi?
        #č tak. už je to equation_planes :)
        self.equation_planes = InfiniteLines(w=samplebox_item, autoredraw=False)
        
        # signals handling:
        # box_runned - handled by .on_box_run() method
        # space_changed - handled automatically by smart items
        # slice_changed - setted up clear() on smart items
        # redraw_called - handled automatically by smart items
        # estimation_added - class does not handle the signal
        #                   nor emits the signal itself 
        #                   (as does not save estimations anywhere for now)
        
        # todo: design estimation record 
        
        self.sb_item.box_runned.connect(self.on_box_run)
        #č Alexi, ten signal může té funkce posilát bůhví co navíc.
        #č (ano. clear() nebere žádné argumenty, takže v cajku)
        self.sb_item.slice_changed.connect(self.giracle.clear)
        self.sb_item.slice_changed.connect(self.equation_planes.clear)
        #č ty naše chytré prvky giracle a equation_planes 
        #č hlídají space_changed a redraw_called sami.
        
        self.schemes = dict()
        self.ndim = self.sb_item.sample_box.nvar
        #☺ na internetu všichni tak dělaj
        self.setup()
        
    def setup(self):
        #č já teďkom dědím ne QSplitter, ale LayoutWidget
        #оӵ Кужым кариськы, Олёш!
        
        #č zkusíme nový (pro WellMet) UI, uživatelské rozhraní
        #оӵ кнопка вылын
        #self.layout = self.addLayout(row=0, col=0)
        #self.tool_layout = QtGui.QHBoxLayout()
        #self.layout.addLayout(self.tool_layout, 0, 0)
        #self.addWidget(self.layout, row=0, col=0)
        
        #č toolbar je obecně super věc, ale mě zlobí umístění v layoutu
        self.toolbar = QtGui.QToolBar(self)
        #č jmenovitě, roztažení mě nefunguje vůbec
        #size_policy = self.toolbar.sizePolicy()
        #size_policy.setHorizontalPolicy(QtGui.QSizePolicy.Expanding)
        #self.toolbar.setSizePolicy(size_policy)
        
        #č draw_convex_hull ja navržena tak, aby brala jíž hotový hull
#        if self.ndim == 2:
#            action = self.toolbar.addAction("draw convex hull", self.draw_convex_hull)
#            btn = self.toolbar.widgetForAction(action)
#            btn.setAutoRaise(False)
        
        action = self.toolbar.addAction("shell out!", self.get_shell_estimation)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        btn.setToolTip("Creates Ghull object")
        #btn.setSizePolicy(size_policy)
        
        action = self.toolbar.addAction("integrate", self.integrate)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        btn.setToolTip("Only uses Ghull object created before")
        #btn.setSizePolicy(size_policy)
        
        action = self.toolbar.addAction("shot!", self.shot)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        
        action = self.toolbar.addAction("fire!", self.fire)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        #btn.setSizePolicy(size_policy)
        
        action = self.toolbar.addAction("boom!", self.boom)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        
        action = self.toolbar.addAction("hide", self.hide)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        #btn.setSizePolicy(size_policy)
        
        action = self.toolbar.addAction("show", self.show)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        
        action = self.toolbar.addAction("clear", self.clear)
        btn = self.toolbar.widgetForAction(action)
        btn.setAutoRaise(False)
        
        #self.tool_layout.addWidget(self.toolbar)
        self.addWidget(self.toolbar, row=0, col=0)
        
        
        #оӵ остальной (люкет) уллапала
        
        ### Create ParameterTree widget
        self.ptree = pg.parametertree.ParameterTree()
        self._set_param()
        self.ptree.setParameters(self.param, showTop=False)
        
        self.splitter = QtGui.QSplitter(self)
        self.splitter.setOrientation(QtCore.Qt.Vertical)
        self.splitter.addWidget(self.ptree)
        
        self.table = pg.TableWidget(sortable=False)
        self.splitter.addWidget(self.table)
        
        #self.addWidget(self.splitter, row=1, col=0, colspan=5)
        self.addWidget(self.splitter, row=1, col=0)
    
    def hide(self):
        self.serint.hide()
        self.giracle.hide()
        self.equation_planes.hide()
        
    def show(self):
        self.serint.show()
        self.giracle.show()
        self.equation_planes.show()
        
    def clear(self):
        self.serint.clear()
        self.giracle.clear()
        self.equation_planes.clear()
    
    #оӵ DirectHull понна гинэ
    #č pouze pro DirectHull
    def get_scheme(self):
        scheme = self.param.getValues()['scheme'][0]
        if scheme == 'random':
            ndir = self.param.getValues()['ndir'][0]
            return sball.get_random_directions(ndir, self.ndim)
        elif scheme in self.schemes:
            return self.schemes[scheme].points
        else:
            Scheme = getattr(quadpy.un, scheme)
            self.schemes[scheme] = Scheme(self.ndim)
            return self.schemes[scheme].points

        
    def _set_param(self):
        params = list()
        params.append({'name': 'method', 'type': 'list', 'value': 'DirectHull', \
                     'values': ['SBall', 'BrickHull', 'DirectHull', 'CompleteHull', 'QHull']})
        params.append({'name': 'space', 'type': 'list', 'tip': "Not used for SBall", \
                    'values': self.sb_item.spaces, 'value': 'G'})
                    
        schemes_list = schemes.un_spheres + ['random']
        params.append({'name': 'scheme', 'type': 'list', \
                     'values': schemes_list, 'value': schemes_list[0], \
                     'tip': "Used only for DirectHull and CompleteHull. Generation can take for a while"})
        params.append({'name': 'ndir', 'type': 'int', \
                    'limits': (1, float('inf')), 'value': 1000, 'default': 1000, \
                    'title': "number of random directions", \
                    'tip': "Used only for random scheme in DirectHull (or CompleteHull)"})   
            
        params.append({'name': 'integrator', 'title': "integrator", 'type': 'list', \
                    'values': ['MC', 'IS', '1DS'], 'value': '1DS' })
        params.append({'name': 'nonG_reduction', 'type': 'float', \
                    'title': "non Gaussian reduction", \
                    'limits': (0, 1), 'value': 0.9, 'default': 0.9,\
                    'tip': "Applied when Ghull integrates non Gaussian convex hulls"})   
        
        params.append({'name': 'use_MC', 'title': "use MC", 'type': 'bool', 'value': False, \
                    'tip': "Used for shot(), fire() and boom() functions"})   
        
        params.append({'name': 'budget', 'type': 'int',  \
                    'limits': (1, float('inf')), 'value': 1000, 'default': 1000,\
                    'tip': "Number of simulations for optimal importance sampling"})   
                    
        params.append({'name': 'node (pixel) size', 'type': 'float',\
                 'limits': (0, float('inf')), 'value': 3.5, 'default': self.sb_item.px_size})
        #ё больше калорий богу калорий!
        params.append({'name': 'r', 'type': 'color', 'value': (189, 204, 0, 255) })
        params.append({'name': 'inside', 'type': 'color', 'value': (133, 172, 102, 255) })
        params.append({'name': 'convex_hull', 'type': 'color', 'value': (85, 170, 255, 255) }) # (186, 109, 0, 255)
        params.append({'name': 'fire', 'type': 'color', 'value': (245, 117, 0, 255) })
        params.append({'name': 'orth', 'type': 'color', 'value': (255, 0, 0, 255) })
        params.append({'name': 'outside', 'type': 'color', 'value': 0.6})
        params.append({'name': 'R', 'type': 'color', 'value': (85, 85, 255, 255) })
        params.append({'name': 'Update as the box runned', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
        params.append({'name': 'index', 'title': "replace previous", 'type': 'bool', 'value': True })
        
        ### Create tree of Parameter objects
        # 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)
        self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
    
    def get_ghull(self): 
        integrator = self.param.getValues()['integrator'][0]
        if integrator == 'MC':
            Integrator = Shell_MC
        elif integrator == 'IS':
            Integrator = Shell_IS
        elif integrator == '1DS':
            Integrator = Shell_1DS
        nonG_reduction = self.param.getValues()['nonG_reduction'][0]
        hull = self.get_hull()
        self.ghull = Ghull(hull, Integrator=Integrator, non_Gaussian_reduction=nonG_reduction)
        return self.ghull
                        
        
    #č jistě potřebuji něco, co zpracuje parameter_tree 
    #č a vratí platný hull pro Ghull
    def get_hull(self):
        #č bez semplu se neobejde
        nsim = self.sb_item.slider.value()
        sample = self.sb_item.sample_box.f_model[:nsim]
        
        # ['SBall', 'BrickHull', 'DirectHull', 'QHull']
        hull_model = self.param.getValues()['method'][0]
        if hull_model == 'SBall':
            return khull.GBall(sample)
        elif hull_model == 'BrickHull':
            space = self.param.getValues()['space'][0]
            return khull.BrickHull(sample, space)
        elif hull_model == 'DirectHull':
            space = self.param.getValues()['space'][0]
            direct_plan = self.get_scheme()
            return khull.DirectHull(sample, direct_plan, space)
        elif hull_model == 'CompleteHull':
            space = self.param.getValues()['space'][0]
            direct_plan = self.get_scheme()
            return khull.CompleteHull(sample, direct_plan, space)
        elif hull_model == 'QHull':
            space = self.param.getValues()['space'][0]
            #č tento widget pokažde generuje obálku znovu
            return khull.QHull(sample, space, incremental=False)
        else:
            raise ValueError("HullEstimationWidget: co to je za obálku?")

    #č ten hlavní modul se dočkal na překopávání
    def on_box_run(self, *args, **kwargs):
        self.clear()
        #č je třeba zkontrolovat autorun a restartovat výpočet
        if self.param.getValues()['Update as the box runned'][0]:
            self.get_shell_estimation()
    
    def index(self, index):
        if self.param.getValues()['index'][0]: # replace previous
            return index
        else:
            return None
    
    def draw_planes(self, equations, space, **kwargs):
        if self.ndim == 2:
            #č musíme něco zavolat na self.equation_planes
            #č equation_planes má funkci add_line()
            #č add_line(self, space='G', index=None, **plot_kwargs)
            #č která pak plot_kwargs přeposilá funkci addLine()
            #č na central widgetu. 
            #č To vše skončí ve pyqtgrafové InfiniteLine třidě.
            #č ta moje třida InfiniteLines sama se stará o shodování prostorů
            #č indexy posilat nebudeme (s nimi je to trošku komplikovanější)
            
            #pos = list() #č navrhové body nakreslíme všechny dohromady
            for equation in equations:
                #č ve 2D bych očekával v rovnici pouze 3 hodnoty (já potřebuji směry)
                x, y, offset = equation
                design_point = [-x*offset, -y*offset]
                #self.sb_item.central_widget.plot(np.array([pos, pos]), symbol='o')
    #                    if y < 0: #č tak to aspoň kreslí
    #                        angle = np.rad2deg(np.arcsin(x))
    #                    else:
    #                        angle = np.rad2deg(np.arccos(y))
                    
                if (x*y) < 0: #č tak to aspoň kreslí
                    angle = np.rad2deg(np.arccos(np.abs(y)))
                else:
                    angle = np.rad2deg(np.arccos(-np.abs(y)))
                self.equation_planes.add_line(space=space, pos=design_point, angle=angle, **kwargs)
                
                
    
    def draw_convex_hull(self, hull):
        try:
            if self.param.getValues()['index'][0]: # replace previous
                self.equation_planes.clear()
            
            #č zatím uděláme jen pro 2D infinite lajny
            design_points = hull.get_design_points()
            
            size = self.param.getValues()['node (pixel) size'][0]
            color = self.param.getValues()['convex_hull'][0] #č tam bude barva
            
            self.giracle.add_serie(design_points, z=31, index=self.index('design points'),\
                            pen=None, symbol='o', symbolPen=pg.mkPen(None), \
                            symbolBrush=color, symbolSize=size, name='design points')
            self.draw_planes(hull.equations, space=hull.space, z=29,  pen=color)
                            
                            
            # orth
            color = self.param.getValues()['orth'][0] #č tam bude barva
            #self.giracle.add_serie(FORM_points, z=32, index=self.index('2FORM points'),\
            #                pen=None, symbol='o', symbolPen=pg.mkPen(None), \
            #                symbolBrush=color, symbolSize=size, name='2FORM points')
            self.draw_planes(hull.get_orth_equations(), space=hull.space, z=30,  pen=color)
            
            
            # 2FORM
            color = self.param.getValues()['fire'][0] #č tam bude barva
            #self.giracle.add_serie(FORM_points, z=32, index=self.index('2FORM points'),\
            #                pen=None, symbol='o', symbolPen=pg.mkPen(None), \
            #                symbolBrush=color, symbolSize=size, name='2FORM points')
            self.draw_planes(hull.get_2FORM_equations(), space=hull.space, z=30,  pen=color)
                            
                            
        except BaseException as e:
            msg = "draw_convex_hull error "
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)
            self.sb_item.errors.append(e)
           
    def draw_ghull(self, r, R):
        # r-circle
        if r < 0:
            r = 0
        color = self.param.getValues()['r'][0] #č tam bude barva
        #č krucí, nevím co mám dělat s indexama. 
        #č co mám dělat s předchozí kresbou? Nechame
        self.giracle.add_circle(r=r, index=self.index('r'),z=32, pen=color, name='r')
        
        # R-circle. #č Při kreslení nahradíme předchozí.
        color = self.param.getValues()['R'][0] #č tam bude barva
        self.giracle.add_circle(R, z=32, index=self.index('R'), pen=color, name='R')
            
        
        
    
    def get_shell_estimation(self):
        ghull = self.get_ghull()
        self.draw_convex_hull(ghull.hull)

        try:
            shell_estimation, global_stats = ghull.get_shell_estimation()
            
#            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({**global_stats, 'shell_estimation':shell_estimation})
            
            self.draw_ghull(global_stats['r'], global_stats['R'])
            
        except BaseException as e:
            msg = "error during estimation "
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)
            self.sb_item.errors.append(e)
        
        
    def shot(self):
        ghull = self.get_ghull()
        self.draw_candidates(ghull.hull.shot)
        
    def fire(self):
        ghull = self.get_ghull()
        self.draw_candidates(ghull.hull.fire)
        
    def boom(self):
        ghull = self.get_ghull()
        self.draw_candidates(ghull.boom)
    
    def draw_candidates(self, source_function):
        #č špatně rozumím, co tím bylo mysleno
        #č že jsem chtěl kreslit náhodné směry?
        ##č zatím máme issue s náhodným planem
        ##č kdyby něco - vyřeším přes ukladání 
        ##č náhodných plánů v parameter_tree
        
        self.draw_convex_hull(self.ghull.hull)
        
        #☺ Krucinal, kdo ten OrderedDict vymyslel?
        params = self.param.getValues()
        ns = params['budget'][0]
        use_MC = params['use_MC'][0]
        try:
            fire = source_function(ns, use_MC=use_MC)
            # draw tečičky
            color = self.param.getValues()['fire'][0] #č tam bude barva
            size = self.param.getValues()['node (pixel) size'][0]
            #brush = pg.mkBrush(color)
            self.giracle.add_serie(fire, z=30, index=self.index('fire'),\
                        pen=None, symbol='o', symbolPen=pg.mkPen(None), \
                        symbolBrush=color, symbolSize=size, name='fire')

        except BaseException as e:
            msg = "error "
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)
            self.sb_item.errors.append(e)        
    
    def integration_callback(self, nodes):
        #č draw tečičky
        size = self.param.getValues()['node (pixel) size'][0]
        plot_params = {'pen':None, 'symbol':'o', 'symbolSize':size, \
                        'symbolPen':pg.mkPen(None)}
        #brush = pg.mkBrush(color)
        mask = nodes.is_outside
        
        index = 'inside'
        color = self.param.getValues()[index][0] #č tam bude barva
        self.serint.add_serie(nodes[~mask], z=30,\
                    symbolBrush=color, name=index, **plot_params)
        
        index = 'outside'
        color = self.param.getValues()[index][0] #č tam bude barva
        self.serint.add_serie(nodes[mask], z=30, \
                    symbolBrush=color, name=index, **plot_params)
                    
        # keep the GUI responsive :)
        self.sb_item.app.processEvents()
            
            
            
    def integrate(self):
        #č integrace se stala stateful
        #č a musím jú taky testovat
        if 'ghull' not in self.__dict__:
            ghull = self.get_ghull()
        else:
            ghull = self.ghull
        nsim = self.sb_item.slider.value()
        sample = self.sb_item.sample_box.f_model[:nsim]
        #č teď - saháme do vnitřku naších obliběných tříd
        ghull.hull.sample = sample
        ghull.sample = sample
        
        self.draw_convex_hull(ghull.hull)
        
        
        #☺ Krucinal, kdo ten OrderedDict vymyslel?
        params = self.param.getValues()
        budget = params['budget'][0]
        
        if self.param.getValues()['index'][0]: # replace previous
            self.serint.clear()

        try:
            data = ghull.integrate(budget, callback_all=self.integration_callback)
            ghull_estimation, convex_hull_estimation, global_stats = data
            
            #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({**global_stats, "ghull_estimation":ghull_estimation,\
                               "convex_hull_estimation": convex_hull_estimation})
                                
            self.draw_ghull(global_stats['r'], global_stats['R'])
            
            
        except ValueError as e: #BaseException
            msg = "error during estimation "
            error_msg = self.__class__.__name__ + ": " + msg + repr(e)
            print(error_msg)  
            self.sb_item.errors.append(e)

        # draw DP
        if ghull.hull.space != 'G':
            size = self.param.getValues()['node (pixel) size'][0] + 3
            plot_params = {'pen':None, 'symbol':'t2', 'symbolSize':size, \
                            'symbolPen':pg.mkPen(None)}
            
            #color = self.param.getValues()[index][0] #č tam bude barva
            self.serint.add_serie(ghull.gint.DP, z=35, index='DP', name='DP', **plot_params)





"""
===========
♥ Чыры-пыры 
č 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)
                    if len(array):
                        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 28117 0907e38499eeca10471c7d104d4b4db30b8b7084 IS_stat.py
100644 blob 6 0916b75b752887809bac2330f3de246c42c245cd __init__.py
100644 blob 73368 3d245b8568158ac63c80fa0847631776a140db0f blackbox.py
100644 blob 11243 10c424c2ce5e8cdd0da97a5aba74c54d1ca71e0d candybox.py
100644 blob 26963 5106dbfd64b5403599d51598c03d9fad60956286 convex_hull.py
100644 blob 84851 811ef4d818e55cbe2d0305da62fcc2e1cada359a dicebox.py
100644 blob 36930 a775d1114bc205bbd1da0a10879297283cca0d4c estimation.py
100644 blob 34394 3f0ab9294a9352a071de18553aa687c2a9e6917a f_models.py
100644 blob 31540 a577087003a885ca7499d1ee9451e703fa9d2d36 g_models.py
100644 blob 20557 521db92b6961df7a46594d147bf4c4d49e828066 ghull.py
100644 blob 42820 1092b3b9f05b11d0c53b3aa63df2460ec355085d gl_plot.py
100644 blob 2718 5d721d117448dbb96c554ea8f0e4651ffe9ac457 gp_plot.py
100644 blob 29393 96162a5d181b8307507ba2f44bafe984aa939163 lukiskon.py
100644 blob 12867 5bc331e3ef3a8a6bfeb7ebe5e1ae4f4c58e8cc06 mart.py
100644 blob 7983 75455aa723db8bab291dcf941b92b9ffdba3aef1 mart3d.py
100644 blob 1364 944337088f060aabe029b611c27145bb28de4b38 maxes.py
100644 blob 5356 faac09f784e48599ff9a67e607a8e8a990b05d80 mgraph.py
100644 blob 2004 6ea8dc8f50a656c48f786d5a00bd6398276c9741 misc.py
100644 blob 3336 ce5171f10153dc0151d824369161d65fcbbda83b mplot.py
100644 blob 1450 4849f178b588e252b8c7f6a940d2d82ad35f6914 plot.py
100644 blob 2807 1feb1d43e90e027f35bbd0a6730ab18501cef63a plotly_plot.py
100644 blob 142508 2dd1eb8becf89c34b1243d424b9cae855b128e12 qt_plot.py
100644 blob 8206 5981023118262109fca8309d9b313b521a25f88f reader.py
100644 blob 4284 a0e0b4e593204ff6254f23a67652804db07800a6 samplebox.py
100644 blob 6558 df0e88ea13c95cd1463a8ba1391e27766b95c3a5 sball.py
100644 blob 5553 bac994ae58f1df80c7f8b3f33955af5402f5a4f3 sball_old.py
100644 blob 2605 0034d2e3f14c056541888235e59127e8f28b131d schemes.py
100644 blob 21623 281aef80556b8d22842b8659f6f0b7dab0ad71af shapeshare.py
100644 blob 48537 10f90c5614e9a04f0cd9f78e75f0db4a6becb3e4 simplex.py
100644 blob 13090 2b9681eed730ecfadc6c61b234d2fb19db95d87d spring.py
100644 blob 10940 6965eabdb5599bb22773e7fef1178f9b2bb51efe stm_df.py
100644 blob 3433 3063a1b6a132cbb5440ab95f1b6af1f1ff4266ac testcases_2D.py
100644 blob 2465 d829bff1dd721bdb8bbbed9a53db73efac471dac welford.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