#!/usr/bin/env python
# coding: utf-8
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from pyqtgraph.Qt import QtCore
import numpy as np
import pandas as pd # required for estimation graph
def qt_gui_plot_2d(sample_box, space='R', *args, **kwargs):
"""
This function will start Qt graph window in event loop
To run code beyond the loop call QtGuiPlot2D directly
"""
qtplot = QtGuiPlot2D(sample_box, space, *args, **kwargs)
## Display the widget as a new window
qtplot.w.show()
## Start the Qt event loop
qtplot.app.exec_()
return qtplot
class QtGuiPlot2D:
#sb_runned = QtCore.pyqtSignal()
# snad pri vykreslování argy-kvargy nevádí
def __init__(self, sample_box, space='R', *args, **kwargs):
self.sample_box = sample_box
#sample_box.sample_box._log = self.logger
self.space = space
self.app = pg.mkQApp()
### Define a top-level widget to hold everything
self.w = QtGui.QMainWindow()
self.w.setWindowTitle(sample_box.gm_signature + " plot")
self.bar = self.w.menuBar()
self.view = self.bar.addMenu("View")
self.graph_menu = self.bar.addMenu("Graph")
self.triangulation_action = QtGui.QAction("Show triangulation", self.w, checkable=True)
self.triangulation_action.triggered.connect(self.triangulation_slot)
self.graph_menu.addAction(self.triangulation_action)
#self.file = self.bar.addMenu("File")
#self.file.addAction("quit")
### Create some widgets to be placed inside
self.combo_space = pg.ComboBox(items=['R', 'Rn', 'P', 'GK', 'G', 'U'], default=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(self.slice_plot_data)
self.label_nsim = QtGui.QLabel()
self.label_nsim.setText(str(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.btn_connect = QtGui.QPushButton('connect')
# self.btn_connect.clicked.connect(lambda:self.sample_box.connect(self.logger))
#
# self.btn_disconnect = QtGui.QPushButton('disconnect')
# self.btn_disconnect.clicked.connect(self.sample_box.disconnect)
# zkusím prostě generovať
self.plotWidget = pg.PlotWidget()
self.plotWidget.setBackground('w')
self.plot_widget_2d()
## Create a grid layout to manage the widgets size and position
self.layout = pg.LayoutWidget()
self.w.setCentralWidget(self.layout)
#self.w.setLayout(self.layout)
## Add widgets to the layout in their proper positions
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.plotWidget, 1, 0, 1, 5)
# Dockables, najzajimavejší věc
self.dockables = []
dock = QtGui.QDockWidget("BlackBox output", self.w)
self.output_label = QtGui.QLabel()
dock.setWidget(self.output_label)
self.dockables.append(dock)
self.w.addDockWidget(QtCore.Qt.BottomDockWidgetArea, dock)
dock = QtGui.QDockWidget("TRI_current estimation graph", self.w)
dock.setWidget(TriEstimationGraph(self.sample_box, tri_estimation_name='TRI_current_estimations'))
self.dockables.append(dock)
self.w.tabifyDockWidget(self.dockables[0], dock)
dock = QtGui.QDockWidget("TRI_overall estimation graph", self.w)
dock.setWidget(TriEstimationGraph(self.sample_box, tri_estimation_name='TRI_overall_estimations'))
self.dockables.append(dock)
self.w.tabifyDockWidget(self.dockables[0], dock)
for dock in self.dockables:
self.view.addAction(dock.toggleViewAction())
#dock.setFloating(True)
#self.w.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.items)
# status bar, mainly to observe BlackBox
self.statusBar = QtGui.QStatusBar()
self.w.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!")
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 _slider_chainged(self, value):
self.label_nsim.setText(str(value))
if not self.slider.isSliderDown(): # co to vůbec děla?
self.slice_plot_data()
def run_sb(self):
sample = self.sample_box()
# slider
self.slider.setMaximum(self.sample_box.nsim)
self.slider.setValue(self.sample_box.nsim)
self.slice_plot_data(sample)
#self.sb_runned.emit()
# zatím tak
for dock in self.dockables:
try:
dock.widget().redraw()
except AttributeError:
pass
#dock.setFloating(True)
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 = (*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 = (*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')
# ne všichni majó definované hranice
try:
bounds = self.sample_box.get_2D_boundary()
for bound in bounds:
self.plotWidget.plot(*getattr(bound, self.space).T, pen='b')
except AttributeError:
pass #print("čo sa děje?")
# 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 change_space(self, space):
self.space = space
self.plot_widget_2d()
self.slice_plot_data()
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 TriEstimationGraph(pg.PlotWidget):
def __init__(self, black_box, tri_estimation_name='TRI_current_estimations', parent = None, *args, **kwargs):
super().__init__(parent)
self.black_box = black_box
self.tri_estimation_name = tri_estimation_name
self.setBackground('w')
x = y = () # zde jen vytvoříme kostru, nakrmime daty v .redraw()
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):
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
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 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))