#!/usr/bin/env python
# coding: utf-8
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from pyqtgraph.Qt import QtCore
from pyqtgraph import console
import numpy as np
import pandas as pd # required for estimation graph
from . import estimation as stm
def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs):
"""
This function will start Qt graph window in event loop
"""
return QtGuiPlot2D(sample_box, space, *args, **kwargs)
### Define a top-level widget to hold everything
class QtGuiPlot2D(QtGui.QMainWindow):
#č dublikuje slice_changed
# do not redraw twice!
box_runned = QtCore.pyqtSignal()
space_changed = QtCore.pyqtSignal()
slice_changed = QtCore.pyqtSignal()
redraw_called = QtCore.pyqtSignal()
estimation_added = QtCore.pyqtSignal()
# snad pri vykreslování argy-kvargy nevádí
def __init__(self, sample_box, space='R', *args, **kwargs):
#E former self.w = QtGui.QMainWindow()
self.app = pg.mkQApp()
super().__init__()
self.setWindowTitle(sample_box.gm_signature + " plot")
self.sample_box = sample_box
#sample_box.sample_box._log = self.logger
self.last_shot = None
self.space = space
# "zapnuté" prostory
#self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'aP', 'GK', 'aGK', 'G', 'aG', 'U', 'aU']
self.spaces = ['R', 'aR', 'Rn', 'aRn', 'P', 'GK', 'G', 'aG', 'U', 'aU']
# initialize central widget
self.initialize_central_widget()
# common setup
self.setup()
self.plot_setup()
## Display the widget as a new window
self.show()
#
self.redraw_called.emit()
## Start the Qt event loop
self.app.exec_()
def initialize_central_widget(self):
self.central_widget = pg.PlotWidget()
self.px_size = 2.5
self.plot_widget_2d()
self.redraw_called.connect(self.central_widget.clear)
def setup(self):
self.bar = self.menuBar()
self.view = self.bar.addMenu("View")
### Create some widgets to be placed inside
self.combo_space = pg.ComboBox(items=self.spaces, default=self.space)
self.combo_space.activated[str].connect(self.change_space)
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal)
self.slider.valueChanged.connect(self._slider_chainged)
self.slider.sliderReleased.connect(lambda:self.slice_changed.emit())
self.slider.setMaximum(self.sample_box.nsim)
self.slider.setValue(self.sample_box.nsim)
self.label_nsim = QtGui.QLabel()
self.label_nsim.setText(str(self.sample_box.nsim))
self.btn = QtGui.QPushButton('run box')
self.btn.clicked.connect(self.run_sb)
self.btn2 = QtGui.QPushButton('connect/disconnect')
self.btn2.setCheckable(True)
self.btn2.clicked.connect(self.bx_connect)
self.btn3 = QtGui.QPushButton('redraw')
self.btn3.clicked.connect(lambda:self.redraw_called.emit())
## Create a grid layout to manage the widgets size and position
self.layout = pg.LayoutWidget()
self.setCentralWidget(self.layout)
#self.w.setLayout(self.layout)
#
self.list_view = QtGui.QListWidget()
## Add widgets to the layout in their proper positions
#self.layout.addWidget(self.list_view, 0, 0, 2, 1)
self.layout.addWidget(self.combo_space, 0, 0)
self.layout.addWidget(self.slider, 0, 1)
self.layout.addWidget(self.label_nsim, 0, 2)
self.layout.addWidget(self.btn, 0, 3)
self.layout.addWidget(self.btn2, 0, 4)
self.layout.addWidget(self.btn3, 0, 5)
self.layout.addWidget(self.central_widget, 1, 0, 1, 6)
# status bar, mainly to observe BlackBox
self.statusBar = QtGui.QStatusBar()
self.setStatusBar(self.statusBar)
self.btn_continue = QtGui.QPushButton('continue')
self.continue_label = QtGui.QLabel()
# self.continue_layout = QtGui.QHBoxLayout()
# self.continue_layout.addWidget(self.btn_continue)
# self.continue_layout.addWidget(self.continue_label)
self.statusBar.addWidget(self.btn_continue)
self.statusBar.addWidget(self.continue_label)
self.btn_continue.hide()
self.continue_label.hide()
self.statusBar.showMessage("Vitáme vás u nás!")
# Dockables, najzajimavejší věc
self.dockables = []
dock = QtGui.QDockWidget("Interactive python console", self)
dock.setWidget(console.ConsoleWidget(namespace={**locals(), **globals()}))
self.dockables.append(dock)
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, dock)
dock = QtGui.QDockWidget("BlackBox output", self)
self.output_label = QtGui.QLabel()
dock.setWidget(self.output_label)
self.dockables.append(dock)
self.tabifyDockWidget(self.dockables[0], dock)
#č graphy už nemusí jít po stm widgetech
dock = QtGui.QDockWidget("TRI_current estimation graph", self)
dock.setWidget(TriEstimationGraph(self, tri_estimation_name='TRI_current_estimations'))
self.dockables.append(dock)
self.tabifyDockWidget(self.dockables[0], dock)
dock = QtGui.QDockWidget("TRI_overall estimation graph", self)
dock.setWidget(TriEstimationGraph(self, tri_estimation_name='TRI_overall_estimations'))
self.dockables.append(dock)
self.tabifyDockWidget(self.dockables[0], dock)
dock = QtGui.QDockWidget("Simplex estimation graph", self)
dock.setWidget(SimpleSimplexEstimationGraph(self.sample_box, self, dock))
self.dockables.append(dock)
self.tabifyDockWidget(self.dockables[0], dock)
dock = QtGui.QDockWidget("Voronoi estimation graph", self)
dock.setWidget(VoronoiEstimationGraph(self.sample_box, self, dock))
self.dockables.append(dock)
self.tabifyDockWidget(self.dockables[0], dock)
dock = QtGui.QDockWidget("View", self)
dock.setWidget(self.list_view)
self.dockables.append(dock)
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
for dock in self.dockables:
self.view.addAction(dock.toggleViewAction())
#dock.setFloating(True)
#self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
def plot_setup(self):
self.graph_menu = self.bar.addMenu("BlackBox")
self.triangulation_action = QtGui.QAction("Show triangulation", self, checkable=True)
self.triangulation_action.triggered.connect(self.triangulation_slot)
self.graph_menu.addAction(self.triangulation_action)
## dock = dock_r = QtGui.QDockWidget("Simplex-based pf estimation", self.w)
## dock.setWidget(SimplexEstimationWidget(self, dock))
#self.view.addAction(dock.toggleViewAction())
## self.dockables.append(dock)
## self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
#!
dock = dock_r = QtGui.QDockWidget("Tesselation-based pf estimation", self)
dock.setWidget(VoronoiEstimationWidget(self, dock))
self.view.addAction(dock.toggleViewAction())
self.dockables.append(dock)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
#self.w.tabifyDockWidget(dock_r, dock)
dock = QtGui.QDockWidget("Blackbox's candidates", self)
dock.setWidget(CandidatesWidget(self, dock))
self.view.addAction(dock.toggleViewAction())
self.dockables.append(dock)
self.tabifyDockWidget(dock_r, dock)
#
#č Tlačítka!
#
def _slider_chainged(self, value):
self.label_nsim.setText(str(value))
if not self.slider.isSliderDown(): # co to vůbec děla?
self.slice_changed.emit()
def change_space(self, space):
self.space = space
self.space_changed.emit()
#self.plot_widget_2d()
#self.slice_plot_data()
def run_sb(self):
with pg.BusyCursor():
self.last_shot = self.sample_box()
# slider
#č zpusobí slice_changed
self.slider.setMaximum(self.sample_box.nsim)
self.slider.setValue(self.sample_box.nsim)
self.box_runned.emit()
def bx_connect(self):
if self.btn2.isChecked():
try:
self.sample_box.connect(self.logger)
except BaseException as e:
print(self.__class__.__name__ + ":", "connection to BlackBox failed", repr(e))
else:
try:
self.sample_box.disconnect()
except BaseException as e:
print(self.__class__.__name__ + ":", "error while disconnecting of BlackBox", repr(e))
def logger(self, *args, msg="", indent=0, **kwargs):
self.continue_label.setText("BlackBox: " + msg)
self.output_label.setText(str(args) + str(kwargs))
loop = QtCore.QEventLoop()
self.btn_continue.clicked.connect(loop.quit)
self.btn_continue.show()
self.continue_label.show()
# i want to clear status bar temporaly
status = self.statusBar.currentMessage()
self.statusBar.clearMessage()
loop.exec_() # Execution stops here until finished called
self.btn_continue.hide()
self.continue_label.hide()
self.statusBar.showMessage(status)
def plot_widget_2d(self):
self.plotWidget.clear()
# Kružničky chcete?
# Кружочки ннада?
if self.space in ('Rn', 'G'):
nrod = 200
phi = np.linspace(0, 6.283185307, nrod, endpoint=True)
for r in range(5):
bound_x = r * np.cos(phi)
bound_y = r * np.sin(phi)
pen = pg.mkPen(color='k', width=6-r)
self.plotWidget.plot(bound_x, bound_y, pen=pen)
elif self.space in ('P', 'U'):
self.plotWidget.plot((0,0,1,1,0), (0,1,1,0,0), pen='k')
x, y, z, *__ = (*getattr(self.sample_box.failure_samples, self.space).T,)
self.failures = self.plotWidget.plot(x, y, pen=None, symbol='x', symbolPen='r', name='Failures') # symbolBrush=0.2,
x, y, z, *__ = (*getattr(self.sample_box.success_samples, self.space).T,)
self.successes = self.plotWidget.plot(x, y, pen=None, symbol='+', symbolPen='g', name='Successes')
x = y = ()
self.last = self.plotWidget.plot(x, y, pen=None, symbol='o', symbolPen='c', name='Last shot', symbolBrush=None)
self.shot = self.plotWidget.plot(x, y, pen=None, symbol='+', symbolPen='c', name='Last shot')
# pro začatek postačí
self.triangulation = []
# slider
self.slider.setMaximum(self.sample_box.nsim)
self.slider.setValue(self.sample_box.nsim)
# малы со кулэ?
return self.plotWidget
def slice_plot_data(self, sample=None):
if sample:
x, y = (*getattr(sample, self.space).T,)
self.last.setData(x, y)
self.shot.setData(x, y)
nsim = self.slider.value()
# Update the data
x, y = (*getattr(self.sample_box[:nsim].failure_samples, self.space).T,)
self.failures.setData(x, y)
x, y = (*getattr(self.sample_box[:nsim].success_samples, self.space).T,)
self.successes.setData(x, y)
# update triangulation
#print("Суредасько", (self.sample_box.nvar==2), self.triangulation_action.isChecked())
if (self.sample_box.nvar==2) and self.triangulation_action.isChecked():
try:
# take coordinates in the space, where triangulation has been performed
sampled_plan_tri = getattr(self.sample_box, self.sample_box.tri_space)
ns = 100
if len(self.triangulation) < len(self.sample_box.tri.simplices):
x = y = ()
gap = len(self.sample_box.tri.simplices) - len(self.triangulation)
for __ in range(gap):
self.triangulation.append(self.plotWidget.plot(x, y, pen=0.7))
for triangle, plot_item in zip(self.sample_box.tri.simplices, self.triangulation):
x_tri = np.linspace(sampled_plan_tri[triangle[0],0], sampled_plan_tri[triangle[1],0], ns, endpoint=False)
y_tri = np.linspace(sampled_plan_tri[triangle[0],1], sampled_plan_tri[triangle[1],1], ns, endpoint=False)
x_tri = np.append(x_tri, np.linspace(sampled_plan_tri[triangle[1],0], sampled_plan_tri[triangle[2],0], ns, endpoint=False))
y_tri = np.append(y_tri, np.linspace(sampled_plan_tri[triangle[1],1], sampled_plan_tri[triangle[2],1], ns, endpoint=False))
x_tri = np.append(x_tri, np.linspace(sampled_plan_tri[triangle[2],0], sampled_plan_tri[triangle[0],0], ns, endpoint=True))
y_tri = np.append(y_tri, np.linspace(sampled_plan_tri[triangle[2],1], sampled_plan_tri[triangle[0],1], ns, endpoint=True))
tri_bound_tri = np.array((x_tri, y_tri)).T
# vytvořme sample
tri_bound = self.sample_box.sampled_plan.new_sample(tri_bound_tri, space=self.sample_box.tri_space)
# Update the data
#print("Суредасько", tri_bound)
plot_item.setData(*getattr(tri_bound, self.space).T)
except BaseException as e:
msg = "error during triangulation drawing"
print(self.__class__.__name__ + ":",msg, repr(e))
def triangulation_slot(self):
if self.triangulation_action.isChecked():
#print("Мед сюредалоз!")
for plot_item in self.triangulation:
plot_item.show()
self.slice_plot_data()
else:
#print("Медам сюреда!")
for plot_item in self.triangulation:
plot_item.hide()
class PlotViewWidget(QtGui.QListWidget):
def __init__(self):
super().__init__()
print(self.addItem("Item 1"))
item = QtGui.QListWidgetItem('testcase_name')
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setCheckState(QtCore.Qt.Checked)
self.addItem(item)
self.addItem("Item 3")
self.addItem("Item 4")
##from PyQt5 import QtWidgets, QtCore
##
##self.listWidgetTestCases = QtWidgets.QListWidget()
##
##for testcases in root.iter('testcase'):
## testcase_name = str(testcases.attrib)
##
## item = QtWidgets.QListWidgetItem(testcase_name)
## item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
## item.setCheckState(QtCore.Qt.Unchecked)
## self.listWidgetTestCases.addItem(item)
"""
=============
График виӝет
Grafy
Estimation graph widgets
========================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
class TriEstimationGraph(pg.PlotWidget):
def __init__(self, samplebox_item, tri_estimation_name='TRI_current_estimations', parent=None, *args, **kwargs):
super().__init__(parent)
self.sb_item = samplebox_item
self.sb_item.box_runned.connect(self.redraw)
self.sb_item.estimation_added.connect(self.redraw)
self.black_box = samplebox_item.sample_box
self.tri_estimation_name = tri_estimation_name
self.setBackground('w')
x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
#self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
pen = pg.mkPen(color=(255, 0, 0), width=3)#, style=QtCore.Qt.DashLine)
self.pen_f = self.plot(x, y, pen=pen) # red
self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
self.pen_exact = self.plot(x, y, pen='b') # blue
self.setLogMode(False, True)
self.redraw()
def redraw(self):
try: # тут всё что угодно может пойти не так
data = self.black_box.guessbox.estimations[self.tri_estimation_name]
x = data[0]
# it can be effectively done with pandas
df = pd.DataFrame(data[1])
# -1 = 'out', 0=success, 1=failure, 2=mix
df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
# Update the data
# když se někde objeví nula se zapnutým LogModem - qtpygraph hned spadne a není možne ten pad zachytit
def nonzero(data): return np.where(data > 0, data, 1)
self.pen_f.setData(np.array(x)[df.failure.to_numpy() > 0], df.failure.to_numpy()[df.failure.to_numpy() > 0])
self.pen_mix.setData(x, nonzero(df.failure))
self.pen_outside.setData(x, nonzero(df.failure+df.mix))
self.pen_success.setData(x, nonzero(df.failure+df.mix+df.out)) # kontrolu, zda je to 1, nechame uživateli
self.pen_exact.setData((min(x),max(x)), (self.black_box.pf_exact, self.black_box.pf_exact))
except BaseException as e:
print(self.__class__.__name__ + ":", repr(e))
# pen_f.opts['logMode']
# pen_outside.setLogMode(False, False)
#setLogMode(False, False)
class SimpleSimplexEstimationGraph(pg.PlotWidget):
def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
super().__init__(parent)
self.sb_item = samplebox_item
self.sb_item.box_runned.connect(self.redraw)
self.sb_item.estimation_added.connect(self.redraw)
self.black_box = black_box
self.log_x_chk = QtGui.QAction("Log X", self.plotItem.ctrlMenu)
self.log_x_chk.setCheckable(True)
self.log_y_chk = QtGui.QAction("Log Y", self.plotItem.ctrlMenu)
self.log_y_chk.setCheckable(True)
# setLogMode(self, x=None, y=None)
self.log_x_chk.triggered.connect(lambda: self.setLogMode(x=self.log_x_chk.isChecked()))
self.log_y_chk.triggered.connect(self.setup)
self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
self.reaction.triggered.connect(self.redraw)
#pw.plotItem.ctrlMenu.actions()
self.plotItem.ctrlMenu.removeAction(self.plotItem.ctrlMenu.actions()[0])
self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.log_y_chk)
self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.log_x_chk)
self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
self.setup()
def setup(self, *args, **kwargs):
self.clear()
self.setBackground('w')
x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
if self.log_y_chk.isChecked():
self.setLogMode(y=True)
#self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
pen = pg.mkPen(color=(255, 0, 0), width=3)#, style=QtCore.Qt.DashLine)
self.pen_f = self.plot(x, y, pen=pen) # red
self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
self.pen_exact = self.plot(x, y, pen='b') # blue
else:
self.setLogMode(y=False)
self.pen_success = self.plot(x, y, fillLevel=0, brush='g') # green
self.pen_outside = self.plot(x, y, fillLevel=0, brush=0.8) # grey
self.pen_mix = self.plot(x, y, fillLevel=0, brush=(255, 165, 0)) # orange
self.pen_f = self.plot(x, y, fillLevel=0, brush='r') # red
self.pen_exact = self.plot(x, y, pen='b') # blue
self.redraw()
def redraw(self):
xmin = np.inf
xmax = -np.inf
tri_estimation = dict()
try: # тут всё что угодно может пойти не так
# kruci, ještě navic i generovať pokažde znovu...
# new-style: šecko leží dohromady a každý si z toho
# bere co chce a jak chce
# ne že by to bylo nějak šetrný
# estimation je slovníkem
for estimation in self.black_box.estimations:
# nsim musí mäť každej odhad
# pokud nemá - je třeba jej prostě opravit
nsim = estimation['nsim']
try:
tri_estimation[nsim] = estimation['TRI_estimation']
if nsim > xmax:
xmax = nsim
if nsim < xmin:
xmin = nsim
except KeyError as e:
pass #print(self.__class__.__name__ + ":", repr(e))
# it can be effectively done with pandas
df = pd.DataFrame(tuple(tri_estimation.values()))
# -1 = 'out', 0=success, 1=failure, 2=mix
df.rename(columns={-1:'out', 0:'success', 1:'failure', 2:'mix'}, inplace=True)
df.insert(loc=0, column='x', value=tuple(tri_estimation.keys()), allow_duplicates=False)
df.sort_values('x', inplace=True)
x = df.x.to_numpy()
if self.log_y_chk.isChecked():
# Update the data
# když se někde objeví nula se zapnutým LogModem - qtpygraph hned spadne a není možne ten pad zachytit
def nonzero(data): return np.where(data > 0, data, 1)
self.pen_f.setData(x[df.failure.to_numpy() > 0], df.failure.to_numpy()[df.failure.to_numpy() > 0])
self.pen_mix.setData(x, nonzero(df.failure))
self.pen_outside.setData(x, nonzero(df.failure+df.mix))
self.pen_success.setData(x, nonzero(df.failure+df.mix+df.out)) # kontrolu, zda je to 1, nechame uživateli
else:
# Update the data
self.pen_f.setData(x, df.failure)
self.pen_mix.setData(x, df.failure+df.mix)
self.pen_outside.setData(x, df.failure+df.mix+df.out)
self.pen_success.setData(x, df.failure+df.mix+df.out+df.success) # kontrolu, zda je to 1, nechame uivateli
if (xmax - xmin) > 0:
if hasattr(self.black_box, 'pf_exact'):
# poslední. I když spadne, tak už nikomu moc nevadí
self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
except BaseException as e:
print(self.__class__.__name__ + ":", repr(e))
# pen_f.opts['logMode']
# pen_outside.setLogMode(False, False)
#setLogMode(False, False)
#f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
#win.addItem(f)
class VoronoiEstimationGraph(pg.PlotWidget):
def __init__(self, black_box, samplebox_item, parent=None, *args, **kwargs):
super().__init__(parent)
self.sb_item = samplebox_item
self.sb_item.box_runned.connect(self.redraw)
self.sb_item.estimation_added.connect(self.redraw)
self.black_box = black_box
self.setBackground('w')
self.reaction = QtGui.QAction("Redraw", self.plotItem.ctrlMenu)
self.reaction.triggered.connect(self.redraw)
self.plotItem.ctrlMenu.insertAction(self.plotItem.ctrlMenu.actions()[0], self.reaction)
# implicitně Y je v logaritmickem měřítku
self.setLogMode(False, True)
x = y = () # zde jen vytvoříme kostru, nakrmíme daty v .redraw()
# nechapu, proč těm Itemům ríkám "propíska"
# propíska? Их есть у нас!
self.Voronoi_2_point_upper_bound = self.plot(x, y, pen='y')
self.Voronoi_2_point_lower_bound = self.plot(x, y, pen='y')
fill_color = (255, 243, 154) # let's try xkcd: dark cream (#fff39a)
self.fill = pg.FillBetweenItem(self.Voronoi_2_point_upper_bound, self.Voronoi_2_point_lower_bound, fill_color)
self.addItem(self.fill)
self.Voronoi_2_point_failure_rate = self.plot(x, y, pen=(195,46,212))
self.Voronoi_2_point_pure_failure_rate = self.plot(x, y, pen='m')
self.Voronoi_failure_rate = self.plot(x, y, pen='r')
self.pen_exact = self.plot(x, y, pen='b') # blue
self.pen_one = self.plot(x, y, pen='k') # black
self.redraw()
def redraw(self):
# kruci, ještě navic i generovať pokažde znovu...
metrics = {'Voronoi_2_point_upper_bound':{},\
'Voronoi_2_point_lower_bound':{},\
'Voronoi_2_point_failure_rate':{},\
'Voronoi_2_point_pure_failure_rate':{},\
'Voronoi_failure_rate':{},}
xmin = np.inf
xmax = -np.inf
try: # тут всё что угодно может пойти не так
# new-style: šecko leží dohromady a každý z toho
# bere co chce a jak chce
# ne že by to bylo nějak šetrný
# estimation je slovníkem
for estimation in self.black_box.estimations:
# nsim musí mäť každej odhad
# pokud nemá - je třeba jej prostě opravit
nsim = estimation['nsim']
for metric, metric_dict in metrics.items():
try:
if estimation[metric] > 0:
metric_dict[nsim] = estimation[metric]
if nsim > xmax:
xmax = nsim
if nsim < xmin:
xmin = nsim
except KeyError as e:
pass #print(self.__class__.__name__ + ":", repr(e))
for metric, metric_dict in metrics.items():
pen = getattr(self, metric)
# nikdo neslibil, že budou v pořadí
x = np.sort(tuple(metric_dict.keys()))
y = np.array(tuple(metric_dict.values()))[np.argsort(tuple(metric_dict.keys()))]
pen.setData(x, y)
if (xmax - xmin) > 0:
self.pen_one.setData((xmin,xmax), (1, 1))
if hasattr(self.black_box, 'pf_exact'):
# poslední. I když spadne, tak už nikomu moc nevadí
self.pen_exact.setData((xmin,xmax), (self.black_box.pf_exact, self.black_box.pf_exact))
except BaseException as e:
print(self.__class__.__name__ + ":", repr(e))
# pen_f.opts['logMode']
# pen_outside.setLogMode(False, False)
#setLogMode(False, False)
#f = pg.FillBetweenItem(curves[i], curves[i+1], brushes[i])
#win.addItem(f)
"""
=============
Эскерон виӝет
Widgety odhadů
Estimation widgets
===================
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
class SimplexEstimationWidget(pg.LayoutWidget):
"""
addLabel(text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs)
"""
# I'd like to get access to the samplebox stuff via the container's reference,
# but relying to Qt's parent mechanism makes me worry.
def __init__(self, samplebox_item, parent=None, *args, **kwargs):
super().__init__(parent)
# sb like samplebox, of course
self.sb_item = samplebox_item
self.sb_item.box_runned.connect(self.on_box_run)
self.sb_item.slice_changed.connect(self.self_clear)
self.sb_item.space_changed.connect(self.on_space_changed)
self.sb_item.redraw_called.connect(self.redraw)
#☺ na internetu všichni tak dělaj
self.setup()
def setup(self):
params = list()
params.append({'name': 'model space', 'type': 'list', 'values': self.sb_item.spaces, 'value': 'Rn'})
params.append({'name': 'sampling space', 'type': 'list', 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
params.append({'name': 'nodes per simplex', 'type': 'int', 'limits': (1, float('inf')), 'value': 1000, 'default': 1000})
params.append({'name': 'node (pixel) size', 'type': 'float', 'limits': (0, float('inf')), 'value': 3.5, 'default': self.sb_item.px_size})
xkcd_green = (167, 255, 181, 255) # xkcd:light seafoam green #a7ffb5
xkcd_red = (253, 193, 197, 255) # xkcd: pale rose (#fdc1c5)
xkcd_cream = (255, 243, 154, 255) # let's try xkcd: dark cream (#fff39a)
params.append({'name': 'failure', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_red, xkcd_red])})
params.append({'name': 'success', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_green, xkcd_green])})
params.append({'name': 'mix', 'type': 'colormap', 'value': pg.colormap.ColorMap((0,1), [xkcd_cream, xkcd_cream])})
params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
### Create tree of Parameter objects
self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
# I don't know why that signals do not work for me
# Only sigTreeStateChanged works, but I don't want to struggle with it
# May be I'll report the issue
#self.param.sigValueChanged.connect(self.param_changed)
#self.param.sigValueChanging.connect(self.param_changing)
### Create ParameterTree widget
self.ptree = pg.parametertree.ParameterTree()
self.ptree.setParameters(self.param, showTop=False)
self.addWidget(self.ptree, row=0, col=0, colspan=2)
self.btn = QtGui.QPushButton('estimate')
self.addWidget(self.btn, row=1, col=0)
self.btn.clicked.connect(self.run_stm)
self.btn2 = QtGui.QPushButton('redraw')
self.addWidget(self.btn2, row=1, col=1)
self.btn2.clicked.connect(self.recolor)
self.table = pg.TableWidget(sortable=False)
self.addWidget(self.table, row=2, col=0, colspan=2)
# pro začatek postačí
# triangulaci kreslím jen v 2D
self.triangulation = []
self.simplices = []
self.max_simplices = {'success':0, 'failure':0, 'mix':0}
def recolor(self):
# indikace
#self.setDisabled(True)
with pg.BusyCursor():
#☺ Krucinal, kdo ten OrderedDict vymyslel?
params = self.param.getValues()
coloring = params['coloring'][0]
# přebarvíme nějak tečičky
# callback vybírám ze svého kódu, ten musí bejt v pořádku
# ne že by to bylo dokonalé bezpečný,
# ale na lokálním počítači asi to není až tak zavadný
coloring_function = getattr(self, coloring)
# hura! Jedeme!
coloring_function()
# indikace
#self.setEnabled(True)
def on_space_changed(self, *args, **kwargs):
# asi stači překreslit propísky z tri_bound'ov
pass
# ten hlavní modul se dočkal na překopávání
def on_box_run(self, *args, **kwargs):
# je třeba zkontrolovat autorun a restartovat výpočet
if self.param.getValues()['Run with the box'][0]:
self.run_stm()
#else:
# self.self_clear()
def redraw(self, *args, **kwargs):
self.triangulation.clear()
self.simplices.clear()
self.max_simplices['success'] = 0
self.max_simplices['failure'] = 0
self.max_simplices['mix'] = 0
def self_clear(self):
# odebereme prvky-propísky z hlavního plotu
for tri_bound, plot_item in self.triangulation:
self.sb_item.central_widget.removeItem(plot_item)
for nodes, plot_item, cell_stats in self.simplices:
self.sb_item.central_widget.removeItem(plot_item)
self.redraw()
def run_stm(self):
# indikace
#self.setDisabled(True)
with pg.BusyCursor():
nsim = self.sb_item.slider.value()
sample_box = self.sb_item.sample_box[:nsim]
#☺ Krucinal, kdo ten OrderedDict vymyslel?
params = self.param.getValues()
model_space = params['model space'][0]
sampling_space = params['sampling space'][0]
if sampling_space == 'None':
sampling_space = None
nis = params['nodes per simplex'][0]
#č je třeba skrýt prvky z minula
self.self_clear()
try:
data = stm.simple_simplex_estimation(sample_box, model_space=model_space,\
sampling_space=sampling_space, nis=nis, callback=self.callback)
if hasattr(self.sb_item.sample_box, 'estimations'):
self.sb_item.sample_box.estimations.append(data)
self.sb_item.estimation_added.emit()
self.table.setData(data)
except BaseException as e:
msg = "error during estimation "
error_msg = self.__class__.__name__ + ": " + msg + repr(e)
print(error_msg)
# indikace
#self.setEnabled(True)
def callback(self, estimation, simplex, nodes, cell_stats, out_nodes, *args, **kwargs):
# stm trianguľaciju pokažde provadí znovu, proto skoro nemá cenu drbat se s její znovupoužitím
if (simplex.nvar==2):
ns = 100
simplex_tri = getattr(simplex, estimation['model_space'])
x_tri = np.linspace(simplex_tri[0,0], simplex_tri[1,0], ns, endpoint=False)
y_tri = np.linspace(simplex_tri[0,1], simplex_tri[1,1], ns, endpoint=False)
x_tri = np.append(x_tri, np.linspace(simplex_tri[1,0], simplex_tri[2,0], ns, endpoint=False))
y_tri = np.append(y_tri, np.linspace(simplex_tri[1,1], simplex_tri[2,1], ns, endpoint=False))
x_tri = np.append(x_tri, np.linspace(simplex_tri[2,0], simplex_tri[0,0], ns, endpoint=True))
y_tri = np.append(y_tri, np.linspace(simplex_tri[2,1], simplex_tri[0,1], ns, endpoint=True))
tri_bound_tri = np.array((x_tri, y_tri)).T
# vytvořme sample
tri_bound = self.sb_item.sample_box.sampled_plan.new_sample(tri_bound_tri, space=estimation['model_space'])
# draw
x, y = (*getattr(tri_bound, self.sb_item.space).T,)
plot_item = self.sb_item.plotWidget.plot(x, y, pen='c')
# uložíme data
self.triangulation.append((tri_bound, plot_item))
#plot_item.show()
#
# tečičky
#
# draw
x, y = (*getattr(nodes, self.sb_item.space).T,)
color = self.get_color(cell_stats)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
plot_item = self.sb_item.plotWidget.plot(x, y, pen=None, symbol='o', symbolPen=None,\
symbolBrush=(color), symbolSize=self.sb_item.px_size, name='IS localized nodes')
# ToDO
# přebarvíme tečičky podle obsahu pravděpodobnosti
## for nodes, plot_item, cell_stats in self.simplices:
## plot_item.setSymbolBrush(self.get_color(cell_stats))
# uložíme data
self.simplices.append((nodes, plot_item, cell_stats))
# keep the GUI responsive :)
self.sb_item.app.processEvents()
def get_color(self, cell_stats):
event = cell_stats['event']
cell_probability = cell_stats['cell_probability']
# generally
if event == 'success':
color = [167, 255, 181]# xkcd:light seafoam green #a7ffb5
elif event == 'failure':
color = [253, 193, 197] # xkcd: pale rose (#fdc1c5)
else:# 'mix'
color = [255, 243, 154] # let's try xkcd: dark cream (#fff39a)
# let's play with blue a little bit
# chcu ještě na konci prekreslit s různejma barvičkama, podle obsahu pravděpodobnosti
if self.max_simplices[event] < cell_probability:
self.max_simplices[event] = cell_probability
# bez modrého - maximální intenzita
color[2] = 0
else:
ratio = cell_probability / self.max_simplices[event]
color[2] = 255 - int(ratio*255)
return tuple(color)
class VoronoiEstimationWidget(pg.LayoutWidget):
"""
addLabel(text=' ', row=None, col=None, rowspan=1, colspan=1, **kargs)
"""
# I'd like to get access to the samplebox stuff via the container's reference,
# but relying to Qt's parent mechanism makes me worry.
def __init__(self, samplebox_item, parent=None, *args, **kwargs):
super().__init__(parent)
# sb like samplebox, of course
self.sb_item = samplebox_item
self.sb_item.box_runned.connect(self.on_box_run)
self.sb_item.slice_changed.connect(self.self_clear)
self.sb_item.space_changed.connect(self.on_space_changed)
self.sb_item.redraw_called.connect(self.redraw)
#☺ na internetu všichni tak dělaj
self.setup()
def setup(self):
# model_space='Rn', sampling_space=None, p_norm=1, budget=20000
params = [{'name': 'method', 'type': 'list', 'values': ['Voronoi_tesselation','Voronoi_2_point_estimation'], 'value': 'Voronoi_2_point_estimation'}]
params.append({'name': 'model space', 'type': 'list', 'values': self.sb_item.spaces, 'value': 'Rn'})
params.append({'name': 'sampling space', 'type': 'list', 'values': ['None'] + self.sb_item.spaces, 'value': 'None'})
params.append({'name': 'p-norm', 'type': 'float', 'limits': (1, float('inf')), 'value': 1, 'default': np.inf})
params.append({'name': 'budget', 'type': 'float', 'limits': (1, float('inf')), 'value': 20000, 'default': 20000})
self.coloring_modes = ['simple_coloring', 'cell_probability_coloring','node_pf_coloring']
params.append({'name': 'coloring', 'type': 'list', 'values': self.coloring_modes, 'value': self.coloring_modes[1]})
params.append({'name': 'node (pixel) size', 'type': 'float', 'limits': (0, float('inf')), 'value': 3, 'default': 1})
params.append({'name': 'Run with the box', 'type': 'bool', 'value': False }) # 'tip': "This is a checkbox"
### Create tree of Parameter objects
self.param = pg.parametertree.Parameter.create(name='params', type='group', children=params)
# I don't know why that signals do not work for me
# Only sigTreeStateChanged works, but I don't want to struggle with it
# May be I'll report the issue
#self.param.sigValueChanged.connect(self.param_changed)
#self.param.sigValueChanging.connect(self.param_changing)
### Create ParameterTree widget
self.ptree = pg.parametertree.ParameterTree()
self.ptree.setParameters(self.param, showTop=False)
self.addWidget(self.ptree, row=0, col=0, colspan=2)
self.btn = QtGui.QPushButton('estimate')
self.addWidget(self.btn, row=1, col=0)
self.btn.clicked.connect(self.run_stm)
self.btn2 = QtGui.QPushButton('redraw')
self.addWidget(self.btn2, row=1, col=1)
self.btn2.clicked.connect(self.recolor)
# self.autorun = QtGui.QCheckBox('Run with the box')
# self.addWidget(self.autorun, row=1, col=1)
self.table = pg.TableWidget(sortable=False)
self.addWidget(self.table, row=2, col=0, colspan=2)
# pro začatek postačí
self.cells = []
# probability of the biggest cell
# used for coloring
self.p_cell_max = {'success':0, 'failure':0}
def on_box_run(self, *args, **kwargs):
# je třeba zkontrolovat autorun a restartovat výpočet
if self.param.getValues()['Run with the box'][0]:
self.run_stm()
#else:
#self.self_clear()
def redraw(self, *args, **kwargs):
self.cells.clear()
self.p_cell_max['success'] = 0
self.p_cell_max['failure'] = 0
# I'll rename after main widget refactoring
def recolor(self):
# indikace
#self.setDisabled(True)
with pg.BusyCursor():
# Krucinal, kdo ten OrderedDict vymyslel?
params = self.param.getValues()
coloring = params['coloring'][0]
# přebarvíme nějak tečičky
# callback vybírám ze svého kódu, ten musí bejt v pořádku
# ne že by to bylo dokonalé bezpečný,
# ale na lokálním počítači asi to není až tak zavadný
coloring_function = getattr(self, coloring)
# hura! Jedeme!
coloring_function()
# indikace
#self.setEnabled(True)
def on_space_changed(self, *args, **kwargs):
# asi stači překreslit propísky z tri_bound'ov
pass
def self_clear(self):
# odebereme prvky-propísky z hlavního plotu
for nodes, plot_item, cell_stats in self.cells:
self.sb_item.central_widget.removeItem(plot_item)
self.redraw()
def run_stm(self):
# indikace
#self.setDisabled(True)
with pg.BusyCursor():
nsim = self.sb_item.slider.value()
sample_box = self.sb_item.sample_box[:nsim]
# Krucinal, kdo ten OrderedDict vymyslel?
params = self.param.getValues()
method = params['method'][0]
model_space = params['model space'][0]
sampling_space = params['sampling space'][0]
if sampling_space == 'None':
sampling_space = None
p_norm = params['p-norm'][0]
budget = params['budget'][0]
coloring = params['coloring'][0]
# je třeba skrýt prvky z minula
self.self_clear()
# přebarvíme nějak tečičky
# callback vybírám ze svého kódu, ten musí bejt v pořádku
# ne že by to bylo dokonalé bezpečný,
# ale na lokálním počítači asi to není až tak zavadný
coloring_function = getattr(self, coloring)
try:
stm_function = getattr(stm, method)
# model_space='Rn', sampling_space=None, p_norm=1, budget=20000
data = stm_function(sample_box, model_space=model_space, sampling_space=sampling_space,\
p_norm=p_norm, budget=budget, callback=coloring_function)
if hasattr(self.sb_item.sample_box, 'estimations'):
self.sb_item.sample_box.estimations.append(data)
self.sb_item.estimation_added.emit()
self.table.setData(data)
except BaseException as e:
msg = "error during estimation "
error_msg = self.__class__.__name__ + ": " + msg + repr(e)
print(error_msg)
# indikace
#self.setEnabled(True)
def node_pf_coloring(self, estimation=None, nodes=None, cell_stats=None, out_nodes=None, *args, **kwargs):
"""
if nodes and cell_stats provided we will add them to self.cells
otherwise function redraw items in self.cells
"""
if nodes is None:
for cell in self.cells:
nodes, plot_item, cell_stats = cell
# odebereme prvky z hlavního plotu
# zde je třeba prvky vygenerovat znovu
# protože nikdo neví co tam bylo před tím
# takhle, nechce se mi drbat s tím, co tam bylo před tím
# komplikace ze strany pyqtgraph
self.sb_item.plotWidget.removeItem(plot_item)
# bacha, potřebuji prvek uložiť in-place
cell[1] = self.node_pf_scatter_plot(nodes, cell_stats)
# máme nodes, tj. jedeme poprvé
else:
plot_item = self.node_pf_scatter_plot(nodes, cell_stats)
# uložíme data
self.cells.append([nodes, plot_item, cell_stats])
# keep the GUI responsive :)
self.sb_item.app.processEvents()
def node_pf_scatter_plot(self, nodes, cell_stats):
pos = getattr(nodes, self.sb_item.space)
symbol_size = self.param.getValues()['node (pixel) size'][0]
# zas, нет ножек - нет мультиков
# node_pf_estimations nemusejí bejt
try:
# zkusmě pro jednoduchost
# čírou RGB hračku
npf = nodes.node_pf_estimations
colors = tuple((npf[i]*255, (1-npf[i])*255, 0) for i in range(len(pos)))
# sice dokumentace popisuje víc možností zadávání,
# ale toto zadávání různejch barviček je pro mě jediné fungujicí. Drbal jsem s tím do znechucení
# je v podstatě opsané z příkladu
# rovnou přes PlotDataItem mi nefunguje
# žádné jiné možností zadávání já jsem v zdrojacích
# pyqtgraph (konkretně v PlotDataItem a v ScatterPlotItem) neuviděl
# tuším, že je to neunosně drahý
list_of_dicts = list({'pos': pos[i], 'size':symbol_size, 'pen': colors[i], 'brush':colors[i], 'symbol':'o'} for i in range(len(pos)))
plot_item = pg.ScatterPlotItem(list_of_dicts)
self.sb_item.plotWidget.addItem(plot_item)
return plot_item
except BaseException as e:
msg = "node_pf_coloring has problems "
error_msg = self.__class__.__name__ + ": " + msg + repr(e)
print(error_msg)
self.error.emit(error_msg)
# simple coloring
event = cell_stats['event']
color = self.get_color(event)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
return self.sb_item.plotWidget.plot(pos, pen=None, symbol='o', symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
def simple_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
"""
if nodes and cell_stats provided we will add them to self.cells
otherwise function redraw items in self.cells
"""
symbol_size = self.param.getValues()['node (pixel) size'][0]
if nodes is None:
for cell in self.cells:
nodes, plot_item, cell_stats = cell
# odebereme prvky z hlavního plotu
# zde je třeba prvky vygenerovat znovu
# protože nikdo neví co tam bylo před tím
# takhle, nechce se mi drbat s tím, co tam bylo před tím
# komplikace ze strany pyqtgraph
self.sb_item.plotWidget.removeItem(plot_item)
# draw
pos = getattr(nodes, self.sb_item.space)
#x, y = (*getattr(nodes, self.sb_item.space).T,)
event = cell_stats['event']
color = self.get_color(event)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
# bacha, potřebuji prvek uložiť in-place
cell[1] = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
# máme nodes, tj. jedeme poprvé
else:
# draw tečičky
#
pos = getattr(nodes, self.sb_item.space)
event = cell_stats['event']
color = self.get_color(event)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
plot_item = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
# uložíme data
self.cells.append([nodes, plot_item, cell_stats])
# keep the GUI responsive :)
self.sb_item.app.processEvents()
def cell_probability_coloring(self, nodes=None, cell_stats=None, *args, **kwargs):
"""
if nodes and cell_stats provided we will add them to self.cells
otherwise function redraw items in self.cells
"""
symbol_size = self.param.getValues()['node (pixel) size'][0]
if nodes is None:
# odebereme prvky z hlavního plotu
# zde je třeba prvky vygenerovat znovu
# protože nikdo neví co tam bylo před tím
# takhle, nechce se mi drbat s tím, co tam bylo před tím
# komplikace ze strany pyqtgraph
for nodes, plot_item, cell_stats in self.cells:
self.sb_item.plotWidget.removeItem(plot_item)
event = cell_stats['event']
cell_probability = cell_stats['cell_probability']
if self.p_cell_max[event] < cell_probability:
self.p_cell_max[event] = cell_probability
# přebarvíme tečičky podle obsahu pravděpodobnosti
for cell in self.cells:
nodes, plot_item, cell_stats = cell
# draw
pos = getattr(nodes, self.sb_item.space)
#x, y = (*getattr(nodes, self.sb_item.space).T,)
event = cell_stats['event']
cell_probability = cell_stats['cell_probability']
# bez modrého - maximální intenzita
blue_intensity = 1 - cell_probability / self.p_cell_max[event]
color = self.get_color(event, blue_intensity)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
# bacha, potřebuji prvek vložit zpätky
cell[1] = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
# máme nodes, tj. jedeme poprvé
else:
event = cell_stats['event']
cell_probability = cell_stats['cell_probability']
# zkontrolujeme probability
if self.p_cell_max[event] < cell_probability:
self.p_cell_max[event] = cell_probability
# a hned všecko dotyčné přebarvíme podle obsahu pravděpodobnosti
for cell in self.cells:
if event == cell[2]['event']:
# bez modrého - maximální intenzita
# zde cell_probability se rovná self.p_cell_max[event]
# ale bacha! Nesplet se jinde!
blue_intensity = 1 - cell[2]['cell_probability'] / cell_probability
color = self.get_color(event, blue_intensity)
# bacha, potřebuji prvek vložit zpätky
cell[1].setSymbolBrush(color)
cell[1].setSymbolPen(color)
# bez modrého - maximální intenzita
blue_intensity = 1 - cell_probability / self.p_cell_max[event]
color = self.get_color(event, blue_intensity)
# draw tečičky
#
pos = getattr(nodes, self.sb_item.space)
#x, y = (*getattr(nodes, self.sb_item.space).T,)
#symbolSize = np.sqrt(nodes.w / min(nodes.w)) # not bad
plot_item = self.sb_item.plotWidget.plot(pos, pen=None, symbol='o',\
symbolPen=color, symbolBrush=color, symbolSize=symbol_size, name='IS localized nodes')
# uložíme data
self.cells.append([nodes, plot_item, cell_stats])
# keep the GUI responsive :)
self.sb_item.app.processEvents()
def get_color(self, event, blue_intensity=None):
"""
get color for 'simple_coloring' or 'cell_probability_coloring'
"""
# generally
if event == 'success':
color = [167, 255, 181]# xkcd:light seafoam green #a7ffb5
elif event == 'failure':
color = [253, 193, 197] # xkcd: pale rose (#fdc1c5)
# já vím, že Voronoi nemá 'mix', эн но юа
else:# 'mix'
color = [255, 243, 154] # let's try xkcd: dark cream (#fff39a)
if blue_intensity is not None:
# let's play with blue a little bit
# chcu mít korektní výstup
# aspoň v něčem chcu být jistý
if blue_intensity > 1:
color[2] = 255
elif blue_intensity < 0:
color[2] = 0
else:
# pyqtgraph žere barvy i s čarkou
# ale my je mu davat nebudeme
color[2] = int(blue_intensity*255)
return tuple(color)
"""
===========
♥ Чыры-пыры
č Jiné
E Miscellaneous
===============
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"""
class CandidatesWidget(pg.LayoutWidget):
"""
"""
# I'd like to get access to the samplebox stuff via the container's reference,
# but relying to Qt's parent mechanism makes me worry.
def __init__(self, samplebox_item, parent=None, *args, **kwargs):
super().__init__(parent)
# sb like samplebox, of course
self.sb_item = samplebox_item
#self.sb_item.box_runned.connect(self.on_box_run)
self.sb_item.slice_changed.connect(self.rerun)
self.sb_item.space_changed.connect(self.rerun)
self.sb_item.redraw_called.connect(self.redraw)
#☺ na internetu všichni tak dělaj
self.setup()
def setup(self):
# 1
#
self.autorun = QtGui.QCheckBox('Show')
self.autorun.stateChanged.connect(self.rerun)
self.addWidget(self.autorun)
self.btn = QtGui.QPushButton('redraw')
self.addWidget(self.btn, row=0, col=1)
self.btn.clicked.connect(self.rerun)
# 2
#
#č predpokladam pandas verzi CandyBox'u
#items = list(self.sb_item.sample_box.candidates_index[-1].df.columns)
try:
#č načíst sloupce prostě z libovolného vzorku
df = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
items = df.columns
except:
#♥ мыным дунне
items = []
self.attr = pg.ComboBox(items=items)
#self.attr.activated.connect(self.redraw)
self.addWidget(self.attr, row=1, col=0, colspan=2)
# 3
#
self.gradient = pg.GradientWidget(self, orientation='right')
self.addWidget(self.gradient, row=2, col=1)
#E pens, i.e. handles of PlotItem
self.pens = []
def run_stm(self):
#č indikace
#self.setDisabled(True)
with pg.BusyCursor():
color_map = self.gradient.colorMap()
try:#č může se tu stat cokoliv
#č načíst sloupce prostě z libovolného vzorku
cb = self.sb_item.sample_box.candidates_index.values().__iter__().__next__()
#č je třeba mít seznam aktualní
self.attr.setItems(list(cb.df.columns))
#č neplest s self.attr!
attr = self.attr.currentText()
#č kruci, nejdřív je třeba najít maxvalue, minvalue je implicitně nula
maxvalue = -np.inf
minvalue = np.inf
for id, cb in self.sb_item.sample_box.candidates_index.items():
array = getattr(cb, attr)
maxcb = np.nanmax(array)
mincb = np.nanmin(array)
if maxcb > maxvalue:
maxvalue = maxcb
if mincb < minvalue:
minvalue = mincb
#č a teď jdeme!
for id, cb in self.sb_item.sample_box.candidates_index.items():
array = getattr(cb, attr)
if np.isnan(array).any():
msg = "%s candidates has nans in %s attribute"%(id, attr)
error_msg = self.__class__.__name__ + ": " + msg
print(error_msg)
mask = np.isfinite(array)
values = array[mask]
norm_values = (values - minvalue) / (maxvalue - minvalue)
pos = getattr(cb, self.sb_item.space)[mask]
#č sehnal jsem toto ze zdrojaků pyqtgraph
style = dict(pen=None, symbol='o', symbolSize=self.sb_item.px_size, symbolPen=pg.mkPen(None))
style['symbolBrush'] = np.array([pg.functions.mkBrush(*x) for x in color_map.map(norm_values)])
pen = self.sb_item.plotWidget.plot(pos, data=values, **style)
pen.setZValue(-1)
self.pens.append(pen)
except BaseException as e:
msg = ""
error_msg = self.__class__.__name__ + ": " + msg + repr(e)
print(error_msg)
self.error.emit(error_msg)
# indikace
#self.setEnabled(True)
#č současně ten hlavní modul se pokusí zavolat redraw při zpouštění boxu
#č ten hlavní modul se těší na překopávání
def rerun(self, *args, **kwargs):
#č uklizení budu chtit jednoznačně
self.self_clear()
#č a teď řešíme, zda je třeba restartovat výpočet
if self.autorun.isChecked():
self.run_stm()
def redraw(self, *args, **kwargs):
self.pens.clear()
def self_clear(self):
#č odebereme prvky-propísky z hlavního plotu
for plot_item in self.pens:
self.sb_item.central_widget.removeItem(plot_item)
self.pens.clear()
#E not implementeed yet on the main window side
# def on_space_changed(self, *args, **kwargs):
# pass