#!/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 show_ax, show_ax3d, show_fig
from .mplot import maxes
from .mplot import maxes3d
from .mplot import mfigs
from .mplot import misc as mmisc
self.matplotlib_menu = self.bar.addMenu("Matplotlib")
self.matplotlib_actions = []
self.matplotlib_2D_menu = self.matplotlib_menu.addMenu("2D plots")
self._setup_mpl_submenu(self.matplotlib_2D_menu, maxes, show_ax)
self.matplotlib_3D_menu = self.matplotlib_menu.addMenu("3D plots")
self._setup_mpl_submenu(self.matplotlib_3D_menu, maxes3d, show_ax3d)
self.matplotlib_figs_menu = self.matplotlib_menu.addMenu("Complex plots")
self._setup_mpl_submenu(self.matplotlib_figs_menu, mfigs, show_fig)
self.matplotlib_misc_menu = self.matplotlib_menu.addMenu("Others")
for smthng in mmisc.__all__:
mpl_action = QtGui.QAction(smthng, self)
show_mpl = self._mpl_prepare_fn(getattr(mmisc, smthng))
mpl_action.triggered.connect(show_mpl)
self.matplotlib_misc_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 _setup_mpl_submenu(self, menu, module, handler):
for drawing in module.__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._mpl_prepare_show_fn(handler, getattr(module, drawing))
mpl_action.triggered.connect(show_mpl)
menu.addAction(mpl_action)
# prevent GC from wiping out both Qt object and our function
self.matplotlib_actions.append((mpl_action, show_mpl))
def _mpl_prepare_show_fn(self, show, to_draw):
return lambda: show(to_draw, self.sample_box, space=self.space)
def _mpl_prepare_fn(self, fn):
return lambda: fn(sample_box=self.sample_box, space=self.space)
# 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