From: jh777916 Date: Wed, 13 Sep 2023 13:36:37 +0000 (+0200) Subject: Adding the StemModel (for diracs); improving the onPick() method in XYView; reducing... X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e57ac46cca925d9d9a13bf2bc52d5facc1c8fe18;p=modules%2Fgui.git Adding the StemModel (for diracs); improving the onPick() method in XYView; reducing the number of repaint() called when setCurrentCurve() is called; Adding the opacity parameter in settings; adding a flatten() function in utils to ease the use of the same mplArtist member for all Models; Adding an hline marker in the list of markers; Adding actions in the right-click menu to show all traces or only the selected one; Clickable legend is fully functionnable (text and symbol handles) --- diff --git a/tools/CurvePlot/src/python/controller/PlotController.py b/tools/CurvePlot/src/python/controller/PlotController.py index af4fe052c..2812bc805 100644 --- a/tools/CurvePlot/src/python/controller/PlotController.py +++ b/tools/CurvePlot/src/python/controller/PlotController.py @@ -22,6 +22,7 @@ from .PlotManager import PlotManager from .CurveTabsView import CurveTabsView from .CurveModel import CurveModel from .BarModel import BarModel +from .StemModel import StemModel from .TableModel import TableModel from .utils import Logger import numpy as np @@ -217,6 +218,31 @@ class PlotController(object): pm.unlockRepaint() return curveID, plotSetID + @classmethod + def AddStemPlot(cls, x, y, curve_label="", x_label="", y_label="", append=True): + """ Testing some stuff with StemPlot""" + + from .XYView import XYView + control = cls.GetInstance() + pm = control._plotManager + t = TableModel(control) + data = np.transpose(np.vstack([x, y])) + t.setData(data) + # ensure a single Matplotlib repaint for all operations to come in AddCurve + prevLock = pm.isRepaintLocked() + if not prevLock: + pm.lockRepaint() + curveID, plotSetID = control.plotStemPlotFromTable(t, x_col_index=0, y_col_index=1, + curve_label=curve_label, append=append) + ps = pm._plotSets[plotSetID] + if x_label != "": + ps.setXLabel(x_label) + if y_label != "": + ps.setYLabel(y_label) + if not prevLock: + pm.unlockRepaint() + return curveID, plotSetID + @classmethod def ExtendCurve(cls, crv_id, x, y): """ Add new points to an already created curve @@ -799,7 +825,7 @@ class PlotController(object): cps.addCurve(bm) Logger.Debug(" --- model ID when adding the barplot : {}".format(bm.getID())) - + mp = self._curveTabsView.mapModId2ViewId() xyview_id = mp[cps.getID()] xyview = self._curveTabsView._XYViews[xyview_id] @@ -814,3 +840,56 @@ class PlotController(object): self.setModelListener(bm, xyview) return bm.getID(),cps.getID() + + def plotStemPlotFromTable(self, table, x_col_index=0, y_col_index=1, curve_label="", append=True): + """ + :returns: a tuple containing the unique curve ID and the plot set ID + """ + # Regardless of 'append', we must create a view if none there: + if self._plotManager.getCurrentPlotSet() is None or not append: + ps = self._plotManager.createXYPlotSet() + self.setModelListener(ps, self._curveBrowserView) + # For curve picking, controller must listen: + self.setModelListener(ps, self) + cps_title = table.getTitle() + else: + cps_title = None + + cps = self._plotManager.getCurrentPlotSet() + + sm = StemModel(self, table, y_col_index) + sm.setXAxisIndex(x_col_index) + + # X axis label + tix = table.getColumnTitle(x_col_index) + if tix != "": + cps.setXLabel(tix) + + # Curve label + if curve_label != "": + sm.setTitle(curve_label) + else: + ti = table.getColumnTitle(y_col_index) + if ti != "": + sm.setTitle(ti) + + # Plot set title + if cps_title != "" and cps_title is not None: + Logger.Debug("about to set title to: " + cps_title) + cps.setTitle(cps_title) + + cps.addCurve(sm) + mp = self._curveTabsView.mapModId2ViewId() + xyview_id = mp[cps.getID()] + xyview = self._curveTabsView._XYViews[xyview_id] + + if cps_title is None: # no plot set was created above + self._plotManager.setCurrentPlotSet(cps.getID()) + + # Make CurveBrowser and CurveView depend on changes in the curve itself: + self.setModelListener(sm, self._curveBrowserView) + self.setModelListener(sm, xyview._curveViews[sm.getID()]) + # Upon change on the curve also update the full plot, notably for the auto-fit and the legend: + self.setModelListener(sm, xyview) + + return sm.getID(),cps.getID() \ No newline at end of file diff --git a/tools/CurvePlot/src/python/controller/__init__.py b/tools/CurvePlot/src/python/controller/__init__.py index ba67712ae..8269a5e03 100644 --- a/tools/CurvePlot/src/python/controller/__init__.py +++ b/tools/CurvePlot/src/python/controller/__init__.py @@ -37,12 +37,14 @@ from .PlotController import PlotController from .TableModel import TableModel from .CurveModel import CurveModel from .BarModel import BarModel +from .StemModel import StemModel from .PlotManager import PlotManager from .XYPlotSetModel import XYPlotSetModel ## The static API of PlotController is the main interface of the package and is hence exposed at package level: AddCurve = PlotController.AddCurve AddBarPlot = PlotController.AddBarPlot +AddStemPlot = PlotController.AddStemPlot AddPlotSet = PlotController.AddPlotSet ExtendCurve = PlotController.ExtendCurve ResetCurve = PlotController.ResetCurve diff --git a/tools/CurvePlot/src/python/controller/test b/tools/CurvePlot/src/python/controller/test new file mode 100755 index 000000000..2dd87150b --- /dev/null +++ b/tools/CurvePlot/src/python/controller/test @@ -0,0 +1,116 @@ +# Copyright (C) 2016-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +class Logger(object): + """ + Debug Info. + """ + LOG_LEVEL = 0 # 0 means all, 1 means all but DEBUG, 2 means all but INFO and DEBUG, 3 only FATAL + + @classmethod + def Debug(cls, msg): + """ + Prints an information message to the standard output. + + :param msg: str -- The message to be printed. + + """ + if cls.LOG_LEVEL <= 0: + cls.__log("[DEBUG]", msg) + + + @classmethod + def Info(cls, msg): + """ + Prints an information message to the standard output. + + :param msg: str -- The message to be printed. + + """ + if cls.LOG_LEVEL <= 1: + cls.__log("[INFO]", msg) + + + @classmethod + def Warning(cls, msg): + """ + Prints a warning message to the standard output. + + :param msg: str -- The message to be printed. + + """ + if cls.LOG_LEVEL <= 2: + cls.__log("[WARNING]", msg) + + + @classmethod + def FatalError(cls, msg): + """ + Prints an error message to the standard output. + + :param msg: str -- The message to be printed. + :raises: Exception. + + """ + if cls.LOG_LEVEL <= 3: + cls.__log("[FATAL]", msg) + raise Exception(msg) + + @classmethod + def __log(cls, typ, msg): + print("%s: %s" % (typ, msg)) + +def trQ(tag, context="CURVEPLOT"): + """ @return a QString read from the translation file """ + from pyqtside.QtWidgets import QApplication + return QApplication.translate(context, tag) + +def trU(tag, context="CURVEPLOT"): + """ @return same as above, but returns a Python unicode string. """ + qs = trQ(tag, context) + return str(qs, 'utf-8') + +def flatten(xs): + if hasattr(xs, '__iter__'): + for x in xs: + if hasattr(x, '__iter__'): + yield from flatten(x) + else: + yield x + else: + yield xs + +def toUnicodeWithWarning(s, method_name): + try: + s = str(s) + except: + Logger.Warning("%s - warning, passing non-unicode, non-ASCII string '%s'! Trying to convert myself to UTF-8 ..." % (method_name, s)) + s = str(s, 'utf-8') + return s + +def completeResPath(fileName): + import os + subPath = "lib/python3.6/site-packages/salome/curveplot" + rd = os.environ.get("CURVEPLOT_ROOT_DIR", None) + if rd is None: + raise Exception("CURVEPLOT_ROOT_DIR is not defined!") + if 0: # do not remove automatically modified in CMake config + subPath = "/volatile/catB/jh777916/Devel/WORK/OPERA-9.9.0-CO7/BUILD/GUI/local/curveplot" + filePath = os.path.join(rd, subPath, fileName) + return filePath diff --git a/tools/CurvePlot/src/python/controller/utils.py.in b/tools/CurvePlot/src/python/controller/utils.py.in index 4af81f726..ef70e904f 100644 --- a/tools/CurvePlot/src/python/controller/utils.py.in +++ b/tools/CurvePlot/src/python/controller/utils.py.in @@ -94,6 +94,21 @@ def toUnicodeWithWarning(s, method_name): s = str(s, 'utf-8') return s +def flatten(xs): + """ Takes a container (list or tuple) that can contain other list/tuples + and returns a list of all the element as flattened. Useful to obtain artists from + matplotlib plotting methods. + @return Flattened list containing all the elements (OR returns xs if xs is not iterable) + """ + if hasattr(xs, '__iter__'): + for x in xs: + if hasattr(x, '__iter__'): + yield from flatten(x) + else: + yield x + else: + yield xs + def completeResPath(fileName): import os subPath = "@SALOME_CURVEPLOT_INSTALL_PYTHON@" diff --git a/tools/CurvePlot/src/python/model/BarModel.py b/tools/CurvePlot/src/python/model/BarModel.py index bc9debadb..b62f603d5 100644 --- a/tools/CurvePlot/src/python/model/BarModel.py +++ b/tools/CurvePlot/src/python/model/BarModel.py @@ -52,8 +52,6 @@ class BarModel(Model): def setIsDirac(self, isD, silent=False): self._isDirac = isD - if not silent: - self.notifyChange("BarTypeChange") def setTable(self, t, silent=False): self._table = t @@ -76,7 +74,7 @@ class BarModel(Model): ti = toUnicodeWithWarning(ti, "BarModel::setTitle()") self._title = ti if not silent: - self.notifyChange("BarTitleChange") + self.notifyChange("CurveTitleChange") def getTitle(self): return self._title diff --git a/tools/CurvePlot/src/python/model/CMakeLists.txt b/tools/CurvePlot/src/python/model/CMakeLists.txt index 400a87853..2cc819175 100644 --- a/tools/CurvePlot/src/python/model/CMakeLists.txt +++ b/tools/CurvePlot/src/python/model/CMakeLists.txt @@ -21,6 +21,7 @@ SET(_all_lib_SCRIPTS Model.py CurveModel.py BarModel.py + StemModel.py TableModel.py PlotManager.py XYPlotSetModel.py diff --git a/tools/CurvePlot/src/python/model/CurveModel.py b/tools/CurvePlot/src/python/model/CurveModel.py index 56367d7ff..7db4e703f 100644 --- a/tools/CurvePlot/src/python/model/CurveModel.py +++ b/tools/CurvePlot/src/python/model/CurveModel.py @@ -86,4 +86,4 @@ class CurveModel(Model): def getID(self): return self._idPlot - + \ No newline at end of file diff --git a/tools/CurvePlot/src/python/model/Model.py b/tools/CurvePlot/src/python/model/Model.py index 4fc9a6330..d0012648c 100644 --- a/tools/CurvePlot/src/python/model/Model.py +++ b/tools/CurvePlot/src/python/model/Model.py @@ -39,9 +39,10 @@ class Model(object): self._controller = controller self._id = self.__GenerateID() # A unique ID for this class of object - # A unique ID for the traces (Curves and Bars), starting from 0 + # A unique ID for the traces (Curves, Bars and Stems), starting from 0 self._idPlot = self.COUNT_MODELS["CurveModel"] \ - + self.COUNT_MODELS["BarModel"] - 1 + + self.COUNT_MODELS["BarModel"] \ + + self.COUNT_MODELS["StemModel"]- 1 def getID(self): return self._id diff --git a/tools/CurvePlot/src/python/model/PlotManager.py b/tools/CurvePlot/src/python/model/PlotManager.py index d577f574c..f2b474c90 100644 --- a/tools/CurvePlot/src/python/model/PlotManager.py +++ b/tools/CurvePlot/src/python/model/PlotManager.py @@ -50,18 +50,23 @@ class PlotManager(Model): return ps return None - def setCurrentCurve(self, curveId): + def setCurrentCurve(self, curveId, silent=False): # TAG CHECK : SILENT ajouté + Logger.Debug("PlotManager::setCurrentCurve() --> CALL") ps = self.getPlotSetContainingCurve(curveId) if ps is None and curveId != -1: raise ValueError("Invalid curve ID (%d)!" % curveId) - self.clearAllCurrentCurve() + Logger.Debug("PlotManager::setCurrentCurve() --> CALL clearAllCurrentCurve()") + self.clearAllCurrentCurve(silent=True) # silencing the CurrentCurveChange : 1 draw less + Logger.Debug("PlotManager::setCurrentCurve() --> DONE clearAllCurrentCurve()") if curveId == -1: return -1 ps_id = ps.getID() currPs = self.getCurrentPlotSet() if currPs is None or currPs.getID() != ps_id: self.setCurrentPlotSet(ps_id) - ps.setCurrentCurve(curveId) + Logger.Debug("PlotManager::setCurrentCurve() --> CALL ps.setCurrentCurve()") + ps.setCurrentCurve(curveId, silent=silent) # will actually notify CurrentCurveChange + Logger.Debug("PlotManager::setCurrentCurve() --> DONE") return ps_id def getCurrentCurve(self): @@ -72,7 +77,7 @@ class PlotManager(Model): def clearAllCurrentCurve(self, silent=False): for psID in self._plotSets: - self._plotSets[psID].setCurrentCurve(-1) + self._plotSets[psID].setCurrentCurve(-1, silent=silent) # ajout du silent : 1 draw less if not silent: self.notifyChange("CurrentCurveChange") @@ -87,7 +92,6 @@ class PlotManager(Model): def removeXYPlotSet(self, plotSetID): Logger.Debug("====> PlotManager::removeXYPlotSet() %d" % plotSetID) if plotSetID not in self._plotSets: - print(self._plotSets) raise ValueError("Plot set ID (%d) not found for deletion!" % plotSetID) ps = self._plotSets.pop(plotSetID) if self._currentPlotSet is ps: @@ -115,4 +119,3 @@ class PlotManager(Model): for obj in self._plotSetsRepaint: obj.notifyChange() self._plotSetsRepaint = set() - diff --git a/tools/CurvePlot/src/python/model/StemModel.py b/tools/CurvePlot/src/python/model/StemModel.py new file mode 100644 index 000000000..4f9339e22 --- /dev/null +++ b/tools/CurvePlot/src/python/model/StemModel.py @@ -0,0 +1,89 @@ +# Copyright (C) 2016-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from .Model import Model +from .utils import toUnicodeWithWarning + +class StemModel(Model): + + def __init__(self, controller, table=None, index=-1): + Model.__init__(self, controller) + + self._name = "StemModel" + self._title = "Stem %d" % self.getID() + self._table = table + self._yaxisIndex = index # column index in the table + self._xaxisIndex = 0 # By default the first column of the table is used for the X-s + + def clone(self): + ret = StemModel(self._controller) + ret._title = self._title + ret._table = self._table # TO CHECK: deep copy here? (I think not needed in Python ...) + ret._yaxisIndex = self._yaxisIndex + ret._xaxisIndex = self._xaxisIndex + return ret + + def setTable(self, t, silent=False): + self._table = t + if not silent: + self.notifyChange("DataChange") + + def getTable(self): + return self._table + + def extendData(self, t, silent=False): + self._table.extend(t) + if not silent: + self.notifyChange("DataChange") + + def resetData(self): + self._table.clear() + self.notifyChange("DataChange") + + def setTitle(self, ti, silent=False): + ti = toUnicodeWithWarning(ti, "StemModel::setTitle()") + self._title = ti + if not silent: + self.notifyChange("CurveTitleChange") + + def getTitle(self): + return self._title + + def getYAxisIndex(self): + return self._yaxisIndex + + def setYAxisIndex(self, idx, silent=False): + self._yaxisIndex = idx + if not silent: + self.notifyChange("YAxisIndexChange") + + def getXAxisIndex(self): + return self._xaxisIndex + + def setXAxisIndex(self, idx, silent=False): + sh = self._table.getShape() + if idx >= sh[1]: + raise ValueError("Index out of bound (is %d, but max is %d)" % (idx, sh[1])) + self._xaxisIndex = idx + if not silent: + self.notifyChange("XAxisIndexChange") + + def getID(self): + return self._idPlot + \ No newline at end of file diff --git a/tools/CurvePlot/src/python/model/XYPlotSetModel.py b/tools/CurvePlot/src/python/model/XYPlotSetModel.py index c960e258b..919733824 100644 --- a/tools/CurvePlot/src/python/model/XYPlotSetModel.py +++ b/tools/CurvePlot/src/python/model/XYPlotSetModel.py @@ -50,26 +50,14 @@ class XYPlotSetModel(Model): raise ValueError("Invalid curve ID (%d)!" % curveID) self._currentCurve = self._curves.get(curveID, None) if not silent: - self.notifyChange("CurrentCurveChange") + self.notifyChange("CurrentCurveChange") def getCurrentCurve(self): return self._currentCurve def addCurve(self, curve, silent=False): - # if self._curves: - # lastID = max(list(self._curves.keys())) - # else : - # lastID = -1 - - # # if (curve.getID() >= lastID): - # # newLastID = curve.getID() - # # else : - # self._lastID += 1 - self._curves[curve.getID()] = curve - Logger.Debug(" ---- XYPlotSetModel::addCurve( curve ) -> curve.getID() = {}".format(curve.getID())) - # Logger.Debug(" ---- XYPlotSetModel::addCurve( curve ) -> _curves new last ID = {}".format(self._lastID)) if not silent: self.notifyChange("AddCurve") diff --git a/tools/CurvePlot/src/python/test/TestDesktop_test.py b/tools/CurvePlot/src/python/test/TestDesktop_test.py index 0a3ef732a..7d68b1214 100755 --- a/tools/CurvePlot/src/python/test/TestDesktop_test.py +++ b/tools/CurvePlot/src/python/test/TestDesktop_test.py @@ -76,8 +76,9 @@ class TestDesktop_test(QMainWindow): self.addTabAction.triggered.connect(self.addTab) self.memAction.triggered.connect(self.memPrint) self.perfTestAction.triggered.connect(self.perfTest) - self.addBarPlotAction.triggered.connect(self.addBarplot) + self.addStemPlotAction.triggered.connect(self.addStemplot) self.addBarPlotNonDiracAction.triggered.connect(self.addBarplotNonDirac) + self.addBarPlotDiracAction.triggered.connect(self.addBarplotDirac) def generateID(self): @@ -95,8 +96,9 @@ class TestDesktop_test(QMainWindow): self.addTabActionID = self.generateID() self.memActionID = self.generateID() self.perfActionID = self.generateID() - self.addBarPlotActionID = self.generateID() + self.addStemPlotActionID = self.generateID() self.addBarPlotNonDiracActionID = self.generateID() + self.addBarPlotDiracActionID = self.generateID() # Menus self.etudeMenuID = self.generateID() @@ -113,8 +115,9 @@ class TestDesktop_test(QMainWindow): self.addTabAction = ca(self.addTabActionID, "Add tab", "Add tab", "", "") self.memAction = ca(self.memActionID, "Display used mem", "Display used mem", "", "") self.perfTestAction = ca(self.perfActionID, "Perf test", "Perf test", "", "") - self.addBarPlotAction = ca(self.addBarPlotActionID, "Add BarPlot - Dirac", "Add BarPlot - Dirac", "", "") - self.addBarPlotNonDiracAction = ca(self.addBarPlotActionID, "Add BarPlot - Non Dirac", "Add BarPlot- Non Dirac", "", "") + self.addStemPlotAction = ca(self.addStemPlotActionID, "Add StemPlot - Dirac", "Add StemPlot - Dirac", "", "") + self.addBarPlotNonDiracAction = ca(self.addBarPlotNonDiracActionID, "Add BarPlot - Non Dirac", "Add BarPlot- Non Dirac", "", "") + self.addBarPlotDiracAction = ca(self.addBarPlotDiracActionID, "Add BarPlot - Dirac", "Add BarPlot - Dirac", "", "") def createToolbars(self): pass @@ -136,8 +139,9 @@ class TestDesktop_test(QMainWindow): self._sgPyQt.createMenu(self.addPSAction, curveMenu) self._sgPyQt.createMenu(self.memAction, curveMenu) self._sgPyQt.createMenu(self.perfTestAction, curveMenu) - self._sgPyQt.createMenu(self.addBarPlotAction, curveMenu) + self._sgPyQt.createMenu(self.addStemPlotAction, curveMenu) self._sgPyQt.createMenu(self.addBarPlotNonDiracAction, curveMenu) + self._sgPyQt.createMenu(self.addBarPlotDiracAction, curveMenu) dummyMenu = self._sgPyQt.createMenu( "Dummy", -1, self.dummyMenuID, self._sgPyQt.defaultMenuGroup() ) self._sgPyQt.createMenu(self.addTabAction, dummyMenu) @@ -193,13 +197,13 @@ class TestDesktop_test(QMainWindow): print("Elapsed: %.2f" % ( time() - t0)) @pyqtSlot() - def addBarplot(self): - energy_val = np.array([8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99]) + def addBarplotDirac(self): + energy_val = np.array([0., 1.15, 5.2, 8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99, 15.1, 17.8, 19.7]) # energy_val = np.array([8.15, 8.42, 8.75, 8.88, 9.1, 9.55, 9.79]) - intensity = np.random.rand(energy_val.size) * 5 + intensity = np.random.rand(energy_val.size) * 10 isDirac = True - width_dirac = np.full(energy_val.size, 0.01) + width_dirac = np.full(energy_val.size, 0.05) _, ps_id = curveplot.AddBarPlot(energy_val, intensity, width_dirac, isDirac, x_label="Energy", y_label="Intensity", append=True) @@ -208,16 +212,32 @@ class TestDesktop_test(QMainWindow): # if self.cnt >= 0: # QTimer.singleShot(self.timeLap, self, SLOT("itemDel()")) + + @pyqtSlot() + def addStemplot(self): + energy_val = np.array([0., 1.15, 5.2, 8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99, 15.1, 17.8, 19.7]) + # energy_val = np.array([8.15, 8.42, 8.75, 8.88, 9.1, 9.55, 9.79]) + + intensity = np.random.rand(energy_val.size) * 10 + + _, ps_id = curveplot.AddStemPlot(energy_val, intensity, + x_label="Energy", y_label="Intensity", append=True) + + curveplot.SetLegendVisible(ps_id, True) + # if self.cnt >= 0: + # QTimer.singleShot(self.timeLap, self, SLOT("itemDel()")) + + @pyqtSlot() def addBarplotNonDirac(self): # Testing with TableModel from curveplot import TableModel from random import random - energy_inf = np.array([8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99]) - energy_sup = np.array([8.33, 8.67, 8.99, 9.01, 9.33, 9.99, 10.01]) + energy_inf = np.array([0., 1.15, 5.2, 8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99, 15.1, 17.8, 19.7]) + energy_sup = np.array([1.15, 5.2, 8.01, 8.33, 8.67, 8.99, 9.01, 9.33, 9.99, 15.1, 17.8, 19.7, 20.]) deltaE = energy_sup - energy_inf - intensity = np.random.rand(energy_inf.size) * 5 + intensity = np.random.rand(energy_inf.size) * 10 isDirac = False t = TableModel(None) diff --git a/tools/CurvePlot/src/python/ui/PlotSettings.py b/tools/CurvePlot/src/python/ui/PlotSettings.py index 876a3847c..6020d41a5 100644 --- a/tools/CurvePlot/src/python/ui/PlotSettings.py +++ b/tools/CurvePlot/src/python/ui/PlotSettings.py @@ -51,6 +51,11 @@ class PlotSettings(QDialog): r, g, b = [c/255.0 for c in col.getRgb()[:3]] self.setRGB(r, g, b) + @pyqtSlot() + def onOpacityChanged(self): + opacity = self.sliderOpacity.value() / 100. + self.valueOpacity.setText(f"{opacity:.2f}") + def setSelectedCurveName(self, name): self.nameCurve.setText(name) if name : diff --git a/tools/CurvePlot/src/python/ui/PlotSettings.ui b/tools/CurvePlot/src/python/ui/PlotSettings.ui index 0672d6f55..12a206fe1 100644 --- a/tools/CurvePlot/src/python/ui/PlotSettings.ui +++ b/tools/CurvePlot/src/python/ui/PlotSettings.ui @@ -135,7 +135,7 @@ 0 - 100 + 120 @@ -173,6 +173,36 @@ + + + + Opacity : + + + + + + + true + + + Qt::Horizontal + + + 0 + + + 100 + + + + + + + + + + @@ -482,6 +512,12 @@ + + sliderOpacity + valueChanged() + PlotSettings + onOpacityChanged() + onShowLegend(int) diff --git a/tools/CurvePlot/src/python/views/BarView.py b/tools/CurvePlot/src/python/views/BarView.py index 47125c925..1c4eb4e4a 100644 --- a/tools/CurvePlot/src/python/views/BarView.py +++ b/tools/CurvePlot/src/python/views/BarView.py @@ -26,12 +26,12 @@ class BarView(View): def __init__(self, controller, parentXYView): View.__init__(self, controller) self._mplAxes = None - self._mplBars = None + self._mplArtist = None self._isHighlighted = False self._initialLineWidth = None self._initialEdgeColorBar = None - self._initialAlpha = None + self._initialOpacity = None self._initialZOrder = None self._parentXYView = parentXYView @@ -42,8 +42,8 @@ class BarView(View): self._mplAxes = axes def erase(self): - self._mplBars.remove() - self._mplBars = None + self._mplArtist.remove() + self._mplArtist = None def draw(self): m = self._model @@ -51,24 +51,28 @@ class BarView(View): x_align = "center" if m.getIsDirac() else "edge" d = self._model.getTable().getData() - self._mplBars = self._mplAxes.bar(d[:, x_idx], d[:, height_idx], width=d[:, width_idx], + # Bar returns a BarContainer (list of Artists) + self._mplArtist = self._mplAxes.bar(d[:, x_idx], d[:, height_idx], width=d[:, width_idx], align=x_align, label=m._title, alpha= 0.7, picker=self._PICKER_PRECISION_BAR) - self._initialLineWidth = 0. #self._mplBars[0].get_linewidth() - self._initialEdgeColorBar = self._mplBars[0].get_edgecolor() - self._initialAlpha = self._mplBars[0].get_alpha() - self._initialZOrder = self._mplBars[0].get_zorder() + self._initialLineWidth = 0. #self._mplArtist[0].get_linewidth() + self._initialEdgeColorBar = self._mplArtist[0].get_edgecolor() + self._initialOpacity = self._mplArtist[0].get_alpha() + self._initialZOrder = self._mplArtist[0].get_zorder() + + # print(f"TYPE ARTISTS BARS: {type(self._mplArtist)}") + # print(f"SIZE ARTISTS BARS: {len(self._mplArtist)}") def onCurveTitleChange(self): - if self._mplBars is None: + if self._mplArtist is None: return - self._mplBars.set_label(self._model._title) + self._mplArtist.set_label(self._model._title) def update(self): Logger.Debug("BarView::udpate") - if self._mplBars is None: + if self._mplArtist is None: return color = self.getColor() opacity = self.getAlpha() @@ -79,7 +83,7 @@ class BarView(View): self.toggleHighlight(self._isHighlighted, force=True) def toggleHighlight(self, highlight, force=False): - bar = self._mplBars.patches # TAG CHECK + bar = self._mplArtist.patches # TAG CHECK if highlight and (force or not self._isHighlighted): for rect in bar : rect.set_linewidth(1.) @@ -90,7 +94,7 @@ class BarView(View): elif not highlight and (force or self._isHighlighted): for rect in bar : rect.set_linewidth(self._initialLineWidth) - rect.set_alpha(self._initialAlpha) + rect.set_alpha(self._initialOpacity) rect.set_edgecolor(self._initialEdgeColorBar) rect.set_zorder(self._initialZOrder) self._isHighlighted = False @@ -102,19 +106,30 @@ class BarView(View): return self._isHighlighted def setColor(self, rgb_color): - for rect in self._mplBars : + for rect in self._mplArtist : rect.set_facecolor(rgb_color) def getColor(self): - if self._mplBars is None: + if self._mplArtist is None: return None - return self._mplBars[0].get_facecolor() + return self._mplArtist[0].get_facecolor() def setAlpha(self, opacity): - for rect in self._mplBars: + for rect in self._mplArtist: rect.set_alpha(opacity) def getAlpha(self): - if self._mplBars is None: + if self._mplArtist is None: return None - return self._mplBars[0].get_alpha() + return self._mplArtist[0].get_alpha() + + def setInitialAlpha(self, opacity): + self._initialOpacity = opacity + + def getInitialAlpha(self): + if self._mplArtist is None: + return None + return self._initialOpacity + + def setLineStyle(self, linestyle=""): + return \ No newline at end of file diff --git a/tools/CurvePlot/src/python/views/CMakeLists.txt b/tools/CurvePlot/src/python/views/CMakeLists.txt index 6ec77d1f1..67f359c31 100644 --- a/tools/CurvePlot/src/python/views/CMakeLists.txt +++ b/tools/CurvePlot/src/python/views/CMakeLists.txt @@ -23,6 +23,7 @@ SET(_all_lib_SCRIPTS CurveTabsView.py CurveView.py BarView.py + StemView.py XYView.py ) diff --git a/tools/CurvePlot/src/python/views/CurveView.py b/tools/CurvePlot/src/python/views/CurveView.py index 064172c46..a7ead94ad 100644 --- a/tools/CurvePlot/src/python/views/CurveView.py +++ b/tools/CurvePlot/src/python/views/CurveView.py @@ -26,39 +26,49 @@ class CurveView(View): def __init__(self, controller, parentXYView): View.__init__(self, controller) self._mplAxes = None - self._mplLines = None + self._mplArtist = None self._isHighlighted = False self._initialLineWidth = None + self._initialOpacity = None + self._initialZOrder = None self._parentXYView = parentXYView self._marker = None self._color = None self._lineStyle = None - + self._opacity = None + def setMPLAxes(self, axes): self._mplAxes = axes def erase(self): - self._mplAxes.lines.remove(self._mplLines[0]) - self._mplLines = None + self._mplAxes.lines.remove(self._mplArtist) + self._mplArtist = None def draw(self): + Logger.Debug("CurveView::draw") m = self._model x_idx, y_idx = m.getXAxisIndex(), m.getYAxisIndex() d = self._model.getTable().getData() - self._mplLines = self._mplAxes.plot(d[:, x_idx], d[:, y_idx], label=m._title, + plots = self._mplAxes.plot(d[:, x_idx], d[:, y_idx], label=m._title, alpha = 1., picker=self._PICKER_PRECISION) - self._initialLineWidth = self._mplLines[0].get_linewidth() - + self._mplArtist = plots[0] + self._initialLineWidth = self._mplArtist.get_linewidth() + self._initialOpacity = self._mplArtist.get_alpha() + self._initialZOrder = self._mplArtist.get_zorder() + + # print(f"TYPE ARTISTS LINES: {type(self._mplArtist)}") + # print(f"SIZE ARTISTS LINES: {len(self._mplArtist)}") + def onCurveTitleChange(self): - if self._mplLines is None: + if self._mplArtist is None: return - self._mplLines[0].set_label(self._model._title) + self._mplArtist.set_label(self._model._title) def update(self): Logger.Debug("CurveView::udpate") - if self._mplLines is None: + if self._mplArtist is None: return lineStyle, marker, color = self.getLineStyle(), self.getMarker(), self.getColor() self.erase() @@ -70,30 +80,34 @@ class CurveView(View): self.toggleHighlight(self._isHighlighted, force=True) def setLineStyle(self, lin_style): - lin = self._mplLines[0] + lin = self._mplArtist lin.set_linestyle(lin_style) def getLineStyle(self): - if self._mplLines is None: + if self._mplArtist is None: return None - return self._mplLines[0].get_linestyle() + return self._mplArtist.get_linestyle() def setMarker(self, marker): - lin = self._mplLines[0] + lin = self._mplArtist lin.set_marker(marker) def getMarker(self): - if self._mplLines is None: + if self._mplArtist is None: return None - return self._mplLines[0].get_marker() + return self._mplArtist.get_marker() def toggleHighlight(self, highlight, force=False): - lin = self._mplLines[0] + lin = self._mplArtist if highlight and (force or not self._isHighlighted): + lin.set_alpha(1.) lin.set_linewidth(2*self._initialLineWidth) + lin.set_zorder(1000) self._isHighlighted = True elif not highlight and (force or self._isHighlighted): + lin.set_alpha(self._initialOpacity) lin.set_linewidth(self._initialLineWidth) + lin.set_zorder(self._initialZOrder) self._isHighlighted = False else: # Nothing to do, already the correct state @@ -103,19 +117,27 @@ class CurveView(View): return self._isHighlighted def setColor(self, rgb_color): - lin = self._mplLines[0] + lin = self._mplArtist lin.set_color(rgb_color) def getColor(self): - if self._mplLines is None: + if self._mplArtist is None: return None - return self._mplLines[0].get_color() + return self._mplArtist.get_color() def setAlpha(self, opacity): - lin = self._mplLines[0] + lin = self._mplArtist lin.set_alpha(opacity) - + def getAlpha(self): - if self._mplLines is None: + if self._mplArtist is None: + return None + return self._mplArtist.get_alpha() + + def setInitialAlpha(self, opacity): + self._initialOpacity = opacity + + def getInitialAlpha(self): + if self._mplArtist is None: return None - return self._mplLines[0].get_alpha() + return self._initialOpacity diff --git a/tools/CurvePlot/src/python/views/StemView.py b/tools/CurvePlot/src/python/views/StemView.py new file mode 100644 index 000000000..3007a64e9 --- /dev/null +++ b/tools/CurvePlot/src/python/views/StemView.py @@ -0,0 +1,180 @@ +# Copyright (C) 2016-2022 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from .View import View +from .utils import Logger + +class StemView(View): + _PICKER_PRECISION = 10 #pts + + def __init__(self, controller, parentXYView): + View.__init__(self, controller) + self._mplAxes = None + self._mplArtist = None + + self._isHighlighted = False + self._initialLineWidth = None + self._initialOpacity = None + self._initialZOrder = None + self._parentXYView = parentXYView + + self._marker = None + self._color = None + self._lineStyle = None + self._opacity = None + + def setMPLAxes(self, axes): + self._mplAxes = axes + + def erase(self): + self._mplArtist.remove() + self._mplArtist = None + + def draw(self): + m = self._model + x_idx, y_idx = m.getXAxisIndex(), m.getYAxisIndex() + d = self._model.getTable().getData() + + # stem returns a StemContainer : (markerline , stemlines, baseline ) + self._mplArtist = self._mplAxes.stem(d[:, x_idx], d[:, y_idx], label=m._title,\ + linefmt='b-', markerfmt='_', basefmt=' ') + + self._initialLineWidth = self._mplArtist[0].get_linewidth() + self._initialZOrder = self._mplArtist[0].get_zorder() + + self.setAlpha(1.) + self.setInitialAlpha(1.) + self.setColor(next(self._mplAxes._get_lines.prop_cycler)['color']) + self.setMarkerEdgeWidth(self._initialLineWidth) + self.setMarkerSize(8) + + # picker for the stemlines + for lin in self._mplArtist[1]: + lin.set_picker(self._PICKER_PRECISION) + + Logger.Debug(f"** Init lw: {self._initialLineWidth}") + Logger.Debug(f"** Init opacity : {self._initialOpacity}") + Logger.Debug(f"** Init zorder : {self._initialZOrder}") + + def onCurveTitleChange(self): + if self._mplArtist is None: + return + self._mplArtist.set_label(self._model._title) + + def update(self): + Logger.Debug("StemView::udpate") + if self._mplArtist is None: + return + lineStyle, marker, color = self.getLineStyle(), self.getMarker(), self.getColor() + self.erase() + self.draw() + # Reset correctly color, marker and highlight state + self.setLineStyle(lineStyle) + self.setMarker(marker) + self.setColor(color) + self.toggleHighlight(self._isHighlighted, force=True) + + def setLineStyle(self, lin_style): + for lin in self._mplArtist[1]: + lin.set_linestyle(lin_style) + + def getLineStyle(self): + if self._mplArtist is None: + return None + return self._mplArtist[1][0].get_linestyle() + + def setMarker(self, marker): + markerline = self._mplArtist[0] + markerline.set_marker(marker) + + def setMarkerSize(self, ms): + markerline = self._mplArtist[0] + markerline.set_markersize(ms) + + def setMarkerEdgeWidth(self, mew): + markerline = self._mplArtist[0] + markerline.set_markeredgewidth(mew) + + def getMarker(self): + if self._mplArtist is None: + return None + return self._mplArtist[0].get_marker() + + def toggleHighlight(self, highlight, force=False): + markerline, stemlines, _ = self._mplArtist + if highlight and (force or not self._isHighlighted): + self.setAlpha(1.) + self.setZOrder(1000) + self.setLineWidth(2*self._initialLineWidth) + self.setMarkerEdgeWidth(2*self._initialLineWidth) + self._isHighlighted = True + elif not highlight and (force or self._isHighlighted): + self.setAlpha(self._initialOpacity) + self.setZOrder(self._initialZOrder) + self.setLineWidth(self._initialLineWidth) + self.setMarkerEdgeWidth(self._initialLineWidth) + self._isHighlighted = False + else: + # Nothing to do, already the correct state + return + + def isHighlighted(self): + return self._isHighlighted + + def setZOrder(self, zorder): + markerline, stemlines, _ = self._mplArtist + markerline.set_zorder(zorder) + for lin in stemlines: + lin.set_zorder(zorder) + + def setLineWidth(self, lw): + markerline, stemlines, _ = self._mplArtist + markerline.set_linewidth(lw) + for lin in stemlines: + lin.set_linewidth(lw) + + def setColor(self, rgb_color): + markerline, stemlines, _ = self._mplArtist + markerline.set_color(rgb_color) + for lin in stemlines: + lin.set_color(rgb_color) + + def getColor(self): + if self._mplArtist is None: + return None + return self._mplArtist[0].get_color() + + def setAlpha(self, opacity): + markerline, stemlines, _ = self._mplArtist + markerline.set_alpha(opacity) + for lin in stemlines: + lin.set_alpha(opacity) + + def getAlpha(self): + if self._mplArtist is None: + return None + return self._mplArtist[0].get_alpha() + + def setInitialAlpha(self, opacity): + self._initialOpacity = opacity + + def getInitialAlpha(self): + if self._mplArtist is None: + return None + return self._initialOpacity diff --git a/tools/CurvePlot/src/python/views/XYView.py b/tools/CurvePlot/src/python/views/XYView.py index 9c039c9d0..dcf016fef 100644 --- a/tools/CurvePlot/src/python/views/XYView.py +++ b/tools/CurvePlot/src/python/views/XYView.py @@ -28,9 +28,10 @@ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationTool from .View import View from .CurveView import CurveView from .BarView import BarView +from .StemView import StemView from .PlotWidget import PlotWidget from .PlotSettings import PlotSettings -from .utils import Logger, trQ +from .utils import Logger, trQ, flatten class EventHandler(QObject): """ Handle the right-click properly so that it only triggers the contextual menu """ @@ -67,6 +68,7 @@ class XYView(View): "v", # triangle_down "H", # hexagon2 "d", # thin diamond + "_", # horizontal line "", # NO MARKER ] @@ -137,6 +139,15 @@ class XYView(View): Logger.Debug(" ** > appendBarplot() crvID = {}".format(curveID)) self._curveViews[curveID] = newB + def appendStemplot(self, curveID): + Logger.Debug(" > Appending a stem model") + newS = StemView(self._controller, self) + newS.setModel(self._model._curves[curveID]) + newS.setMPLAxes(self._mplAxes) + newS.draw() + Logger.Debug(" ** > appendStemplot() crvID = {}".format(curveID)) + self._curveViews[curveID] = newS + def removeCurve(self, curveID): v = self._curveViews.pop(curveID) v.erase() @@ -186,9 +197,12 @@ class XYView(View): def onPick(self, event): """ MPL callback when picking """ - Logger.Debug(" > Event onPick : {}".format(event)) + Logger.Debug(" > Event onPick : {} ---> START EVENT".format(event)) + + if event.mouseevent.dblclick: + Logger.Debug(" > > > Double click !") - if event.mouseevent.button == 1: + if (event.mouseevent.button == 1 and not event.mouseevent.dblclick): selected_id = -1 a = event.artist Logger.Debug(" > Artist picked : {}".format(a)) @@ -197,48 +211,65 @@ class XYView(View): if self._legend is not None: h, l = self._mplAxes.get_legend_handles_labels() - # For text + # Checks if the text legend has been clicked for leg_idx,legText in enumerate(self._legend.get_texts()): if legText is a : # Gets the associated plot from the axes.legend handles selected_plot = h[leg_idx] # Gets the id from the curveViews for crv_id, cv in list(self._curveViews.items()): - if (cv._model._name == "BarModel") : - if selected_plot is cv._mplBars: - selected_id = crv_id - if (cv._model._name == "CurveModel") : - if selected_plot in cv._mplLines: + if selected_plot is cv._mplArtist: selected_id = crv_id + break + # Checks if the plot symbol legend has been clicked for leg_idx,legHandler in enumerate(self._legend.legendHandles): if legHandler is a : # Gets the associated plot from the axes.legend handles selected_plot = h[leg_idx] # Gets the id from the curveViews for crv_id, cv in list(self._curveViews.items()): - if (cv._model._name == "BarModel") : - if selected_plot is cv._mplBars: - selected_id = crv_id - if (cv._model._name == "CurveModel") : - if selected_plot in cv._mplLines: + if selected_plot is cv._mplArtist: selected_id = crv_id + break Logger.Debug("Legend {} selected".format(selected_id)) + # Checks if an artist has been picked inside the plotting area for crv_id, cv in list(self._curveViews.items()): - if (cv._model._name == "BarModel") : - # Checks if the picked artist is in the list of Rectangles - if a in cv._mplBars: - selected_id = crv_id - Logger.Debug("Barplot {} selected".format(selected_id)) - else: - if cv._mplLines[0] is a: - selected_id = crv_id - Logger.Debug("Curve {} selected".format(selected_id)) - - # Use the plotmanager so that other plot sets get their current reset: - self._controller._plotManager.setCurrentCurve(selected_id) + # Permits to get back to the intiial opacity of each Artists ... let's keep it in case we want that + # self._curveViews[crv_id].setAlpha(self._curveViews[crv_id].getInitialAlpha()) + + # Checks if the picked artist is in the list of artists + if a in flatten(cv._mplArtist): + selected_id = crv_id + Logger.Debug("Curve/Barplot/Stemplot {} selected".format(selected_id)) + break + + # Use the plotmanager to set the current curve so that other plot sets get their current reset: + if self._currCrv is not None: + if selected_id != self._currCrv.getID() : + # Setting the current curve only if different + if event.mouseevent.dblclick: + # if double click (2nd onPick event on same artist) : set the _currCrv variable without notifying + Logger.Debug(" onPick::setCurrentCurve() SILENT TRUE ...") + self._controller._plotManager.setCurrentCurve(selected_id, silent=True) + Logger.Debug(" onPick::setCurrentCurve() SILENT TRUE : DONE") + else : + # if NOT double click : set the _currCrv variable and notifying (repaint) + Logger.Debug(" onPick::setCurrentCurve() SILENT FALSE ...") + self._controller._plotManager.setCurrentCurve(selected_id, silent=False) + Logger.Debug(" onPick::setCurrentCurve() SILENT FALSE : DONE") + else : + Logger.Debug(" onPick::setCurrentCurve() SILENT FALSE ...") + self._controller._plotManager.setCurrentCurve(selected_id, silent=False) + Logger.Debug(" onPick::setCurrentCurve() SILENT FALSE : DONE") + + else : #if event.mouseevent.dblclick: + self.showOnlySelected() + + Logger.Debug(" > Event onPick : {} ---> END EVENT".format(event)) + def createAndAddLocalAction(self, icon_file, short_name): return self._toolbar.addAction(self._sgPyQt.loadIcon("CURVEPLOT", icon_file), short_name) @@ -248,6 +279,7 @@ class XYView(View): self._mplCanvas = FigureCanvasQTAgg(self._mplFigure) self._mplCanvas.installEventFilter(self._eventHandler) self._mplCanvas.mpl_connect('pick_event', self.onPick) + self._mplAxes = self._mplFigure.add_subplot(1, 1, 1) self._plotWidget = PlotWidget() self._toobarMPL = NavigationToolbar2QT(self._mplCanvas, None) @@ -260,6 +292,12 @@ class XYView(View): self._popupMenu = QtWidgets.QMenu() self._popupMenu.addAction(self._actionLegend) + self._actionShowAll = self._sgPyQt.createAction(2, "Show all", "Show all", "", "") + self._actionShowOnlySelected = self._sgPyQt.createAction(3, "Show only selected", "Show only selected", "", "") + self._popupMenu.addAction(self._actionShowAll) + self._popupMenu.addAction(self._actionShowOnlySelected) + self._actionShowAll.triggered.connect(self.showAll) + self._actionShowOnlySelected.triggered.connect(self.showOnlySelected) # Connect evenement for the graphic scene self._mplCanvas.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) @@ -340,7 +378,8 @@ class XYView(View): filters, trQ("DUMP_VIEW_FILE"), False ) - name = str(fileName) + name = str(fileName[0]) # Modif portage + Logger.Debug(f" >> Save fig filename : {name}") if name != "": self._mplAxes.figure.savefig(name) pass @@ -380,12 +419,10 @@ class XYView(View): action = self._curveActionGroup.checkedAction() if action is self._pointsAction : for crv_view in list(self._curveViews.values()): - if (crv_view._model._name != "BarModel") : - crv_view.setLineStyle("None") + crv_view.setLineStyle("None") elif action is self._linesAction : for crv_view in list(self._curveViews.values()): - if (crv_view._model._name != "BarModel") : - crv_view.setLineStyle("-") + crv_view.setLineStyle("-") else : raise NotImplementedError if repaint: @@ -480,6 +517,23 @@ class XYView(View): self._actionLegend.setChecked(False) self.showHideLegend(repaint=repaint) + def showAll(self): + for crv_id, cv in list(self._curveViews.items()): + cv.toggleHighlight(False, force=True) + # self._controller._plotManager.clearAllCurrentCurve() + current_ps = self._controller._plotManager.getCurrentPlotSet() + current_ps.setCurrentCurve(-1) + return + + def showOnlySelected(self): + """ Show only selected curve/barplot """ + if self._currCrv is not None: + for crv_id, cv in list(self._curveViews.items()): + if (crv_id != self._currCrv.getID()) : + cv.setAlpha(0.05) + self.showHideLegend() # redo legend + return + def showHideLegend(self, actionChecked=None, repaint=True): if not self.__repaintOK(): # Show/hide legend is extremely costly return @@ -536,15 +590,8 @@ class XYView(View): curr_crv = self._model._currentCurve if curr_crv is not None : h, l = self._mplAxes.get_legend_handles_labels() - print(h) view = self._curveViews[curr_crv.getID()] - if curr_crv._name == "CurveModel": - whatToGet = view._mplLines[0] - elif curr_crv._name == "BarModel": - whatToGet = view._mplBars - else: - raise Exception("Invalid model for the current curve") - legCurr_idx = h.index(whatToGet) + legCurr_idx = h.index(view._mplArtist) legLabelCurr_crv = self._legend.get_texts()[legCurr_idx] legLabelCurr_crv.set_backgroundcolor('0.85') else : @@ -578,18 +625,26 @@ class XYView(View): if curr_crv is None: dlg.colorCurve.setEnabled(False) dlg.markerCurve.setEnabled(False) + dlg.sliderOpacity.setEnabled(False) dlg.setSelectedCurveName("") view = None else: dlg.colorCurve.setEnabled(True) + dlg.sliderOpacity.setEnabled(True) + + # dlg.sliderOpacity.valueChanged.connect(dlg.onOpacityChanged()) name = curr_crv.getTitle() dlg.setSelectedCurveName(name) view = self._curveViews[curr_crv.getID()] color = view.getColor() + + opacity = view.getInitialAlpha() + dlg.sliderOpacity.setValue(opacity*100) + rgb = colors.colorConverter.to_rgb(color) dlg.setRGB(rgb[0],rgb[1],rgb[2]) - if curr_crv._name == "CurveModel": + if (curr_crv._name == "CurveModel" or curr_crv._name == "StemModel"): # List of markers dlg.markerCurve.show() dlg.markerCurveLabel.show() @@ -652,7 +707,9 @@ class XYView(View): if view: view.setColor(dlg.getRGB()) crvModel = view._model - if curr_crv._name == "CurveModel": + newOpacity = dlg.sliderOpacity.value() / 100. + view.setInitialAlpha(newOpacity) + if (curr_crv._name == "CurveModel" or curr_crv._name == "StemModel"): view.setMarker(self.CURVE_MARKERS[dlg.markerCurve.currentIndex()]) if dlg.nameCurve.text() != crvModel.getTitle(): Logger.Debug("XYView : about to cahnge crv title after settings") @@ -673,18 +730,37 @@ class XYView(View): pass def onCurrentCurveChange(self): - Logger.Debug("XYView::onCurrentCurveChange()") + Logger.Debug("XYView::onCurrentCurveChange() : CALL") curr_crv2 = self._model.getCurrentCurve() + + if self._currCrv is None : + id_debug1 = "None" + else : + id_debug1 = self._currCrv.getID() + + if curr_crv2 is None : + id_debug2 = "None" + else : + id_debug2 = curr_crv2.getID() + + Logger.Debug(f"XYView::onCurrentCurveChange() : Curr crv 1 ID : {id_debug1}") + Logger.Debug(f"XYView::onCurrentCurveChange() : Curr crv 2 ID : {id_debug2}") + if curr_crv2 != self._currCrv: + Logger.Debug("XYView::onCurrentCurveChange() : NEW CURVE SELECTED") if self._currCrv is not None: + Logger.Debug("XYView::onCurrentCurveChange() : Toggle -> False") view = self._curveViews[self._currCrv.getID()] view.toggleHighlight(False) if not curr_crv2 is None: + Logger.Debug("XYView::onCurrentCurveChange() : Toggle -> True") view = self._curveViews[curr_crv2.getID()] view.toggleHighlight(True) self._currCrv = curr_crv2 self.showHideLegend(repaint=False) # redo legend self.repaint() + Logger.Debug("XYView::onCurrentCurveChange() : REPAINT") + Logger.Debug("XYView::onCurrentCurveChange() : END") def changeFormatAxis(self) : if not self.__repaintOK(): @@ -716,15 +792,15 @@ class XYView(View): set_mod = set(self._model._curves.keys()) set_view = set(self._curveViews.keys()) - Logger.Debug(" --- List of models ID: {}".format(set_mod)) - Logger.Debug(" --- List of views ID: {}".format(set_view)) + # Logger.Debug(" --- List of models ID: {}".format(set_mod)) + # Logger.Debug(" --- List of views ID: {}".format(set_view)) # Deleted/Added curves: dels = set_view - set_mod added = set_mod - set_view - Logger.Debug(" --- List of dels ID: {}".format(dels)) - Logger.Debug(" --- List of added ID: {}".format(added)) + # Logger.Debug(" --- List of dels ID: {}".format(dels)) + # Logger.Debug(" --- List of added ID: {}".format(added)) for d in dels: self.removeCurve(d) @@ -739,6 +815,8 @@ class XYView(View): self.appendCurve(a) elif ( self._model._curves[a]._name == "BarModel" ) : self.appendBarplot(a) + elif ( self._model._curves[a]._name == "StemModel" ) : + self.appendStemplot(a) else: # Should not happen raise Exception("Invalid specified curve type")