diff --git a/.travis.yml b/.travis.yml
index ee6c1aa..3866824 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -48,7 +48,7 @@ install:
- conda create -y -c anaconda --name $PYN python=$PY `head -n1 requirements_conda.txt`
- source activate $PYN
- python ./service/installreq.py
- - python setup.py install
+ - python setup.py develop
# Builds Complete
- virtualenv --version
- easy_install --version
diff --git a/src/rrpam_wds/gui/dialogs.py b/src/rrpam_wds/gui/dialogs.py
index c70eefb..c9d218c 100644
--- a/src/rrpam_wds/gui/dialogs.py
+++ b/src/rrpam_wds/gui/dialogs.py
@@ -1,5 +1,6 @@
from rrpam_wds.gui import set_pyqt_api # isort:skip # NOQA
+import math
import random
import sys
@@ -13,6 +14,7 @@
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from numpy import arange
+from numpy import array
from numpy import interp
from numpy import linspace
from numpy import pi
@@ -42,7 +44,6 @@
CONF.set("plot", "selection/distance", 10.0)
# todo: This has to be saved as project's setting file (CONF.save provides that facility)
-
STYLE = style_generator()
@@ -60,16 +61,22 @@ class CurveDialogWithClosable(CurveDialog):
"""
def __init__(self, *args, **kwargs):
- super(CurveDialogWithClosable, self).__init__(*args, **kwargs)
+ kwargs_ = dict(kwargs)
+ del kwargs_["mainwindow"]
+ super(CurveDialogWithClosable, self).__init__(*args, **kwargs_)
+ self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self._can_be_closed = True
self.get_plot().set_antialiasing(True)
self.add_tools()
+ self.get_plot().SIG_ITEM_SELECTION_CHANGED.connect(kwargs['mainwindow'].selected_holder)
+ self.get_plot().SIG_ITEM_REMOVED.connect(self.__item_removed)
+ self.myplotitems = {}
def set_all_private(self):
"""" Set all current items in the plot private"""
[x.set_private(True) for x in self.get_plot().get_items()]
- def set_scale(self, axes_limits=None):
+ def set_axes_limits(self, axes_limits=None):
"""Sets axes limits axes_limits should be a list with four float values [x0,x1,y0,y1] """
self.get_plot().PREFERRED_AXES_LIMITS = axes_limits
# now autoscale
@@ -85,6 +92,7 @@ def setClosable(self, closable=True):
def closeEvent(self, evnt):
if self._can_be_closed:
super(CurveDialogWithClosable, self).closeEvent(evnt)
+
else:
evnt.ignore()
self.setWindowState(QtCore.Qt.WindowMinimized)
@@ -95,47 +103,104 @@ def keyPressEvent(self, e):
else:
pass
+ def plot_item(self, id_, data, title="Point", icon="pipe.png"):
+ raise NotImplemented
+
+ def add_plot_item_to_record(self, id_, item):
+ """All the plot items register here by calling this method. See also: remove_plot_item_from_record"""
+ self.myplotitems[id_] = item
+
+ def remove_plot_item_from_record(self, id_):
+ """When removing a plot item it should be notified to this function. See also: add_plot_item_to_record """
+ del self.myplotitems[id_]
+
+ def __item_removed(self, goner):
+ tmplist = dict(self.myplotitems)
+ for id_, item in tmplist.items():
+ if goner in item:
+ # first remove related items.
+ others = [x for x in item if x != goner]
+ for i in others:
+ try:
+ self.get_plot().del_item(i)
+ except:
+ pass
+ try:
+ self.remove_plot_item_from_record(id_)
+ except:
+ pass
+
class RiskMatrix(CurveDialogWithClosable):
SCALE = 10.
- def __init__(self, name="Risk Matrix", parent=None, options={}, axes_limits=[0, 15000, 0, 100]):
+ def __init__(self, name="Risk Matrix", mainwindow=None, parent=None,
+ units=units["EURO"], options={}, axes_limits=[0, 15000, 0, 100]):
if("xlabel" not in options):
- options['xlabel'] = "Consequence ($)"
+ options['xlabel'] = "Consequence (%s)" % (units)
if("ylabel" not in options):
options['ylabel'] = "Proabability(-)"
if("gridparam" not in options):
options['gridparam'] = make.gridparam()
super(RiskMatrix, self).__init__(edit=False,
- icon="guiqwt.svg",
+ icon="risk.svg",
toolbar=True,
options=options,
parent=parent,
panels=None,
- wintitle=name)
- self.set_scale(axes_limits)
+ wintitle=name,
+ mainwindow=mainwindow)
+ self.setClosable(False)
+ _axes_limits = axes_limits[0], axes_limits[1] * 1.1, axes_limits[2], axes_limits[3] * 1.1
+ self.set_axes_limits(_axes_limits)
+
+ l = make.legend("TR")
+ self.get_plot().add_item(l)
+ self.set_all_private()
+
+ def get_ellipse_xaxis(self, consequence, probability):
+ l = self.get_plot().PREFERRED_AXES_LIMITS
+ SCALE = self.get_scale(consequence, probability, l)
+ return consequence - SCALE, probability + SCALE,\
+ consequence + SCALE, probability - SCALE
+
+ def get_scale(self, consequence, probability, l):
+ SCALE = self.SCALE * math.pow(consequence * probability, .25) / math.pow((l[1] * l[3]), .25)
+ return SCALE
+
+ def get_proper_axis_limits(self):
+ return
- def plot_item(self, consequence, probability, title="Point"):
+ def plot_item(self, id_, data, title="Point", icon="pipe.png"):
global STYLE
- ci = make.ellipse(consequence - self.SCALE, probability - self.SCALE,
- consequence + self.SCALE, probability + self.SCALE,
- title=title)
+ consequence, probability = data
+
+ ci = make.ellipse(*self.get_ellipse_xaxis(consequence, probability),
+ title=title)
ci.shapeparam._DataSet__icon = u.get_icon('Risk')
ci.shapeparam._DataSet__title = title
param = ci.shapeparam
param.fill.color = QColor('red')
+ param.sel_fill.color = QColor('purple')
+ param.sel_fill.alpha = .7
+ param.sel_symbol.Marker = "NoSymbol"
+ param.sel_symbol.Color = QColor('red')
update_style_attr('-r', param)
param.update_shape(ci)
+ ci.id_ = id_ # add the ide to the item before plotting.
self.get_plot().add_item(ci)
- self.get_plot().add_item(make.legend("TR"))
- ci.plot().replot()
+ # now add a label with title
+ # ci
+ # la = make.label(title, ci.get_center(), (0, 0), "C")
+ self.add_plot_item_to_record(id_, [ci])
class NetworkMap(CurveDialogWithClosable):
- def __init__(self, name, nodes=None, links=None, parent=None, options={}):
+ def __init__(self, name="Network Map", mainwindow=None,
+ nodes=None, links=None, parent=None, options={}):
pass
if("xlabel" not in options):
options['xlabel'] = "X (distance units)"
@@ -145,11 +210,15 @@ def __init__(self, name, nodes=None, links=None, parent=None, options={}):
gridparam = make.gridparam()
super(NetworkMap, self).__init__(edit=False,
- icon="guiqwt.svg",
+ icon="network.svg",
toolbar=True,
options=dict(gridparam=gridparam),
parent=parent,
- panels=None)
+ wintitle=name,
+ panels=None,
+ mainwindow=mainwindow)
+ self.setClosable(False)
+
# legend = make.legend("TR")
# self.get_plot().add_item(legend)
self.set_all_private()
@@ -177,19 +246,28 @@ def interp_curve(self, x, y):
def draw_links(self, links):
for link in links:
pts = [(link.start.x, link.start.y)] + link.vertices + [(link.end.x, link.end.y)]
- x = [n[0] for n in pts]
- y = [n[1] for n in pts]
- x_, y_ = self.interp_curve(x, y)
- cu = make.curve(x_, y_, title=u.get_title(link))
- cu.curveparam._DataSet__icon = u.get_icon(link)
- cu.curveparam._DataSet__title = u.get_title(link)
- self.get_plot().add_item(cu)
-
- # create a label for the node and add it to the plot
- l = int(len(x_) / 2.0)
- la = make.label(link.id, (x_[l], y_[l]), (0, 0), "C")
- la.set_private(True)
- self.get_plot().add_item(la)
+ title = u.get_title(link)
+ icon = u.get_icon(link)
+ id_ = link.id
+ self.plot_item(id_, pts, title, icon)
+
+ def plot_item(self, id_, data, title, icon="pipe.png"):
+ x = [n[0] for n in data]
+ y = [n[1] for n in data]
+ x_, y_ = self.interp_curve(x, y)
+ cu = make.curve(x_, y_, title=title)
+ cu.curveparam._DataSet__icon = icon
+ cu.curveparam._DataSet__title = title
+ cu.id_ = id_ # add the ide to the item before plotting.
+ self.get_plot().add_item(cu)
+
+ # create a label for the node and add it to the plot
+ l = int(len(x_) / 2.0)
+ la = make.label(id_, (x_[l], y_[l]), (0, 0), "C")
+ la.set_private(True)
+ self.get_plot().add_item(la)
+
+ self.add_plot_item_to_record(id_, [cu, la])
def draw_nodes(self, nodes):
@@ -213,24 +291,27 @@ def draw_nodes(self, nodes):
class optimalTimeGraph(CurveDialogWithClosable):
- def __init__(self, name, year, damagecost, renewalcost,
- units=units["EURO"], parent=None, options={}):
+ def __init__(self, name="Whole life cost", mainwindow=None, year=None,
+ damagecost=None, renewalcost=None, units=units["EURO"],
+ parent=None, options={}):
+ self.mainwindow = mainwindow
if("xlabel" not in options):
options['xlabel'] = "Time(years)"
if("ylabel" not in options):
options['ylabel'] = "Cost (%s)" % (units)
- # if("wintitle" not in options):
- # options['wintitle'] = "Costs against time"
-
self.curvesets = []
super(optimalTimeGraph, self).__init__(edit=False,
- icon="guiqwt.svg",
+ icon="wlc.svg",
toolbar=True,
options=options,
parent=parent,
- panels=None)
+ panels=None,
+ wintitle=name,
+ mainwindow=mainwindow)
+ if (isinstance(self.mainwindow, MainWindow)):
+ self.mainwindow.optimaltimegraphs[id(self)] = self
legend = make.legend("TR")
self.get_plot().add_item(legend)
if(year is None or damagecost is None or renewalcost is None):
@@ -238,7 +319,26 @@ def __init__(self, name, year, damagecost, renewalcost,
else:
self.plotCurveSet(name, year, damagecost, renewalcost)
- def plotCurveSet(self, name, year, damagecost, renewalcost):
+ def closeEvent(self, evnt):
+ if (not isinstance(self.mainwindow, MainWindow)):
+ _can_be_closed = True
+ elif (len(self.mainwindow.optimaltimegraphs) > 1):
+ _can_be_closed = True
+ del(self.mainwindow.optimaltimegraphs[id(self)])
+ else:
+ _can_be_closed = False
+
+ if _can_be_closed:
+ super(optimalTimeGraph, self).closeEvent(evnt)
+ else:
+ evnt.ignore()
+ self.setWindowState(QtCore.Qt.WindowMinimized)
+
+ def plot_item(self, id_, data, title, icon="pipe.png"):
+ year, damagecost, renewalcost = data
+ self.add_plot_item_to_record(id_, self.plotCurveSet(title, year, damagecost, renewalcost))
+
+ def plotCurveSet(self, id_, year, damagecost, renewalcost):
c = curve_colors[len(self.curvesets) % len(curve_colors)]
dc = make.curve(
year, damagecost, title="Damage Cost", color=c, linestyle="DashLine",
@@ -248,6 +348,7 @@ def plotCurveSet(self, name, year, damagecost, renewalcost):
markeredgecolor=None, shade=None,
curvestyle=None, baseline=None,
xaxis="bottom", yaxis="left")
+ dc.id_ = id_ # add the ide to the item before plotting.
self.get_plot().add_item(dc)
rc = make.curve(
year, renewalcost, title="Renewal Cost", color=c, linestyle="DotLine",
@@ -257,74 +358,130 @@ def plotCurveSet(self, name, year, damagecost, renewalcost):
markeredgecolor=None, shade=None,
curvestyle=None, baseline=None,
xaxis="bottom", yaxis="left")
+ rc.id_ = id_ # add the ide to the item before plotting.
self.get_plot().add_item(rc)
tc = make.curve(
- year, damagecost + renewalcost, title="Total Cost", color=c, linestyle=None,
+ year, array(damagecost) + array(renewalcost), title="Total Cost", color=c, linestyle=None,
linewidth=5, marker=None,
markersize=None,
markerfacecolor=None,
markeredgecolor=None, shade=None,
curvestyle="Lines", baseline=None,
xaxis="bottom", yaxis="left")
+ tc.id_ = id_ # add the ide to the item before plotting.
self.get_plot().add_item(tc)
- self.curvesets.append([name, dc, tc, rc])
+ self.curvesets.append([id_, dc, tc, rc])
+ return [dc, tc, rc]
class MainWindow(QMainWindow):
"""The maion 'container' of the application. This is a multi-document interface where all other
windows live in."""
- count = 0
+
+ class emptyclass:
+ pass
+ menuitems = emptyclass
+ menuitems.new_wlc = "New WLC window"
+ menuitems.cascade = "Cascade"
+ menuitems.tiled = "Tiled"
+
+ update_selected_items = True
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
+ self.optimaltimegraphs = {}
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
self.setMenu()
- # self.new_window(closable=False)
+ self.standard_windows()
+
+ def standard_windows(self):
+ self.add_networkmap()
+ self.add_riskmatrix()
+ self.add_optimaltimegraph()
+
+ def selected_holder(self, widget):
+ """ When mocking remember do not patch slots. This is a slot. So, instead patch the function this calls below. """
+ if(self.update_selected_items):
+ self.update_all_plots_with_selection(widget)
+
+ def update_all_plots_with_selection(self, widget):
+ print("selection changed!")
+ # firt get all subplots
+ subplots = [x.get_plot() for x in self.optimaltimegraphs.values()]
+ subplots.append(self.riskmatrix.get_plot())
+ subplots.append(self.networkmap.get_plot())
+ # OK, now remove the plot represented by the argument 'widget'
+ subplots = filter(lambda a: a != widget, subplots)
+ # now select the selections of 'widget' in them.
+ selected_ids = [x.id_ for x in widget.get_selected_items()]
+ for p in subplots:
+ # first switch off responding to selections
+ self.update_selected_items = False
+ # find corressponding items
+ targets = [x for x in p.get_items() if getattr(x, 'id_', None) in selected_ids]
+ # now update
+ p.select_some_items(targets)
+ # don't forget to reset
+ self.update_selected_items = True
+
+ def add_optimaltimegraph(self):
+ wlc = optimalTimeGraph(mainwindow=self)
+ self.mdi.addSubWindow(wlc)
+ wlc.show()
+
+ def add_riskmatrix(self):
+ if(not any([x for x in self.mdi.subWindowList() if isinstance(x.widget(), RiskMatrix)])):
+ self.riskmatrix = RiskMatrix(mainwindow=self)
+ self.mdi.addSubWindow(self.riskmatrix)
+ self.riskmatrix.show()
+
+ def add_networkmap(self):
+ if(not any([x for x in self.mdi.subWindowList() if isinstance(x.widget(), NetworkMap)])):
+ self.networkmap = NetworkMap("Network Map", mainwindow=self)
+ self.mdi.addSubWindow(self.networkmap)
+ self.networkmap.show()
def setMenu(self):
bar = self.menuBar()
file = bar.addMenu("File")
- file.addAction("New guiqwt")
- file.addAction("New matplotlib")
+ file.addAction(self.menuitems.new_wlc)
file.triggered[QAction].connect(self.windowaction)
file2 = bar.addMenu("View")
- file2.addAction("cascade")
- file2.addAction("Tiled")
+ file2.addAction(self.menuitems.cascade)
+ file2.addAction(self.menuitems.tiled)
file2.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI demo")
def windowaction(self, q):
print("triggered")
- if q.text() == "New guiqwt":
- MainWindow.count = MainWindow.count + 1
-
- self.new_window()
+ if q.text() == self.menuitems.new_wlc:
+ self.add_optimaltimegraph()
if q.text() == "New matplotlib":
- MainWindow.count = MainWindow.count + 1
+ # MainWindow.count = MainWindow.count + 1
self.new_matplotlib_window()
- if q.text() == "cascade":
+ if q.text() == self.menuitems.cascade:
self.mdi.cascadeSubWindows()
- if q.text() == "Tiled":
+ if q.text() == self.menuitems.tiled:
self.mdi.tileSubWindows()
def addSubWindow(self, *args, **kwargs):
self.mdi.addSubWindow(*args, **kwargs)
- def new_window(self, closable=True):
+ def new_window(self, closable=True, mainwindow=None):
win = CurveDialogWithClosable(
- edit=False, toolbar=True, wintitle="CurveDialog test",
+ edit=False, toolbar=True, wintitle="CurveDialog test", mainwindow=mainwindow,
options=dict(title="Title", xlabel="xlabel", ylabel="ylabel"))
win.setClosable(closable)
self.plot_some_junk(win)
- win.setWindowTitle("subwindow" + str(MainWindow.count))
+ # win.setWindowTitle("subwindow" + str(MainWindow.count))
self.mdi.addSubWindow(win)
win.show()
return win
@@ -334,7 +491,7 @@ def new_matplotlib_window(self, closable=True):
# win.setClosable(closable)
# self.plot_some_junk(win)
- win.setWindowTitle("subwindow" + str(MainWindow.count))
+ # win.setWindowTitle("subwindow" + str(MainWindow.count))
self.mdi.addSubWindow(win)
win.show()
diff --git a/src/rrpam_wds/gui/images/network.svg b/src/rrpam_wds/gui/images/network.svg
new file mode 100644
index 0000000..f32e5fd
--- /dev/null
+++ b/src/rrpam_wds/gui/images/network.svg
@@ -0,0 +1,46 @@
+
+
+
diff --git a/src/rrpam_wds/gui/images/risk.svg b/src/rrpam_wds/gui/images/risk.svg
new file mode 100644
index 0000000..733fbdf
--- /dev/null
+++ b/src/rrpam_wds/gui/images/risk.svg
@@ -0,0 +1,38 @@
+
+
+
diff --git a/src/rrpam_wds/gui/images/wlc.svg b/src/rrpam_wds/gui/images/wlc.svg
new file mode 100644
index 0000000..9be0ede
--- /dev/null
+++ b/src/rrpam_wds/gui/images/wlc.svg
@@ -0,0 +1,40 @@
+
+
+
diff --git a/src/rrpam_wds/gui/monkey_patch_guiqwt_guidata.py b/src/rrpam_wds/gui/monkey_patch_guiqwt_guidata.py
index 4463a15..b8d7b77 100644
--- a/src/rrpam_wds/gui/monkey_patch_guiqwt_guidata.py
+++ b/src/rrpam_wds/gui/monkey_patch_guiqwt_guidata.py
@@ -13,6 +13,30 @@ def _patch_all():
_patch_item_list()
_patch_curve_do_autoscale()
_patch_curveitem_hit_test()
+ _patch_curveplot___del__()
+
+
+def _patch_curveplot___del__():
+ """1. Close a subwindow within qmidarea. 2. Close the application
+ It crashes with the message:
+ Traceback (most recent call last):
+ File "/home/user/miniconda3/envs/py34/lib/python3.5/site-packages/guiqwt/curve.py", line 1404, in __del__
+ canvas.removeEventFilter(self.filter)
+RuntimeError: wrapped C/C++ object of type QwtPlotCanvas has been deleted
+
+ Currently I assume this is a bug in the curve.__del__ routine, not an issure of my implementation.
+ So, just adding a try: except clause
+ """
+ orig___del__ = CurvePlot.__del__
+
+ def custom__del__(self):
+ try:
+ orig___del__(self)
+ except:
+ print("Better to fix me later.")
+
+ # now monkey patch
+ CurvePlot.__del__ = custom__del__
def _patch_curveitem_hit_test():
diff --git a/src/rrpam_wds/gui/utils.py b/src/rrpam_wds/gui/utils.py
index f01353c..f351062 100644
--- a/src/rrpam_wds/gui/utils.py
+++ b/src/rrpam_wds/gui/utils.py
@@ -19,4 +19,4 @@ def _get_type(epanet_network_item):
if(epanet_network_item == "Risk"):
return "R:", 'link.png'
- return "None", None
+ return "None", "curve.png"
diff --git a/tests/test_closable_graph.py b/tests/test_closable_graph.py
index 0ccbd93..297263c 100755
--- a/tests/test_closable_graph.py
+++ b/tests/test_closable_graph.py
@@ -38,9 +38,9 @@ def tearDown(self):
def test_closable_graph_can_be_closed_by_user(self):
dummytitle = uniquestring()
title = uniquestring()
- self.dummy = CurveDialogWithClosable(wintitle=dummytitle)
+ self.dummy = CurveDialogWithClosable(wintitle=dummytitle, mainwindow=self.aw)
self.aw.addSubWindow(self.dummy)
- self.graph = CurveDialogWithClosable(wintitle=title)
+ self.graph = CurveDialogWithClosable(wintitle=title, mainwindow=self.aw)
self.aw.addSubWindow(self.graph)
self.assertNotEqual(self.graph.windowTitle, self.dummy.windowTitle)
self.assertEqual(self.aw.mdi.subWindowList()[-1].windowTitle(), title)
@@ -51,9 +51,9 @@ def test_closable_graph_can_be_closed_by_user(self):
def test_closable_graph_closable_false_minized(self):
dummytitle = uniquestring()
title = uniquestring()
- self.dummy = CurveDialogWithClosable(wintitle=dummytitle)
+ self.dummy = CurveDialogWithClosable(wintitle=dummytitle, mainwindow=self.aw)
self.aw.addSubWindow(self.dummy)
- self.graph = CurveDialogWithClosable(wintitle=title)
+ self.graph = CurveDialogWithClosable(wintitle=title, mainwindow=self.aw)
self.graph.setClosable(False)
self.aw.addSubWindow(self.graph)
self.assertNotEqual(self.graph.windowTitle, self.dummy.windowTitle)
@@ -66,9 +66,9 @@ def test_closable_graph_closable_false_minized(self):
def test_presseing_esc_does_not_close_or_clear_the_closable_graph(self):
dummytitle = uniquestring()
title = uniquestring()
- self.dummy = CurveDialogWithClosable(wintitle=dummytitle)
+ self.dummy = CurveDialogWithClosable(wintitle=dummytitle, mainwindow=self.aw)
self.aw.addSubWindow(self.dummy)
- self.graph = CurveDialogWithClosable(wintitle=title)
+ self.graph = CurveDialogWithClosable(wintitle=title, mainwindow=self.aw)
self.graph.setClosable(False)
self.aw.addSubWindow(self.graph)
self.aw.show()
diff --git a/tests/test_keeping_records_of_adding_removing_plot_items.py b/tests/test_keeping_records_of_adding_removing_plot_items.py
new file mode 100644
index 0000000..009e11b
--- /dev/null
+++ b/tests/test_keeping_records_of_adding_removing_plot_items.py
@@ -0,0 +1,144 @@
+from rrpam_wds.gui import set_pyqt_api # isort:skip # NOQA
+import os
+import sys
+import time
+import unittest
+
+import mock
+import numpy as np
+import pytest
+from guiqwt import tests
+from guiqwt.curve import CurveItem
+from guiqwt.plot import CurveDialog
+from guiqwt.shapes import EllipseShape
+from numpy.testing import assert_array_almost_equal
+from PyQt5.QtCore import Qt
+from PyQt5.QtCore import QTimer
+from PyQt5.QtTest import QTest
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtWidgets import QMdiArea
+
+from rrpam_wds.gui.dialogs import CurveDialogWithClosable
+from rrpam_wds.gui.dialogs import MainWindow
+from rrpam_wds.gui.dialogs import NetworkMap
+from rrpam_wds.gui.dialogs import RiskMatrix
+from rrpam_wds.gui.dialogs import optimalTimeGraph
+
+
+class test_keeping_records(unittest.TestCase):
+ start = 0
+ stop = 0
+
+ def setUp(self):
+ global start
+ self.app = QApplication(sys.argv)
+ start = time.time()
+ self.aw = MainWindow()
+ self.aw.setWindowTitle("Records tests")
+
+ pass
+
+ def tearDown(self):
+ global stop
+ stop = time.time()
+ print("\ncalculation took %0.2f seconds." % (stop - start))
+ self.aw = None
+ pass
+
+ def runTest(self):
+ """ otherwise python 2.7 returns an error
+ ValueError: no such test method in : runTest"""
+ pass
+
+ def test_riskmatrix_report_adding_to_the_register(self):
+ rm = self.aw.riskmatrix
+
+ with mock.patch.object(rm, 'add_plot_item_to_record', autospec=True) as mock_add_plot_item_to_record:
+ self.assertFalse(mock_add_plot_item_to_record.called)
+ rm.plot_item("fox", [5000, 50], title="fox")
+ self.assertTrue(mock_add_plot_item_to_record.called)
+
+ def test_riskmatrix_report_removing_to_the_register(self):
+ rm = self.aw.riskmatrix
+
+ with mock.patch.object(rm, 'remove_plot_item_from_record', autospec=True) as mock_remove_plot_item_from_record:
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ rm.plot_item("fox", [5000, 50], title="fox")
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ risk_item = [x for x in rm.get_plot().get_items() if isinstance(x, EllipseShape)][0]
+ rm.get_plot().del_item(risk_item)
+ self.assertTrue(mock_remove_plot_item_from_record.called)
+
+ def test_networkmap_report_adding_to_the_register(self):
+ otg = self.aw.networkmap
+
+ with mock.patch.object(otg, 'add_plot_item_to_record', autospec=True) as mock_add_plot_item_to_record:
+ self.assertFalse(mock_add_plot_item_to_record.called)
+ otg.plot_item("fox", [(5, 10), (8, 3), (24, 1)], "fox")
+ self.assertTrue(mock_add_plot_item_to_record.called)
+
+ def test_networkmap_report_removing_to_the_register(self):
+ otg = self.aw.networkmap
+
+ with mock.patch.object(otg, 'remove_plot_item_from_record', autospec=True) as mock_remove_plot_item_from_record:
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ otg.plot_item("fox", [(5, 10), (8, 3), (24, 1)], "fox")
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ nw_item = [x for x in otg.get_plot().get_items() if isinstance(x, CurveItem)][0]
+ otg.get_plot().del_item(nw_item)
+ self.assertTrue(mock_remove_plot_item_from_record.called)
+
+ def test_optimaltimegraph_report_adding_to_the_register(self):
+ otg = list(self.aw.optimaltimegraphs.values())[0]
+
+ with mock.patch.object(otg, 'add_plot_item_to_record', autospec=True) as mock_add_plot_item_to_record:
+ self.assertFalse(mock_add_plot_item_to_record.called)
+ otg.plot_item(
+ "fox", [[1997, 1998, 2005, 2008], [5, 10, 25, 95], [100, 50, 25, 12]], "fox")
+ self.assertTrue(mock_add_plot_item_to_record.called)
+
+ def test_optimaltimegraph_report_removing_to_the_register(self):
+ otg = list(self.aw.optimaltimegraphs.values())[0]
+
+ with mock.patch.object(otg, 'remove_plot_item_from_record', autospec=True) as mock_remove_plot_item_from_record:
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ otg.plot_item(
+ "fox", [[1997, 1998, 2005, 2008], [5, 10, 25, 95], [100, 50, 25, 12]], "fox")
+ self.assertFalse(mock_remove_plot_item_from_record.called)
+ nw_item = [x for x in otg.get_plot().get_items() if isinstance(x, CurveItem)][0]
+ otg.get_plot().del_item(nw_item)
+ self.assertTrue(mock_remove_plot_item_from_record.called)
+
+ def test_deleting_a_curve_in_optimaltimegraph_removes_all_three_curves(self):
+ # for the heck of it add another optimal time graph
+ self.aw.add_optimaltimegraph()
+ l = list(self.aw.optimaltimegraphs.values())
+ otg1 = l[0]
+ otg2 = l[1]
+ self.assertEqual(len(otg1.myplotitems), 0)
+ otg1.plot_item("fox", [[1997, 1998, 2005, 2008], [5, 10, 25, 95], [100, 50, 25, 12]], "fox")
+ otg2.plot_item("fox", [[1997, 1998, 2005, 2008], [5, 10, 25, 95], [100, 50, 25, 12]], "fox")
+ self.assertEqual(len(otg1.myplotitems), 1)
+ self.assertEqual(len(otg2.myplotitems), 1)
+ otg_item = [x for x in otg1.get_plot().get_items() if isinstance(x, CurveItem)][0]
+ otg1.get_plot().del_item(otg_item)
+ self.assertEqual(len(otg1.myplotitems), 0)
+ otg_item = [x for x in otg2.get_plot().get_items() if isinstance(x, CurveItem)][
+ 2] # pick a different curve from the set!
+ otg2.get_plot().del_item(otg_item)
+ self.assertEqual(len(otg2.myplotitems), 0)
+
+
+def drive(test=True): # pragma: no cover
+ if(test):
+ unittest.main(verbosity=2)
+ else:
+ ot = test_keeping_records()
+ ot.setUp()
+ ot.test_deleting_a_curve_in_optimaltimegraph_removes_all_three_curves()
+ ot.aw.show()
+ sys.exit(ot.app.exec_())
+
+if __name__ == '__main__': # pragma: no cover
+ drive(test=False)
diff --git a/tests/test_main_window.py b/tests/test_main_window.py
new file mode 100644
index 0000000..c870df6
--- /dev/null
+++ b/tests/test_main_window.py
@@ -0,0 +1,121 @@
+from rrpam_wds.gui import set_pyqt_api # isort:skip # NOQA
+import os
+import sys
+import time
+import unittest
+
+import numpy as np
+import pytest
+from guiqwt import tests
+from guiqwt.plot import CurveDialog
+from numpy.testing import assert_array_almost_equal
+from PyQt5.QtCore import Qt
+from PyQt5.QtCore import QTimer
+from PyQt5.QtTest import QTest
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtWidgets import QMdiArea
+
+from rrpam_wds.gui.dialogs import CurveDialogWithClosable
+from rrpam_wds.gui.dialogs import MainWindow
+from rrpam_wds.gui.dialogs import NetworkMap
+from rrpam_wds.gui.dialogs import RiskMatrix
+from rrpam_wds.gui.dialogs import optimalTimeGraph
+
+
+class test_main_window(unittest.TestCase):
+ start = 0
+ stop = 0
+
+ def setUp(self):
+ global start
+ self.app = QApplication(sys.argv)
+ start = time.time()
+ self.aw = MainWindow()
+ self.aw.setWindowTitle("Testing main window")
+
+ pass
+
+ def tearDown(self):
+ global stop
+ stop = time.time()
+ print("\ncalculation took %0.2f seconds." % (stop - start))
+ self.aw = None
+ pass
+
+ def runTest(self):
+ """ otherwise python 2.7 returns an error
+ ValueError: no such test method in : runTest"""
+ pass
+
+ def test_mainwindow_is_derived_from_QMainWindow(self):
+ """optimalTimeGraph should be derived from CurveDialogWithClosable class"""
+ self.assertIsInstance(self.aw, QMainWindow)
+
+ def test_mainwindow_has_a_mdi_Area(self):
+ self.assertIsInstance(self.aw.mdi, QMdiArea)
+
+ def test_mainwindow_always_has_a_network_map_and_risk_matrix_one_each(self):
+ list1 = self.aw.mdi.subWindowList()
+ self.assertTrue(len([x for x in list1 if (isinstance(x.widget(), RiskMatrix))]), 1)
+ self.assertTrue(len([x for x in list1 if (isinstance(x.widget(), NetworkMap))]), 1)
+
+ def test_main_window_will_not_add_more_than_one_network_map_or_risk_matrix(self):
+ self.aw.standard_windows() # Adds riskmatrix, network map and a optimaltimegraph
+ list1 = self.aw.mdi.subWindowList() # should have above three
+ self.aw.add_riskmatrix() # try adding a rm
+ self.aw.add_networkmap() # try adding a nm
+ self.aw.standard_windows() # this will add only an extra optimaltimegraph
+ list2 = self.aw.mdi.subWindowList()
+ list1 = [x for x in list1 if not isinstance(x.widget(), optimalTimeGraph)]
+ list2 = [x for x in list2 if not isinstance(x.widget(), optimalTimeGraph)]
+ self.assertEqual(list1, list2)
+
+ def test_attempting_to_close_will_minimize_network_map_and_risk_matrix_and_the_last_optimal_time_graph(
+ self):
+
+ list1 = self.aw.mdi.subWindowList()
+ self.assertFalse(self.aw.riskmatrix.isMinimized())
+ self.assertFalse(self.aw.networkmap.isMinimized())
+ self.close_all_windows()
+ list2 = self.aw.mdi.subWindowList()
+ self.assertEqual(list1, list2)
+ self.assertTrue(self.aw.networkmap.isMinimized())
+ self.assertTrue(self.aw.networkmap.isMinimized())
+
+ def close_all_windows(self):
+ for w in self.aw.mdi.subWindowList():
+ w.close()
+
+ def test_multiple_optimal_time_graphs_can_be_added(self):
+ list1 = self.aw.mdi.subWindowList()
+ self.assertTrue(len([x for x in list1 if (isinstance(x.widget(), optimalTimeGraph))]), 1)
+ self.aw.add_optimaltimegraph()
+ self.assertEqual(len(list1) + 1, len(self.aw.mdi.subWindowList()))
+
+ def test_last_remaining_optimal_time_graph_will_not_be_deleted_but_minimized(self):
+ list1 = self.aw.mdi.subWindowList()
+ self.aw.add_optimaltimegraph() # now we have two
+ self.aw.add_optimaltimegraph() # now we have
+ self.close_all_windows()
+ list2 = self.aw.mdi.subWindowList()
+ # print(list1)
+ # print(list2)
+ self.assertEqual(len(list1), len(list2))
+
+ for w in self.aw.mdi.subWindowList():
+ self.assertTrue(w.isMinimized())
+
+
+def drive(test=True): # pragma: no cover
+ if(test):
+ unittest.main(verbosity=2)
+ else:
+ ot = test_main_window()
+ ot.setUp()
+ ot.test_last_remaining_optimal_time_graph_will_not_be_deleted_but_minimized()
+ # ot.aw.show()
+ # sys.exit(ot.app.exec_())
+
+if __name__ == '__main__': # pragma: no cover
+ drive(test=False)
diff --git a/tests/test_network_map.py b/tests/test_network_map.py
index f3b9043..7d0b720 100644
--- a/tests/test_network_map.py
+++ b/tests/test_network_map.py
@@ -47,7 +47,7 @@ def runTest(self):
def test_NetworkMap_is_derived_from_CurveDialogWithClosable(self):
"""NetworkMaph should be derived from CurveDialogWithClosable class"""
- nwm = NetworkMap("foo", None, None, parent=self.aw)
+ nwm = NetworkMap(name="foo", nodes=None, links=None, parent=self.aw, mainwindow=self.aw)
self.assertIsInstance(nwm, CurveDialogWithClosable)
self.aw.addSubWindow(nwm)
@@ -65,7 +65,7 @@ def draw_a_network(self, network=ex.networks[0]):
e1 = hs.pdd_service(network, coords=True, adfcalc=False)
nodes = e1.nodes.values()
links = e1.links.values()
- nwm = NetworkMap("foo", nodes, links, parent=self.aw)
+ nwm = NetworkMap(name="foo", nodes=nodes, links=links, parent=self.aw, mainwindow=self.aw)
self.aw.addSubWindow(nwm)
self.aw.show()
@@ -82,11 +82,11 @@ def test_NetworkMap_scales_to_fit_network_on_creation(self):
plot = nwm.get_plot()
_xmin, _xmax = plot.get_axis_limits("bottom")
_ymin, _ymax = plot.get_axis_limits("left")
- delta=20.
- self.assertAlmostEqual(xmin-delta, _xmin, delta=delta)
- self.assertAlmostEqual(xmax+delta, _xmax, delta=delta)
- self.assertAlmostEqual(ymin-delta, _ymin, delta=delta)
- self.assertAlmostEqual(ymax+delta, _ymax, delta=delta)
+ delta = 20.
+ self.assertAlmostEqual(xmin - delta, _xmin, delta=delta)
+ self.assertAlmostEqual(xmax + delta, _xmax, delta=delta)
+ self.assertAlmostEqual(ymin - delta, _ymin, delta=delta)
+ self.assertAlmostEqual(ymax + delta, _ymax, delta=delta)
pass
def test_NetworkMap_has_correct_number_of_link_representations(self):
diff --git a/tests/test_optimal_time_graph.py b/tests/test_optimal_time_graph.py
index 0894cda..7ff6493 100644
--- a/tests/test_optimal_time_graph.py
+++ b/tests/test_optimal_time_graph.py
@@ -44,7 +44,8 @@ def runTest(self):
def test_optimalTimeGraph_is_derived_from_CurveDialogWithClosable(self):
"""optimalTimeGraph should be derived from CurveDialogWithClosable class"""
- tg1 = optimalTimeGraph("set1", None, None, None, parent=self.aw)
+ tg1 = optimalTimeGraph(name="set1", damagecost=None, renewalcost=None,
+ year=None, parent=self.aw, mainwindow=self.aw)
self.assertIsInstance(tg1, CurveDialogWithClosable)
self.aw.addSubWindow(tg1)
@@ -54,7 +55,8 @@ def test_optimalTimeGraph_creates_right_three_curves(self):
damagecost = year**2.1
renewalcost = (100 - year)**1.9
tg1 = optimalTimeGraph(
- "set1", year, damagecost, renewalcost, parent=self.aw)
+ "set1", year=year, damagecost=damagecost, renewalcost=renewalcost,
+ parent=self.aw, mainwindow=self.aw)
self.aw.addSubWindow(tg1)
it = [x for x in tg1.get_plot().get_items() if (
isinstance(x, CurveItem))]
@@ -80,7 +82,7 @@ def drive(test=True): # pragma: no cover
else:
ot = test_optimal_time_graph()
ot.setUp()
- ot.test_optimalTimeGraph_is_derived_from_CurveDialogWithClosable()
+ ot.test_optimalTimeGraph_creates_right_three_curves()
ot.aw.show()
sys.exit(ot.app.exec_())
diff --git a/tests/test_pytest_mainwindow.py b/tests/test_pytest_mainwindow.py
new file mode 100644
index 0000000..a6b4dcf
--- /dev/null
+++ b/tests/test_pytest_mainwindow.py
@@ -0,0 +1,44 @@
+import subprocess
+import sys
+
+from PyQt5.QtCore import QTimer
+from PyQt5.QtWidgets import QApplication
+
+from rrpam_wds.gui.dialogs import CurveDialogWithClosable
+from rrpam_wds.gui.dialogs import MainWindow
+from rrpam_wds.gui.dialogs import NetworkMap
+from rrpam_wds.gui.dialogs import RiskMatrix
+from rrpam_wds.gui.dialogs import optimalTimeGraph
+
+# def test_closing_a_optimal_time_graph_window_does_not_cause_error_at_exit():
+ #""" See notes at: monkey_patch_guiqwt_guidata._patch_curveplot___del__
+
+ # At the moment this test is useless.
+
+ #"""
+ # print("Running: ",[sys.executable,__file__])
+ # p = subprocess.Popen([sys.executable,__file__],
+ # stdout=subprocess.PIPE,
+ # stderr=subprocess.PIPE,
+ # stdin=subprocess.PIPE)
+ # output = p.communicate()
+ # print("out:", output[0])
+ # print("err:", output[1])
+
+ # assert output[1]==b""
+ # assert output[0]==b""
+ # assert False
+
+if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ aw = MainWindow()
+ aw.add_optimaltimegraph()
+
+ for w in aw.mdi.subWindowList():
+ w.close()
+ # following should not raise exceptions
+ aw.show()
+ aw.deleteLater()
+ QTimer.singleShot(5000, app.quit) # Make the application quit just after start
+ print("Boo")
+ val = app.exec_()
diff --git a/tests/test_reset_zoom_tool.py b/tests/test_reset_zoom_tool.py
index 0e7b34c..be143cb 100644
--- a/tests/test_reset_zoom_tool.py
+++ b/tests/test_reset_zoom_tool.py
@@ -29,7 +29,7 @@ def setUp(self):
start = time.time()
self.aw = MainWindow()
self.aw.setWindowTitle("Testing optimal time graph")
- self.win = self.aw.new_window()
+ self.win = self.aw.new_window(mainwindow=self.aw)
pass
def tearDown(self):
diff --git a/tests/test_risk_matrix.py b/tests/test_risk_matrix.py
index 2c1a595..026eda4 100644
--- a/tests/test_risk_matrix.py
+++ b/tests/test_risk_matrix.py
@@ -31,7 +31,7 @@ def setUp(self):
start = time.time()
self.aw = MainWindow()
self.aw.setWindowTitle("Testing risk matrix")
- self.rm = RiskMatrix()
+ self.rm = RiskMatrix(mainwindow=self.aw)
self.aw.addSubWindow(self.rm)
self.rm.show()
pass
@@ -54,11 +54,13 @@ def test_Risk_Map_is_derived_from_CurveDialogWithClosable(self):
def test_plot_item_will_create_a_circle(self):
pts0 = [x for x in self.rm.get_plot().get_items() if isinstance(x, EllipseShape)]
- self.rm.plot_item(5000.0, 50, title="foo")
- self.rm.plot_item(1000.0, 20, title="bar")
- self.rm.plot_item(8000.0, 70, title="bax")
+ self.rm.plot_item("foo", [5000.0, 50], title="foo")
+ self.rm.plot_item("bar", [1000.0, 20], title="bar")
+ self.rm.plot_item("bax", [8000.0, 70], title="bax")
+ self.rm.plot_item("bax", [15000.0, 100], title="bax")
pts1 = [x for x in self.rm.get_plot().get_items() if isinstance(x, EllipseShape)]
- self.assertEqual(len(pts1), len(pts0) + 3)
+ self.assertEqual(len(pts1), len(pts0) + 4)
+ self.assertEqual(pts1[1].get_xdiameter(), self.rm.get_ellipse_xaxis(1000., 20.))
def drive(test=True): # pragma: no cover
diff --git a/tests/test_signalling_among_plots.py b/tests/test_signalling_among_plots.py
new file mode 100644
index 0000000..762b10b
--- /dev/null
+++ b/tests/test_signalling_among_plots.py
@@ -0,0 +1,150 @@
+from rrpam_wds.gui import set_pyqt_api # isort:skip # NOQA
+import os
+import sys
+import time
+import unittest
+
+import mock
+import numpy as np
+import pytest
+from guiqwt import tests
+from guiqwt.curve import CurveItem
+from guiqwt.plot import CurveDialog
+from guiqwt.shapes import EllipseShape
+from numpy.testing import assert_array_almost_equal
+from PyQt5.QtCore import Qt
+from PyQt5.QtCore import QTimer
+from PyQt5.QtTest import QTest
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.QtWidgets import QMdiArea
+
+from rrpam_wds.gui.dialogs import CurveDialogWithClosable
+from rrpam_wds.gui.dialogs import MainWindow
+from rrpam_wds.gui.dialogs import NetworkMap
+from rrpam_wds.gui.dialogs import RiskMatrix
+from rrpam_wds.gui.dialogs import optimalTimeGraph
+
+
+class test_main_window(unittest.TestCase):
+ start = 0
+ stop = 0
+
+ def setUp(self):
+ global start
+ self.app = QApplication(sys.argv)
+ start = time.time()
+ self.aw = MainWindow()
+ self.aw.setWindowTitle("Signalling tests")
+
+ pass
+
+ def tearDown(self):
+ global stop
+ stop = time.time()
+ print("\ncalculation took %0.2f seconds." % (stop - start))
+ self.aw = None
+ pass
+
+ def runTest(self):
+ """ otherwise python 2.7 returns an error
+ ValueError: no such test method in : runTest"""
+ pass
+
+ def test_every_plot_triggers_selection_update_function_in_the_main_window(self):
+ nm, rm, ot = self.plot_a_random_dataset()
+ with mock.patch.object(self.aw, 'update_all_plots_with_selection', autospec=True) as mock_update_all_plots_with_selection:
+ self.assertFalse(mock_update_all_plots_with_selection.called)
+ risk_item = [x for x in rm.get_plot().get_items() if isinstance(x, EllipseShape)][0]
+ rm.get_plot().select_item(risk_item)
+ self.assertTrue(mock_update_all_plots_with_selection.called)
+ mock_update_all_plots_with_selection.reset_mock()
+ self.assertFalse(mock_update_all_plots_with_selection.called)
+ link_item = [x for x in nm.get_plot().get_items() if isinstance(x, CurveItem)][0]
+ nm.get_plot().select_item(link_item)
+ mock_update_all_plots_with_selection.assert_called_with(nm.get_plot())
+
+ mock_update_all_plots_with_selection.reset_mock()
+ self.assertFalse(mock_update_all_plots_with_selection.called)
+ ot_item = [x for x in ot.get_plot().get_items() if isinstance(x, CurveItem)][2]
+ ot.get_plot().select_item(ot_item)
+ mock_update_all_plots_with_selection.assert_called_with(ot.get_plot())
+
+ def test_selecting_items_in_riskmatrix_plot_update_slections_to_match_in_other_plots(self):
+ nm, rm, ot = self.plot_a_random_dataset()
+
+ risk_item = [x for x in rm.get_plot().get_items() if isinstance(x, EllipseShape)][5]
+ # ^ lets select something that is also represented in the current optimaltimegraph (see plot_a_random_dataset)
+ self.assertFalse(nm.get_plot().get_selected_items())
+ rm.get_plot().select_item(risk_item)
+ self.assertEqual(nm.get_plot().get_selected_items()[0].id_, risk_item.id_)
+ self.assertEqual(ot.get_plot().get_selected_items()[0].id_, risk_item.id_)
+
+ def test_selecting_items_in_networkmap_plot_update_slections_to_match_in_other_plots(self):
+ nm, rm, ot = self.plot_a_random_dataset()
+
+ network_item = [x for x in nm.get_plot().get_items() if isinstance(x, CurveItem)][2]
+ # ^ now this curve is not represented in the optimaltimegraph (see plot_a_random_dataset)
+
+ nm.get_plot().select_item(network_item)
+ self.assertEqual(rm.get_plot().get_selected_items()[0].id_, network_item.id_)
+
+ def test_selecting_items_in_optimaltimegraph_plot_update_slections_to_match_in_other_plots(self):
+ nm, rm, ot = self.plot_a_random_dataset()
+
+ ot_item = [x for x in ot.get_plot().get_items() if isinstance(x, CurveItem)][4]
+ ot.get_plot().select_item(ot_item)
+ self.assertEqual(nm.get_plot().get_selected_items()[0].id_, ot_item.id_)
+ self.assertEqual(rm.get_plot().get_selected_items()[0].id_, ot_item.id_)
+
+ def plot_a_random_dataset(self):
+ import string
+ import random
+ import math
+ rm = self.aw.riskmatrix
+ nm = self.aw.networkmap
+ ot = list(self.aw.optimaltimegraphs.values())[0]
+
+ def id_generator(size=3, chars=string.ascii_letters + " " + string.digits):
+ return ''.join(random.choice(chars) for _ in range(size))
+
+ def plot_link(x1, y1, x2, y2, id):
+ link = mock.MagicMock()
+ link.start.x = x1
+ link.start.y = y1
+ link.end.x = x2
+ link.end.y = y2
+ link.vertices = []
+ link.id = id
+ nm.draw_links([link])
+
+ N = 10
+ x1 = np.random.rand(N) * 500
+ y1 = np.random.rand(N) * 1000
+ x2 = np.random.rand(N) * 500
+ y2 = np.random.rand(N) * 1000
+ ids = [id_generator(4) for x in range(N)]
+
+ for i in range(N):
+ plot_link(x1[i], y1[i], x2[i], y2[i], ids[i])
+ rm.plot_item(ids[i], [random.random() * 15000, random.random() * 100], title=ids[i])
+ for i in range(5, 8):
+ years = [1997, 1998, 1999, 2005, 2008]
+ val = random.random() / 10.
+ ot.plotCurveSet(ids[i], years, [1000 * math.exp(val * (x - years[0]))
+ for x in years], [1000 - 1000 * math.exp(-val * 2 * (x - years[0])) for x in years])
+ return nm, rm, ot
+
+
+def drive(test=True): # pragma: no cover
+ if(test):
+ unittest.main(verbosity=2)
+ else:
+ ot = test_main_window()
+ ot.setUp()
+ ot.test_selecting_items_in_riskmatrix_plot_update_slections_to_match_in_other_plots()
+ ot.aw.show()
+ sys.exit(ot.app.exec_())
+
+if __name__ == '__main__': # pragma: no cover
+ drive(test=False)