From 89f93c70eda6f91440e88af501c2fc1d34cf9df4 Mon Sep 17 00:00:00 2001 From: Henri Payno Date: Thu, 8 Aug 2019 13:40:24 +0200 Subject: [PATCH] [orangecontrib] normalization work - orange signal 'spectra' is renamed xas_obj - update to the new orange way to define Input and Output - add a converter widget to convert from xas object to data table --- doc/tutorials/example_larch.ows | 8 +- doc/tutorials/example_pymca.ows | 10 +- orangecontrib/xas/process.py | 6 +- orangecontrib/xas/test/test_larch_workflow.py | 10 +- orangecontrib/xas/test/test_pymca_workflow.py | 10 +- orangecontrib/xas/utils/converter.py | 4 + orangecontrib/xas/widgets/larch/autobk.py | 25 ++- orangecontrib/xas/widgets/larch/mback.py | 25 ++- orangecontrib/xas/widgets/larch/mback_norm.py | 25 ++- orangecontrib/xas/widgets/larch/pre_edge.py | 25 ++- orangecontrib/xas/widgets/larch/xftf.py | 25 ++- orangecontrib/xas/widgets/pymca/exafs.py | 28 +++- orangecontrib/xas/widgets/pymca/ft.py | 24 ++- orangecontrib/xas/widgets/pymca/k_weight.py | 24 ++- .../xas/widgets/pymca/normalization.py | 25 ++- orangecontrib/xas/widgets/utils/converter.py | 69 +++++++++ .../xas/widgets/utils/icons/converter.png | Bin 0 -> 4212 bytes .../xas/widgets/utils/icons/converter.svg | 143 ++++++++++++++++++ orangecontrib/xas/widgets/utils/roi.py | 27 +++- orangecontrib/xas/widgets/utils/xas_input.py | 10 +- orangecontrib/xas/widgets/utils/xas_output.py | 9 +- xas/pushworkflowactors/test/test_workflow.py | 16 +- 22 files changed, 474 insertions(+), 74 deletions(-) create mode 100644 orangecontrib/xas/widgets/utils/converter.py create mode 100644 orangecontrib/xas/widgets/utils/icons/converter.png create mode 100644 orangecontrib/xas/widgets/utils/icons/converter.svg diff --git a/doc/tutorials/example_larch.ows b/doc/tutorials/example_larch.ows index 7e792a7..fa486c1 100644 --- a/doc/tutorials/example_larch.ows +++ b/doc/tutorials/example_larch.ows @@ -8,10 +8,10 @@ - - - - + + + + A File widget. Double click to open it and select the dataset file. diff --git a/doc/tutorials/example_pymca.ows b/doc/tutorials/example_pymca.ows index a41e2a5..2f498e6 100644 --- a/doc/tutorials/example_pymca.ows +++ b/doc/tutorials/example_pymca.ows @@ -9,11 +9,11 @@ - - - - - + + + + + A File widget. Double click to open it and select the dataset file. diff --git a/orangecontrib/xas/process.py b/orangecontrib/xas/process.py index a7d5351..3bc1d51 100644 --- a/orangecontrib/xas/process.py +++ b/orangecontrib/xas/process.py @@ -37,11 +37,13 @@ _logger = logging.getLogger(__file__) class _ProcessForOrangeMixIn(object): """ - Group processing and progress display in a common class for pymca process. + Group processing and progress display in a common class for xasObject + process. If this process own a widget to display the xas object then this one should be named '_window' """ + def __init__(self): # progress self._progress = gui.ProgressBar(self, 100) @@ -73,7 +75,7 @@ class _ProcessForOrangeMixIn(object): if hasattr(self, '_window') and hasattr(self._window, 'xasObjViewer'): self._window.xasObjViewer.setXASObj(xas_obj=xas_obj) # emit signal for the plot - self.send("spectra", xas_obj) + self.Outputs.res_xas_obj.send(xas_obj) def _canProcess(self): return self.__processingThread is None or not self.__processingThread.isRunning() diff --git a/orangecontrib/xas/test/test_larch_workflow.py b/orangecontrib/xas/test/test_larch_workflow.py index c39e835..41fc0b7 100644 --- a/orangecontrib/xas/test/test_larch_workflow.py +++ b/orangecontrib/xas/test/test_larch_workflow.py @@ -88,11 +88,11 @@ class TestSimpleLarchWorkflow(OrangeWorflowTest): cls.processOrangeEvents(cls) - cls.link(cls, xasInputNode, "spectra", xasPreEdgeNode, "spectra") - cls.link(cls, xasPreEdgeNode, "spectra", xasAutobkNode, "spectra") - cls.link(cls, xasAutobkNode, "spectra", xasXFTFNode, "spectra") - cls.link(cls, xasXFTFNode, "spectra", xasMBackNormNode, "spectra") - cls.link(cls, xasMBackNormNode, "spectra", xasOutputNode, "spectra") + cls.link(cls, xasInputNode, "xas_obj", xasPreEdgeNode, "xas_obj") + cls.link(cls, xasPreEdgeNode, "xas_obj", xasAutobkNode, "xas_obj") + cls.link(cls, xasAutobkNode, "xas_obj", xasXFTFNode, "xas_obj") + cls.link(cls, xasXFTFNode, "xas_obj", xasMBackNormNode, "xas_obj") + cls.link(cls, xasMBackNormNode, "xas_obj", xasOutputNode, "xas_obj") cls.processOrangeEvents(cls) cls.xasInputWidget = cls.getWidgetForNode(cls, xasInputNode) diff --git a/orangecontrib/xas/test/test_pymca_workflow.py b/orangecontrib/xas/test/test_pymca_workflow.py index cb53c13..fad06fc 100644 --- a/orangecontrib/xas/test/test_pymca_workflow.py +++ b/orangecontrib/xas/test/test_pymca_workflow.py @@ -86,11 +86,11 @@ class TestSimplePyMcaWorkflow(OrangeWorflowTest): cls.processOrangeEvents(cls) - cls.link(cls, xasInputNode, "spectra", xasNormalizationNode, "spectra") - cls.link(cls, xasNormalizationNode, "spectra", xasEXAFSNode, "spectra") - cls.link(cls, xasEXAFSNode, "spectra", xasKWeightNode, "spectra") - cls.link(cls, xasKWeightNode, "spectra", xasFTNode, "spectra") - cls.link(cls, xasFTNode, "spectra", xasOutputNode, "spectra") + cls.link(cls, xasInputNode, "xas_obj", xasNormalizationNode, "xas_obj") + cls.link(cls, xasNormalizationNode, "xas_obj", xasEXAFSNode, "xas_obj") + cls.link(cls, xasEXAFSNode, "xas_obj", xasKWeightNode, "xas_obj") + cls.link(cls, xasKWeightNode, "xas_obj", xasFTNode, "xas_obj") + cls.link(cls, xasFTNode, "xas_obj", xasOutputNode, "xas_obj") cls.processOrangeEvents(cls) cls.xasInputWidget = cls.getWidgetForNode(cls, xasInputNode) diff --git a/orangecontrib/xas/utils/converter.py b/orangecontrib/xas/utils/converter.py index 12649f7..3f87477 100644 --- a/orangecontrib/xas/utils/converter.py +++ b/orangecontrib/xas/utils/converter.py @@ -51,6 +51,10 @@ class Converter(object): @staticmethod def toDataTable(xas_object): + _logger.warning('casting xas_object to Orange.data.Table might bring ' + 'lost of some information (process flow, ' + 'treatment result...). Only keep energy and absorbed ' + 'beam information') spectra = XASObject._spectra_volume(xas_object.spectra, key='mu', dim_1=xas_object.dim1, diff --git a/orangecontrib/xas/widgets/larch/autobk.py b/orangecontrib/xas/widgets/larch/autobk.py index 68c2384..2404189 100644 --- a/orangecontrib/xas/widgets/larch/autobk.py +++ b/orangecontrib/xas/widgets/larch/autobk.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt from silx.gui.plot import LegendSelector import xas.core.process.larch.autobk @@ -42,6 +44,7 @@ from xas.core.types import XASObject, Spectrum from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType from xas.gui.larch.autobk import _AutobkParameters from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -139,15 +142,22 @@ class AutobkOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.larch.autobk.Larch_autobk _settings = Setting(dict()) """Store the configuration of the PyMca XASClass""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -172,6 +182,13 @@ class AutobkOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._settings = self._window._parametersWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/larch/mback.py b/orangecontrib/xas/widgets/larch/mback.py index 37b742a..e0fa473 100644 --- a/orangecontrib/xas/widgets/larch/mback.py +++ b/orangecontrib/xas/widgets/larch/mback.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt from silx.gui.plot import LegendSelector import xas.core.process.larch.mback @@ -43,6 +45,7 @@ from xas.gui.XasObjectViewer import XasObjectViewer, ViewType from xas.gui.larch.mback import _MBackParameters from orangecontrib.xas.progress import QProgress from xas.gui.XasObjectViewer import _plot_norm, _plot_raw, _plot_fpp, _plot_f2 +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -115,15 +118,22 @@ class MbackOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.larch.mback.Larch_mback _larchSettings = Setting(dict()) """Store the configuration of the larch configuration""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -147,6 +157,13 @@ class MbackOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._larchSettings = self._window._parametersWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/larch/mback_norm.py b/orangecontrib/xas/widgets/larch/mback_norm.py index 37bf74f..f71abd1 100644 --- a/orangecontrib/xas/widgets/larch/mback_norm.py +++ b/orangecontrib/xas/widgets/larch/mback_norm.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt from silx.gui.plot import LegendSelector import xas.core.process.larch.mback_norm @@ -43,6 +45,7 @@ from xas.gui.XasObjectViewer import XasObjectViewer, ViewType from xas.gui.XasObjectViewer import _plot_norm, _plot_mback_mu from xas.gui.larch.mback import _MBackParameters from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -115,15 +118,22 @@ class Mback_normOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.larch.mback_norm.Larch_mback_norm _larchSettings = Setting(dict()) """Store the configuration of the larch configuration""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -147,6 +157,13 @@ class Mback_normOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._larchSettings = self._window._parametersWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/larch/pre_edge.py b/orangecontrib/xas/widgets/larch/pre_edge.py index 5412383..e37dcc0 100644 --- a/orangecontrib/xas/widgets/larch/pre_edge.py +++ b/orangecontrib/xas/widgets/larch/pre_edge.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt from silx.gui.plot import LegendSelector import xas.core.process.larch.pre_edge @@ -44,6 +46,7 @@ from xas.gui.XasObjectViewer import (_plot_edge, _plot_norm, _plot_norm_area, _plot_post_edge, _plot_pre_edge) from xas.gui.larch.pre_edge import _MPreEdgeParameters from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -125,15 +128,22 @@ class PreEdgeOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.larch.pre_edge.Larch_pre_edge _larchSettings = Setting(dict()) """Store the configuration of the larch configuration""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -157,6 +167,13 @@ class PreEdgeOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._larchSettings = self._window._parametersWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/larch/xftf.py b/orangecontrib/xas/widgets/larch/xftf.py index 4749348..c44b845 100644 --- a/orangecontrib/xas/widgets/larch/xftf.py +++ b/orangecontrib/xas/widgets/larch/xftf.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt from silx.gui.plot import LegendSelector import xas.core.process.larch.xftf @@ -42,6 +44,7 @@ from xas.core.types import XASObject, Spectrum from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType from xas.gui.larch.xftf import _MXFTFParameters from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -163,15 +166,22 @@ class XFTFOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.larch.xftf.Larch_xftf _larchSettings = Setting(dict()) """Store the configuration of the larch configuration""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -195,6 +205,13 @@ class XFTFOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._larchSettings = self._window._parametersWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/pymca/exafs.py b/orangecontrib/xas/widgets/pymca/exafs.py index 9acf599..38b5437 100644 --- a/orangecontrib/xas/widgets/pymca/exafs.py +++ b/orangecontrib/xas/widgets/pymca/exafs.py @@ -34,6 +34,9 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data +from xas.core.types import XASObject from PyMca5.PyMcaGui.physics.xas.XASPostEdgeParameters import \ XASPostEdgeParameters from silx.gui import qt @@ -42,9 +45,11 @@ from silx.gui.plot import LegendSelector import xas.core.process.pymca.exafs from orangecontrib.xas.process import _ProcessForOrangeMixIn, \ ProcessRunnable -from xas.core.types import XASObject, Spectrum +from xas.core.types import Spectrum from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter + _logger = logging.getLogger(__file__) @@ -165,14 +170,22 @@ class ExafsOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.pymca.exafs.PyMca_exafs _larchSettings = Setting(dict()) """Store the configuration of the PyMca XASClass""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -199,6 +212,13 @@ class ExafsOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._larchSettings = self._window._pymcaWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/pymca/ft.py b/orangecontrib/xas/widgets/pymca/ft.py index 89ddcc0..aa14074 100644 --- a/orangecontrib/xas/widgets/pymca/ft.py +++ b/orangecontrib/xas/widgets/pymca/ft.py @@ -34,6 +34,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from PyMca5.PyMcaGui.physics.xas.XASFourierTransformParameters import \ XASFourierTransformParameters from silx.gui import qt @@ -45,6 +47,7 @@ from orangecontrib.xas.process import _ProcessForOrangeMixIn, \ from xas.core.types import XASObject, Spectrum from xas.gui.XasObjectViewer import XasObjectViewer, _CurveOperation, ViewType from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -189,14 +192,22 @@ class FTOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.pymca.ft.PyMca_ft _pymcaSettings = Setting(dict()) """Store the configuration of the PyMca XASClass""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -219,6 +230,13 @@ class FTOW(_ProcessForOrangeMixIn, OWWidget): if self._latest_xas_obj: self.process(xas_obj=self._latest_xas_obj) + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/pymca/k_weight.py b/orangecontrib/xas/widgets/pymca/k_weight.py index e58d317..d2c6b76 100644 --- a/orangecontrib/xas/widgets/pymca/k_weight.py +++ b/orangecontrib/xas/widgets/pymca/k_weight.py @@ -33,6 +33,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from silx.gui import qt import xas.core.process.pymca.k_weight @@ -40,6 +42,7 @@ from orangecontrib.xas.process import _ProcessForOrangeMixIn, \ ProcessRunnable from xas.core.types import XASObject from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -79,14 +82,22 @@ class KWeightOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.pymca.k_weight.PyMca_k_weight _kWeightSetting = Setting(int(3)) """Store the configuration of the PyMca XASClass""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -109,6 +120,13 @@ class KWeightOW(_ProcessForOrangeMixIn, OWWidget): if self._latest_xas_obj: self.process(self._latest_xas_obj) + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/pymca/normalization.py b/orangecontrib/xas/widgets/pymca/normalization.py index 7dbce4d..557d9dc 100644 --- a/orangecontrib/xas/widgets/pymca/normalization.py +++ b/orangecontrib/xas/widgets/pymca/normalization.py @@ -34,6 +34,8 @@ import logging from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data from PyMca5.PyMcaGui.physics.xas.XASNormalizationParameters import \ XASNormalizationParameters from silx.gui import qt @@ -46,6 +48,7 @@ from orangecontrib.xas.process import ProcessRunnable from xas.core.types import XASObject from xas.gui.XasObjectViewer import XasObjectViewer, ViewType from orangecontrib.xas.progress import QProgress +from orangecontrib.xas.utils import Converter _logger = logging.getLogger(__file__) @@ -116,15 +119,22 @@ class NormalizationOW(_ProcessForOrangeMixIn, OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, "process")] - - outputs = [("spectra", XASObject), ("curves", tuple)] - process_function = xas.core.process.pymca.normalization.PyMca_normalization _pymcaSettings = Setting(dict()) """Store the configuration of the PyMca XASClass""" + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._latest_xas_obj = None @@ -152,6 +162,13 @@ class NormalizationOW(_ProcessForOrangeMixIn, OWWidget): def _update_settings(self): self._pymcaSettings = self._window._pymcaWindow.getParameters() + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/orangecontrib/xas/widgets/utils/converter.py b/orangecontrib/xas/widgets/utils/converter.py new file mode 100644 index 0000000..684ed62 --- /dev/null +++ b/orangecontrib/xas/widgets/utils/converter.py @@ -0,0 +1,69 @@ +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2016-2017 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ + +__authors__ = ["H. Payno"] +__license__ = "MIT" +__date__ = "08/08/2019" + + +from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +from xas.core.types import XASObject +from orangecontrib.xas.utils import Converter +import Orange.data + + +class ConverterOW(OWWidget): + """ + Offer a conversion from XASObject to Orange.data.Table, commonly used + from Orange widget + """ + name = "converter xas_obj -> Table" + id = "orange.widgets.xas.utils.converter" + description = "convert a XASObject to a Orange.data.Table" + icon = "icons/converter.png" + priority = 5 + category = "esrfWidgets" + keywords = ["spectroscopy", "signal", "output", "file"] + + want_main_area = False + resizing_enabled = False + + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + + class Outputs: + res_data_table = Output('Data', Orange.data.Table) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + + @Inputs.xas_obj + def process(self, xas_object): + if xas_object is None: + return + data_table = Converter.toDataTable(xas_object=xas_object) + self.Outputs.res_data_table.send(data_table) \ No newline at end of file diff --git a/orangecontrib/xas/widgets/utils/icons/converter.png b/orangecontrib/xas/widgets/utils/icons/converter.png new file mode 100644 index 0000000000000000000000000000000000000000..50aca4d2d95b990a92b0e7e4839f732a74a509dd GIT binary patch literal 4212 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 + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/orangecontrib/xas/widgets/utils/roi.py b/orangecontrib/xas/widgets/utils/roi.py index ef373b6..02742c7 100644 --- a/orangecontrib/xas/widgets/utils/roi.py +++ b/orangecontrib/xas/widgets/utils/roi.py @@ -29,10 +29,12 @@ __date__ = "02/10/2018" import logging -from Orange.canvas.registry.description import InputSignal, OutputSignal from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Input, Output +import Orange.data +from orangecontrib.xas.utils import Converter from silx.gui import qt import xas.core.process.roi @@ -57,9 +59,6 @@ class RoiSelectionOW(OWWidget): category = "esrfWidgets" keywords = ["dataset", "data", "selection", "ROI", "Region of Interest"] - inputs = [InputSignal(name="spectra", type=XASObject, handler='process')] - outputs = [OutputSignal(name="spectra", type=XASObject)] - process_function = xas.core.process.roi.ROIProcess want_main_area = True @@ -69,6 +68,17 @@ class RoiSelectionOW(OWWidget): _roi_origin = Setting(tuple()) _roi_size = Setting(tuple()) + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + # simple compatibility for some Orange widget and especialy the + # 'spectroscopy add-on' + data_table = Input('Data', Orange.data.Table) + + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() @@ -89,6 +99,13 @@ class RoiSelectionOW(OWWidget): self.setROI = self._widget.setROI self.getROI = self._widget.getROI + @Inputs.data_table + def processFrmDataTable(self, data_table): + if data_table is None: + return + self.process(Converter.toXASObject(data_table=data_table)) + + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return @@ -112,7 +129,7 @@ class RoiSelectionOW(OWWidget): # we want to keep the raw data in roi object, to be able to resize # the roi (especially increase it size) xas_obj = roi_process.process(xas_obj=self._widget.getXasObject().copy()) - self.send("spectra", xas_obj) + self.Outputs.res_xas_obj.send(xas_obj) except Exception as e: _logger.error(e) else: diff --git a/orangecontrib/xas/widgets/utils/xas_input.py b/orangecontrib/xas/widgets/utils/xas_input.py index 37357a9..76ca5f0 100644 --- a/orangecontrib/xas/widgets/utils/xas_input.py +++ b/orangecontrib/xas/widgets/utils/xas_input.py @@ -34,6 +34,7 @@ import os from Orange.widgets import gui from Orange.widgets.settings import Setting from Orange.widgets.widget import OWWidget +from Orange.widgets.widget import Output from silx.gui import qt from silx.io.url import DataUrl @@ -62,8 +63,6 @@ class XASInputOW(OWWidget): want_main_area = True resizing_enabled = True - outputs = [("spectra", XASObject)] - _input_file_setting = Setting(str()) _spectra_url_setting = Setting(str()) _energy_url_setting = Setting(str()) @@ -71,6 +70,11 @@ class XASInputOW(OWWidget): process_function = xas.core.io.read_frm_file + class Outputs: + res_xas_obj = Output('xas_obj', XASObject) + # by default we want to avoid sending 'Orange.data.Table' to avoid + # loosing the XASObject flow process and results. + def __init__(self): super().__init__() self._inputWindow = qt.QWidget(parent=self) @@ -111,7 +115,7 @@ class XASInputOW(OWWidget): roiProcess = ROIProcess() roiProcess.setRoi(origin=(0, 0), size=(10, 10)) xas_obj = roiProcess.process(xas_obj) - self.send("spectra", xas_obj) + self.Outputs.res_xas_obj.send(xas_obj) def _manageSettings(self): input_type = xas.io.InputType.hdf5_spectra diff --git a/orangecontrib/xas/widgets/utils/xas_output.py b/orangecontrib/xas/widgets/utils/xas_output.py index 43aaf00..1cb975e 100644 --- a/orangecontrib/xas/widgets/utils/xas_output.py +++ b/orangecontrib/xas/widgets/utils/xas_output.py @@ -30,8 +30,9 @@ __date__ = "06/11/2019" from Orange.widgets import gui from Orange.widgets.widget import OWWidget -from silx.gui import qt from Orange.widgets.settings import Setting +from Orange.widgets.widget import Input +from silx.gui import qt from xas.core.types import XASObject import xas.core.io import logging @@ -54,11 +55,12 @@ class XASOutputOW(OWWidget): want_main_area = True resizing_enabled = True - inputs = [("spectra", XASObject, 'process')] - _output_file_setting = Setting(str()) process_function = xas.core.io.XASWriter + class Inputs: + xas_obj = Input('xas_obj', XASObject, default=True) + def __init__(self): super().__init__() self._outputWindow = qt.QWidget(parent=self) @@ -114,6 +116,7 @@ class XASOutputOW(OWWidget): def _getFileSelected(self): return self._inputLe.text() + @Inputs.xas_obj def process(self, xas_obj): if xas_obj is None: return diff --git a/xas/pushworkflowactors/test/test_workflow.py b/xas/pushworkflowactors/test/test_workflow.py index c028341..d097aa3 100644 --- a/xas/pushworkflowactors/test/test_workflow.py +++ b/xas/pushworkflowactors/test/test_workflow.py @@ -66,14 +66,14 @@ class TestWorkflowFunctions(unittest.TestCase): read_task, normalization_task, exafs_task, k_weight_task, ft_task) links = [ - Link(source_node=read_task, source_channel='spectra', - sink_node=normalization_task, sink_channel='spectra'), - Link(source_node=normalization_task, source_channel='spectra', - sink_node=exafs_task, sink_channel='spectra'), - Link(source_node=exafs_task, source_channel='spectra', - sink_node=k_weight_task, sink_channel='spectra'), - Link(source_node=k_weight_task, source_channel='spectra', - sink_node=ft_task, sink_channel='spectra'), + Link(source_node=read_task, source_channel='xas_obj', + sink_node=normalization_task, sink_channel='xas_obj'), + Link(source_node=normalization_task, source_channel='xas_obj', + sink_node=exafs_task, sink_channel='xas_obj'), + Link(source_node=exafs_task, source_channel='xas_obj', + sink_node=k_weight_task, sink_channel='xas_obj'), + Link(source_node=k_weight_task, source_channel='xas_obj', + sink_node=ft_task, sink_channel='xas_obj'), ] self.scheme = Scheme(nodes=nodes, links=links) -- GitLab