summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2018-09-20 09:58:07 +0200
committerPicca Frédéric-Emmanuel <picca@debian.org>2018-09-20 09:58:07 +0200
commit184bbc8e7e31657479978aff481f9d96d344e376 (patch)
treecd7182afcc53e0cd730ecdd13f579b4abc29bdd8
parent0c737c7331790e9825a69d65b26d08075aded68a (diff)
New upstream version 5.4.0+dfsg
-rw-r--r--MANIFEST.in9
-rw-r--r--PKG-INFO4
-rw-r--r--PyMca5.egg-info/PKG-INFO4
-rw-r--r--PyMca5.egg-info/SOURCES.txt137
-rw-r--r--PyMca5.egg-info/requires.txt2
-rw-r--r--PyMca5/EPDL97/EADLParser.py172
-rw-r--r--PyMca5/EPDL97/EPDL97Parser.py136
-rw-r--r--PyMca5/Object3D/ClippingPlaneConfiguration.py19
-rw-r--r--PyMca5/Object3D/GLToolBar.py1
-rw-r--r--PyMca5/Object3D/GLWidgetCachePixmap.py10
-rw-r--r--PyMca5/Object3D/Object3DBase.py9
-rw-r--r--PyMca5/Object3D/Object3DColormap.py17
-rw-r--r--PyMca5/PyMcaCore/EdfFileDataSource.py21
-rw-r--r--PyMca5/PyMcaCore/EdfFileLayer.py20
-rw-r--r--PyMca5/PyMcaCore/EventHandler.py7
-rw-r--r--PyMca5/PyMcaCore/HtmlIndex.py9
-rw-r--r--PyMca5/PyMcaCore/LoggingLevel.py89
-rw-r--r--PyMca5/PyMcaCore/NexusDataSource.py44
-rw-r--r--PyMca5/PyMcaCore/NexusTools.py13
-rw-r--r--PyMca5/PyMcaCore/Plugin1DBase.py29
-rw-r--r--PyMca5/PyMcaCore/Plugin2DBase.py124
-rw-r--r--PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py21
-rw-r--r--PyMca5/PyMcaCore/PyMcaDirs.py13
-rw-r--r--PyMca5/PyMcaCore/PyMcaMatplotlibSave.py10
-rw-r--r--PyMca5/PyMcaCore/SpecFileDataSource.py30
-rw-r--r--PyMca5/PyMcaCore/SpsDataSource.py13
-rw-r--r--PyMca5/PyMcaCore/StackBase.py186
-rw-r--r--PyMca5/PyMcaCore/StackPluginBase.py18
-rw-r--r--PyMca5/PyMcaCore/StackROIBatch.py12
-rw-r--r--PyMca5/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html24
-rw-r--r--PyMca5/PyMcaGraph/Colormap.py9
-rw-r--r--PyMca5/PyMcaGraph/Colors.py10
-rw-r--r--PyMca5/PyMcaGraph/Plot.py12
-rw-r--r--PyMca5/PyMcaGraph/PlotBackend.py10
-rw-r--r--PyMca5/PyMcaGraph/PlotBase.py13
-rw-r--r--PyMca5/PyMcaGraph/PluginLoader.py17
-rw-r--r--PyMca5/PyMcaGraph/backends/__init__.py9
-rw-r--r--PyMca5/PyMcaGui/PluginsToolButton.py41
-rw-r--r--PyMca5/PyMcaGui/PyMcaQt.py18
-rw-r--r--PyMca5/PyMcaGui/__init__.py5
-rw-r--r--PyMca5/PyMcaGui/io/QEdfFileWidget.py336
-rw-r--r--PyMca5/PyMcaGui/io/QSelectorWidget.py18
-rw-r--r--PyMca5/PyMcaGui/io/QSourceSelector.py19
-rw-r--r--PyMca5/PyMcaGui/io/QSpecFileWidget.py48
-rw-r--r--PyMca5/PyMcaGui/io/QSpsWidget.py106
-rw-r--r--PyMca5/PyMcaGui/io/SpecFileCntTable.py3
-rw-r--r--PyMca5/PyMcaGui/io/SpecFileMcaTable.py11
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/HDF5CounterTable.py7
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/HDF5McaTable.py7
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/HDF5Selection.py2
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/HDF5Widget.py12
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/Hdf5NodeView.py103
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/QNexusWidget.py70
-rw-r--r--PyMca5/PyMcaGui/io/hdf5/QNexusWidgetActions.py17
-rw-r--r--PyMca5/PyMcaGui/math/FFTAlignmentWindow.py1
-rw-r--r--PyMca5/PyMcaGui/math/NNMADialog.py25
-rw-r--r--PyMca5/PyMcaGui/math/PCADialog.py27
-rw-r--r--PyMca5/PyMcaGui/math/PCAWindow.py23
-rw-r--r--PyMca5/PyMcaGui/math/SGWindow.py29
-rw-r--r--PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py16
-rw-r--r--PyMca5/PyMcaGui/math/SNIPWindow.py62
-rw-r--r--PyMca5/PyMcaGui/math/SimpleActions.py322
-rw-r--r--PyMca5/PyMcaGui/math/StripBackgroundWidget.py37
-rw-r--r--PyMca5/PyMcaGui/math/fitting/McaTable.py8
-rw-r--r--PyMca5/PyMcaGui/math/fitting/MultiParameters.py8
-rw-r--r--PyMca5/PyMcaGui/math/fitting/Parameters.py69
-rw-r--r--PyMca5/PyMcaGui/math/fitting/RateLawWindow.py44
-rw-r--r--PyMca5/PyMcaGui/math/fitting/SimpleFitConfigurationGui.py37
-rw-r--r--PyMca5/PyMcaGui/math/fitting/SimpleFitGui.py71
-rw-r--r--PyMca5/PyMcaGui/math/fitting/SpecfitGui.py31
-rw-r--r--PyMca5/PyMcaGui/math/fitting/TextField.py11
-rw-r--r--PyMca5/PyMcaGui/misc/DoubleSlider.py8
-rw-r--r--PyMca5/PyMcaGui/misc/SelectionTable.py1
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASFourierTransformParameters.py33
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASNormalizationParameters.py33
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASNormalizationWindow.py64
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASParameters.py11
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASPostEdgeParameters.py27
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASSelfattenuationWindow.py21
-rw-r--r--PyMca5/PyMcaGui/physics/xas/XASWindow.py93
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/AttenuatorsTable.py25
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/ConcentrationsWidget.py21
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/ElementsInfo.py14
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/EnergyTable.py50
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/FastXRFLinearFitWindow.py4
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/FitParam.py43
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/FitPeakSelect.py9
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/MaterialEditor.py55
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/McaAdvancedFit.py412
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/McaAdvancedTable.py13
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/McaCalWidget.py132
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/PeakIdentifier.py7
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/PeakTableWidget.py64
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/QXTube.py66
-rw-r--r--PyMca5/PyMcaGui/physics/xrf/StrategyHandler.py17
-rw-r--r--PyMca5/PyMcaGui/plotting/ColormapDialog.py75
-rw-r--r--PyMca5/PyMcaGui/plotting/ImageView.py898
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskImageTools.py6
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskImageWidget.py291
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskScatterWidget.py584
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskToolBar.py331
-rw-r--r--PyMca5/PyMcaGui/plotting/McaROIWidget.py26
-rw-r--r--PyMca5/PyMcaGui/plotting/PlotWidget.py15
-rw-r--r--PyMca5/PyMcaGui/plotting/PlotWindow.py5
-rw-r--r--PyMca5/PyMcaGui/plotting/ProfileScanWidget.py4
-rw-r--r--PyMca5/PyMcaGui/plotting/PyMca_Icons.py13
-rw-r--r--PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py11
-rw-r--r--PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py178
-rw-r--r--PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py4
-rw-r--r--PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py32
-rw-r--r--PyMca5/PyMcaGui/plotting/_ImageProfile.py34
-rw-r--r--PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py24
-rw-r--r--PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py13
-rw-r--r--PyMca5/PyMcaGui/pymca/LegacyScanWindow.py1591
-rw-r--r--PyMca5/PyMcaGui/pymca/Mca2Edf.py9
-rw-r--r--PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py26
-rw-r--r--PyMca5/PyMcaGui/pymca/McaLegendselector.py103
-rw-r--r--PyMca5/PyMcaGui/pymca/McaWindow.py1151
-rw-r--r--PyMca5/PyMcaGui/pymca/Median2DBrowser.py12
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaBatch.py99
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaGLWindow.py36
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaHKLImageWindow.py9
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaImageWindow.py27
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaMain.py206
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaMdi.py27
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaNexusWidget.py20
-rw-r--r--PyMca5/PyMcaGui/pymca/PyMcaPostBatch.py8
-rw-r--r--PyMca5/PyMcaGui/pymca/QDispatcher.py108
-rw-r--r--PyMca5/PyMcaGui/pymca/QHDF5Stack1D.py3
-rw-r--r--PyMca5/PyMcaGui/pymca/QHDF5StackWizard.py138
-rw-r--r--PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave.py55
-rw-r--r--PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave1D.py9
-rw-r--r--PyMca5/PyMcaGui/pymca/QSource.py33
-rw-r--r--PyMca5/PyMcaGui/pymca/QStackWidget.py196
-rw-r--r--PyMca5/PyMcaGui/pymca/RGBCorrelator.py10
-rw-r--r--PyMca5/PyMcaGui/pymca/RGBCorrelatorSlider.py13
-rw-r--r--PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py14
-rw-r--r--PyMca5/PyMcaGui/pymca/RGBImageCalculator.py16
-rw-r--r--PyMca5/PyMcaGui/pymca/ScanFitToolButton.py158
-rw-r--r--PyMca5/PyMcaGui/pymca/ScanWindow.py1854
-rw-r--r--PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py333
-rw-r--r--PyMca5/PyMcaGui/pymca/StackBrowser.py7
-rw-r--r--PyMca5/PyMcaGui/pymca/StackSelector.py9
-rw-r--r--PyMca5/PyMcaGui/pymca/SumRulesTool.py234
-rw-r--r--PyMca5/PyMcaGui/pymca/XMCDWindow.py218
-rw-r--r--PyMca5/PyMcaIO/ArraySave.py302
-rw-r--r--PyMca5/PyMcaIO/BAXSCSVFileParser.py7
-rw-r--r--PyMca5/PyMcaIO/EDFStack.py31
-rw-r--r--PyMca5/PyMcaIO/EdfFile.py33
-rw-r--r--PyMca5/PyMcaIO/HDF5Stack1D.py51
-rw-r--r--PyMca5/PyMcaIO/JcampFileParser.py33
-rw-r--r--PyMca5/PyMcaIO/JcampReader.py21
-rw-r--r--PyMca5/PyMcaIO/LispixMap.py46
-rw-r--r--PyMca5/PyMcaIO/MRCMap.py7
-rw-r--r--PyMca5/PyMcaIO/NumpyStack.py2
-rw-r--r--PyMca5/PyMcaIO/OlympusCSVFileParser.py9
-rw-r--r--PyMca5/PyMcaIO/OmnicMap.py40
-rw-r--r--PyMca5/PyMcaIO/PilatusCBF.py28
-rw-r--r--PyMca5/PyMcaIO/SRSFileParser.py7
-rw-r--r--PyMca5/PyMcaIO/SpecFileAbstractClass.py22
-rw-r--r--PyMca5/PyMcaIO/SpecFileStack.py23
-rw-r--r--PyMca5/PyMcaIO/SupaVisioMap.py9
-rw-r--r--PyMca5/PyMcaIO/TextImageStack.py16
-rw-r--r--PyMca5/PyMcaIO/ThermoEMSFileParser.py9
-rw-r--r--PyMca5/PyMcaIO/TiffIO.py78
-rw-r--r--PyMca5/PyMcaIO/specfile/src/sfinit.c26
-rw-r--r--PyMca5/PyMcaIO/specfilewrapper.py37
-rw-r--r--PyMca5/PyMcaMath/SimpleMath.py15
-rw-r--r--PyMca5/PyMcaMath/fitting/SimpleFitAll.py3
-rw-r--r--PyMca5/PyMcaMath/fitting/SimpleFitModule.py101
-rw-r--r--PyMca5/PyMcaMath/fitting/Specfit.py29
-rw-r--r--PyMca5/PyMcaMath/fitting/SpecfitFunctions.py6
-rw-r--r--PyMca5/PyMcaMath/fitting/StackSimpleFit.py31
-rw-r--r--PyMca5/PyMcaMath/mva/NNMAModule.py13
-rw-r--r--PyMca5/PyMcaMath/mva/PCAModule.py59
-rw-r--r--PyMca5/PyMcaMath/mva/PCATools.py58
-rw-r--r--PyMca5/PyMcaMisc/PhysicalMemory.py9
-rw-r--r--PyMca5/PyMcaPhysics/xas/XASClass.py76
-rw-r--r--PyMca5/PyMcaPhysics/xas/XASNormalization.py16
-rw-r--r--PyMca5/PyMcaPhysics/xas/XASStackBatch.py21
-rw-r--r--PyMca5/PyMcaPhysics/xrf/ClassMcaTheory.py42
-rw-r--r--PyMca5/PyMcaPhysics/xrf/Elements.py6
-rw-r--r--PyMca5/PyMcaPhysics/xrf/FastXRFLinearFit.py72
-rw-r--r--PyMca5/PyMcaPhysics/xrf/FisxHelper.py208
-rw-r--r--PyMca5/PyMcaPhysics/xrf/SingleLayerStrategy.py15
-rw-r--r--PyMca5/PyMcaPhysics/xrf/XRFMC/XMSOParser.py23
-rw-r--r--PyMca5/PyMcaPlugins/AdvancedAlignmentScanPlugin.py189
-rw-r--r--PyMca5/PyMcaPlugins/AlignmentScanPlugin.py8
-rw-r--r--PyMca5/PyMcaPlugins/BackgroundStackPlugin.py6
-rw-r--r--PyMca5/PyMcaPlugins/ExternalImagesStackPlugin.py11
-rw-r--r--PyMca5/PyMcaPlugins/FastXRFLinearFitStackPlugin.py20
-rw-r--r--PyMca5/PyMcaPlugins/FitStackPlugin.py10
-rw-r--r--PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py93
-rw-r--r--PyMca5/PyMcaPlugins/KineticsPlugin.py12
-rw-r--r--PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py13
-rw-r--r--PyMca5/PyMcaPlugins/Medfilt2DPlugin.py208
-rw-r--r--PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py18
-rw-r--r--PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py13
-rw-r--r--PyMca5/PyMcaPlugins/MotorInfoPlugin.py10
-rw-r--r--PyMca5/PyMcaPlugins/MotorInfoWindow.py15
-rw-r--r--PyMca5/PyMcaPlugins/MultipleScanToMeshPlugin.py20
-rw-r--r--PyMca5/PyMcaPlugins/NNMAStackPlugin.py38
-rw-r--r--PyMca5/PyMcaPlugins/PCAStackPlugin.py16
-rw-r--r--PyMca5/PyMcaPlugins/ROIStackPlugin.py28
-rw-r--r--PyMca5/PyMcaPlugins/RegularMeshPlugin.py26
-rw-r--r--PyMca5/PyMcaPlugins/ReverseStackPlugin.py7
-rw-r--r--PyMca5/PyMcaPlugins/SilxRoiStackPlugin.py13
-rw-r--r--PyMca5/PyMcaPlugins/StackAxesPlugin.py7
-rw-r--r--PyMca5/PyMcaPlugins/StackBrowserPlugin.py23
-rw-r--r--PyMca5/PyMcaPlugins/StackNormalizationPlugin.py9
-rw-r--r--PyMca5/PyMcaPlugins/StackROIBatchPlugin.py23
-rw-r--r--PyMca5/PyMcaPlugins/StackScanWindowPlugin.py9
-rw-r--r--PyMca5/PyMcaPlugins/StackShowSpectra.py21
-rw-r--r--PyMca5/PyMcaPlugins/XASPlugin.py11
-rw-r--r--PyMca5/PyMcaPlugins/XASStackBatchPlugin.py17
-rw-r--r--PyMca5/PyMcaPlugins/XASStackNormalizationPlugin.py12
-rw-r--r--PyMca5/PyMcaPlugins/XMCDPlugin.py20
-rw-r--r--PyMca5/PyMcaPlugins/optional/JsonRpc1DPlugin.py10
-rw-r--r--PyMca5/PyMcaPlugins/optional/TaurusPlugin1D.py29
-rw-r--r--PyMca5/__init__.py36
-rw-r--r--PyMca5/tests/ElementsTest.py16
-rw-r--r--PyMca5/tests/WidgetsTest.py111
-rw-r--r--changelog.txt19
-rw-r--r--cx_setup.py11
-rw-r--r--doc/man/pymca.19
-rw-r--r--doc/man/pymcaroitool.19
-rw-r--r--doc/source/customization/index.rst2
-rw-r--r--doc/source/customization/plugins/plugins1d.rst10
-rw-r--r--doc/source/customization/plugins/stackplugins.rst4
-rw-r--r--doc/source/customization/settings.rst4
-rw-r--r--doc/source/customization/settings/img/settings_01.pngbin0 -> 10733 bytes
-rw-r--r--doc/source/customization/settings/img/settings_02.pngbin0 -> 26112 bytes
-rw-r--r--doc/source/customization/settings/index.rst71
-rw-r--r--doc/source/index.rst3
-rw-r--r--doc/source/license.rst2
-rw-r--r--doc/source/recipes.rst7
-rw-r--r--doc/source/recipes/recipescode/GenerateHDF5Stack.py105
-rw-r--r--doc/source/recipes/xrfembedpyqt.rst15
-rw-r--r--doc/source/recipes/xrfhdf5stack.rst87
-rw-r--r--doc/source/training/matrix/img/matrix_01.pngbin0 -> 110739 bytes
-rw-r--r--doc/source/training/matrix/img/matrix_02.pngbin0 -> 54887 bytes
-rw-r--r--doc/source/training/matrix/img/matrix_03.pngbin0 -> 56825 bytes
-rw-r--r--doc/source/training/matrix/img/matrix_04.pngbin0 -> 15242 bytes
-rw-r--r--doc/source/training/matrix/img/tertiary_01.pngbin0 -> 18372 bytes
-rw-r--r--doc/source/training/matrix/img/tertiary_03.pngbin0 -> 56151 bytes
-rw-r--r--doc/source/training/matrix/img/tertiary_04.pngbin0 -> 43209 bytes
-rw-r--r--doc/source/training/matrix/index.rst83
-rw-r--r--doc/source/training/quantification/img/quantification_01.pngbin0 -> 134481 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_02.pngbin0 -> 133255 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_03.pngbin0 -> 133429 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_04.pngbin0 -> 153974 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_05.pngbin0 -> 119006 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_06.pngbin0 -> 29025 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_07.pngbin0 -> 72960 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_08.pngbin0 -> 127428 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_09.pngbin0 -> 122441 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_10.pngbin0 -> 147754 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_11.pngbin0 -> 131580 bytes
-rw-r--r--doc/source/training/quantification/img/quantification_12.pngbin0 -> 127802 bytes
-rw-r--r--doc/source/training/quantification/index.rst221
-rw-r--r--doc/source/training/tertiary/img/tertiary_01.pngbin0 -> 18372 bytes
-rw-r--r--doc/source/training/tertiary/img/tertiary_02.pngbin0 -> 111921 bytes
-rw-r--r--doc/source/training/tertiary/img/tertiary_03.pngbin0 -> 56151 bytes
-rw-r--r--doc/source/training/tertiary/img/tertiary_04.pngbin0 -> 43209 bytes
-rw-r--r--doc/source/training/tertiary/index.rst65
-rw-r--r--doc/source/training/xraydata/img/xraydata_01.pngbin0 -> 76401 bytes
-rw-r--r--doc/source/training/xraydata/img/xraydata_02.pngbin0 -> 80811 bytes
-rw-r--r--doc/source/training/xraydata/index.rst71
-rw-r--r--doc/source/tutorials.rst43
-rw-r--r--package/debian8/changelog6
-rw-r--r--package/debian8/control86
-rw-r--r--package/debian9/changelog6
-rw-r--r--package/debian9/control8
-rw-r--r--requirements.txt4
-rw-r--r--setup.py2
275 files changed, 9502 insertions, 7645 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index b7d32b2..3bde16e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -46,14 +46,5 @@ recursive-include PyMca5/scripts *
recursive-include PyMca5/tests *.py
recursive-include third-party/qhull *.c *.h *.txt
recursive-include third-party/khronos_headers *.h
-include third-party/fisx/changelog.txt
-include third-party/fisx/LICENSE
-include third-party/fisx/MANIFEST.in
-include third-party/fisx/README.rst
-include third-party/fisx/setup.py
-include third-party/fisx/TODO
-recursive-include third-party/fisx/fisx_data *.dat
-recursive-include third-party/fisx/python *.py *.pyx *.pxd *.cpp
-recursive-include third-party/fisx/src *.h *.cpp
recursive-include scripts *.py *.bat
recursive-include package *
diff --git a/PKG-INFO b/PKG-INFO
index d997002..cf22011 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: PyMca5
-Version: 5.3.2
+Version: 5.4.0
Summary: Mapping and X-Ray Fluorescence Analysis
Home-page: http://pymca.sourceforge.net
Author: V. Armando Sole
Author-email: sole@esrf.fr
License: MIT
-Download-URL: https://github.com/vasole/pymca/archive/v5.3.2.tar.gz
+Download-URL: https://github.com/vasole/pymca/archive/v5.4.0.tar.gz
Description: Stand-alone application and Python tools for interactive and/or batch processing analysis of X-Ray Fluorescence Spectra. Graphical user interface (GUI) and batch processing capabilities provided
Platform: any
diff --git a/PyMca5.egg-info/PKG-INFO b/PyMca5.egg-info/PKG-INFO
index d997002..cf22011 100644
--- a/PyMca5.egg-info/PKG-INFO
+++ b/PyMca5.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: PyMca5
-Version: 5.3.2
+Version: 5.4.0
Summary: Mapping and X-Ray Fluorescence Analysis
Home-page: http://pymca.sourceforge.net
Author: V. Armando Sole
Author-email: sole@esrf.fr
License: MIT
-Download-URL: https://github.com/vasole/pymca/archive/v5.3.2.tar.gz
+Download-URL: https://github.com/vasole/pymca/archive/v5.4.0.tar.gz
Description: Stand-alone application and Python tools for interactive and/or batch processing analysis of X-Ray Fluorescence Spectra. Graphical user interface (GUI) and batch processing capabilities provided
Platform: any
diff --git a/PyMca5.egg-info/SOURCES.txt b/PyMca5.egg-info/SOURCES.txt
index 40702b0..950923c 100644
--- a/PyMca5.egg-info/SOURCES.txt
+++ b/PyMca5.egg-info/SOURCES.txt
@@ -99,9 +99,11 @@ PyMca5/PyMcaCore/EdfFileDataSource.py
PyMca5/PyMcaCore/EdfFileLayer.py
PyMca5/PyMcaCore/EventHandler.py
PyMca5/PyMcaCore/HtmlIndex.py
+PyMca5/PyMcaCore/LoggingLevel.py
PyMca5/PyMcaCore/NexusDataSource.py
PyMca5/PyMcaCore/NexusTools.py
PyMca5/PyMcaCore/Plugin1DBase.py
+PyMca5/PyMcaCore/Plugin2DBase.py
PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py
PyMca5/PyMcaCore/PyMcaDirs.py
PyMca5/PyMcaCore/PyMcaLogo.py
@@ -389,6 +391,7 @@ PyMca5/PyMcaGui/math/PCAWindow.py
PyMca5/PyMcaGui/math/SGWindow.py
PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py
PyMca5/PyMcaGui/math/SNIPWindow.py
+PyMca5/PyMcaGui/math/SimpleActions.py
PyMca5/PyMcaGui/math/StripBackgroundWidget.py
PyMca5/PyMcaGui/math/__init__.py
PyMca5/PyMcaGui/math/fitting/CheckField.py
@@ -460,6 +463,7 @@ PyMca5/PyMcaGui/plotting/LegendSelector.py
PyMca5/PyMcaGui/plotting/MaskImageTools.py
PyMca5/PyMcaGui/plotting/MaskImageWidget.py
PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
+PyMca5/PyMcaGui/plotting/MaskToolBar.py
PyMca5/PyMcaGui/plotting/McaROIWidget.py
PyMca5/PyMcaGui/plotting/ObjectPrintConfigurationDialog.py
PyMca5/PyMcaGui/plotting/PlotWidget.py
@@ -479,9 +483,11 @@ PyMca5/PyMcaGui/pymca/ChangeLog.py
PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py
PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py
PyMca5/PyMcaGui/pymca/Fit2Spec.py
+PyMca5/PyMcaGui/pymca/LegacyScanWindow.py
PyMca5/PyMcaGui/pymca/Mca2Edf.py
PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py
PyMca5/PyMcaGui/pymca/McaCustomEvent.py
+PyMca5/PyMcaGui/pymca/McaLegendselector.py
PyMca5/PyMcaGui/pymca/McaSimpleFit.py
PyMca5/PyMcaGui/pymca/McaWindow.py
PyMca5/PyMcaGui/pymca/Median2DBrowser.py
@@ -511,6 +517,7 @@ PyMca5/PyMcaGui/pymca/RGBCorrelatorTable.py
PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py
PyMca5/PyMcaGui/pymca/RGBImageCalculator.py
PyMca5/PyMcaGui/pymca/ScanFit.py
+PyMca5/PyMcaGui/pymca/ScanFitToolButton.py
PyMca5/PyMcaGui/pymca/ScanWindow.py
PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py
PyMca5/PyMcaGui/pymca/SilxExternalImagesWindow.py
@@ -715,6 +722,7 @@ PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py
PyMca5/PyMcaPlugins/KineticsPlugin.py
PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py
PyMca5/PyMcaPlugins/MathPlugins.py
+PyMca5/PyMcaPlugins/Medfilt2DPlugin.py
PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py
PyMca5/PyMcaPlugins/MedianFilterScanPlugin.py
PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py
@@ -767,6 +775,7 @@ PyMca5/tests/SpecfileTest.py
PyMca5/tests/StackBaseTest.py
PyMca5/tests/StackInfoTest.py
PyMca5/tests/TestAll.py
+PyMca5/tests/WidgetsTest.py
PyMca5/tests/XrfTest.py
PyMca5/tests/__init__.py
PyMca5/tests/specfilewrapperTest.py
@@ -786,20 +795,55 @@ doc/source/index.rst
doc/source/install.rst
doc/source/license.rst
doc/source/overview.rst
+doc/source/recipes.rst
doc/source/tutorials.rst
doc/source/_templates/localtoc.html
doc/source/_templates/pagesource.html
doc/source/customization/index.rst
-doc/source/customization/settings.rst
doc/source/customization/plugins/index.rst
doc/source/customization/plugins/plugins1d.rst
doc/source/customization/plugins/stackplugins.rst
+doc/source/customization/settings/index.rst
+doc/source/customization/settings/img/settings_01.png
+doc/source/customization/settings/img/settings_02.png
doc/source/hdf5/index.rst
doc/source/img/PyMca.ico
doc/source/img/PyMca_256x256.png
doc/source/modules/index.rst
doc/source/modules/core/index.rst
doc/source/modules/core/nexustools.rst
+doc/source/recipes/xrfembedpyqt.rst
+doc/source/recipes/xrfhdf5stack.rst
+doc/source/recipes/recipescode/GenerateHDF5Stack.py
+doc/source/training/matrix/index.rst
+doc/source/training/matrix/img/matrix_01.png
+doc/source/training/matrix/img/matrix_02.png
+doc/source/training/matrix/img/matrix_03.png
+doc/source/training/matrix/img/matrix_04.png
+doc/source/training/matrix/img/tertiary_01.png
+doc/source/training/matrix/img/tertiary_03.png
+doc/source/training/matrix/img/tertiary_04.png
+doc/source/training/quantification/index.rst
+doc/source/training/quantification/img/quantification_01.png
+doc/source/training/quantification/img/quantification_02.png
+doc/source/training/quantification/img/quantification_03.png
+doc/source/training/quantification/img/quantification_04.png
+doc/source/training/quantification/img/quantification_05.png
+doc/source/training/quantification/img/quantification_06.png
+doc/source/training/quantification/img/quantification_07.png
+doc/source/training/quantification/img/quantification_08.png
+doc/source/training/quantification/img/quantification_09.png
+doc/source/training/quantification/img/quantification_10.png
+doc/source/training/quantification/img/quantification_11.png
+doc/source/training/quantification/img/quantification_12.png
+doc/source/training/tertiary/index.rst
+doc/source/training/tertiary/img/tertiary_01.png
+doc/source/training/tertiary/img/tertiary_02.png
+doc/source/training/tertiary/img/tertiary_03.png
+doc/source/training/tertiary/img/tertiary_04.png
+doc/source/training/xraydata/index.rst
+doc/source/training/xraydata/img/xraydata_01.png
+doc/source/training/xraydata/img/xraydata_02.png
doc/source/xrf/material-definition/index.rst
doc/source/xrf/material-definition/img/materials_01.jpg
doc/source/xrf/material-definition/img/materials_02.jpg
@@ -853,97 +897,6 @@ scripts/pymcabatch.bat
scripts/pymcapostbatch.bat
scripts/pymcaroitool.bat
scripts/rgbcorrelator.bat
-third-party/fisx/LICENSE
-third-party/fisx/MANIFEST.in
-third-party/fisx/README.rst
-third-party/fisx/TODO
-third-party/fisx/changelog.txt
-third-party/fisx/setup.py
-third-party/fisx/fisx_data/BindingEnergies.dat
-third-party/fisx/fisx_data/EADL97_BindingEnergies.dat
-third-party/fisx/fisx_data/EADL97_KShellConstants.dat
-third-party/fisx/fisx_data/EADL97_KShellNonradiativeRates.dat
-third-party/fisx/fisx_data/EADL97_KShellRadiativeRates.dat
-third-party/fisx/fisx_data/EADL97_LShellConstants.dat
-third-party/fisx/fisx_data/EADL97_LShellNonradiativeRates.dat
-third-party/fisx/fisx_data/EADL97_LShellRadiativeRates.dat
-third-party/fisx/fisx_data/EADL97_MShellConstants.dat
-third-party/fisx/fisx_data/EADL97_MShellNonradiativeRates.dat
-third-party/fisx/fisx_data/EADL97_MShellRadiativeRates.dat
-third-party/fisx/fisx_data/EPDL97_CrossSections.dat
-third-party/fisx/fisx_data/KShellConstants.dat
-third-party/fisx/fisx_data/KShellRates.dat
-third-party/fisx/fisx_data/LShellConstants.dat
-third-party/fisx/fisx_data/LShellRates.dat
-third-party/fisx/fisx_data/MShellConstants.dat
-third-party/fisx/fisx_data/MShellRates.dat
-third-party/fisx/fisx_data/XCOM_CrossSections.dat
-third-party/fisx/python/cython/Detector.pxd
-third-party/fisx/python/cython/EPDL97.pxd
-third-party/fisx/python/cython/Element.pxd
-third-party/fisx/python/cython/Elements.pxd
-third-party/fisx/python/cython/Layer.pxd
-third-party/fisx/python/cython/Material.pxd
-third-party/fisx/python/cython/Math.pxd
-third-party/fisx/python/cython/PyDetector.pyx
-third-party/fisx/python/cython/PyEPDL97.pyx
-third-party/fisx/python/cython/PyElement.pyx
-third-party/fisx/python/cython/PyElements.pyx
-third-party/fisx/python/cython/PyLayer.pyx
-third-party/fisx/python/cython/PyMaterial.pyx
-third-party/fisx/python/cython/PyMath.pyx
-third-party/fisx/python/cython/PyShell.pyx
-third-party/fisx/python/cython/PySimpleIni.pyx
-third-party/fisx/python/cython/PySimpleSpecfile.pyx
-third-party/fisx/python/cython/PyVersion.pyx
-third-party/fisx/python/cython/PyXRF.pyx
-third-party/fisx/python/cython/Shell.pxd
-third-party/fisx/python/cython/SimpleIni.pxd
-third-party/fisx/python/cython/SimpleSpecfile.pxd
-third-party/fisx/python/cython/Version.pxd
-third-party/fisx/python/cython/XRF.pxd
-third-party/fisx/python/cython/_fisx.pyx
-third-party/fisx/python/cython/default/_fisx.cpp
-third-party/fisx/python/fisx/DataDir.py
-third-party/fisx/python/fisx/FisxCythonTools.py
-third-party/fisx/python/fisx/__init__.py
-third-party/fisx/python/fisx/tests/__init__.py
-third-party/fisx/python/fisx/tests/testAll.py
-third-party/fisx/python/fisx/tests/testDataDir.py
-third-party/fisx/python/fisx/tests/testEPDL97.py
-third-party/fisx/python/fisx/tests/testElements.py
-third-party/fisx/python/fisx/tests/testSimpleSpecfile.py
-third-party/fisx/python/fisx/tests/testXRF.py
-third-party/fisx/src/fisx_beam.cpp
-third-party/fisx/src/fisx_beam.h
-third-party/fisx/src/fisx_defaultelementsinfo.h
-third-party/fisx/src/fisx_detector.cpp
-third-party/fisx/src/fisx_detector.h
-third-party/fisx/src/fisx_element.cpp
-third-party/fisx/src/fisx_element.h
-third-party/fisx/src/fisx_elements.cpp
-third-party/fisx/src/fisx_elements.h
-third-party/fisx/src/fisx_epdl97.cpp
-third-party/fisx/src/fisx_epdl97.h
-third-party/fisx/src/fisx_layer.cpp
-third-party/fisx/src/fisx_layer.h
-third-party/fisx/src/fisx_material.cpp
-third-party/fisx/src/fisx_material.h
-third-party/fisx/src/fisx_math.cpp
-third-party/fisx/src/fisx_math.h
-third-party/fisx/src/fisx_multilayer.cpp
-third-party/fisx/src/fisx_shell.cpp
-third-party/fisx/src/fisx_shell.h
-third-party/fisx/src/fisx_simpleini.cpp
-third-party/fisx/src/fisx_simpleini.h
-third-party/fisx/src/fisx_simplespecfile.cpp
-third-party/fisx/src/fisx_simplespecfile.h
-third-party/fisx/src/fisx_version.cpp
-third-party/fisx/src/fisx_version.h
-third-party/fisx/src/fisx_xrf.cpp
-third-party/fisx/src/fisx_xrf.h
-third-party/fisx/src/fisx_xrfconfig.cpp
-third-party/fisx/src/fisx_xrfconfig.h
third-party/khronos_headers/GL/glcorearb.h
third-party/khronos_headers/GL/glext.h
third-party/khronos_headers/GL/glxext.h
diff --git a/PyMca5.egg-info/requires.txt b/PyMca5.egg-info/requires.txt
index 265c771..409ddbf 100644
--- a/PyMca5.egg-info/requires.txt
+++ b/PyMca5.egg-info/requires.txt
@@ -1,4 +1,4 @@
-fisx>=1.1.4
+fisx>=1.1.6
h5py
matplotlib>1.0
numpy
diff --git a/PyMca5/EPDL97/EADLParser.py b/PyMca5/EPDL97/EADLParser.py
index 7c22e57..72fb885 100644
--- a/PyMca5/EPDL97/EADLParser.py
+++ b/PyMca5/EPDL97/EADLParser.py
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
__doc__ =\
"""
The 1997 release of the Evaluated Atomic Data Library (EADL97)
@@ -159,7 +160,8 @@ SHELL_LIST = EADLSubshells.SHELL_LIST
getSubshellFromValue = EADLSubshells.getSubshellFromValue
getValueFromSubshell = EADLSubshells.getValueFromSubshell
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
AVOGADRO_NUMBER = 6.02214179E23
#
@@ -414,14 +416,14 @@ def parseHeader1(line):
ddict['subshell_code'] = 0
ddict['subshell'] = 'none'
else:
- print("Inconsistent data")
- print("X1 = ", X1, "S = ", S)
+ _logger.error("Inconsistent data")
+ _logger.error("X1 = %s; S = %s", X1, S)
sys.exit(1)
return ddict
def parseHeader(line0, line1):
- #print "line0 = ", line0
- #print "line1 = ", line1
+ #_logger.info "line0 = ", line0
+ #_logger.info "line1 = ", line1
ddict = parseHeader0(line0)
ddict.update(parseHeader1(line1))
return ddict
@@ -429,12 +431,12 @@ def parseHeader(line0, line1):
if 0:
ddict = parseHeader0(EADL97_DATA[0])
for key in ddict.keys():
- print(key, ddict[key])
+ _logger.info("%s: %s", key, ddict[key])
if 0:
ddict = parseHeader1(EADL97_DATA[1])
for key in ddict.keys():
- print(key, ddict[key])
+ _logger.info("%s: %s", key, ddict[key])
def getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I):
@@ -459,59 +461,46 @@ def getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I):
try:
ddict = parseHeader(lines[i], lines[i+1])
except:
- print("Error with lines")
- print("line index = %d" % i)
- print(lines[i])
- print(lines[i+1])
- print(sys.exc_info())
+ _logger.error("Error with lines")
+ _logger.error("line index = %d", i)
+ _logger.error(lines[i])
+ _logger.error(lines[i+1])
+ _logger.error(sys.exc_info())
raise
if 0:
- print(ddict['Z'], z)
- print(ddict['Yi'], Yi)
- print(ddict['C'], C)
- print(ddict['S'], S)
- print(ddict['X1'], X1)
- print(ddict['Yo'], Yo)
- print(ddict['I'], I)
- if DEBUG:
- if ddict['Z'] == z:
- print("Z found")
- if ddict['Yi'] == Yi:
- print("Yi found")
- if ddict['C'] == C:
- print("C found")
- if ddict['S'] == S:
- print("S found with X1 = ", ddict['X1'])
- print("Requested X1 = ", X1)
- print(lines[i])
- print(lines[i+1])
- if ddict['X1'] == X1:
- print("Requested Yo = ", Yo)
- print("Found Yo = ", ddict['Yo'])
- if ddict['Yo'] == Yo:
- print("Requested I = ",I)
- if ddict['I'] == I:
- print("FOUND!")
- print(lines[i])
- print(lines[i+1])
- LAST_INDEX = i - 1
- return i
- break
- else:
- if ddict['Z'] == z:
- if ddict['Yi'] == Yi:
- if ddict['C'] == C:
- if ddict['S'] == S:
- if ddict['X1'] == X1:
- if ddict['Yo'] == Yo:
- if ddict['I'] == I:
- LAST_INDEX = i - 1
- return i
- break
+ _logger.info("%s, %s", ddict['Z'], z)
+ _logger.info("%s, %s", ddict['Yi'], Yi)
+ _logger.info("%s, %s", ddict['C'], C)
+ _logger.info("%s, %s", ddict['S'], S)
+ _logger.info("%s, %s", ddict['X1'], X1)
+ _logger.info("%s, %s", ddict['Yo'], Yo)
+ _logger.info("%s, %s", ddict['I'], I)
+
+ if ddict['Z'] == z:
+ _logger.debug("Z found")
+ if ddict['Yi'] == Yi:
+ _logger.debug("Yi found")
+ if ddict['C'] == C:
+ _logger.debug("C found")
+ if ddict['S'] == S:
+ _logger.debug("S found with X1 = %s", ddict['X1'])
+ _logger.debug("Requested X1 = %s", X1)
+ _logger.debug(lines[i])
+ _logger.debug(lines[i+1])
+ if ddict['X1'] == X1:
+ _logger.debug("Requested Yo = %s", Yo)
+ _logger.debug("Found Yo = %s", ddict['Yo'])
+ if ddict['Yo'] == Yo:
+ _logger.debug("Requested I = %s", I)
+ if ddict['I'] == I:
+ _logger.debug("FOUND!")
+ _logger.debug(lines[i])
+ _logger.debug(lines[i+1])
+ LAST_INDEX = i - 1
+ return i
i += 1
if LAST_INDEX > 0:
- if DEBUG:
- print("REPEATING")
+ _logger.debug("REPEATING")
LAST_INDEX = -1
return getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I)
return -1
@@ -524,13 +513,12 @@ def getActualDataFromLinesAndOffset(lines, index):
data_end += 1
end_line = lines[data_end + 1]
data_end += 1
- if DEBUG:
- print("COMPLETE DATA SET")
- print(lines[index:data_end])
- print("END DATA SET")
- print("ADDITIONAL LINE")
- print(lines[data_end])
- print("END ADDITIONAL LINE")
+ _logger.debug("COMPLETE DATA SET")
+ _logger.debug(lines[index:data_end])
+ _logger.debug("END DATA SET")
+ _logger.debug("ADDITIONAL LINE")
+ _logger.debug(lines[data_end])
+ _logger.debug("END ADDITIONAL LINE")
ndata = data_end - data_begin
energy = numpy.zeros((ndata,), numpy.float)
t = lines[data_begin].split()
@@ -614,8 +602,7 @@ def getRadiativeWidths(z, lines=None):
if index < 0:
raise IOError("Requested data not found")
shell_codes, value = getActualDataFromLinesAndOffset(lines, index)
- if DEBUG:
- print("shell_codes, value ",shell_codes, value)
+ _logger.debug("shell_codes %s, value %s", shell_codes, value)
i = 0
ddict = getBaseShellDict()
for code in shell_codes:
@@ -636,8 +623,7 @@ def getNonradiativeWidths(z, lines=None):
if index < 0:
raise IOError("Requested data not found")
shell_codes, value = getActualDataFromLinesAndOffset(lines, index)
- if DEBUG:
- print("shell_codes, value ",shell_codes, value)
+ _logger.debug("shell_codes %s, value %s", shell_codes, value)
i = 0
ddict = getBaseShellDict()
for code in shell_codes:
@@ -673,8 +659,7 @@ def getRadiativeTransitionProbabilities(z, shell='K', lines=None):
#this error may happen when requesting non existing data too
raise IOError("Requested data not found")
shell_codes, values = getActualDataFromLinesAndOffset(lines, index)
- if DEBUG:
- print("shell_codes, values ",shell_codes, values)
+ _logger.debug("shell_codes %s, values %s", shell_codes, values)
i = 0
ddict = getBaseShellDict(nvalues=2)
for code in shell_codes:
@@ -711,8 +696,7 @@ def getNonradiativeTransitionProbabilities(z, shell='K', lines=None):
#this error may happen when requesting non existing data too
raise IOError("Requested data not found")
shell_codes, values = getActualDataFromLinesAndOffset(lines, index)
- if DEBUG:
- print("shell_codes, values ",shell_codes, values)
+ _logger.debug("shell_codes %s, values %s", shell_codes, values)
i = 0
ddict = {}#getBaseShellDict()
for code in shell_codes:
@@ -737,8 +721,7 @@ def getBindingEnergies(z, lines=None):
if index < 0:
raise IOError("Requested data not found")
shell_codes, value = getActualDataFromLinesAndOffset(lines, index)
- if DEBUG:
- print("shell_codes, value ",shell_codes, value)
+ _logger.debug("shell_codes %s, value %s", shell_codes, value)
i = 0
ddict = getBaseShellDict()
for code in shell_codes:
@@ -841,41 +824,41 @@ if __name__ == "__main__":
element = sys.argv[1]
else:
element = 'Pb'
- print("Getting binding energies for element %s" % element)
+ _logger.info("Getting binding energies for element %s", element)
ddict = getBindingEnergies(Elements.index(element)+1)
for key in getBaseShellList():
if ddict[key] > 0.0:
- print("Shell = %s Energy (keV) = %.7E" % (key, ddict[key] * 1000.))
- print("Getting fluorescence yields for element %s" % element)
+ _logger.info("Shell = %s Energy (keV) = %.7E", key, ddict[key] * 1000.)
+ _logger.info("Getting fluorescence yields for element %s", element)
ddict = getFluorescenceYields(Elements.index(element)+1)
for key in getBaseShellList():
if key in ddict:
if ddict[key] > 0.0:
- print("Shell = %s Yield = %.7E" % (key, ddict[key]))
+ _logger.info("Shell = %s Yield = %.7E", key, ddict[key])
#total_emission = 0.0
for shell in ['K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5']:
try:
ddict = getRadiativeTransitionProbabilities(Elements.index(element)+1,
- shell=shell)
- print("%s Shell radiative emission probabilities " % shell)
+ shell=shell)
+ _logger.info("%s Shell radiative emission probabilities ", shell)
except IOError:
continue
total = 0.0
for key in getBaseShellList():
if key in ddict:
if ddict[key][0] > 0.0:
- print("Shell = %s Yield = %.7E Energy = %.7E" % (key, ddict[key][0],
- ddict[key][1] * 1000.))
+ _logger.info("Shell = %s Yield = %.7E Energy = %.7E",
+ key, ddict[key][0], ddict[key][1] * 1000.)
total += ddict[key][0]
- print("Total %s-shell emission probability = %.7E" % (shell, total))
+ _logger.info("Total %s-shell emission probability = %.7E", shell, total)
#total_emission += total
- #print "total_emission = ", total_emission
+ #_logger.info "total_emission = ", total_emission
for shell in ['K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5']:
try:
ddict = getNonradiativeTransitionProbabilities(Elements.index(element)+1,
- shell=shell)
- print("%s Shell Nonradiative emission probabilities " % shell)
+ shell=shell)
+ _logger.info("%s Shell Nonradiative emission probabilities ", shell)
except IOError:
continue
total = 0.0
@@ -885,12 +868,13 @@ if __name__ == "__main__":
key = "%s-%s%s" % (shell, key0.split()[0], key1.split()[0])
if key in ddict:
if ddict[key][0] > 0.0:
- print("Shell = %s Yield = %.7E Energy = %.7E" %\
- (key, ddict[key][0], ddict[key][1] * 1000.))
+ _logger.info("Shell = %s Yield = %.7E Energy = %.7E",
+ key, ddict[key][0], ddict[key][1] * 1000.)
total += ddict[key][0]
- print("Total %s-shell non-radiative emission probability = %.7E" % (shell, total))
+ _logger.info("Total %s-shell non-radiative emission probability = %.7E",
+ shell, total)
if shell in ['K']:
- for key0 in ['L1', 'L2' ,'L3']:
+ for key0 in ['L1', 'L2', 'L3']:
subtotal = 0.0
for key1 in shell_list:
tmpKey = key1.split()[0]
@@ -900,10 +884,10 @@ if __name__ == "__main__":
subtotal += ddict[key][0]
if tmpKey == key0:
subtotal += ddict[key][0]
- print("%s vacancies for nonradiative transition to %s shell = %.7E"%\
- (key0, shell, subtotal))
+ _logger.info("%s vacancies for nonradiative transition to %s shell = %.7E",
+ key0, shell, subtotal)
- #print(getNonradiativeTransitionProbabilities(Elements.index(element)+1, 'L1'))
- print(getMShellCosterKronigYields(Elements.index(element)+1))
- print("atomic weight = ", getAtomicWeights()[Elements.index(element)])
+ #_logger.info(getNonradiativeTransitionProbabilities(Elements.index(element)+1, 'L1'))
+ _logger.info(getMShellCosterKronigYields(Elements.index(element)+1))
+ _logger.info("atomic weight = %s", getAtomicWeights()[Elements.index(element)])
sys.exit(0)
diff --git a/PyMca5/EPDL97/EPDL97Parser.py b/PyMca5/EPDL97/EPDL97Parser.py
index 887d2ff..d6805a7 100644
--- a/PyMca5/EPDL97/EPDL97Parser.py
+++ b/PyMca5/EPDL97/EPDL97Parser.py
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
__doc__ =\
"""
The 1997 release of the Evaluated Photon Data Library (EPDL97)
@@ -213,7 +214,8 @@ SHELL_LIST = EADLSubshells
getSubshellFromValue = EADLSubshells.getSubshellFromValue
getValueFromSubshell = EADLSubshells.getValueFromSubshell
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
AVOGADRO_NUMBER = 6.02214179E23
#Read the EPDL library
@@ -463,8 +465,8 @@ def parseHeader1(line):
ddict['subshell_code'] = 0
ddict['subshell'] = 'none'
else:
- print("Inconsistent data")
- print("X1 = ", X1, "S = ", S)
+ _logger.error("Inconsistent data")
+ _logger.error("X1 = %s; S = %s", X1, S)
sys.exit(1)
return ddict
@@ -478,12 +480,12 @@ def parseHeader(line0, line1):
if 0:
ddict = parseHeader0(EPDL97_DATA[0])
for key in ddict.keys():
- print(key, ddict[key])
+ _logger.info("%s: %s", key, ddict[key])
if 0:
ddict = parseHeader1(EPDL97_DATA[1])
for key in ddict.keys():
- print (key, ddict[key])
+ _logger.info("%s: %s", key, ddict[key])
def getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I, getmode=True):
@@ -500,61 +502,46 @@ def getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I, getmode=True):
try:
ddict = parseHeader(lines[i], lines[i+1])
except:
- print("Error with lines")
- print(lines[i])
- print(lines[i+1])
- print(sys.exc_info())
+ _logger.error("Error with lines")
+ _logger.error(lines[i])
+ _logger.error(lines[i+1])
+ _logger.error(sys.exc_info())
raise
if 0:
- print(ddict['Z'], z)
- print(ddict['Yi'], Yi)
- print(ddict['C'], C)
- print(ddict['S'], S)
- print(ddict['X1'], X1)
- print(ddict['Yo'], Yo)
- print(ddict['I'], I)
- if DEBUG:
- if ddict['Z'] == z:
- print("Z found")
- if ddict['Yi'] == Yi:
- print("Yi found")
- if ddict['C'] == C:
- print("C found")
- if ddict['S'] == S:
- print("S found with X1 = ", ddict['X1'])
- print("Requested X1 = ", X1)
- print(lines[i])
- print(lines[i+1])
- if ddict['X1'] == X1:
- if ddict['Yo'] == Yo:
- if ddict['I'] == I:
- print("FOUND!")
- print(lines[i])
- print(lines[i+1])
- LAST_INDEX = i - 1
- if getmode:
- return i, ddict['interpolation_type']
- else:
- return i
- break
- else:
- if ddict['Z'] == z:
- if ddict['Yi'] == Yi:
- if ddict['C'] == C:
- if ddict['S'] == S:
- if ddict['X1'] == X1:
- if ddict['Yo'] == Yo:
- if ddict['I'] == I:
- LAST_INDEX = i - 1
- if getmode:
- return i, ddict['interpolation_type']
- else:
- return i
- break
+ _logger.info("%s, %s", ddict['Z'], z)
+ _logger.info("%s, %s", ddict['Yi'], Yi)
+ _logger.info("%s, %s", ddict['C'], C)
+ _logger.info("%s, %s", ddict['S'], S)
+ _logger.info("%s, %s", ddict['X1'], X1)
+ _logger.info("%s, %s", ddict['Yo'], Yo)
+ _logger.info("%s, %s", ddict['I'], I)
+
+ if ddict['Z'] == z:
+ _logger.debug("Z found")
+ if ddict['Yi'] == Yi:
+ _logger.debug("Yi found")
+ if ddict['C'] == C:
+ _logger.debug("C found")
+ if ddict['S'] == S:
+ _logger.debug("S found with X1 = %s", ddict['X1'])
+ _logger.debug("Requested X1 = %s", X1)
+ _logger.debug(lines[i])
+ _logger.debug(lines[i+1])
+ if ddict['X1'] == X1:
+ if ddict['Yo'] == Yo:
+ if ddict['I'] == I:
+ _logger.debug("FOUND!")
+ _logger.debug(lines[i])
+ _logger.debug(lines[i+1])
+ LAST_INDEX = i - 1
+ if getmode:
+ return i, ddict['interpolation_type']
+ else:
+ return i
+
i += 1
if LAST_INDEX > 0:
- if DEBUG:
- print("REPEATING")
+ _logger.debug("REPEATING")
LAST_INDEX = -1
return getDataLineIndex(lines, z, Yi, C, S, X1, Yo, I, getmode=getmode)
if getmode:
@@ -567,12 +554,11 @@ def getActualDataFromLinesAndOffset(lines, index):
data_end = index + 2
while len(lines[data_end].split()) == 2:
data_end += 1
- if DEBUG:
- print("COMPLETE DATA SET")
- print(lines[index:data_end])
- print("END DATA SET")
- print(lines[data_end])
- print("ADDITIONAL LINE")
+ _logger.debug("COMPLETE DATA SET")
+ _logger.debug(lines[index:data_end])
+ _logger.debug("END DATA SET")
+ _logger.debug(lines[data_end])
+ _logger.debug("ADDITIONAL LINE")
ndata = data_end - data_begin
energy = numpy.zeros((ndata,), numpy.float)
value = numpy.zeros((ndata,), numpy.float)
@@ -714,45 +700,45 @@ if __name__ == "__main__":
else:
Z = 82
energy, value, mode = getTotalCoherentCrossSection(Z, EPDL97_DATA, getmode=True)
- print("TOTAL COHERENT ", mode)
+ _logger.info("TOTAL COHERENT %s", mode)
for i in range(len(energy)):
if energy[i] > 0.010:
if energy[i] < 0.020:
- print(energy[i], value[i])
+ _logger.info("%s, %s", energy[i], value[i])
energy, value, mode = getTotalIncoherentCrossSection(Z, EPDL97_DATA , getmode=True)
- print("TOTAL INCOHERENT ", mode)
+ _logger.info("TOTAL INCOHERENT %s", mode)
for i in range(len(energy)):
if energy[i] > 0.010:
if energy[i] < 0.020:
- print(energy[i], value[i])
+ _logger.info("%s, %s", energy[i], value[i])
energy, value, mode = getTotalPhotoelectricCrossSection(Z, EPDL97_DATA, getmode=True)
- print("TOTAL PHOTOELECTRIC ", mode)
+ _logger.info("TOTAL PHOTOELECTRIC %s", mode)
for i in range(len(energy)):
if energy[i] > 0.010:
if energy[i] < 0.020:
- print(energy[i], value[i])
+ _logger.info("%s, %s", energy[i], value[i])
energy, value, mode = getTotalPairCrossSection(Z, EPDL97_DATA, getmode=True)
- print(" TOTAL PAIR ", mode)
+ _logger.info(" TOTAL PAIR %s", mode)
for i in range(len(energy)):
if energy[i] > 0.010:
if energy[i] < 0.020:
- print(energy[i], value[i])
+ _logger.info("%s, %s", energy[i], value[i])
energy, value, mode = getPartialPhotoelectricCrossSection(Z, 'L1', EPDL97_DATA, getmode=True)
- print("L1 SHELL PARTIAL PHOTOELECTRIC IDX")
+ _logger.info("L1 SHELL PARTIAL PHOTOELECTRIC IDX")
for i in range(len(energy)):
if energy[i] > 0.010:
if energy[i] < 0.020:
- print(energy[i], value[i], mode)
+ _logger.info("%s, %s, %s", energy[i], value[i], mode)
energy, value, mode = getPartialPhotoelectricCrossSection(Z, 'K', EPDL97_DATA, getmode=True)
- print("K SHELL PARTIAL PHOTOELECTRIC")
+ _logger.info("K SHELL PARTIAL PHOTOELECTRIC")
for i in range(len(energy)):
if energy[i] > 0.088:
if energy[i] < 0.090:
- print(energy[i], value[i], mode)
+ _logger.info("%s, %s, %s", energy[i], value[i], mode)
- print("atomic weight = ", getAtomicWeights()[Z-1])
+ _logger.info("atomic weight = %s", getAtomicWeights()[Z-1])
diff --git a/PyMca5/Object3D/ClippingPlaneConfiguration.py b/PyMca5/Object3D/ClippingPlaneConfiguration.py
index 6443752..092c1dc 100644
--- a/PyMca5/Object3D/ClippingPlaneConfiguration.py
+++ b/PyMca5/Object3D/ClippingPlaneConfiguration.py
@@ -30,8 +30,11 @@ from . import Object3DQt as qt
from . import Object3DSlider
from .Object3DMovement import Object3DRotationWidget, Object3DTranslationWidget
import numpy
+import logging
+
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class ClippingPlaneConfiguration(qt.QGroupBox):
sigClippingPlaneSignal = qt.pyqtSignal(object)
@@ -107,8 +110,7 @@ class ClippingPlaneConfiguration(qt.QGroupBox):
def _sliderSlot(self, *var):
if self.__disconnected: return
- if DEBUG:
- print("sliderSlot")
+ _logger.debug("sliderSlot")
for i in range(3):
value = self.planeList[i][5].value()
self.planeList[i][4].setText("%f" % value)
@@ -116,8 +118,7 @@ class ClippingPlaneConfiguration(qt.QGroupBox):
self._signal()
def _lineSlot(self):
- if DEBUG:
- print("lineSlot")
+ _logger.debug("lineSlot")
for i in range(3):
oldValue = self.planeList[i][5].value()
value = float(str(self.planeList[i][4].text()))
@@ -219,8 +220,7 @@ class UserClippingPlaneWidget(qt.QWidget):
def _emitSignal(self, event=None):
if self.__disconnected: return
- if DEBUG:
- print("Emitting UserClippingPlaneSignal")
+ _logger.debug("Emitting UserClippingPlaneSignal")
if event is None:
event="U0PlaneUpdated"
ddict = self.getParameters()
@@ -319,8 +319,7 @@ class ClippingPlaneWidget(qt.QWidget):
return [A, B, C, D]
def _emitSignal(self, event = None):
- if DEBUG:
- print("Emitting ClippingPlaneWidgetSignal")
+ _logger.debug("Emitting ClippingPlaneWidgetSignal")
if event is None:
event = 'ClippingPlaneWidgetUpdated'
ddict = self.standardClippingPlane.getParameters()
@@ -337,7 +336,7 @@ if __name__ == "__main__":
app = qt.QApplication(sys.argv)
def myslot(ddict):
print("Signal received")
- print("ddict = ", ddict)
+ print("ddict = %s" % ddict)
if 0:
w = ClippingPlaneConfiguration()
w.sigClippingPlaneSignal.connect(myslot)
diff --git a/PyMca5/Object3D/GLToolBar.py b/PyMca5/Object3D/GLToolBar.py
index 987574c..d843c0f 100644
--- a/PyMca5/Object3D/GLToolBar.py
+++ b/PyMca5/Object3D/GLToolBar.py
@@ -31,7 +31,6 @@ from . import Object3DQt as qt
from . import Object3DIcons
from .HorizontalSpacer import HorizontalSpacer
-DEBUG = 0
class GLToolBar(qt.QWidget):
diff --git a/PyMca5/Object3D/GLWidgetCachePixmap.py b/PyMca5/Object3D/GLWidgetCachePixmap.py
index bff365a..d82399d 100644
--- a/PyMca5/Object3D/GLWidgetCachePixmap.py
+++ b/PyMca5/Object3D/GLWidgetCachePixmap.py
@@ -32,7 +32,10 @@ except ImportError:
raise ImportError("OpenGL must be installed to use these functionalities")
from . import Object3DQt as qt
import numpy
-DEBUG = 0
+import logging
+
+_logger = logging.getLogger(__name__)
+
class GLWidgetCachePixmap(object):
def __init__(self, name="Unnamed"):
@@ -47,8 +50,7 @@ class GLWidgetCachePixmap(object):
return self.__textureId
def openGLCleanup(self):
- if DEBUG:
- print("CLEANING OPENGL")
+ _logger.debug("CLEANING OPENGL")
if self.drawList <= 0:
GL.glDeleteLists(self.drawList, 1)
self.drawList = 0
@@ -162,7 +164,7 @@ class GLWidgetCachePixmap(object):
GL.glDeleteTextures([self.__textureId])
self.__textureId = GL.glGenTextures(1)
if self.__textureId is None:
- print("no valid texture id?")
+ _logger.info("no valid texture id?")
return
if self._useNewTexture:
GL.glBindTexture(GL.GL_TEXTURE_2D, self.__textureId)
diff --git a/PyMca5/Object3D/Object3DBase.py b/PyMca5/Object3D/Object3DBase.py
index 1031f87..c77579b 100644
--- a/PyMca5/Object3D/Object3DBase.py
+++ b/PyMca5/Object3D/Object3DBase.py
@@ -26,6 +26,7 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "LGPL2+"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
import numpy
import weakref
import sys
@@ -37,7 +38,8 @@ try:
except ImportError:
raise ImportError("OpenGL must be installed to use these functionalities")
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
DRAW_MODES = ['NONE',
'POINT',
@@ -97,9 +99,8 @@ class Object3D(object):
if GL is not None:
if self.boundingBoxList != 0:
GL.glDeleteLists(self.boundingBoxList, 1)
- if DEBUG:
- print("DELETING Object3d base")
- print(self.name(), "DELETED")
+ _logger.debug("DELETING Object3d base")
+ _logger.debug("%s DELETED", self.name())
def name(self):
return self.__name
diff --git a/PyMca5/Object3D/Object3DColormap.py b/PyMca5/Object3D/Object3DColormap.py
index 2ffe3ea..9ae37ac 100644
--- a/PyMca5/Object3D/Object3DColormap.py
+++ b/PyMca5/Object3D/Object3DColormap.py
@@ -27,10 +27,13 @@ __contact__ = "sole@esrf.fr"
__license__ = "LGPL2+"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from . import Object3DQt as qt
from . import Object3DSlider
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
class Object3DColormap(qt.QGroupBox):
sigObject3DColormapSignal = qt.pyqtSignal(object)
@@ -200,8 +203,7 @@ class Object3DColormap(qt.QGroupBox):
def sliderChanged(self, value):
if self.__disconnected:
return
- if DEBUG:
- print("sliderChanged")
+ _logger.debug("sliderChanged")
value0 = self.sliderList[0].value()
value1 = self.sliderList[1].value()
self.maxText.setText("%f" % max(value0, value1))
@@ -212,8 +214,7 @@ class Object3DColormap(qt.QGroupBox):
self._emitSignal()
def _update(self):
- if DEBUG:
- print("colormap _update called")
+ _logger.debug("colormap _update called")
self.__disconnected = True
delta = (self.dataMax - self.dataMin)/ 200.
self.sliderList[0].setRange(self.dataMin, self.dataMax, delta)
@@ -233,15 +234,13 @@ class Object3DColormap(qt.QGroupBox):
return
if event is None:
event = 'ColormapChanged'
- if DEBUG:
- print("sending colormap")
+ _logger.debug("sending colormap")
ddict = self.getParameters()
ddict['event'] = event
self.sigObject3DColormapSignal.emit(ddict)
def setAutoscale(self, val):
- if DEBUG:
- print("setAutoscale called", val)
+ _logger.debug("setAutoscale called %s", val)
if val:
self.autoScaleButton.setChecked(True)
self.autoScale90Button.setChecked(False)
diff --git a/PyMca5/PyMcaCore/EdfFileDataSource.py b/PyMca5/PyMcaCore/EdfFileDataSource.py
index 35ecef3..72b3cf3 100644
--- a/PyMca5/PyMcaCore/EdfFileDataSource.py
+++ b/PyMca5/PyMcaCore/EdfFileDataSource.py
@@ -36,9 +36,12 @@ import types
import sys
import os
import numpy
+import logging
SOURCE_TYPE = "EdfFile"
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
class EdfFileDataSource(object):
def __init__(self,nameInput, fastedf=False):
@@ -60,7 +63,7 @@ class EdfFileDataSource(object):
#self._fastedf = True
self._fastedf = fastedf
if fastedf:
- print("fastedf is unsafe!")
+ _logger.warning("fastedf is unsafe!")
self.refresh()
def refresh(self):
@@ -98,8 +101,7 @@ class EdfFileDataSource(object):
return self.__getKeyInfo(key)
else:
#should we raise a KeyError?
- if DEBUG:
- print("Error key not in list ")
+ _logger.debug("Error key not in list ")
return {}
def __getKeyInfo(self,key):
@@ -109,8 +111,7 @@ class EdfFileDataSource(object):
image = int(image)-1
except:
#should we rise an error?
- if DEBUG:
- print("Error trying to interpret key =",key)
+ _logger.debug("Error trying to interpret key = %s", key)
return {}
sourceObject = self._sourceObjectList[index]
@@ -179,8 +180,7 @@ class EdfFileDataSource(object):
image = int(image)-1
MCAIMP = 0
if len(key_split) == 4:
- if DEBUG:
- print("mca like selection")
+ _logger.debug("mca like selection")
#print data.info
if 1:
MCAIMP = 1
@@ -192,8 +192,7 @@ class EdfFileDataSource(object):
size = (1,int(data.info['Dim_2']))
data.info['selectiontype'] = "1D"
else:
- if DEBUG:
- print("mca like selection not yet implemented")
+ _logger.debug("mca like selection not yet implemented")
pos = None
size = None
data.info['selectiontype'] = "1D"
@@ -263,7 +262,7 @@ if __name__ == "__main__":
sourcename=sys.argv[1]
key =sys.argv[2]
except:
- print("Usage: EdfFileDataSource <file> <key>")
+ _logger.error("Usage: EdfFileDataSource <file> <key>")
sys.exit()
#one can use this:
obj = EdfFileDataSource(sourcename)
diff --git a/PyMca5/PyMcaCore/EdfFileLayer.py b/PyMca5/PyMcaCore/EdfFileLayer.py
index de0fc14..4e8adbf 100644
--- a/PyMca5/PyMcaCore/EdfFileLayer.py
+++ b/PyMca5/PyMcaCore/EdfFileLayer.py
@@ -38,12 +38,14 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
################################################################################
+import logging
#import fast_EdfFile as EdfFile
from PyMca5.PyMcaIO import EdfFile
################################################################################
+_logger = logging.getLogger(__name__)
SOURCE_TYPE = "EdfFile"
-DEBUG = 0
+
class EdfFileLayer(object):
"""
@@ -87,20 +89,19 @@ class EdfFileLayer(object):
self.Source= source_obj
else:
if (type(source_name) == type([])):
- if DEBUG:
- print("List of files")
+ _logger.debug("List of files")
self.Source=[]
for name in source_name:
try:
self.Source.append(EdfFile.EdfFile(name,fastedf=self.fastedf))
except:
- #print("EdfFileLayer.SetSource: Error trying to read EDF file %s" % name)
+ # _logger.info("EdfFileLayer.SetSource: Error trying to read EDF file %s", name)
self.Source.append( None)
else:
try:
self.Source = EdfFile.EdfFile(source_name, fastedf=self.fastedf)
except:
- #print("EdfFileLayer.SetSource: Error trying to read EDF file")
+ # _logger.info("EdfFileLayer.SetSource: Error trying to read EDF file")
self.Source=None
else:
self.Source=None
@@ -200,7 +201,7 @@ class EdfFileLayer(object):
index = int(index)-1
image = int(image)-1
except:
- print("Error trying to interpret key = %s" % key)
+ _logger.error("Error trying to interpret key = %s", key)
return {}
source = self.Source[index]
NumImages=source.GetNumImages()
@@ -379,7 +380,8 @@ class EdfFileLayer(object):
"""
#AS if append==0: Data.Delete(self)
numimages=self.Source.GetNumImages()
- if key_list == "ALL": key_list=range(numimages)
+ if key_list == "ALL":
+ key_list=range(numimages)
elif type(key_list) != type([]): key_list=[key_list]
#AS elif type(key_list) is types.IntType: key_list=[key_list]
if pos is not None:
@@ -445,11 +447,11 @@ if __name__ == "__main__":
fast = int(sys.argv[3])
obj=EdfFileLayer(fastedf=fast)
if not obj.SetSource([filename]):
- print("ERROR: cannot open file %s" % filename)
+ _logger.error("ERROR: cannot open file %s" % filename)
sys.exit()
#obj.LoadSource(key)
except:
- print("Usage: EdfFileData.py <filename> <image> <fastflag>")
+ _logger.error("Usage: EdfFileData.py <filename> <image> <fastflag>")
sys.exit()
print(obj.GetSourceInfo())
for i in range(1):
diff --git a/PyMca5/PyMcaCore/EventHandler.py b/PyMca5/PyMcaCore/EventHandler.py
index 9741351..3749051 100644
--- a/PyMca5/PyMcaCore/EventHandler.py
+++ b/PyMca5/PyMcaCore/EventHandler.py
@@ -78,6 +78,11 @@ Full event names: A string with the event name fully specified (i.e. a.b.c)
"""
__version__ = '0.1Beta'
+import logging
+
+_logger = logging.getLogger(__name__)
+
+
class Event(object):
pass
@@ -212,7 +217,7 @@ class EventHandler(object):
for cb in self.callbacks[event]:
cb(*args, **kw)
else:
- print("Warning: missing event ",event)
+ _logger.warning("Warning: missing event: %s", event)
def getfullevents(self):
""" return a list with fully specified event names (a.b.c) """
diff --git a/PyMca5/PyMcaCore/HtmlIndex.py b/PyMca5/PyMcaCore/HtmlIndex.py
index 3a75c6f..7f0d4f2 100644
--- a/PyMca5/PyMcaCore/HtmlIndex.py
+++ b/PyMca5/PyMcaCore/HtmlIndex.py
@@ -30,11 +30,14 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
import os
import sys
import time
from . import PyMcaLogo
+_logger = logging.getLogger(__name__)
+
class HtmlIndex(object):
def __init__(self, htmldir):
if htmldir is None:htmldir = "/tmp/HTML"
@@ -150,7 +153,7 @@ class HtmlIndex(object):
try:
os.remove(index)
except:
- print("cannot delete file %s" % index)
+ _logger.error("cannot delete file %s", index)
continue
def _getHtmlFileList(self, directory):
@@ -166,7 +169,7 @@ class HtmlIndex(object):
try:
os.remove(index)
except:
- print("cannot delete file %s" % index)
+ _logger.error("cannot delete file %s", index)
return
filelist = self._getHtmlFileList(directory)
text = ""
@@ -185,7 +188,7 @@ class HtmlIndex(object):
try:
os.remove(index)
except:
- print("cannot delete file %s" % index)
+ _logger.error("cannot delete file %s", index)
return
directorylist = self._getHtmlDirList(directory)
text = ""
diff --git a/PyMca5/PyMcaCore/LoggingLevel.py b/PyMca5/PyMcaCore/LoggingLevel.py
new file mode 100644
index 0000000..eca68d7
--- /dev/null
+++ b/PyMca5/PyMcaCore/LoggingLevel.py
@@ -0,0 +1,89 @@
+
+#!/usr/bin/env python
+#/*##########################################################################
+# Copyright (C) 2004-2014 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""Module for parsing command line options related to the logging level."""
+__author__ = "P. Knobel"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
+import logging
+
+
+DEFAULT_LOGGING_LEVEL = logging.WARNING
+
+
+def getLoggingLevel(opts):
+ """Find logging level from the output of `getopt.getopt()`.
+ This level can be specified via one of two long options:
+ --debug or --logging. If both are specified, --logging overrules
+ --debug.
+
+ When specifying the level with --logging, the level can be
+ specified explicitly as a string (debug, info, warning, error, critical),
+ or as an integer in the range 0--4, in increasing order of verbosity
+ (0 is "critical", 4 is "debug").
+
+ The option --debug only allows to chose between the default logging level
+ (--debug=0) or debugging mode with maximum verbosity (--debug=1).
+
+ :param opts: Command line options as a list of 2-tuples of strings
+ (e.g. ``[('--logging', 'debug'), ('--cfg', 'config.ini')]``).
+ :returns: logging level
+ :rtype: int"""
+ logging_level = None
+ for opt, arg in opts:
+ if opt == '--logging':
+ levels_dict = {
+ # Explicit args
+ 'debug': logging.DEBUG,
+ 'info': logging.INFO,
+ 'warning': logging.WARNING,
+ 'error': logging.ERROR,
+ 'critical': logging.CRITICAL,
+ # int args sorted by increasing verbosity
+ '0': logging.CRITICAL,
+ '1': logging.ERROR,
+ '2': logging.WARNING,
+ '3': logging.INFO,
+ '4': logging.DEBUG}
+
+ logging_level = levels_dict.get(arg.lower())
+ if logging_level is None:
+ raise ValueError("Unknown logging level <%s>" % arg)
+ # if --logging is specified, ignore --debug
+ return logging_level
+ if opt == '--debug':
+ # simpler option to choose between the default logging or DEBUG
+ if arg.lower() in ["0", "false"]:
+ logging_level = logging.INFO
+ elif arg.lower() in ["1", "true"]:
+ logging_level = logging.DEBUG
+ else:
+ raise ValueError("Incorrect debug parameter <%s> (should be 0 or 1)" % arg)
+ if logging_level is None:
+ return DEFAULT_LOGGING_LEVEL
+ return logging_level
diff --git a/PyMca5/PyMcaCore/NexusDataSource.py b/PyMca5/PyMcaCore/NexusDataSource.py
index 80daa9d..6cc5dc8 100644
--- a/PyMca5/PyMcaCore/NexusDataSource.py
+++ b/PyMca5/PyMcaCore/NexusDataSource.py
@@ -37,6 +37,7 @@ import h5py
from operator import itemgetter
import re
import posixpath
+import logging
phynx = h5py
if sys.version_info >= (3,):
@@ -46,7 +47,8 @@ from . import DataObject
from . import NexusTools
SOURCE_TYPE = "HDF5"
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
#sorting method
def h5py_sorting(object_list):
@@ -89,8 +91,8 @@ def h5py_sorting(object_list):
#The only way to reach this point is to have different
#structures among the different entries. In that case
#defaults to the unfiltered case
- print("WARNING: Default ordering")
- print("Probably all entries do not have the key %s" % sorting_key)
+ _logger.warning("Default ordering")
+ _logger.warning("Probably all entries do not have the key %s", sorting_key)
return object_list
def _get_number_list(txt):
@@ -262,8 +264,7 @@ class NexusDataSource(object):
return self.__getKeyInfo(key)
else:
#should we raise a KeyError?
- if DEBUG:
- print("Error key not in list ")
+ _logger.debug("Error key not in list ")
return {}
def __getKeyInfo(self,key):
@@ -273,8 +274,7 @@ class NexusDataSource(object):
entry = int(entry)-1
except:
#should we rise an error?
- if DEBUG:
- print("Error trying to interpret key = %s" % key)
+ _logger.debug("Error trying to interpret key = %s", key)
return {}
sourceObject = self._sourceObjectList[index]
@@ -293,8 +293,7 @@ class NexusDataSource(object):
starting by 1.
selection: a dictionnary generated via QNexusWidget
"""
- if DEBUG:
- print("getDataObject selection = ", selection)
+ _logger.debug("getDataObject selection = %s", selection)
if selection is not None:
if 'sourcename' in selection:
filename = selection['sourcename']
@@ -314,7 +313,7 @@ class NexusDataSource(object):
actual_key = "%d.%d" % (fileIndex+1, entryIndex+1)
if actual_key != key:
if entry != "/":
- print("Warning selection keys do not match")
+ _logger.warning("selection keys do not match")
else:
#Probably I should find the acual entry following h5py_ordering output
#and search for an NXdata plot.
@@ -355,9 +354,8 @@ class NexusDataSource(object):
if path in h5:
dataset = h5[path].value
if dataset is None:
- if DEBUG:
- print("Broken link? Ignoring key %s = % s" % \
- (key, mcaDatasetObjectPath ))
+ _logger.debug("Broken link? Ignoring key %s = %s",
+ key, mcaDatasetObjectPath)
del mcaObjectPaths[key]
else:
mcaObjectPaths[key] = dataset
@@ -405,9 +403,9 @@ class NexusDataSource(object):
if selection['mcaselectiontype'].lower() != "sum":
output.info["McaLiveTime"] /= divider
except:
- import traceback
- print("exception", sys.exc_info())
- print(("%s " % value) + ''.join(traceback.format_tb(trace)))
+ # import traceback
+ _logger.error("%s", sys.exc_info())
+ # print(("%s " % value) + ''.join(traceback.format_tb(trace)))
return output
output.x = [mcaChannels]
output.y = [mcaData]
@@ -444,8 +442,7 @@ class NexusDataSource(object):
output.info['MotorValues'].append(value)
except:
# I cannot affort to fail here for something probably not used
- if DEBUG:
- print("Error reading positioners ", sys.exc_info())
+ _logger.debug("Error reading positioners\n%s", sys.exc_info())
for cnt in ['y', 'x', 'm']:
if not cnt in selection:
continue
@@ -471,16 +468,15 @@ class NexusDataSource(object):
nSpectra *= iDummy
if mcaselectiontype == "sum":
# sum already calculated
- if DEBUG:
- print("SUM")
+ _logger.debug("SUM")
elif mcaselectiontype in ["avg", "average"]:
# calculate the average
- if DEBUG:
- print("AVERAGE")
+ _logger.debug("AVERAGE")
data /= nSpectra
else:
- print("Unsupported selection type %s" % mcaselectiontype)
- print("Calculating average")
+ _logger.warning("Unsupported selection type %s",
+ mcaselectiontype)
+ _logger.warning("Calculating average")
data /= nSpectra
elif len(data.shape) == 2:
if min(data.shape) == 1:
diff --git a/PyMca5/PyMcaCore/NexusTools.py b/PyMca5/PyMcaCore/NexusTools.py
index 9385920..55d2c69 100644
--- a/PyMca5/PyMcaCore/NexusTools.py
+++ b/PyMca5/PyMcaCore/NexusTools.py
@@ -35,7 +35,9 @@ from operator import itemgetter
import re
import posixpath
from h5py import File, Dataset, Group
-DEBUG = 0
+import logging
+
+_logger = logging.getLogger(__name__)
#sorting method
def h5py_sorting(object_list):
@@ -54,8 +56,7 @@ def h5py_sorting(object_list):
posixNames = [item[1].name for item in object_list]
except AttributeError:
# Typical of broken external links
- if DEBUG:
- print("HDF5Widget: Cannot get posixNames")
+ _logger.debug("HDF5Widget: Cannot get posixNames")
return object_list
# This implementation only sorts entries
@@ -91,8 +92,8 @@ def h5py_sorting(object_list):
#The only way to reach this point is to have different
#structures among the different entries. In that case
#defaults to the unfiltered case
- print("WARNING: Default ordering")
- print("Probably all entries do not have the key %s" % sorting_key)
+ _logger.warning("Default ordering. "
+ "Probably all entries do not have the key %s", sorting_key)
return object_list
def _get_number_list(txt):
@@ -421,7 +422,7 @@ def getInstrumentGroup(h5file, path):
return None
else:
if n > 1:
- print("WARNING: More than one instrument associated to the same entry")
+ _logger.warning("More than one instrument associated to the same entry")
return groups[0]
def getScannedPositioners(h5file, path):
diff --git a/PyMca5/PyMcaCore/Plugin1DBase.py b/PyMca5/PyMcaCore/Plugin1DBase.py
index 2cae8d6..b27cb99 100644
--- a/PyMca5/PyMcaCore/Plugin1DBase.py
+++ b/PyMca5/PyMcaCore/Plugin1DBase.py
@@ -40,7 +40,7 @@ Plugins can be automatically installed provided they are in the appropriate plac
or *${HOME}/PyMca5/plugins* (older PyMca installation)
- In *"My Documents\\\\PyMca\\\\plugins"* (Windows)
-A plugin inherit the :class:`Plugin1DBase` class and implement the methods:
+Plugins inherit the :class:`Plugin1DBase` class and implement the methods:
- :meth:`Plugin1DBase.getMethods`
- :meth:`Plugin1DBase.getMethodToolTip` (optional but convenient)
@@ -50,6 +50,9 @@ A plugin inherit the :class:`Plugin1DBase` class and implement the methods:
and modify the static module variable :const:`MENU_TEXT` and the static module function
:func:`getPlugin1DInstance` according to the defined plugin.
+Optionally, plugins may also implement :meth:`Plugin1DBase.activeCurveChanged`
+to react to data selection in the plot.
+
These plugins will be compatible with any 1D-plot window that implements the Plot1D
interface. The plot window interface is described in the Plot1DBase class.
@@ -162,14 +165,19 @@ class Plugin1DBase(object):
"""
self._plotWindow = weakref.proxy(plotWindow)
- self._legacy = True
- """The plot window can be a legacy PyMca plot, in which case
+ self._legacy = False
+ """
+ In the transition phase from PyMca plot to silx plot,
+ the plot window could be a legacy PyMca plot, in which case
:attr:`_legacy` is set to *True*, or a :class:`PluginsToolButton`
acting as proxy for a *silx* PlotWindow (*legacy=False*).
+ But now we don't expect to see PyMca plots any longer.
"""
- if hasattr(plotWindow, "plot"): # PluginsToolButton.plot -> silx plot
- self._legacy = False
+ # PyMcaGraph.Plot has a PLUGINS_DIR class attribute,
+ # PluginsToolButton does not
+ if hasattr(plotWindow, "PLUGINS_DIR"):
+ self._legacy = True
# Window related functions
def windowTitle(self):
@@ -480,6 +488,17 @@ class Plugin1DBase(object):
print("applyMethod not implemented")
return
+ def activeCurveChanged(self, prev, new):
+ """A plugin may implement this method which is called
+ when the active curve changes in the plot.
+
+ :param prev: Legend of the previous active curve,
+ or None if no curve was active.
+ :param new: Legend of the new active curve,
+ or None if no curve is currently active.
+ """
+ pass
+
MENU_TEXT = "Plugin1D Base"
"""This is the name of the plugin, as it appears in the plugins menu."""
diff --git a/PyMca5/PyMcaCore/Plugin2DBase.py b/PyMca5/PyMcaCore/Plugin2DBase.py
new file mode 100644
index 0000000..5cc71df
--- /dev/null
+++ b/PyMca5/PyMcaCore/Plugin2DBase.py
@@ -0,0 +1,124 @@
+#/*##########################################################################
+#
+# The PyMca X-Ray Fluorescence Toolkit
+#
+# Copyright (c) 2004-2016 European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""
+A 2D plugin is a module that can be added to the PyMca 2D window in order to
+perform user defined operations of the plotted 2D data.
+
+Plugins can be automatically installed provided they are in the appropriate place:
+
+ - In the user home directory (POSIX systems): *${HOME}/.pymca/plugins*
+ or *${HOME}/PyMca5/plugins* (older PyMca installation)
+ - In *"My Documents\\\\PyMca\\\\plugins"* (Windows)
+
+A plugin inherits the :class:`Plugin2DBase` class and implements the methods:
+
+ - :meth:`Plugin2DBase.getMethods`
+ - :meth:`Plugin2DBase.getMethodToolTip` (optional but convenient)
+ - :meth:`Plugin2DBase.getMethodPixmap` (optional)
+ - :meth:`Plugin2DBase.applyMethod`
+
+and modifies the static module variable :const:`MENU_TEXT` and the static module function
+:func:`getPlugin2DInstance` according to the defined plugin.
+
+It may also optionally implement :meth:`Plugin2DBase.activeImageChanged`.
+
+"""
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
+import weakref
+
+
+class Plugin2DBase(object):
+ def __init__(self, plotWindow, **kw):
+ """
+ plotWindow is the plot on which the plugin operates.
+
+
+ """
+ self._plotWindow = weakref.proxy(plotWindow)
+
+ # Methods to be implemented by the plugin
+ def getMethods(self, plottype=None):
+ """
+
+ :return: A list with the NAMES associated to the callable methods
+ that are applicable to the specified type plot. The list can be empty.
+ :rtype: list[string]
+ """
+ print("getMethods not implemented")
+ return []
+
+ def getMethodToolTip(self, name):
+ """
+ Returns the help associated to the particular method name or None.
+
+ :param name: The method for which a tooltip is asked
+ :rtype: string
+ """
+ return None
+
+ def getMethodPixmap(self, name):
+ """
+ :param name: The method for which a pixmap is asked
+ :rtype: QPixmap or None
+ """
+ return None
+
+ def applyMethod(self, name):
+ """
+ The plugin is asked to apply the method associated to name.
+ """
+ print("applyMethod not implemented")
+ return
+
+ def activeImageChanged(self, prev, new):
+ """A plugin may implement this method which is called
+ when the active image changes in the plot.
+
+ :param prev: Legend of the previous active image,
+ or None if no image was active.
+ :param new: Legend of the new active curve,
+ or None if no image is currently active.
+ """
+ pass
+
+
+MENU_TEXT = "Plugin2D Base"
+"""This is the name of the plugin, as it appears in the plugins menu."""
+
+
+def getPlugin2DInstance(plotWindow, **kw):
+ """
+ This function will be called by the plot window instantiating and calling
+ the plugins. It passes itself as first argument, but the default implementation
+ of the base class only keeps a weak reference to prevent circular references.
+ """
+ ob = Plugin2DBase(plotWindow)
+ return ob
diff --git a/PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py b/PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py
index 85baefc..3a619d2 100644
--- a/PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py
+++ b/PyMca5/PyMcaCore/PyMcaBatchBuildOutput.py
@@ -33,9 +33,10 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import numpy
+import logging
from PyMca5.PyMcaIO import EdfFile
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class PyMcaBatchBuildOutput(object):
def __init__(self, inputdir=None, outputdir=None):
@@ -50,8 +51,7 @@ class PyMcaBatchBuildOutput(object):
if delete is None:
if outputdir == inputdir:
delete = True
- if DEBUG:
- print("delete option = ", delete)
+ _logger.debug("delete option = %s", delete)
allfiles = os.listdir(inputdir)
partialedflist = []
partialdatlist = []
@@ -64,8 +64,7 @@ class PyMcaBatchBuildOutput(object):
#IMAGES
edfoutlist = []
for filename in partialedflist:
- if DEBUG:
- print("Dealing with filename %s" % filename)
+ _logger.debug("Dealing with filename %s", filename)
edflist = self.getIndexedFileList(os.path.join(inputdir, filename))
i = 0
for edfname in edflist:
@@ -83,11 +82,9 @@ class PyMcaBatchBuildOutput(object):
i += 1
edfname = filename.replace('_000000_partial.edf',".edf")
edfoutname = os.path.join(outputdir, edfname)
- if DEBUG:
- print("Dealing with output filename %s" % edfoutname)
+ _logger.debug("Dealing with output filename %s", edfoutname)
if os.path.exists(edfoutname):
- if DEBUG:
- print("Output file already exists, trying to delete it")
+ _logger.debug("Output file already exists, trying to delete it")
os.remove(edfoutname)
edfout = EdfFile.EdfFile(edfoutname, access="wb")
edfout.WriteImage (header , data, Append=0)
@@ -98,7 +95,7 @@ class PyMcaBatchBuildOutput(object):
try:
os.remove(filename)
except:
- print("Cannot delete file %s" % filename)
+ _logger.warning("Cannot delete file %s" % filename)
#DAT IMAGES
datoutlist = []
@@ -215,8 +212,8 @@ class PyMcaBatchBuildOutput(object):
prefix = name[0:n-i+1]
prefix = os.path.join(os.path.dirname(filename),prefix)
if not os.path.exists(prefix + number + suffix):
- print("Internal error in EDFStack")
- print("file should exist: %s " % (prefix + number + suffix))
+ _logger.error("Internal error in EDFStack")
+ _logger.error("file should exist: %s " % (prefix + number + suffix))
return
i = 0
if begin is None:
diff --git a/PyMca5/PyMcaCore/PyMcaDirs.py b/PyMca5/PyMcaCore/PyMcaDirs.py
index e4b2135..a1ef8b8 100644
--- a/PyMca5/PyMcaCore/PyMcaDirs.py
+++ b/PyMca5/PyMcaCore/PyMcaDirs.py
@@ -32,8 +32,10 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
inputDir = None
outputDir = None
nativeFileDialogs = False
@@ -43,8 +45,7 @@ class __ModuleWrapper:
self.__dict__["_ModuleWrapper__wrapped"] = wrapped
def __getattr__(self, name):
- if DEBUG:
- print("getting ", name)
+ _logger.debug("getting %s", name)
if name == "inputDir":
if self.__wrapped.__dict__[name] is None:
if self.__wrapped.__dict__['outputDir'] is not None:
@@ -63,13 +64,11 @@ class __ModuleWrapper:
if not os.path.isdir(value):
value = os.getcwd()
self.__setattr__('outputDir', value)
- if DEBUG:
- print("got ", name, getattr(self.__wrapped, name))
+ _logger.debug("got %s %s", name, getattr(self.__wrapped, name))
return getattr(self.__wrapped, name)
def __setattr__(self, name, value):
- if DEBUG:
- print("setting ", name, value)
+ _logger.debug("setting %s %s", name, value)
if name == "inputDir":
if os.path.isdir(value):
self.__wrapped.__dict__[name]=value
diff --git a/PyMca5/PyMcaCore/PyMcaMatplotlibSave.py b/PyMca5/PyMcaCore/PyMcaMatplotlibSave.py
index 860a263..724078a 100644
--- a/PyMca5/PyMcaCore/PyMcaMatplotlibSave.py
+++ b/PyMca5/PyMcaCore/PyMcaMatplotlibSave.py
@@ -33,6 +33,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import numpy
+import logging
from matplotlib import cm
from matplotlib import __version__ as matplotlib_version
from matplotlib.font_manager import FontProperties
@@ -41,7 +42,8 @@ from matplotlib.figure import Figure
from matplotlib.colors import LinearSegmentedColormap, LogNorm, Normalize
from matplotlib.ticker import MaxNLocator, AutoLocator
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
colordict = {}
colordict['blue'] = '#0000ff'
@@ -171,8 +173,7 @@ class PyMcaMatplotlibSave(FigureCanvas):
n = self._filterData(x, y)
if n == 0:
#nothing to plot
- if DEBUG:
- print("nothing to plot")
+ _logger.debug("nothing to plot")
return
style = None
if color is None:
@@ -473,7 +474,8 @@ class PyMcaMatplotlibSaveImage:
elif self.config['colormap'] == 'ylgnbu_r':
cmap = cm.YlGnBu_r
else:
- print("Unsupported colormap %s" % self.config['colormap'])
+ _logger.warning("Unsupported colormap %s", self.config['colormap'])
+ _logger.warning("Defaulting to grayscale.")
if self.config['extent'] is None:
h, w = self.imageData.shape
diff --git a/PyMca5/PyMcaCore/SpecFileDataSource.py b/PyMca5/PyMcaCore/SpecFileDataSource.py
index e1cc082..da1f3a2 100644
--- a/PyMca5/PyMcaCore/SpecFileDataSource.py
+++ b/PyMca5/PyMcaCore/SpecFileDataSource.py
@@ -34,11 +34,14 @@ import sys
import os
import numpy
import types
+import logging
from . import DataObject
from PyMca5.PyMcaIO import specfilewrapper as specfile
+_logger = logging.getLogger(__name__)
+
+
SOURCE_TYPE = "SpecFile"
-DEBUG = 0
# Scan types
# ----------
@@ -115,8 +118,7 @@ class SpecFileDataSource(object):
try:
self.__fileHeaderList[0] = sel.fileheader('')
except:
- if DEBUG:
- print("getSourceInfo %s" % sys.exc_info()[1])
+ _logger.debug("getSourceInfo %s", sys.exc_info()[1])
self.__fileHeaderList[0] = None
try:
n = sel.nbmca()
@@ -219,8 +221,7 @@ class SpecFileDataSource(object):
try:
self.__fileHeaderList[index] = scandata.fileheader('')
except:
- if DEBUG:
- print("getScanInfo %s" % sys.exc_info()[1])
+ _logger.debug("getScanInfo %s", sys.exc_info()[1])
self.__fileHeaderList[index] = None
info["FileHeader"] = self.__fileHeaderList[index]
try: info["Number"] = scandata.number()
@@ -284,8 +285,7 @@ class SpecFileDataSource(object):
if len(calib) == info["NbMcaDet"]:
calib = [calib[mcainfo["McaDet"]-1]]
else:
- if DEBUG:
- print("Warning","Number of calibrations does not match number of MCAs")
+ _logger.debug("Number of calibrations does not match number of MCAs")
if len(calib) == 1:
pass
else:
@@ -304,8 +304,7 @@ class SpecFileDataSource(object):
if len(ctime) == info["NbMcaDet"]:
ctime = [ctime[mcainfo["McaDet"]-1]]
else:
- if DEBUG:
- print("Warning","Number of counting times does not match number of MCAs")
+ _logger.debug("Number of counting times does not match number of MCAs")
if len(ctime) == 1:
pass
else:
@@ -324,8 +323,7 @@ class SpecFileDataSource(object):
if len(chann) == info["NbMcaDet"]:
chann = [chann[mcainfo["McaDet"] - 1]]
else:
- if DEBUG:
- print("Warning","Number of @CHANN information does not match number of MCAs")
+ _logger.debug("Number of @CHANN information does not match number of MCAs")
if len(chann) == 1:
pass
else:
@@ -408,9 +406,8 @@ class SpecFileDataSource(object):
raise KeyError("Key %s not in source keys" % key)
mca3D = False
- if DEBUG:
- print("SELECTION = ", selection)
- print("key_type = ", key_type)
+ _logger.debug("SELECTION = %s", selection)
+ _logger.debug("key_type = %s", key_type)
if key_type == "scan":
if selection is not None:
if 'mcalist' in selection:
@@ -704,9 +701,8 @@ class SpecFileDataSource(object):
#mca_no= 1 + int(key_split[2]) + int(key_split[3])*mot1
mca_no = (int(key_split[2])-1) * scan_info["NbMcaDet"] + \
int(key_split[3])
- if DEBUG:
- print("try to read mca number = ",mca_no)
- print("total number of mca = ",scan_info["NbMca"])
+ _logger.debug("try to read mca number = %s", mca_no)
+ _logger.debug("total number of mca = %s", scan_info["NbMca"])
scan_data = scan_obj.mca(mca_no)
except:
raise IOError("SF_MESH+SF_MCA read failed")
diff --git a/PyMca5/PyMcaCore/SpsDataSource.py b/PyMca5/PyMcaCore/SpsDataSource.py
index 3e1706f..e437b54 100644
--- a/PyMca5/PyMcaCore/SpsDataSource.py
+++ b/PyMca5/PyMcaCore/SpsDataSource.py
@@ -31,10 +31,13 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import copy
+import logging
from . import DataObject
from PyMca5.PyMcaIO import spswrap as sps
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
SOURCE_TYPE = 'SPS'
@@ -186,8 +189,7 @@ class SpsDataSource(object):
if (arrayflag & sps.TAG_ARRAY) == sps.TAG_ARRAY:
arraylist.append(array)
continue
- if DEBUG:
- print("array not added %s" % array)
+ _logger.debug("array not added %s", array)
source_info = {}
source_info["Size"] = len(arraylist)
source_info["KeyList"] = arraylist
@@ -226,7 +228,7 @@ class SpsDataSource(object):
try:
labels = [(int(x),x) for x in labels]
except:
- print("SpsDataSource error reverting to old behavior")
+ _logger.warning("SpsDataSource error reverting to old behavior")
labels = [(x, x) for x in labels]
labels.sort()
if len(labels):
@@ -292,8 +294,7 @@ class SpsDataSource(object):
return info
def _buildLabelsList(self, instr):
- if DEBUG:
- print('SpsDataSource : building counter list')
+ _logger.debug('SpsDataSource : building counter list')
state = 0
llist = ['']
for letter in instr:
diff --git a/PyMca5/PyMcaCore/StackBase.py b/PyMca5/PyMcaCore/StackBase.py
index f7f9352..a253d27 100644
--- a/PyMca5/PyMcaCore/StackBase.py
+++ b/PyMca5/PyMcaCore/StackBase.py
@@ -40,7 +40,11 @@ import time
import os
import sys
import glob
-DEBUG = 0
+import logging
+
+logger = logging.getLogger(__name__)
+
+
PLUGINS_DIR = None
try:
import PyMca5
@@ -182,8 +186,8 @@ class StackBase(object):
sys.modules[plugin].getStackPluginInstance(self)
self.pluginList.append(plugin)
except:
- if DEBUG:
- print("Problem importing module %s" % plugin)
+ logger.debug("Problem importing module %s", plugin)
+ if logger.getEffectiveLevel() == logging.DEBUG:
raise
return len(self.pluginList)
@@ -264,17 +268,15 @@ class StackBase(object):
axis=self.mcaIndex,
dtype=numpy.float)
#original ICR mca
- if DEBUG:
- print("(self.otherIndex, self.fileIndex) = (%d, %d)" %\
- (self.otherIndex, self.fileIndex))
+ logger.debug("(self.otherIndex, self.fileIndex) = (%d, %d)",
+ self.otherIndex, self.fileIndex)
i = max(self.otherIndex, self.fileIndex)
j = min(self.otherIndex, self.fileIndex)
mcaData0 = numpy.sum(numpy.sum(self._stack.data,
axis=i,
dtype=numpy.float), j)
else:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
shape = self._stack.data.shape
if self.mcaIndex in [2, -1]:
self._stackImageData = numpy.zeros((shape[0], shape[1]),
@@ -308,11 +310,9 @@ class StackBase(object):
mcaData0[i] = tmpData.sum()
else:
raise ValueError("Unhandled case 1D index = %d" % self.mcaIndex)
- if DEBUG:
- print("Print dynamic loading elapsed = %f" % (time.time() - t0))
+ logger.debug("Print dynamic loading elapsed = %f", time.time() - t0)
- if DEBUG:
- print("__stackImageData.shape = ", self._stackImageData.shape)
+ logger.debug("__stackImageData.shape = %s", self._stackImageData.shape)
if previousStackImageSize != self._stackImageData.size:
self._clearPositioners()
@@ -386,7 +386,7 @@ class StackBase(object):
def handleNonFiniteData(self):
text = "Your data contain infinite values or nans.\n"
text += "Pixels containing those values will be ignored."
- print(text)
+ logger.info(text)
def updateROIImages(self, ddict=None):
if ddict is None:
@@ -411,15 +411,13 @@ class StackBase(object):
if len(i1):
i1 = min(i1)
else:
- if DEBUG:
- print("updateROIImages: nothing to be made")
+ logger.debug("updateROIImages: nothing to be made")
return
i2 = numpy.nonzero(xw <= ddict['to'])[0]
if len(i2):
i2 = max(i2) + 1
else:
- if DEBUG:
- print("updateROIImages: nothing to be made")
+ logger.debug("updateROIImages: nothing to be made")
return
pos = 0.5 * (ddict['from'] + ddict['to'])
imiddle = max(numpy.nonzero(xw <= pos)[0])
@@ -428,15 +426,13 @@ class StackBase(object):
if len(i2):
i2 = max(i2)
else:
- if DEBUG:
- print("updateROIImages: nothing to be made")
+ logger.debug("updateROIImages: nothing to be made")
return
i1 = numpy.nonzero(xw <= ddict['to'])[0]
if len(i1):
i1 = min(i1) + 1
else:
- if DEBUG:
- print("updateROIImages: nothing to be made")
+ logger.debug("updateROIImages: nothing to be made")
return
pos = 0.5 * (ddict['from'] + ddict['to'])
imiddle = min(numpy.nonzero(xw <= pos)[0])
@@ -505,12 +501,10 @@ class StackBase(object):
self.showROIImageList(imageList, image_names=imageNames)
def showOriginalImage(self):
- if DEBUG:
- print("showOriginalImage to be implemented")
+ logger.debug("showOriginalImage to be implemented")
def showOriginalMca(self):
- if DEBUG:
- print("showOriginalMca to be implemented")
+ logger.debug("showOriginalMca to be implemented")
def showROIImageList(self, imageList, image_names=None):
self._ROIImageList = imageList
@@ -533,12 +527,10 @@ class StackBase(object):
return
mcaData = None
goodData = numpy.isfinite(self._mcaData0.y[0].sum())
- if DEBUG:
- print("Stack data is not finite")
+ logger.debug("Stack data is not finite")
if (self._selectionMask is None) and goodData:
if normalize:
- if DEBUG:
- print("Case 1")
+ logger.debug("Case 1")
npixels = self._stackImageData.shape[0] *\
self._stackImageData.shape[1] * 1.0
dataObject = DataObject.DataObject()
@@ -548,8 +540,7 @@ class StackBase(object):
if "McaLiveTime" in dataObject.info:
dataObject.info["McaLiveTime"] /= float(npixels)
else:
- if DEBUG:
- print("Case 2")
+ logger.debug("Case 2")
dataObject = self._mcaData0
return dataObject
@@ -570,8 +561,7 @@ class StackBase(object):
npixels = actualSelectionMask.sum()
if (npixels == 0) and goodData:
if normalize:
- if DEBUG:
- print("Case 3")
+ logger.debug("Case 3")
npixels = self._stackImageData.shape[0] * self._stackImageData.shape[1] * 1.0
dataObject = DataObject.DataObject()
dataObject.info.update(self._mcaData0.info)
@@ -580,8 +570,7 @@ class StackBase(object):
if "McaLiveTime" in dataObject.info:
dataObject.info["McaLiveTime"] /= float(npixels)
else:
- if DEBUG:
- print("Case 4")
+ logger.debug("Case 4")
dataObject = self._mcaData0
return dataObject
@@ -597,28 +586,22 @@ class StackBase(object):
else:
arrayMask = (actualSelectionMask > 0)
- if DEBUG:
- print("Reached MCA calculation")
+ logger.debug("Reached MCA calculation")
cleanMask = numpy.nonzero(arrayMask)
- if DEBUG:
- print("self.fileIndex, self.mcaIndex = %d , %d" %\
- (self.fileIndex, self.mcaIndex))
- if DEBUG:
- t0 = time.time()
+ logger.debug("self.fileIndex, self.mcaIndex = %d , %d",
+ self.fileIndex, self.mcaIndex)
+ t0 = time.time()
if len(cleanMask[0]) and len(cleanMask[1]):
- if DEBUG:
- print("USING MASK")
+ logger.debug("USING MASK")
cleanMask = numpy.array(cleanMask).transpose()
if self.fileIndex == 2:
if self.mcaIndex == 0:
if isinstance(self._stack.data, numpy.ndarray):
- if DEBUG:
- print("In memory case 0")
+ logger.debug("In memory case 0")
for r, c in cleanMask:
mcaData += self._stack.data[:, r, c]
else:
- if DEBUG:
- print("Dynamic loading case 0")
+ logger.debug("Dynamic loading case 0")
#no other choice than to read all images
#for the time being, one by one
rMin = cleanMask[0][0]
@@ -644,13 +627,11 @@ class StackBase(object):
elif self.fileIndex == 1:
if self.mcaIndex == 0:
if isinstance(self._stack.data, numpy.ndarray):
- if DEBUG:
- print("In memory case 2")
+ logger.debug("In memory case 2")
for r, c in cleanMask:
mcaData += self._stack.data[:, r, c]
else:
- if DEBUG:
- print("Dynamic loading case 2")
+ logger.debug("Dynamic loading case 2")
#no other choice than to read all images
#for the time being, one by one
if 1:
@@ -675,13 +656,11 @@ class StackBase(object):
mcaData[i] = (tmpData[0] * arrayMask).sum(dtype=numpy.float)
elif self.mcaIndex == 2:
if isinstance(self._stack.data, numpy.ndarray):
- if DEBUG:
- print("In memory case 3")
+ logger.debug("In memory case 3")
for r, c in cleanMask:
mcaData += self._stack.data[r, c, :]
else:
- if DEBUG:
- print("Dynamic loading case 3")
+ logger.debug("Dynamic loading case 3")
#try to minimize access to the file
row_list = []
row_dict = {}
@@ -699,21 +678,18 @@ class StackBase(object):
elif self.fileIndex == 0:
if self.mcaIndex == 1:
if isinstance(self._stack.data, numpy.ndarray):
- if DEBUG:
- print("In memory case 4")
+ logger.debug("In memory case 4")
for r, c in cleanMask:
mcaData += self._stack.data[r, :, c]
else:
raise IndexError("Dynamic loading case 4")
elif self.mcaIndex in [2, -1]:
if isinstance(self._stack.data, numpy.ndarray):
- if DEBUG:
- print("In memory case 5")
+ logger.debug("In memory case 5")
for r, c in cleanMask:
mcaData += self._stack.data[r, c, :]
else:
- if DEBUG:
- print("Dynamic loading case 5")
+ logger.debug("Dynamic loading case 5")
#try to minimize access to the file
row_list = []
row_dict = {}
@@ -731,11 +707,9 @@ class StackBase(object):
else:
raise IndexError("File index undefined")
else:
- if DEBUG:
- print("NOT USING MASK !")
+ logger.debug("NOT USING MASK !")
- if DEBUG:
- print("Mca sum elapsed = %f" % (time.time() - t0))
+ logger.debug("Mca sum elapsed = %f", time.time() - t0)
if goodData:
if n_nonselected < npixels:
mcaData = self._mcaData0.y[0] - mcaData
@@ -764,8 +738,7 @@ class StackBase(object):
return dataObject
def calculateROIImages(self, index1, index2, imiddle=None, energy=None):
- if DEBUG:
- print("Calculating ROI images")
+ logger.debug("Calculating ROI images")
i1 = min(index1, index2)
i2 = max(index1, index2)
if imiddle is None:
@@ -797,8 +770,7 @@ class StackBase(object):
minImage = energy[(numpy.argmin(dataImage, axis=1) + i1)]
isUsingSuppliedEnergyAxis = True
else:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if self._tryNumpy and\
isinstance(self._stack.data, numpy.ndarray):
leftImage = self._stack.data[:, :, i1]
@@ -810,9 +782,8 @@ class StackBase(object):
maxImage = energy[numpy.argmax(dataImage, axis=2) + i1]
minImage = energy[numpy.argmin(dataImage, axis=2) + i1]
isUsingSuppliedEnergyAxis = True
- if DEBUG:
- print("Case 1 ROI image calculation elapsed = %f " %\
- (time.time() - t0))
+ logger.debug("Case 1 ROI image calculation elapsed = %f ",
+ time.time() - t0)
else:
shape = self._stack.data.shape
roiImage = numpy.zeros(self._stackImageData.shape,
@@ -841,13 +812,11 @@ class StackBase(object):
isUsingSuppliedEnergyAxis = True
minImage = energy[minImage]
maxImage = energy[maxImage]
- if DEBUG:
- print("2 Dynamic ROI image calculation elapsed = %f " %\
- (time.time() - t0))
+ logger.debug("2 Dynamic ROI image calculation elapsed = %f ",
+ time.time() - t0)
elif self.fileIndex == 1:
if self.mcaIndex == 0:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if isinstance(self._stack.data, numpy.ndarray) and\
self._tryNumpy:
leftImage = self._stack.data[i1, :, :]
@@ -884,9 +853,8 @@ class StackBase(object):
isUsingSuppliedEnergyAxis = True
background = 0.5 * (i2 - i1) * (leftImage + rightImage)
roiImage = numpy.sum(dataImage, axis=0, dtype=numpy.float)
- if DEBUG:
- print("Case 3 ROI image calculation elapsed = %f " %\
- (time.time() - t0))
+ logger.debug("Case 3 ROI image calculation elapsed = %f ",
+ time.time() - t0)
else:
shape = self._stack.data.shape
roiImage = numpy.zeros(self._stackImageData.shape,
@@ -928,12 +896,10 @@ class StackBase(object):
maxImage = energy[maxImage]
if i2 > i1:
background = (leftImage + rightImage) * 0.5 * (i2 - i1)
- if DEBUG:
- print("Case 4 Dynamic ROI elapsed = %f" %\
- (time.time() - t0))
+ logger.debug("Case 4 Dynamic ROI elapsed = %f",
+ time.time() - t0)
else:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if self._tryNumpy and\
isinstance(self._stack.data, numpy.ndarray):
leftImage = self._stack.data[:, :, i1]
@@ -945,9 +911,8 @@ class StackBase(object):
maxImage = energy[numpy.argmax(dataImage, axis=2) + i1]
minImage = energy[numpy.argmin(dataImage, axis=2) + i1]
isUsingSuppliedEnergyAxis = True
- if DEBUG:
- print("Case 5 ROI Image elapsed = %f" %\
- (time.time() - t0))
+ logger.debug("Case 5 ROI Image elapsed = %f",
+ time.time() - t0)
else:
shape = self._stack.data.shape
roiImage = numpy.zeros(self._stackImageData.shape,
@@ -974,13 +939,11 @@ class StackBase(object):
middleImage[i:i+step, :] += tmpData[:, :, imiddle-i1]
rightImage[i:i+step, :] += tmpData[:, :,-1]
background = 0.5*(i2-i1)*(leftImage+rightImage)
- if DEBUG:
- print("Case 6 Dynamic ROI image calculation elapsed = %f" %\
- (time.time() - t0))
+ logger.debug("Case 6 Dynamic ROI image calculation elapsed = %f",
+ time.time() - t0)
else:
#self.fileIndex = 2
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if self.mcaIndex == 0:
leftImage = self._stack.data[i1]
middleImage = self._stack.data[imiddle]
@@ -991,9 +954,8 @@ class StackBase(object):
minImage = energy[numpy.argmin(dataImage, axis=0) + i1]
maxImage = energy[numpy.argmax(dataImage, axis=0) + i1]
isUsingSuppliedEnergyAxis = True
- if DEBUG:
- print("Case 7 Default ROI image calculation elapsed = %f" %\
- (time.time() - t0))
+ logger.debug("Case 7 Default ROI image calculation elapsed = %f",
+ time.time() - t0)
else:
leftImage = self._stack.data[:, i1, :]
middleImage = self._stack.data[:, imiddle, :]
@@ -1004,9 +966,8 @@ class StackBase(object):
minImage = energy[numpy.argmin(dataImage, axis=1) + i1]
maxImage = energy[numpy.argmax(dataImage, axis=1) + i1]
isUsingSuppliedEnergyAxis = True
- if DEBUG:
- print("Case 8 Default ROI image calculation elapsed = %f" %\
- (time.time() - t0))
+ logger.debug("Case 8 Default ROI image calculation elapsed = %f",
+ time.time() - t0)
imageDict = {'ROI': roiImage,
'Maximum': maxImage,
@@ -1016,13 +977,11 @@ class StackBase(object):
'Right': rightImage,
'Background': background}
self.__ROIImageCalculationIsUsingSuppliedEnergyAxis = isUsingSuppliedEnergyAxis
- if DEBUG:
- print("ROI images calculated")
+ logger.debug("ROI images calculated")
return imageDict
def setSelectionMask(self, mask):
- if DEBUG:
- print("setSelectionMask called")
+ logger.debug("setSelectionMask called")
goodData = numpy.isfinite(self._mcaData0.y[0].sum())
if goodData:
@@ -1038,8 +997,7 @@ class StackBase(object):
self.pluginInstanceDict[key].selectionMaskUpdated()
def getSelectionMask(self):
- if DEBUG:
- print("getSelectionMask called")
+ logger.debug("getSelectionMask called")
return self._selectionMask
def addImage(self, image, name, info=None, replace=False, replot=True):
@@ -1092,8 +1050,7 @@ class StackBase(object):
If just_legend is True:
The legend of the active curve (or None) is returned.
"""
- if DEBUG:
- print("getActiveCurve default implementation")
+ logger.debug("getActiveCurve default implementation")
info = {}
info['xlabel'] = 'Channel'
info['ylabel'] = 'Counts'
@@ -1101,13 +1058,11 @@ class StackBase(object):
return self._mcaData0.x[0], self._mcaData0.y[0], legend, info
def getGraphXLimits(self):
- if DEBUG:
- print("getGraphXLimits default implementation")
+ logger.debug("getGraphXLimits default implementation")
return self._mcaData0.x[0].min(), self._mcaData0.x[0].max()
def getGraphYLimits(self):
- if DEBUG:
- print("getGraphYLimits default implementation")
+ logger.debug("getGraphYLimits default implementation")
return self._mcaData0.y[0].min(), self._mcaData0.y[0].max()
def getStackDataObject(self):
@@ -1163,12 +1118,11 @@ class StackBase(object):
"Wrong type for positioner %s. " % motorName +
"Valid types are numpy arrays, scalars or list of scalars.")
- if DEBUG and len(stackPositioners) != len(positioners):
+ if len(stackPositioners) != len(positioners):
ignored_motors = list(set(positioners.keys()) -
set(stackPositioners.keys()))
-
- print("Ignored motors due to mismatch in number of values: " +
- ', '.join(ignored_motors))
+ logger.debug("Ignored motors due to mismatch in number of values: %s",
+ ', '.join(ignored_motors))
self._stack.info["positioners"] = stackPositioners
diff --git a/PyMca5/PyMcaCore/StackPluginBase.py b/PyMca5/PyMcaCore/StackPluginBase.py
index d586a1f..5f1909f 100644
--- a/PyMca5/PyMcaCore/StackPluginBase.py
+++ b/PyMca5/PyMcaCore/StackPluginBase.py
@@ -116,7 +116,10 @@ These plugins will be compatible with any stack window that provides the followi
"""
import weakref
-DEBUG = 0
+import logging
+
+pluginBaseLogger = logging.getLogger(__name__)
+
class StackPluginBase(object):
def __init__(self, stackWindow, **kw):
@@ -218,12 +221,10 @@ class StackPluginBase(object):
return self._stackWindow.getGraphYLabel()
def stackUpdated(self):
- if DEBUG:
- print("stackUpdated(self) not implemented")
+ pluginBaseLogger.debug("stackUpdated(self) not implemented")
def stackROIImageListUpdated(self):
- if DEBUG:
- print("stackROIImageListUpdated(self) not implemented")
+ pluginBaseLogger.debug("stackROIImageListUpdated(self) not implemented")
return
def stackClosed(self):
@@ -240,8 +241,7 @@ class StackPluginBase(object):
self._widget.close()
def selectionMaskUpdated(self):
- if DEBUG:
- print("selectionMaskUpdated(self) not implemented")
+ pluginBaseLogger.debug("selectionMaskUpdated(self) not implemented")
#Methods to be implemented by the plugin
def getMethods(self):
@@ -249,7 +249,7 @@ class StackPluginBase(object):
A list with the NAMES associated to the callable methods
that are applicable to the specified stack.
"""
- print("BASE STACK getMethods not implemented")
+ pluginBaseLogger.debug("BASE STACK getMethods not implemented")
return []
def getMethodToolTip(self, name):
@@ -268,7 +268,7 @@ class StackPluginBase(object):
"""
The plugin is asked to apply the method associated to name.
"""
- print("applyMethod not implemented")
+ pluginBaseLogger.debug("applyMethod not implemented")
return
diff --git a/PyMca5/PyMcaCore/StackROIBatch.py b/PyMca5/PyMcaCore/StackROIBatch.py
index 0f10331..3b66421 100644
--- a/PyMca5/PyMcaCore/StackROIBatch.py
+++ b/PyMca5/PyMcaCore/StackROIBatch.py
@@ -37,8 +37,10 @@ import os
import numpy
from PyMca5.PyMcaIO import ConfigDict
import time
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class StackROIBatch(object):
def __init__(self):
@@ -98,7 +100,7 @@ class StackROIBatch(object):
except AttributeError:
txt = "%s" % type(data)
if 'h5py' in txt:
- print("Implementing h5py workaround")
+ _logger.info("Implementing h5py workaround")
import h5py
data = h5py.Dataset(data.id)
else:
@@ -108,8 +110,6 @@ class StackROIBatch(object):
if x is None:
x = numpy.arange(data.shape[index]).astype(numpy.float32)
- if DEBUG:
- t0 = time.time()
if configuration is not None:
self.setConfiguration(configuration)
@@ -252,12 +252,12 @@ def getFileListFromPattern(pattern, begin, end, increment=None):
return fileList
if __name__ == "__main__":
- DEBUG = True
import glob
import sys
from PyMca5.PyMca import EDFStack
from PyMca5.PyMca import ArraySave
import getopt
+ _logger.setLevel(logging.DEBUG)
options = ''
longoptions = ['cfg=', 'outdir=',
'tif=', #'listfile=',
@@ -269,7 +269,7 @@ if __name__ == "__main__":
options,
longoptions)
except:
- print(sys.exc_info()[1])
+ _logger.error(sys.exc_info()[1])
sys.exit(1)
fileRoot = ""
outputDir = None
diff --git a/PyMca5/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html b/PyMca5/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html
index 40c4d44..8154a4b 100644
--- a/PyMca5/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html
+++ b/PyMca5/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html
@@ -177,14 +177,14 @@ switches between two sets of data where one set aligns the other one it is highl
to consult the table in the Alignment window to check if every element in the two different
sets of data is assigned to its correct counterpart before applying the shift.</br>
</br>
-If the data in the plot window is zoomed in to a distinct feature, only of the data is used to
-calculate the shift.
+If the data in the plot window is zoomed in to a distinct feature, only the visible data range
+is used to calculate the shift.
</div>
<br><a href=#Up>up</a>
<H3><a NAME=Methods>
-1. Usage and Description
+2. Methods used by the plug-in
</a></H3>
<div class='main'>
@@ -194,30 +194,30 @@ FIT DRV.
<div class=elem><i>FFT</i></div>
<div class='indent'>
- Uses the Fourier Transform of the curves to calculated their cross-correlation. The maximum
- of the correlation is determined and yields the shift value. This method is the default option,
- since it is not affected by the peak shape, fast and numerically robust. Notice: the shifts
+ Uses the Fourier Transform of the curves to calculate their cross-correlation. The maximum
+ of the correlation is determined and yields the shift value. This method is the default option.
+ Since it is not affected by the peak shape, it is fast and numerically robust. Notice: the shifts
are given in real space values.
</div>
<div class=elem><i>MAX</i></div>
<div class='indent'>
- Determines the maximum of each curve, the shift is given by its the differences in the x-position
+ Determines the maximum of each curve. The shift is given by the differences in the x-position
of the maxima. Notice that this method is highly vulnerable to noise in the data and spikes.
</div>
<div class=elem><i>FIT</i></div>
<div class='indent'>
- Method subtracts a background from the data using the SNIP algorithm (c.f. plug-in section,
+ This method subtracts a background from the data using the SNIP algorithm (c.f. plug-in section,
Background subtraction tools) and searches for peaks in the data. For every curve, the single
- most pronounced feature is selected. The peak is fitted by a Gaussian model, the shifts are then
+ most pronounced feature is selected. The peak is fitted by a Gaussian model. The shifts are then
given by differences in the x-offsets of the fitted Gaussians.
</div>
-<div class=elem><i>FIT</i></div>
+<div class=elem><i>FIT DRV</i></div>
<div class='indent'>
- Uses the same procedure as the FIT method, however the fit is applied to the first derivative of
- the data. This method only recommended for X-ray absorption data.
+ Uses the same procedure as the FIT method. However the fit is applied to the first derivative of
+ the data. This method is only recommended for X-ray absorption data.
</div>
<div class='main'>
diff --git a/PyMca5/PyMcaGraph/Colormap.py b/PyMca5/PyMcaGraph/Colormap.py
index 4d7dbd9..d2d735a 100644
--- a/PyMca5/PyMcaGraph/Colormap.py
+++ b/PyMca5/PyMcaGraph/Colormap.py
@@ -38,6 +38,15 @@ __doc__ = """Convert data to a RGBA colormap."""
import numpy as np
from . import ctools
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.matplotlib.Colormap instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
# default colormaps ###########################################################
diff --git a/PyMca5/PyMcaGraph/Colors.py b/PyMca5/PyMcaGraph/Colors.py
index 0d65881..349f40f 100644
--- a/PyMca5/PyMcaGraph/Colors.py
+++ b/PyMca5/PyMcaGraph/Colors.py
@@ -33,6 +33,16 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
Dictionary of common colors.
"""
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.Colors instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
+
COLORDICT = {}
COLORDICT['b'] = COLORDICT['blue'] = '#0000ff'
diff --git a/PyMca5/PyMcaGraph/Plot.py b/PyMca5/PyMcaGraph/Plot.py
index 4f25cd4..aca2d36 100644
--- a/PyMca5/PyMcaGraph/Plot.py
+++ b/PyMca5/PyMcaGraph/Plot.py
@@ -45,9 +45,21 @@ from . import PlotBase
from . import PlotBackend
from . import Colors
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
DEBUG = 0
if DEBUG:
PlotBase.DEBUG = True
+ _logger.setLevel(logging.DEBUG)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.PlotWidget instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
+
_COLORDICT = Colors.COLORDICT
_COLORLIST = [_COLORDICT['black'],
diff --git a/PyMca5/PyMcaGraph/PlotBackend.py b/PyMca5/PyMcaGraph/PlotBackend.py
index ee7dad5..7700dc6 100644
--- a/PyMca5/PyMcaGraph/PlotBackend.py
+++ b/PyMca5/PyMcaGraph/PlotBackend.py
@@ -177,6 +177,16 @@ DEBUG = 0
from . import Colors
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.backends.BackendBase instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
+
class PlotBackend(object):
COLORDICT = Colors.COLORDICT
diff --git a/PyMca5/PyMcaGraph/PlotBase.py b/PyMca5/PyMcaGraph/PlotBase.py
index bdd72f9..b42e20e 100644
--- a/PyMca5/PyMcaGraph/PlotBase.py
+++ b/PyMca5/PyMcaGraph/PlotBase.py
@@ -58,9 +58,6 @@ The plugins will be compatible with any plot window that provides the methods:
The simplest way to achieve that is to inherit from Plot
"""
-import os
-import sys
-import glob
try:
from numpy import argsort, nonzero, take
except ImportError:
@@ -69,6 +66,16 @@ except ImportError:
from . import PlotBackend
from . import PluginLoader
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.Colors instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
+
DEBUG = 0
class PlotBase(PlotBackend.PlotBackend, PluginLoader.PluginLoader):
diff --git a/PyMca5/PyMcaGraph/PluginLoader.py b/PyMca5/PyMcaGraph/PluginLoader.py
index 443c37a..2c1b2c6 100644
--- a/PyMca5/PyMcaGraph/PluginLoader.py
+++ b/PyMca5/PyMcaGraph/PluginLoader.py
@@ -41,10 +41,12 @@ directory and stores them into the attributes pluginList and pluginInstanceDict
import os
import sys
import glob
+import logging
PLUGINS_DIR = None
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class PluginLoader(object):
def __init__(self, method=None, directoryList=None):
@@ -89,9 +91,8 @@ class PluginLoader(object):
directoryList = self._pluginDirList
if directoryList in [None, []]:
directoryList = [PLUGINS_DIR]
- if DEBUG:
- print("method: %s" % targetMethod)
- print("directoryList: %s" % directoryList)
+ _logger.debug("method: %s", targetMethod)
+ _logger.debug("directoryList: %s", directoryList)
exceptionMessage = ""
self._pluginDirList = directoryList
self.pluginList = []
@@ -118,8 +119,7 @@ class PluginLoader(object):
for module in moduleList:
try:
pluginName = os.path.basename(module)[:-3]
- if DEBUG:
- print("pluginName %s" % pluginName)
+ _logger.debug("pluginName %s", pluginName)
plugin = pluginName
if directory not in sys.path:
sys.path.insert(0, directory)
@@ -148,9 +148,8 @@ class PluginLoader(object):
exceptionMessage += "%s\n" % sys.exc_info()[1]
exceptionMessage += "%s\n" % sys.exc_info()[2]
- if len(exceptionMessage):
- if DEBUG:
- raise IOError(exceptionMessage)
+ if len(exceptionMessage) and _logger.getEffectiveLevel() == logging.DEBUG:
+ raise IOError(exceptionMessage)
if exceptions:
return len(self.pluginList), exceptionMessage
else:
diff --git a/PyMca5/PyMcaGraph/backends/__init__.py b/PyMca5/PyMcaGraph/backends/__init__.py
index e69de29..9205aa4 100644
--- a/PyMca5/PyMcaGraph/backends/__init__.py
+++ b/PyMca5/PyMcaGraph/backends/__init__.py
@@ -0,0 +1,9 @@
+import logging
+import traceback
+_logger = logging.getLogger(__name__)
+
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.backends instead",
+ __name__)
+for line in traceback.format_stack(limit=4):
+ _logger.warning(line.rstrip())
diff --git a/PyMca5/PyMcaGui/PluginsToolButton.py b/PyMca5/PyMcaGui/PluginsToolButton.py
index 8cf9066..77ddae4 100644
--- a/PyMca5/PyMcaGui/PluginsToolButton.py
+++ b/PyMca5/PyMcaGui/PluginsToolButton.py
@@ -74,21 +74,25 @@ class PluginsToolButton(qt.QToolButton, PluginLoader):
:param parent: Parent QWidget widget
"""
- def __init__(self, plot, parent=None):
+ def __init__(self, plot, parent=None, method="getPlugin1DInstance"):
qt.QToolButton.__init__(self, parent)
self.setIcon(qt.QIcon(qt.QPixmap(IconDict["plugin"])))
- self.setToolTip("Call/Load 1D Plugins")
+ if method == "getPlugin1DInstance":
+ self.setToolTip("Call/Load 1D Plugins")
+ elif method == "getPlugin2DInstance":
+ self.setToolTip("Call/Load 2D Plugins")
# fill attr pluginList and pluginInstanceDict with existing plugins
- PluginLoader.__init__(self, method='getPlugin1DInstance')
+ PluginLoader.__init__(self, method=method)
# plugins expect a legacy API, not the silx Plot API
self.plot = weakref.proxy(plot, self._ooPlotDestroyed)
+ self._plotType = getattr(self.plot, "_plotType", None)
self.clicked.connect(self._pluginClicked)
- def _ooPlotDestroyed(self):
+ def _ooPlotDestroyed(self, obj=None):
self.setEnabled(False)
def __getattr__(self, attr):
@@ -101,6 +105,30 @@ class PluginsToolButton(qt.QToolButton, PluginLoader):
raise AttributeError(
self.plot.__class__.__name__ + " has no attribute " + attr)
+ def _connectPlotSignals(self):
+ for name, plugin in self.pluginInstanceDict.items():
+ if hasattr(plugin, "activeCurveChanged") and callable(plugin.activeCurveChanged):
+ # Can we just assume it has the proper signature?
+ self.plot.sigActiveCurveChanged.connect(plugin.activeCurveChanged)
+ if hasattr(plugin, "activeImageChanged") and callable(plugin.activeImageChanged):
+ # Can we just assume it has the proper signature?
+ self.plot.sigActiveImageChanged.connect(plugin.activeImageChanged)
+
+ def _disconnectPlotSignals(self):
+ for name, plugin in self.pluginInstanceDict.items():
+ if hasattr(plugin, "activeCurveChanged") and callable(plugin.activeCurveChanged):
+ # Can we just assume it has the proper signature?
+ self.plot.sigActiveCurveChanged.disconnect(plugin.activeCurveChanged)
+ if hasattr(plugin, "activeImageChanged") and callable(plugin.activeImageChanged):
+ # Can we just assume it has the proper signature?
+ self.plot.sigActiveImageChanged.disconnect(plugin.activeImageChanged)
+
+ def getPlugins(self, method=None, directoryList=None, exceptions=False):
+ """method overloaded to update signal connections when loading plugins"""
+ self._disconnectPlotSignals()
+ PluginLoader.getPlugins(self, method, directoryList, exceptions)
+ self._connectPlotSignals()
+
def _pluginClicked(self):
actionNames = []
menu = qt.QMenu(self)
@@ -133,7 +161,7 @@ class PluginsToolButton(qt.QToolButton, PluginLoader):
text = text[:-3]
methods = pluginInstances[pluginName].getMethods(
- plottype=self.plot._plotType)
+ plottype=self._plotType)
if not len(methods):
continue
elif len(methods) == 1:
@@ -178,10 +206,11 @@ class PluginsToolButton(qt.QToolButton, PluginLoader):
return
if "Toggle DEBUG mode" in a.text():
_toggleLogger()
+ return
key = callableKeys[idx]
methods = pluginInstances[key].getMethods(
- plottype=self.plot._plotType)
+ plottype=self._plotType)
if len(methods) == 1:
idx = 0
else:
diff --git a/PyMca5/PyMcaGui/PyMcaQt.py b/PyMca5/PyMcaGui/PyMcaQt.py
index 3adbf8e..72d1db8 100644
--- a/PyMca5/PyMcaGui/PyMcaQt.py
+++ b/PyMca5/PyMcaGui/PyMcaQt.py
@@ -65,8 +65,13 @@ else: # Try the different bindings
if sys.version_info < (3,):
try:
import sip
- sip.setapi("QString", 2)
- sip.setapi("QVariant", 2)
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ sip.setapi('QDate', 2)
+ sip.setapi('QDateTime', 2)
+ sip.setapi('QTextStream', 2)
+ sip.setapi('QTime', 2)
+ sip.setapi('QUrl', 2)
except:
print("Cannot set sip API") # Console widget not available
import PyQt4
@@ -108,8 +113,13 @@ elif BINDING == "PyQt4":
if sys.version_info < (3,):
try:
import sip
- sip.setapi("QString", 2)
- sip.setapi("QVariant", 2)
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ sip.setapi('QDate', 2)
+ sip.setapi('QDateTime', 2)
+ sip.setapi('QTextStream', 2)
+ sip.setapi('QTime', 2)
+ sip.setapi('QUrl', 2)
except:
print("Cannot set sip API") # Console widget not available
from PyQt4.QtCore import *
diff --git a/PyMca5/PyMcaGui/__init__.py b/PyMca5/PyMcaGui/__init__.py
index 396fb96..121b4d7 100644
--- a/PyMca5/PyMcaGui/__init__.py
+++ b/PyMca5/PyMcaGui/__init__.py
@@ -42,6 +42,10 @@ def getPackages(directory):
from .plotting import PyMca_Icons
from .plotting.PyMca_Icons import IconDict
+## legacy (not used within PyMca)
+#import silx.gui.widgets.PrintPreview as PyMcaPrintPreview
+#PyMcaPrintPreview.PyMcaPrintPreview = PyMcaPrintPreview.SingletonPrintPreviewDialog
+
# this is the package level directory PyMcaGui
baseDirectory = os.path.dirname(__file__)
__path__ += [baseDirectory]
@@ -51,3 +55,4 @@ for directory in ["io", "math", "misc",
if os.path.exists(os.path.join(tmpDir, "__init__.py")):
__path__ += [tmpDir]
__path__ += getPackages(tmpDir)
+
diff --git a/PyMca5/PyMcaGui/io/QEdfFileWidget.py b/PyMca5/PyMcaGui/io/QEdfFileWidget.py
index 7b9819d..4a5d963 100644
--- a/PyMca5/PyMcaGui/io/QEdfFileWidget.py
+++ b/PyMca5/PyMcaGui/io/QEdfFileWidget.py
@@ -30,9 +30,18 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os.path
import numpy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
-from PyMca5.PyMcaGui import PlotWidget
+from silx.gui.plot import PlotWidget
+from silx.gui.plot.PrintPreviewToolButton import SingletonPrintPreviewToolButton
+from silx.gui import icons as silx_icons
+
+if sys.version_info[0] == 3:
+ from io import BytesIO
+else:
+ import cStringIO as _StringIO
+ BytesIO = _StringIO.StringIO
if not hasattr(qt, 'QString'):
QString = qt.safe_str
@@ -46,19 +55,43 @@ from PyMca5.PyMcaGui import QPyMcaMatplotlibSave
MATPLOTLIB = True
from PyMca5.PyMcaGui import IconDict
from PyMca5.PyMcaGui import ColormapDialog
-from PyMca5.PyMcaGui import PyMcaPrintPreview
from PyMca5.PyMcaIO import ArraySave
from PyMca5 import PyMcaDirs
from . import SpecFileDataInfo
from PyMca5 import spslut
+
+_logger = logging.getLogger(__name__)
+
+
COLORMAPLIST = [spslut.GREYSCALE, spslut.REVERSEGREY, spslut.TEMP,
spslut.RED, spslut.GREEN, spslut.BLUE, spslut.MANY]
-DEBUG = 0
SOURCE_TYPE = 'EdfFile'
__revision__ = "$Revision: 1.35 $"
+
+def convertToRowAndColumn(x, y, shape, xScale=None, yScale=None, safe=True):
+ if xScale is None:
+ c = x
+ else:
+ c = (x - xScale[0]) / xScale[1]
+ if yScale is None:
+ r = y
+ else:
+ r = ( y - yScale[0]) / yScale[1]
+
+ if safe:
+ c = min(int(c), shape[1] - 1)
+ c = max(c, 0)
+ r = min(int(r), shape[0] - 1)
+ r = max(r, 0)
+ else:
+ c = int(c)
+ r = int(r)
+ return r, c
+
+
class EdfFile_StandardArray(qt.QWidget):
sigWidgetSignal = qt.pyqtSignal(object)
@@ -228,30 +261,28 @@ class QEdfFileWidget(qt.QWidget):
self.lastInputDir = None
self.colormapDialog = None
self.colormap = None
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
- if DEBUG:
- print("printPreview id = %d" % id(self.printPreview))
#self.selectPixmap= qt.QPixmap(icons.selected)
#self.unselectPixamp= qt.QPixmap(icons.unselected)
self.mapComboName= {}
- self.mainLayout= qt.QVBoxLayout(self)
- self.toolBar = None
- self._buildToolBar()
-
# --- splitter
- self.splitter= qt.QSplitter(self)
+ self.splitter = qt.QSplitter(self)
self.splitter.setOrientation(qt.Qt.Vertical)
# --- graph
- self.graph=PlotWidget.PlotWidget(self.splitter, backend=None)
+ self.graph = PlotWidget(self.splitter, backend=None)
self.graph.setGraphTitle('')
self.graph.setGraphXLabel('Columns')
self.graph.setGraphYLabel('Rows')
self.graph.sigPlotSignal.connect(self.widgetSignal)
self._x1Limit = self.graph.getGraphXLimits()[-1]
self._y1Limit = self.graph.getGraphYLimits()[-1]
+
+ self.mainLayout = qt.QVBoxLayout(self)
+ self.toolBar = None
+ self._buildToolBar()
+
#self.graph.hide()
# --- array parameter
self.__dummyW = qt.QWidget(self.splitter)
@@ -305,6 +336,7 @@ class QEdfFileWidget(qt.QWidget):
self.zoomResetIcon = qt.QIcon(qt.QPixmap(IconDict["zoomreset"]))
self.printIcon = qt.QIcon(qt.QPixmap(IconDict["fileprint"]))
self.saveIcon = qt.QIcon(qt.QPixmap(IconDict["filesave"]))
+ self.copyIcon = silx_icons.getQIcon("edit-copy")
try:
self.infoIcon = qt.QApplication.style().\
standardIcon(qt.QStyle.SP_MessageBoxInformation)
@@ -346,8 +378,8 @@ class QEdfFileWidget(qt.QWidget):
#save
if MATPLOTLIB:
tb = self._addToolButton(self.saveIcon,
- self.__saveIconSignal,
- 'Export Graph')
+ self.__saveIconSignal,
+ 'Export Graph')
self._saveMenu = qt.QMenu()
self._saveMenu.addAction(QString("Standard"), self._saveIconSignal)
self._saveMenu.addAction(QString("Matplotlib") , self._saveMatplotlibImage)
@@ -356,6 +388,18 @@ class QEdfFileWidget(qt.QWidget):
self._saveIconSignal,
'Export Graph')
+ self.copyToolButton = self._addToolButton(self.copyIcon,
+ self._copyIconSignal,
+ "Copy graph to clipboard")
+
+ self.printPreview = SingletonPrintPreviewToolButton(parent=self,
+ plot=self.graph)
+ self.printPreview.setIcon(self.printIcon)
+ self.toolBarLayout.addWidget(self.printPreview)
+
+ _logger.debug("printPreview id = %d",
+ id(self.printPreview.printPreviewDialog))
+
#info
self.infoText = qt.QLabel(self.toolBar)
self.infoText.setText(" X = ???? Y = ???? Z = ????")
@@ -363,22 +407,12 @@ class QEdfFileWidget(qt.QWidget):
self.toolBarLayout.addWidget(qt.HorizontalSpacer(self.toolBar))
- # ---print
- tb = self._addToolButton(self.printIcon,
- self.printGraph,
- 'Print the Graph')
def _hFlipIconSignal(self):
- if DEBUG:
- print("_hFlipIconSignal called")
- if self.graph.isYAxisInverted():
- self.graph.invertYAxis(False)
- else:
- self.graph.invertYAxis(True)
- self.graph.replot()
+ _logger.debug("_hFlipIconSignal called")
+ self.graph.setYAxisInverted(not self.graph.isYAxisInverted())
def _aspectButtonSignal(self):
- if DEBUG:
- print("_aspectButtonSignal")
+ _logger.debug("_aspectButtonSignal")
if self._keepDataAspectRatioFlag:
self.keepDataAspectRatio(False)
else:
@@ -386,15 +420,13 @@ class QEdfFileWidget(qt.QWidget):
def keepDataAspectRatio(self, flag=True):
if flag:
- self._keepDataAspectRatioFlag = True
self.aspectButton.setIcon(self.solidEllipseIcon)
self.aspectButton.setToolTip("Set free data aspect ratio")
else:
- self._keepDataAspectRatioFlag = False
self.aspectButton.setIcon(self.solidCircleIcon)
self.aspectButton.setToolTip("Keep data aspect ratio")
- self.graph.keepDataAspectRatio(self._keepDataAspectRatioFlag)
-
+ self._keepDataAspectRatioFlag = flag
+ self.graph.setKeepDataAspectRatio(flag)
def _addToolButton(self, icon, action, tip, toggle=None):
tb = qt.QToolButton(self.toolBar)
@@ -435,10 +467,19 @@ class QEdfFileWidget(qt.QWidget):
self._dataInfoClosed(ddict)
def _zoomReset(self):
- if DEBUG:
- print("_zoomReset")
+ _logger.debug("_zoomReset")
self.graph.resetZoom()
+ def _copyIconSignal(self):
+ pngFile = BytesIO()
+ self.graph.saveGraph(pngFile, fileFormat='png')
+ pngFile.flush()
+ pngFile.seek(0)
+ pngData = pngFile.read()
+ pngFile.close()
+ image = qt.QImage.fromData(pngData, 'png')
+ qt.QApplication.clipboard().setImage(image)
+
def _saveMatplotlibImage(self):
if self._matplotlibSaveImage is None:
if (self.currentArray is None) or \
@@ -553,22 +594,25 @@ class QEdfFileWidget(qt.QWidget):
else:
self.saveGraphWidget(outputFile)
- def saveGraphImage(self, filename,original=True):
- fformat = filename[-3:].upper()
- #This is the whole image, not the zoomed one ...
- rgbData, legend, info, pixmap = self.graph.getActiveImage()
+ def saveGraphImage(self, filename, original=False):
+ format_ = filename[-3:].upper()
+ activeImage = self.graph.getActiveImage()
+ rgbdata = activeImage.getRgbaImageData()
+ # silx to pymca scale convention (a + b x)
+ xScale = activeImage.getOrigin()[0], activeImage.getScale()[0]
+ yScale = activeImage.getOrigin()[1], activeImage.getScale()[1]
if original:
# save whole image
- bgrData = numpy.array(rgbData, copy=True)
- bgrData[:,:,0] = rgbData[:, :, 2]
- bgrData[:,:,2] = rgbData[:, :, 0]
+ bgradata = numpy.array(rgbdata, copy=True)
+ bgradata[:, :, 0] = rgbdata[:, :, 2]
+ bgradata[:, :, 2] = rgbdata[:, :, 0]
else:
- shape = rgbData.shape[:2]
+ shape = rgbdata.shape[:2]
xmin, xmax = self.graph.getGraphXLimits()
ymin, ymax = self.graph.getGraphYLimits()
# save zoomed image, for that we have to get the limits
- r0, c0 = ymin, xmin
- r1, c1 = ymax, xmax
+ r0, c0 = convertToRowAndColumn(xmin, ymin, shape, xScale=xScale, yScale=yScale, safe=True)
+ r1, c1 = convertToRowAndColumn(xmax, ymax, shape, xScale=xScale, yScale=yScale, safe=True)
row0 = int(min(r0, r1))
row1 = int(max(r0, r1))
col0 = int(min(c0, c1))
@@ -577,26 +621,27 @@ class QEdfFileWidget(qt.QWidget):
row1 += 1
if col1 < shape[1]:
col1 += 1
- tmpArray = rgbData[row0:row1, col0:col1, :]
- bgrData = numpy.array(tmpArray, copy=True, dtype=rgbData.dtype)
- bgrData[:,:,0] = tmpArray[:, :, 2]
- bgrData[:,:,2] = tmpArray[:, :, 0]
+ tmpArray = rgbdata[row0:row1, col0:col1, :]
+ bgradata = numpy.array(tmpArray, copy=True, dtype=rgbdata.dtype)
+ bgradata[:, :, 0] = tmpArray[:, :, 2]
+ bgradata[:, :, 2] = tmpArray[:, :, 0]
if self.graph.isYAxisInverted():
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32)
else:
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32).mirrored(False, True)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32).mirrored(False, True)
pixmap = qt.QPixmap.fromImage(qImage)
- if pixmap.save(filename, fformat):
+ if pixmap.save(filename, format_):
return
else:
- qt.QMessageBox.critical(self, "Save Error", "%s" % sys.exc_info()[1])
+ qt.QMessageBox.critical(self, "Save Error",
+ "%s" % sys.exc_info()[1])
return
def saveGraphWidget(self, filename):
fformat = filename[-3:].upper()
- if hasattr(qt.QPixmap, "graphWidget"):
+ if hasattr(qt.QPixmap, "grabWidget"):
# Qt4
pixmap = qt.QPixmap.grabWidget(self.graph)
else:
@@ -615,18 +660,6 @@ class QEdfFileWidget(qt.QWidget):
else:
return False
- def printGraph(self):
- if hasattr(qt.QPixmap, "graphWidget"):
- # Qt4
- pixmap = qt.QPixmap.grabWidget(self.graph)
- else:
- #Qt5
- pixmap = self.graph.grab()
- self.printPreview.addPixmap(pixmap)
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
-
def _buildActions(self):
self.buttonBox = qt.QWidget(self)
buttonBox = self.buttonBox
@@ -794,17 +827,14 @@ class QEdfFileWidget(qt.QWidget):
else:
self.removeSelection([nsel])
elif dict['event'] == 'imageChanged':
- if DEBUG:
- print("Image changed")
+ _logger.debug("Image changed")
if dict['index'] != self.currentArray:
self.currentArray = dict['index']
self.refresh()
- if DEBUG:
- print("self.currentArray = ",self.currentArray)
+ _logger.debug("self.currentArray = %s", self.currentArray)
def openFile(self, filename=None,justloaded=None):
- if DEBUG:
- print("openfile = %s" % filename)
+ _logger.debug("openfile = %s", filename)
if justloaded is None:justloaded = 0
if filename is None:
self.lastInputDir = PyMcaDirs.inputDir
@@ -1023,10 +1053,9 @@ class QEdfFileWidget(qt.QWidget):
var[3],
var[4],
var[5]]
- #self.graph.invertYAxis(True)
+ #self.graph.setYAxisInverted(True)
pixmap = self.getPixmapFromData(self.lastData, self.colormap)
self.graph.addImage(pixmap, legend="QEdfFileWidget")
- self.graph.replot()
def closeFile(self, filename=None):
if filename is None:
@@ -1051,8 +1080,7 @@ class QEdfFileWidget(qt.QWidget):
try:
self.sigDelSelection.emit((self.data.SourceName, mcakeys))
except:
- if DEBUG:
- print("sigDelSelection is to be implemented")
+ _logger.debug("sigDelSelection is to be implemented")
for idx in range(self.fileCombo.count()):
itext = self.fileCombo.itemText(idx)
@@ -1085,22 +1113,18 @@ class QEdfFileWidget(qt.QWidget):
self.graph.removeImage(legend="QEdfFileWidget")
self.oldsource = None
self.graph.clearMarkers()
- self.graph.replot()
wid = self.__getParamWidget('array')
wid.setImages(1)
- wid.setDataSize(0,0)
-
+ wid.setDataSize(0, 0)
def setDataSource(self,data=None):
- if DEBUG:
- print("setData(self, data) called")
- print("data = ",data)
+ _logger.debug("setData(self, data) called")
+ _logger.debug("data = %s", data)
self.data= data
self.refresh()
def refresh(self):
- if DEBUG:
- print("refresh method called")
+ _logger.debug("refresh method called")
if self.data is None:
self._reset()
#wid = self.__getParamWidget('array')
@@ -1110,10 +1134,9 @@ class QEdfFileWidget(qt.QWidget):
return
self.currentFile = self.data.sourceName
#this gives the number of images in the file
- infoSource= self.data.getSourceInfo()
- if DEBUG:
- print("info :")
- print(infoSource)
+ infoSource = self.data.getSourceInfo()
+ _logger.debug("info :")
+ _logger.debug("%s", infoSource)
nimages=len(infoSource['KeyList'])
#print self.data.SourceName,"nimages = ",nimages
@@ -1127,19 +1150,16 @@ class QEdfFileWidget(qt.QWidget):
#print "SUM = ",loadsum, infoSource['KeyList']
#print self.currentArray
if (self.oldsource != self.currentFile) or (self.oldcurrentArray != self.currentArray):
- if DEBUG:
- print("I have to read again ... ")
+ _logger.debug("I have to read again ... ")
if not loadsum:
- if DEBUG:
- print("Not Loading the sum")
+ _logger.debug("Not Loading the sum")
dataObject = self.data.getDataObject(infoSource['KeyList']\
[self.currentArray])
info = dataObject.info
data = dataObject.data
imageinfo = infoSource['KeyList']
else:
- if DEBUG:
- print("Loading the sum")
+ _logger.debug("Loading the sum")
dataObject = self.data.getDataObject('0.0')
info = dataObject.info
data = dataObject.data
@@ -1157,9 +1177,9 @@ class QEdfFileWidget(qt.QWidget):
if 'Title' in header:
imageinfo[i] += "- " + header['Title']
i+=1
- if DEBUG:
- print("NOT ADDING 0.0 - SUM KEY")
- wid.setImages(nimages+1,info = imageinfo+["0.0 - SUM"])
+ _logger.debug("NOT ADDING 0.0 - SUM KEY")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ wid.setImages(nimages+1, info = imageinfo+["0.0 - SUM"])
wid.setImages(nimages,info = imageinfo)
else:
if 'Title' in info:
@@ -1168,10 +1188,9 @@ class QEdfFileWidget(qt.QWidget):
wid.setCurrentImage(self.currentArray)
#P.B. -> pointer(a,d1,d2,i1,i2) = a+ (i1+i2 * d1)
wid.setDataSize(int(info["Dim_2"]), int(info["Dim_1"]))
- if DEBUG:
- print("Image size = %d x %d" % (int(info["Dim_2"]),
- int(info["Dim_1"])))
- print("data size = ", data.shape)
+ _logger.debug("Image size = %d x %d",
+ int(info["Dim_2"]), int(info["Dim_1"]))
+ _logger.debug("data size = %s", data.shape)
if self.graph.isHidden():
self.graph.show()
@@ -1205,7 +1224,6 @@ class QEdfFileWidget(qt.QWidget):
pixmap = self.getPixmapFromData(data, self.colormap)
self.graph.addImage(pixmap, legend="QEdfFileWidget")
self.__refreshSelection()
- self.graph.replot()
self.oldsource = "%s" % self.data.sourceName
self.oldcurrentArray = self.currentArray * 1
@@ -1213,13 +1231,11 @@ class QEdfFileWidget(qt.QWidget):
return self.paramWidget
def _replaceClicked(self):
- if DEBUG:
- print("replace clicked")
+ _logger.debug("replace clicked")
selkeys= self.__getSelectedKeys()
if len(selkeys):
#self.eh.event(self.repEvent, selkeys)
- if DEBUG:
- print("Replace event")
+ _logger.debug("Replace event")
if self.allImages:
arraynamelist = self.data.getSourceInfo()['KeyList']
else:
@@ -1268,8 +1284,7 @@ class QEdfFileWidget(qt.QWidget):
self.sigReplaceSelection.emit(signalsellist)
def _add2DClicked(self, replace=False, emit=True):
- if DEBUG:
- print("ADD 2D clicked")
+ _logger.debug("ADD 2D clicked")
if (self.data is None) or \
(self.currentArray is None):
return
@@ -1299,8 +1314,7 @@ class QEdfFileWidget(qt.QWidget):
return [sel]
def _remove2DClicked(self):
- if DEBUG:
- print("REMOVE 2D clicked")
+ _logger.debug("REMOVE 2D clicked")
infoSource= self.data.getSourceInfo()
sel = {}
sel['SourceType'] = infoSource['SourceType']
@@ -1318,8 +1332,7 @@ class QEdfFileWidget(qt.QWidget):
self.sigRemoveSelection.emit([sel])
def _replace2DClicked(self):
- if DEBUG:
- print("REPLACE 2D clicked")
+ _logger.debug("REPLACE 2D clicked")
self._add2DClicked(replace=True)
def currentSelectionList(self):
@@ -1329,15 +1342,12 @@ class QEdfFileWidget(qt.QWidget):
return a
def _addClicked(self, emit=True):
- if DEBUG:
- print("select clicked")
+ _logger.debug("select clicked")
selkeys= self.__getSelectedKeys()
- if DEBUG:
- print("selected keys = ",selkeys)
+ _logger.debug("selected keys = %s", selkeys)
if len(selkeys):
#self.eh.event(self.addEvent, selkeys)
- if DEBUG:
- print("Select event")
+ _logger.debug("Select event")
if self.allImages:
arraynamelist = self.data.getSourceInfo()['KeyList']
else:
@@ -1416,16 +1426,14 @@ class QEdfFileWidget(qt.QWidget):
return selkeys
def _removeClicked(self):
- if DEBUG:
- print("remove clicked")
+ _logger.debug("remove clicked")
selkeys= self.__getSelectedKeys()
returnedselection=[]
signalsellist = []
if len(selkeys):
#self.eh.event(self.delEvent, selkeys)
- if DEBUG:
- print("Remove Event")
- print("self.selection before = ",self.selection)
+ _logger.debug("Remove Event")
+ _logger.debug("self.selection before = %s", self.selection)
if self.allImages:
arraynamelist = self.data.getSourceInfo()['KeyList']
else:
@@ -1453,17 +1461,13 @@ class QEdfFileWidget(qt.QWidget):
if selection['plot'] == 'rows':
sel[arrayname]['rows'].append({'x':selection['x'],'y':selection['y']})
if self.selection is not None:
- if DEBUG:
- print("step 1")
+ _logger.debug("step 1")
if sel['SourceName'] in self.selection:
- if DEBUG:
- print("step 2")
+ _logger.debug("step 2")
if arrayname in self.selection[sel['SourceName']]:
- if DEBUG:
- print("step 3")
+ _logger.debug("step 3")
if 'rows' in self.selection[sel['SourceName']][arrayname]:
- if DEBUG:
- print("step 4")
+ _logger.debug("step 4")
for couple in sel[arrayname]['rows']:
if couple in self.selection[sel['SourceName']][arrayname]['rows']:
index= self.selection[sel['SourceName']][arrayname]['rows'].index(couple)
@@ -1512,17 +1516,13 @@ class QEdfFileWidget(qt.QWidget):
for sel in selection:
arrayname = sel['Key']
if self.selection is not None:
- if DEBUG:
- print("step 1")
+ _logger.debug("step 1")
if sel['SourceName'] in self.selection:
- if DEBUG:
- print("step 2")
+ _logger.debug("step 2")
if arrayname in self.selection[sel['SourceName']]:
- if DEBUG:
- print("step 3")
+ _logger.debug("step 3")
if 'rows' in self.selection[sel['SourceName']][arrayname]:
- if DEBUG:
- print("step 4")
+ _logger.debug("step 4")
for couple in sel[arrayname]['rows']:
if couple in self.selection[sel['SourceName']][arrayname]['rows']:
index= self.selection[sel['SourceName']][arrayname]['rows'].index(couple)
@@ -1564,11 +1564,10 @@ class QEdfFileWidget(qt.QWidget):
self.sigRemoveSelection.emit(signalsellist)
def setSelected(self,sellist,reset=1):
- if DEBUG:
- print("setSelected(self,sellist,reset=1) called")
- print("sellist = ",sellist)
- print("selection before = ",self.selection)
- print("reset = ",reset)
+ _logger.debug("setSelected(self,sellist,reset=1) called")
+ _logger.debug("sellist = %s", sellist)
+ _logger.debug("selection before = %s", self.selection)
+ _logger.debug("reset = %s", reset)
if reset:
self.selection = {}
elif self.selection is None:
@@ -1598,8 +1597,7 @@ class QEdfFileWidget(qt.QWidget):
for rowsel in sel[selkey]['cols']:
if rowsel not in self.selection[specname][selkey]['cols']:
self.selection[specname][selkey]['cols'].append(rowsel)
- if DEBUG:
- print("self.selection after = ",self.selection)
+ _logger.debug("self.selection after = %s", self.selection)
self.__refreshSelection()
def getSelection(self):
@@ -1621,10 +1619,9 @@ class QEdfFileWidget(qt.QWidget):
def __refreshSelection(self):
- if DEBUG:
- print("__refreshSelection(self) called")
- print(self.selection)
- print("self.data.SourceName = ",self.data.sourceName)
+ _logger.debug("__refreshSelection(self) called")
+ _logger.debug(self.selection)
+ _logger.debug("self.data.SourceName = %s", self.data.sourceName)
if self.selection is not None:
if self.data is None:
return
@@ -1650,9 +1647,9 @@ class QEdfFileWidget(qt.QWidget):
for key in sel.keys():
if (sel[key]['rows'] != []) or (sel[key]['cols'] != []):
selkeys.append(key)
- if DEBUG:
- print("selected images =",selkeys,"but self.selection = ",self.selection)
- print("and self.selection.get(self.data.SourceName, {}) =",sel)
+ _logger.debug("selected images = %s but self.selection = %s",
+ selkeys, self.selection)
+ _logger.debug("and self.selection.get(self.data.SourceName, {}) = %s ", sel)
wid = self.__getParamWidget("array")
wid.markImageSelected(selkeys)
@@ -1681,17 +1678,16 @@ class QEdfFileWidget(qt.QWidget):
self.graph.clearMarkers()
for i in rows:
label = "R%d" % i
- marker=self.graph.insertYMarker(i,
- label,
- text=label,
- color='white')
+ marker = self.graph.addYMarker(i,
+ label,
+ text=label,
+ color='white')
for i in cols:
label = "C%d" % i
- marker=self.graph.insertXMarker(i,
- label,
- text=label,
- color='white')
- self.graph.replot()
+ marker = self.graph.addXMarker(i,
+ label,
+ text=label,
+ color='white')
return
def closeEvent(self, event):
@@ -1720,9 +1716,12 @@ def test():
def addSelection(sel):
print("addSelection", sel)
- a= qt.QApplication(sys.argv)
- a.lastWindowClosed.connect(a.quit)
-
+ if qt.QApplication.instance() is None:
+ a = qt.QApplication(sys.argv)
+ a.lastWindowClosed.connect(a.quit)
+ sys.excepthook = qt.exceptionHandler
+ else:
+ a = None
w = QEdfFileWidget()
#print w
if len(sys.argv) > 1:
@@ -1738,8 +1737,11 @@ def test():
w.sigRemoveSelection.connect(removeSelection)
w.sigReplaceSelection.connect(replaceSelection)
w.show()
- a.exec_()
+ if a is not None:
+ a.exec_()
+ else:
+ return w
-if __name__=="__main__":
+if __name__ == "__main__":
test()
diff --git a/PyMca5/PyMcaGui/io/QSelectorWidget.py b/PyMca5/PyMcaGui/io/QSelectorWidget.py
index 148d6f9..5d7b6fe 100644
--- a/PyMca5/PyMcaGui/io/QSelectorWidget.py
+++ b/PyMca5/PyMcaGui/io/QSelectorWidget.py
@@ -27,11 +27,13 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class QSelectorWidget(qt.QWidget):
def __init__(self, parent=None):
@@ -44,8 +46,7 @@ class QSelectorWidget(qt.QWidget):
"""
Method to be overwritten to build the main widget
"""
- if DEBUG:
- print("_build():Method to be overwritten")
+ _logger.debug("_build():Method to be overwritten")
pass
def _buildActions(self):
@@ -74,16 +75,13 @@ class QSelectorWidget(qt.QWidget):
self._addClicked()
def _addClicked(self):
- if DEBUG:
- print("_addClicked()")
+ _logger.debug("_addClicked()")
def _removeClicked(self):
- if DEBUG:
- print("_removeClicked()")
+ _logger.debug("_removeClicked()")
def _replaceClicked(self):
- if DEBUG: print(
- "_replaceClicked()")
+ _logger.debug("_replaceClicked()")
def test():
diff --git a/PyMca5/PyMcaGui/io/QSourceSelector.py b/PyMca5/PyMcaGui/io/QSourceSelector.py
index 8d16946..e7be450 100644
--- a/PyMca5/PyMcaGui/io/QSourceSelector.py
+++ b/PyMca5/PyMcaGui/io/QSourceSelector.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
from PyMca5.PyMcaGui import PyMca_Icons as icons
@@ -36,7 +37,7 @@ from PyMca5.PyMcaIO import spswrap as sps
from PyMca5 import PyMcaDirs
from PyMca5.PyMcaGui.io import PyMcaFileDialogs
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class QSourceSelector(qt.QWidget):
sigSourceSelectorSignal = qt.pyqtSignal(object)
@@ -116,8 +117,7 @@ class QSourceSelector(qt.QWidget):
self.mainLayout.addWidget(self.fileWidget)
def _reload(self):
- if DEBUG:
- print("_reload called")
+ _logger.debug("_reload called")
qstring = self.fileCombo.currentText()
if not len(qstring):
return
@@ -141,8 +141,7 @@ class QSourceSelector(qt.QWidget):
self.openFile(sourcename, specsession=specsession)
def openFile(self, filename=None, justloaded=None, specsession = False):
- if DEBUG:
- print("openfile = ",filename)
+ _logger.debug("openfile = %s", filename)
staticDialog = False
if not specsession:
if justloaded is None:
@@ -218,8 +217,7 @@ class QSourceSelector(qt.QWidget):
self.sigSourceSelectorSignal.emit(ddict)
def closeFile(self):
- if DEBUG:
- print("closeFile called")
+ _logger.debug("closeFile called")
#get current combobox key
qstring = self.fileCombo.currentText()
if not len(qstring):
@@ -244,9 +242,7 @@ class QSourceSelector(qt.QWidget):
"No SPEC Shared Memory Found",
"No shared memory source available")
return
- if QTVERSION < '4.0.0':
- print("should I keep Qt3 version?")
- return
+
menu = qt.QMenu()
for spec in speclist:
if hasattr(qt, "QString"):
@@ -258,8 +254,7 @@ class QSourceSelector(qt.QWidget):
menu.exec_(self.cursor().pos())
def _fileSelection(self, qstring):
- if DEBUG:
- print("file selected ", qstring)
+ _logger.debug("file selected %s", qstring)
key = str(qstring)
ddict = {}
ddict["event"] = "SourceSelected"
diff --git a/PyMca5/PyMcaGui/io/QSpecFileWidget.py b/PyMca5/PyMcaGui/io/QSpecFileWidget.py
index 4f868c9..3aacfc3 100644
--- a/PyMca5/PyMcaGui/io/QSpecFileWidget.py
+++ b/PyMca5/PyMcaGui/io/QSpecFileWidget.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui.io import QSelectorWidget
from PyMca5.PyMcaGui.io import SpecFileDataInfo
@@ -36,9 +37,10 @@ from PyMca5.PyMcaGui.io import SpecFileCntTable
OBJECT3D = SpecFileCntTable.OBJECT3D
from PyMca5.PyMcaGui.io import SpecFileMcaTable
+_logger = logging.getLogger(__name__)
+
QTVERSION = qt.qVersion()
-DEBUG = 0
if QTVERSION > '4.2.0':
class MyQTreeWidgetItem(qt.QTreeWidgetItem):
def __lt__(self, other):
@@ -264,9 +266,8 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
#
#NEW data management
def setDataSource(self, datasource):
- if DEBUG:
- print("setDataSource(self, datasource) called")
- print("datasource = ", datasource)
+ _logger.debug("setDataSource(self, datasource) called")
+ _logger.debug("datasource = %s", datasource)
self.data = datasource
self.refresh()
@@ -282,9 +283,8 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
#OLD data management
def setData(self, specfiledata):
- if DEBUG:
- print("setData(self, specfiledata) called")
- print("specfiledata = ",specfiledata)
+ _logger.debug("setData(self, specfiledata) called")
+ _logger.debug("specfiledata = %s", specfiledata)
self.data= specfiledata
self.refresh()
@@ -335,8 +335,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
item.setText(0, "")
def _autoReplace(self, scanlist=None):
- if DEBUG:
- print("autoreplace called with ",scanlist)
+ _logger.debug("autoreplace called with %s", scanlist)
if self.autoReplaceBox.isChecked():
self._replaceClicked()
elif self.autoAddBox.isChecked():
@@ -353,12 +352,10 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
def __selectionChanged(self):
- if DEBUG:
- print("__selectionChanged")
+ _logger.debug("__selectionChanged")
itemlist = self.list.selectedItems()
sel = [str(item.text(1)) for item in itemlist]
- if DEBUG:
- print("selection = ",sel)
+ _logger.debug("selection = %s", sel)
if not len(sel):
return
info = self.data.getKeyInfo(sel[0])
@@ -412,10 +409,8 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
self.list.sortItems(index, qt.Qt.AscendingOrder)
#print "index = ", index
-
def __doubleClicked(self, item):
- if DEBUG:
- print("__doubleClicked")
+ _logger.debug("__doubleClicked")
if item is not None:
sn = str(item.text(1))
ddict={}
@@ -429,8 +424,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
self._addClicked()
def __contextMenu(self, point):
- if DEBUG:
- print("__contextMenu",point)
+ _logger.debug("__contextMenu %s", point)
item = self.list.itemAt(point)
if item is not None:
sn= str(item.text(1))
@@ -474,8 +468,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
if idx is None:
if QTVERSION > '4.0.0':
idx = self.menu_idx
- if DEBUG:
- print("Scan information:")
+ _logger.debug("Scan information:")
try:
info = self.data.getDataObject(self.scans[idx]).info
@@ -485,7 +478,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
text = "Error: %s\n accessing scan information." % (sys.exc_info()[1])
msg.setText(text)
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
return
@@ -508,8 +501,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
self._dataInfoClosed(ddict)
def _addClicked(self, emit=True):
- if DEBUG:
- print("Overwritten _addClicked method")
+ _logger.debug("Overwritten _addClicked method")
#get selected scan keys
if QTVERSION < '4.0.0':
@@ -574,10 +566,8 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
def currentSelectionList(self):
return self._addClicked(emit=False)
-
def _removeClicked(self):
- if DEBUG:
- print("Overwritten _removeClicked method")
+ _logger.debug("Overwritten _removeClicked method")
#get selected scan keys
itemlist = self.list.selectedItems()
@@ -625,8 +615,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
self.sigRemoveSelection.emit(sel_list)
def _replaceClicked(self):
- if DEBUG:
- print("Overwritten _replaceClicked method")
+ _logger.debug("Overwritten _replaceClicked method")
#get selected scan keys
itemlist = self.list.selectedItems()
scan_sel = [str(item.text(1)) for item in itemlist]
@@ -682,8 +671,7 @@ class QSpecFileWidget(QSelectorWidget.QSelectorWidget):
self.sigReplaceSelection.emit(sel_list)
def _tabChanged(self, value):
- if DEBUG:
- print("self._tabChanged(value), value = ",value)
+ _logger.debug("self._tabChanged(value), value = %s", value)
text = str(self.mainTab.tabText(value))
if self.data is None: return
diff --git a/PyMca5/PyMcaGui/io/QSpsWidget.py b/PyMca5/PyMcaGui/io/QSpsWidget.py
index 1ef3733..5c667b1 100644
--- a/PyMca5/PyMcaGui/io/QSpsWidget.py
+++ b/PyMca5/PyMcaGui/io/QSpsWidget.py
@@ -27,14 +27,16 @@ __author__ = "E. Papillon, V.A. Sole - ESRF Software Group"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+import logging
from PyMca5.PyMcaIO import spswrap as sps
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui.io import SpecFileCntTable
from PyMca5.PyMcaGui import MaskImageWidget
QTVERSION = qt.qVersion()
from PyMca5.PyMcaGui import PyMca_Icons as icons
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
SOURCE_TYPE = 'SPS'
SCAN_MODE = True
@@ -111,8 +113,7 @@ class SPSFramesMcaWidget(qt.QWidget):
class SPSScanArrayWidget(SpecFileCntTable.SpecFileCntTable):
def setInfo(self, info):
- if DEBUG:
- print("info = ", info)
+ _logger.debug("info = %s", info)
if "LabelNames" in info:
# new style
cntList = info.get("LabelNames", [])
@@ -124,10 +125,8 @@ class SPSScanArrayWidget(SpecFileCntTable.SpecFileCntTable):
#We have environment information
if "datafile" in info["envdict"]:
if info["envdict"]["datafile"] != "/dev/null":
- if DEBUG:
- print("I should send a signal, either from here or from the parent to the dispatcher")
- if DEBUG:
- print("SPEC data file = %s" % datafile)
+ _logger.debug("I should send a signal, either from here or from the parent to the dispatcher")
+ _logger.debug("SPEC data file = %s", info["envdict"]["datafile"])
#usefull keys = ["datafile", "scantype", "axistitles","plotlist", "xlabel", "ylabel"]
#
#info = self.data.getKeyInfo(sel[0])
@@ -244,8 +243,7 @@ class SPSXiaArrayWidget(qt.QWidget):
layout.addWidget(self.title, 0, 0)
layout.setAlignment(self.title, qt.Qt.AlignCenter)
##layout.addRowSpacing(0, 40)
- if DEBUG:
- print("row spacing")
+ _logger.debug("row spacing")
layout.addWidget(self.detList, 1, 0)
def setTitle(self, title):
@@ -554,17 +552,15 @@ class QSpsWidget(qt.QWidget):
mainLayout.addWidget(butWidget)
def setData(self,data=None):
- if DEBUG:
- print("setData(self, data) called")
- print("spec data = ",data)
+ _logger.debug("setData(self, data) called")
+ _logger.debug("spec data = %s", data)
self.data= data
self.refreshSpecList()
self.refreshDataSelection()
def setDataSource(self,data=None):
- if DEBUG:
- print("setDataSource(self, data) called")
- print("spec data = ",data)
+ _logger.debug("setDataSource(self, data) called")
+ _logger.debug("spec data = %s", data)
self.data= data
self.refreshSpecList()
self.refreshDataSelection()
@@ -639,10 +635,9 @@ class QSpsWidget(qt.QWidget):
cols= info[1]
type= info[2]
flag= info[3]
- if DEBUG:
- print(" array = ", array)
- print(" flag = ", flag)
- print(" type = ", type)
+ _logger.debug(" array = %s", array)
+ _logger.debug(" flag = %s", flag)
+ _logger.debug(" type = %s", type)
if type!=sps.STRING:
if (flag & sps.TAG_ARRAY) == sps.TAG_ARRAY:
arraylist[array]= (rows, cols)
@@ -736,13 +731,11 @@ class QSpsWidget(qt.QWidget):
return wid
def __replaceClicked(self):
- if DEBUG:
- print("replace clicked")
+ _logger.debug("replace clicked")
selkeys= self.__getSelectedKeys()
if len(selkeys):
#self.eh.event(self.repEvent, selkeys)
- if DEBUG:
- print("Replace event")
+ _logger.debug("Replace event")
sel = {}
sel['SourceType'] = SOURCE_TYPE
sellistsignal = []
@@ -841,15 +834,12 @@ class QSpsWidget(qt.QWidget):
return self._addClicked()
def _addClicked(self, emit=True):
- if DEBUG:
- print("select clicked")
+ _logger.debug("select clicked")
selkeys= self.__getSelectedKeys()
- if DEBUG:
- print("selected keys = ",selkeys )
+ _logger.debug("selected keys = %s", selkeys )
if len(selkeys):
#self.eh.event(self.addEvent, selkeys)
- if DEBUG:
- print("Select event")
+ _logger.debug("Select event")
sel = {}
sel['SourceType'] = SOURCE_TYPE
sellistsignal = []
@@ -962,14 +952,12 @@ class QSpsWidget(qt.QWidget):
return selkeys
def __removeClicked(self):
- if DEBUG:
- print("remove clicked")
+ _logger.debug("remove clicked")
selkeys= self.__getSelectedKeys()
if len(selkeys):
#self.eh.event(self.delEvent, selkeys)
- if DEBUG:
- print("Remove Event")
- print("self.selection before = ",self.selection)
+ _logger.debug("Remove Event")
+ _logger.debug("self.selection before = %s", self.selection)
returnedselection=[]
sellistsignal = []
for selection in selkeys:
@@ -1043,17 +1031,13 @@ class QSpsWidget(qt.QWidget):
sellistsignal.append(selsignal)
returnedselection.append(sel)
if self.selection is not None:
- if DEBUG:
- print("step 1")
+ _logger.debug("step 1")
if sel['SourceName'] in self.selection:
- if DEBUG:
- print("step 2")
+ _logger.debug("step 2")
if arrayname in self.selection[sel['SourceName']]:
- if DEBUG:
- print("step 3")
+ _logger.debug("step 3")
if 'rows' in self.selection[sel['SourceName']][arrayname]:
- if DEBUG:
- print("step 4")
+ _logger.debug("step 4")
for couple in sel[arrayname]['rows']:
if couple in self.selection[sel['SourceName']][arrayname]['rows']:
index= self.selection[sel['SourceName']][arrayname]['rows'].index(couple)
@@ -1077,17 +1061,13 @@ class QSpsWidget(qt.QWidget):
for sel in selection:
arrayname = sel['Key']
if self.selection is not None:
- if DEBUG:
- print("step 1")
+ _logger.debug("step 1")
if sel['SourceName'] in self.selection:
- if DEBUG:
- print("step 2")
+ _logger.debug("step 2")
if arrayname in self.selection[sel['SourceName']]:
- if DEBUG:
- print("step 3")
+ _logger.debug("step 3")
if 'rows' in self.selection[sel['SourceName']][arrayname]:
- if DEBUG:
- print("step 4")
+ _logger.debug("step 4")
for couple in sel[arrayname]['rows']:
if couple in self.selection[sel['SourceName']][arrayname]['rows']:
index= self.selection[sel['SourceName']][arrayname]['rows'].index(couple)
@@ -1105,11 +1085,10 @@ class QSpsWidget(qt.QWidget):
self.sigRemoveSelection.emit((selection))
def setSelected(self,sellist,reset=1):
- if DEBUG:
- print("setSelected(self,sellist,reset=1) called")
- print("sellist = ",sellist)
- print("selection before = ",self.selection)
- print("reset = ",reset)
+ _logger.debug("setSelected(self,sellist,reset=1) called")
+ _logger.debug("sellist = %s", sellist)
+ _logger.debug("selection before = %s", self.selection)
+ _logger.debug("reset = %s", reset)
if reset:
self.selection = {}
elif self.selection is None:
@@ -1133,8 +1112,7 @@ class QSpsWidget(qt.QWidget):
for rowsel in sel[selkey]['cols']:
if rowsel not in self.selection[specname][selkey]['cols']:
self.selection[specname][selkey]['cols'].append(rowsel)
- if DEBUG:
- print("self.selection after = ",self.selection)
+ _logger.debug("self.selection after = %s", self.selection)
self.__refreshSelection()
def getSelection(self):
@@ -1157,19 +1135,17 @@ class QSpsWidget(qt.QWidget):
def __refreshSelection(self):
return
- if DEBUG:
- print("__refreshSelection(self) called")
- print(self.selection)
+ _logger.debug("__refreshSelection(self) called")
+ _logger.debug(selection)
if self.selection is not None:
sel = self.selection.get(self.data.SourceName, {})
selkeys = []
for key in sel.keys():
if (sel[key]['mca'] != []) or (sel[key]['scan']['Ycnt'] != []):
selkeys.append(key)
- if DEBUG:
- print("selected scans =",selkeys)
- print("but self.selection = ",self.selection)
- print("and self.selection.get(self.data.SourceName, {}) =",sel)
+ _logger.debug("selected scans = %s", selkeys)
+ _logger.debug("but self.selection = %s", self.selection)
+ _logger.debug("and self.selection.get(self.data.SourceName, {}) = %s", sel)
self.scanList.markScanSelected(selkeys)
scandict = sel.get(self.currentScan, {})
if 'mca' in scandict:
diff --git a/PyMca5/PyMcaGui/io/SpecFileCntTable.py b/PyMca5/PyMcaGui/io/SpecFileCntTable.py
index ecc675c..84cb0e9 100644
--- a/PyMca5/PyMcaGui/io/SpecFileCntTable.py
+++ b/PyMca5/PyMcaGui/io/SpecFileCntTable.py
@@ -27,10 +27,9 @@ __author__ = "E. Papillon, V.A. Sole - ESRF Software Group"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
try:
import PyMca5.Object3D
diff --git a/PyMca5/PyMcaGui/io/SpecFileMcaTable.py b/PyMca5/PyMcaGui/io/SpecFileMcaTable.py
index 63f8221..f31b148 100644
--- a/PyMca5/PyMcaGui/io/SpecFileMcaTable.py
+++ b/PyMca5/PyMcaGui/io/SpecFileMcaTable.py
@@ -27,12 +27,13 @@ __author__ = "E. Papillon, V.A. Sole - ESRF Software Group"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class SpecFileMcaTable(qt.QWidget):
sigMcaDeviceSelected = qt.pyqtSignal(object)
@@ -131,16 +132,14 @@ class SpecFileMcaTable(qt.QWidget):
item.setText("X")
def _cellClicked(self, row, col):
- if DEBUG:
- print("_cellClicked %d %d " % (row, col))
+ _logger.debug("_cellClicked %d %d ", row, col)
item = self.table.item(row, col)
if item is None:
item = qt.QTableWidgetItem('',qt.QTableWidgetItem.Type)
self.table.setItem(row, col, item)
def _cellDoubleClicked(self, row, col):
- if DEBUG:
- print("_cellDoubleClicked %d %d" % (row, col))
+ _logger.debug("_cellDoubleClicked %d %d", (row, col))
#self._toggleCell(row, col)
pass
diff --git a/PyMca5/PyMcaGui/io/hdf5/HDF5CounterTable.py b/PyMca5/PyMcaGui/io/hdf5/HDF5CounterTable.py
index af1cddd..9ea31b8 100644
--- a/PyMca5/PyMcaGui/io/hdf5/HDF5CounterTable.py
+++ b/PyMca5/PyMcaGui/io/hdf5/HDF5CounterTable.py
@@ -28,10 +28,12 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import posixpath
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
safe_str = qt.safe_str
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class HDF5CounterTable(qt.QTableWidget):
@@ -256,8 +258,7 @@ class HDF5CounterTable(qt.QTableWidget):
return ddict
def setCounterSelection(self, ddict):
- if DEBUG:
- print("HDF5CounterTable.setCounterSelection", ddict)
+ _logger.debug("HDF5CounterTable.setCounterSelection %s", ddict)
keys = ddict.keys()
if 'cntlist' in keys:
cntlist = ddict['cntlist']
diff --git a/PyMca5/PyMcaGui/io/hdf5/HDF5McaTable.py b/PyMca5/PyMcaGui/io/hdf5/HDF5McaTable.py
index d66aafe..4dcc4a2 100644
--- a/PyMca5/PyMcaGui/io/hdf5/HDF5McaTable.py
+++ b/PyMca5/PyMcaGui/io/hdf5/HDF5McaTable.py
@@ -28,10 +28,12 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import posixpath
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
safe_str = qt.safe_str
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class McaSelectionType(qt.QWidget):
sigMcaSelectionTypeSignal = qt.pyqtSignal(object)
@@ -204,8 +206,7 @@ class HDF5McaTable(qt.QTableWidget):
self._update(row, col)
def _mySlot(self, ddict):
- if DEBUG:
- print("HDF5McaTable._mySlot", ddict)
+ _logger.debug("HDF5McaTable._mySlot %s", ddict)
row = ddict["row"]
col = ddict["column"]
if col == 1:
diff --git a/PyMca5/PyMcaGui/io/hdf5/HDF5Selection.py b/PyMca5/PyMcaGui/io/hdf5/HDF5Selection.py
index 78bd6c2..3b10de8 100644
--- a/PyMca5/PyMcaGui/io/hdf5/HDF5Selection.py
+++ b/PyMca5/PyMcaGui/io/hdf5/HDF5Selection.py
@@ -27,10 +27,10 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
from PyMca5.PyMcaGui import PyMcaQt as qt
safe_str = qt.safe_str
-DEBUG = 0
class HDF5Selection(qt.QWidget):
def __init__(self, parent=None):
diff --git a/PyMca5/PyMcaGui/io/hdf5/HDF5Widget.py b/PyMca5/PyMcaGui/io/hdf5/HDF5Widget.py
index 6775387..97d10cc 100644
--- a/PyMca5/PyMcaGui/io/hdf5/HDF5Widget.py
+++ b/PyMca5/PyMcaGui/io/hdf5/HDF5Widget.py
@@ -34,6 +34,7 @@ import posixpath
import gc
import re
from operator import itemgetter
+import logging
import h5py
import weakref
@@ -60,7 +61,8 @@ else:
return x
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
QVERSION = qt.qVersion()
@@ -81,8 +83,7 @@ def h5py_sorting(object_list):
posixNames = [item[1].name for item in object_list]
except AttributeError:
# Typical of broken external links
- if DEBUG:
- print("HDF5Widget: Cannot get posixNames")
+ _logger.debug("HDF5Widget: Cannot get posixNames")
return object_list
# This implementation only sorts entries
@@ -223,7 +224,7 @@ class H5NodeProxy(object):
except:
#one cannot afford any error, so I revert to the old
# method where values where used instead of items
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
else:
# tmpList = list(self.getNode(self.name).values())
@@ -581,8 +582,7 @@ class FileModel(qt.QAbstractItemModel):
self.sigFileAppended.emit(ddict)
def clear(self):
- if DEBUG:
- print("Clear called")
+ _logger.debug("Clear called")
# reset is considered obsolete under Qt 5.
if hasattr(self, "reset"):
self.reset()
diff --git a/PyMca5/PyMcaGui/io/hdf5/Hdf5NodeView.py b/PyMca5/PyMcaGui/io/hdf5/Hdf5NodeView.py
index c042515..d1c3c6a 100644
--- a/PyMca5/PyMcaGui/io/hdf5/Hdf5NodeView.py
+++ b/PyMca5/PyMcaGui/io/hdf5/Hdf5NodeView.py
@@ -46,7 +46,7 @@ import silx
from silx.gui.data.DataViewerFrame import DataViewerFrame
from silx.gui.data import DataViews
from silx.gui.data import NXdataWidgets
-from silx.gui.plot import Plot1D
+from silx.gui.plot import Plot1D, Plot2D
from silx.gui import icons
@@ -134,6 +134,35 @@ class Plot1DViewWithPlugins(DataViews._Plot1dView):
return Plot1DWithPlugins(parent=parent)
+class Plot2DWithPlugins(Plot2D):
+ """Add a plugin toolbutton to a Plot2D"""
+ def __init__(self, parent=None):
+ Plot2D.__init__(self, parent)
+
+ self._toolbar = qt.QToolBar(self)
+ self.addToolBar(self._toolbar)
+ pluginsToolButton = PluginsToolButton(plot=self, parent=self,
+ method="getPlugin2DInstance")
+
+ if PLUGINS_DIR:
+ pluginsToolButton.getPlugins(
+ method="getPlugin2DInstance",
+ directoryList=PLUGINS_DIR)
+ self._toolbar.addWidget(pluginsToolButton)
+
+
+class Plot2DViewWithPlugins(DataViews._Plot2dView):
+ def createWidget(self, parent):
+ widget = Plot2DWithPlugins(parent=parent)
+ widget.setDefaultColormap(self.defaultColormap())
+ widget.getColormapAction().setColorDialog(self.defaultColorDialog())
+ widget.getIntensityHistogramAction().setVisible(True)
+ widget.setKeepDataAspectRatio(True)
+ widget.getXAxis().setLabel('X')
+ widget.getYAxis().setLabel('Y')
+ return widget
+
+
class ArrayCurvePlotWithPlugins(NXdataWidgets.ArrayCurvePlot):
"""Adds a plugin toolbutton to an ArrayCurvePlot widget"""
def __init__(self, parent=None):
@@ -159,43 +188,30 @@ class NXdataCurveViewWithPlugins(DataViews._NXdataCurveView):
return ArrayCurvePlotWithPlugins(parent=parent)
-class NXdataViewWithPlugins(DataViews.CompositeDataView):
- """Re-implement DataViews._NXdataView to use the 1D view with
- a plugin toolbutton in the composite view."""
- # This widget is needed only for silx < 0.7.
- def __init__(self, parent):
- super(NXdataViewWithPlugins, self).__init__(
- parent=parent,
- label="NXdata",
- icon=icons.getQIcon("view-nexus"))
-
- if silx.version >= "0.7.0":
- self.addView(DataViews._InvalidNXdataView(parent))
- self.addView(DataViews._NXdataScalarView(parent))
- self.addView(NXdataCurveViewWithPlugins(parent))
- self.addView(DataViews._NXdataXYVScatterView(parent))
- self.addView(DataViews._NXdataImageView(parent))
- self.addView(DataViews._NXdataStackView(parent))
-
-
-class DataViewerFrameWithPlugins(DataViewerFrame):
- """Overloaded DataViewerFrame with the 1D view replaced by
- Plot1DViewWithPlugins"""
- # This widget is needed only for silx < 0.7.
- def createDefaultViews(self, parent=None):
- views = list(DataViewerFrame.createDefaultViews(self, parent=parent))
+class ArrayImagePlotWithPlugins(NXdataWidgets.ArrayImagePlot):
+ """Adds a plugin toolbutton to an ArrayImagePlot widget"""
+ def __init__(self, parent=None):
+ NXdataWidgets.ArrayImagePlot.__init__(self, parent)
- # replace 1d view
- oldView = [v for v in views if v.modeId() == DataViews.PLOT1D_MODE][0]
- newView = Plot1DViewWithPlugins(parent=parent)
- views[views.index(oldView)] = newView
+ self._toolbar = qt.QToolBar(self)
+ self.getPlot().addToolBar(self._toolbar)
+ pluginsToolButton = PluginsToolButton(plot=self.getPlot(),
+ parent=self,
+ method="getPlugin2DInstance")
+ if PLUGINS_DIR:
+ pluginsToolButton.getPlugins(
+ method="getPlugin2DInstance",
+ directoryList=PLUGINS_DIR)
+ self._toolbar.addWidget(pluginsToolButton)
- # replace NXdataView
- oldView = [v for v in views if isinstance(v, DataViews._NXdataView)][0]
- newView = NXdataViewWithPlugins(parent=parent)
- views[views.index(oldView)] = newView
- return views
+class NXdataImageViewWithPlugins(DataViews._NXdataImageView):
+ """Use the widget with a :class:`PluginsToolButton`"""
+ def createWidget(self, parent):
+ widget = ArrayImagePlotWithPlugins(parent)
+ widget.getPlot().setDefaultColormap(self.defaultColormap())
+ widget.getPlot().getColormapAction().setColorDialog(self.defaultColorDialog())
+ return widget
class Hdf5NodeView(CloseEventNotifyingWidget.CloseEventNotifyingWidget):
@@ -213,14 +229,15 @@ class Hdf5NodeView(CloseEventNotifyingWidget.CloseEventNotifyingWidget):
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.setSpacing(0)
- if silx.hexversion >= 0x000700f0: # 0.7.0 final
- self.viewWidget = DataViewerFrame(self)
- self.viewWidget.replaceView(DataViews.PLOT1D_MODE,
- Plot1DViewWithPlugins(self))
- self.viewWidget.replaceView(DataViews.NXDATA_CURVE_MODE,
- NXdataCurveViewWithPlugins(self))
- else:
- self.viewWidget = DataViewerFrameWithPlugins(self)
+ self.viewWidget = DataViewerFrame(self)
+ self.viewWidget.replaceView(DataViews.PLOT1D_MODE,
+ Plot1DViewWithPlugins(self))
+ self.viewWidget.replaceView(DataViews.PLOT2D_MODE,
+ Plot2DViewWithPlugins(self))
+ self.viewWidget.replaceView(DataViews.NXDATA_CURVE_MODE,
+ NXdataCurveViewWithPlugins(self))
+ self.viewWidget.replaceView(DataViews.NXDATA_IMAGE_MODE,
+ NXdataImageViewWithPlugins(self))
self.mainLayout.addWidget(self.viewWidget)
diff --git a/PyMca5/PyMcaGui/io/hdf5/QNexusWidget.py b/PyMca5/PyMcaGui/io/hdf5/QNexusWidget.py
index ba3ddbc..dda5514 100644
--- a/PyMca5/PyMcaGui/io/hdf5/QNexusWidget.py
+++ b/PyMca5/PyMcaGui/io/hdf5/QNexusWidget.py
@@ -33,6 +33,7 @@ import posixpath
import weakref
import gc
import h5py
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaCore import NexusTools
@@ -57,7 +58,8 @@ from PyMca5.PyMcaIO import ConfigDict
if "PyMcaDirs" in sys.modules:
from PyMca5 import PyMcaDirs
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
class Buttons(qt.QWidget):
@@ -296,8 +298,7 @@ class QNexusWidget(qt.QWidget):
else:
ddict['HDF5'] ={'WidgetConfiguration':\
self.getWidgetConfiguration()}
- if DEBUG:
- print("TODO - Add selection options")
+ _logger.debug("TODO - Add selection options")
ddict.write(fname)
def _deleteAllCountersFromTable(self):
@@ -401,8 +402,7 @@ class QNexusWidget(qt.QWidget):
if type(self._aliasList) == type(""):
self._aliasList = [ddict['aliases']]
self.cntTable.build(self._cntList, self._aliasList)
- if DEBUG:
- print("TODO - Add selection options")
+ _logger.debug("TODO - Add selection options")
def setDataSource(self, dataSource):
self.data = dataSource
@@ -480,7 +480,7 @@ class QNexusWidget(qt.QWidget):
try:
widget.w.setDataset(dataset)
except:
- print("Error filling table")
+ _logger.error("Error filling table")
widget.addTab(widget.w, 'DataView')
widget.setCurrentWidget(widget.w)
elif Hdf5NodeView is not None:
@@ -661,19 +661,16 @@ class QNexusWidget(qt.QWidget):
self.tableTab.insertTab(2, self.mcaTable, "MCA")
elif (len(mcaList)==0) and (nTabs > 2):
self.tableTab.removeTab(2)
- if DEBUG:
- print("currentTab = ", currentTab)
+ _logger.debug("currentTab = %s", currentTab)
if currentTab != "USER":
if (len(mcaList) > 0) and (len(cntList) == 0):
idx = self.tableTabOrder.index("MCA")
self.tableTab.setCurrentIndex(idx)
- if DEBUG:
- print("setting tab = ", idx, "MCA")
+ _logger.debug("setting tab = %s MCA", idx)
elif (len(mcaList) == 0) and (len(cntList) > 0):
idx = self.tableTabOrder.index("AUTO")
self.tableTab.setCurrentIndex(idx)
- if DEBUG:
- print("setting tab = ", idx, "AUTO")
+ _logger.debug("setting tab = %s AUTO", idx)
self._lastEntry = currentEntry
if ddict['event'] == 'itemClicked':
if ddict['mouse'] == "right":
@@ -697,8 +694,7 @@ class QNexusWidget(qt.QWidget):
else:
self.tableTab.setCurrentIndex(0)
if not self._isNumericType(ddict['dtype']):
- if DEBUG:
- print("string like %s" % ddict['dtype'])
+ _logger.debug("string like %s", ddict['dtype'])
else:
root = ddict['name'].split('/')
root = "/" + root[1]
@@ -737,8 +733,7 @@ class QNexusWidget(qt.QWidget):
root = "/" + root[1]
cnt = ddict['name'].split(root)[-1]
if cnt not in self._cntList:
- if DEBUG:
- print("USING SECOND WAY")
+ _logger.debug("USING SECOND WAY")
self._cntList.append(cnt)
basename = posixpath.basename(cnt)
if basename not in self._aliasList:
@@ -747,36 +742,30 @@ class QNexusWidget(qt.QWidget):
self._aliasList.append(cnt)
self.cntTable.build(self._cntList, self._aliasList)
return
- if DEBUG:
- print("Unhandled item type: %s" % ddict['dtype'])
+ _logger.debug("Unhandled item type: %s", ddict['dtype'])
def _addMcaAction(self):
- if DEBUG:
- print("_addMcaAction received")
+ _logger.debug("_addMcaAction received")
self.mcaAction("ADD")
def _removeMcaAction(self):
- if DEBUG:
- print("_removeMcaAction received")
+ _logger.debug("_removeMcaAction received")
self.mcaAction("REMOVE")
def _replaceMcaAction(self):
- if DEBUG:
- print("_replaceMcaAction received")
+ _logger.debug("_replaceMcaAction received")
self.mcaAction("REPLACE")
def mcaAction(self, action="ADD"):
- if DEBUG:
- print("mcaAction %s" % action)
+ _logger.debug("mcaAction %s", action)
self.mcaTable.getMcaSelection()
ddict = {}
ddict['action'] = "%s MCA" % action
self.buttonsSlot(ddict, emit=True)
def _addAction(self):
- if DEBUG:
- print("_addAction received")
+ _logger.debug("_addAction received")
# formerly we had action and selection type
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "MCA":
@@ -791,8 +780,7 @@ class QNexusWidget(qt.QWidget):
self.buttonsSlot(ddict, emit=True)
def _removeAction(self):
- if DEBUG:
- print("_removeAction received")
+ _logger.debug("_removeAction received")
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "MCA":
self._removeMcaAction()
@@ -806,8 +794,7 @@ class QNexusWidget(qt.QWidget):
self.buttonsSlot(ddict, emit=True)
def _replaceAction(self):
- if DEBUG:
- print("_replaceAction received")
+ _logger.debug("_replaceAction received")
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "MCA":
self._replaceMcaAction()
@@ -821,8 +808,7 @@ class QNexusWidget(qt.QWidget):
self.buttonsSlot(ddict, emit=True)
def _configurationChangedAction(self, ddict):
- if DEBUG:
- print("_configurationChangedAction received", ddict)
+ _logger.debug("_configurationChangedAction received %s", ddict)
if ddict["3d"]:
self.autoTable.set3DEnabled(True, emit=False)
self.cntTable.set3DEnabled(True, emit=False)
@@ -834,8 +820,7 @@ class QNexusWidget(qt.QWidget):
self.cntTable.set2DEnabled(False, emit=False)
def _autoTableUpdated(self, ddict):
- if DEBUG:
- print("_autoTableUpdated(self, ddict) ", ddict)
+ _logger.debug("_autoTableUpdated(self, ddict) %s", ddict)
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "AUTO":
actions = self.actions.getConfiguration()
@@ -846,8 +831,7 @@ class QNexusWidget(qt.QWidget):
self._replaceAction()
def _userTableUpdated(self, ddict):
- if DEBUG:
- print("_userTableUpdated(self, ddict) ", ddict)
+ _logger.debug("_userTableUpdated(self, ddict) %s", ddict)
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "USER":
actions = self.actions.getConfiguration()
@@ -858,8 +842,7 @@ class QNexusWidget(qt.QWidget):
self._replaceAction()
def _mcaTableUpdated(self, ddict):
- if DEBUG:
- print("_mcaTableUpdated(self, ddict) ", ddict)
+ _logger.debug("_mcaTableUpdated(self, ddict) %s", ddict)
text = qt.safe_str(self.tableTab.tabText(self.tableTab.currentIndex()))
if text.upper() == "MCA":
actions = self.actions.getConfiguration()
@@ -870,8 +853,7 @@ class QNexusWidget(qt.QWidget):
self._replaceAction()
def buttonsSlot(self, ddict, emit=True):
- if DEBUG:
- print("buttonsSlot(self, ddict,emit=True)", ddict, "emit = ", emit)
+ _logger.debug("buttonsSlot(self, %s,emit=%s)", ddict, emit)
if self.data is None:
return
action, selectionType = ddict['action'].split()
@@ -1057,10 +1039,10 @@ class QNexusWidget(qt.QWidget):
if 'event' in ddict:
if ddict['event'] == "closeEventSignal":
if ddict['id'] in self._widgetDict:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
try:
widget = self._widgetDict[ddict['id']]
- print("DELETING %s" % widget.windowTitle())
+ _logger.debug("DELETING %s", widget.windowTitle())
except:
pass
del self._widgetDict[ddict['id']]
diff --git a/PyMca5/PyMcaGui/io/hdf5/QNexusWidgetActions.py b/PyMca5/PyMcaGui/io/hdf5/QNexusWidgetActions.py
index 18dda50..178a41c 100644
--- a/PyMca5/PyMcaGui/io/hdf5/QNexusWidgetActions.py
+++ b/PyMca5/PyMcaGui/io/hdf5/QNexusWidgetActions.py
@@ -28,8 +28,11 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
class QNexusWidgetActions(qt.QWidget):
sigAddSelection = qt.pyqtSignal()
@@ -173,23 +176,19 @@ class QNexusWidgetActions(qt.QWidget):
self._addClicked()
def _addClicked(self):
- if DEBUG:
- print("_addClicked()")
+ _logger.debug("_addClicked()")
self.sigAddSelection.emit()
def _removeClicked(self):
- if DEBUG:
- print("_removeClicked()")
+ _logger.debug("_removeClicked()")
self.sigRemoveSelection.emit()
def _replaceClicked(self):
- if DEBUG:
- print("_replaceClicked()")
+ _logger.debug("_replaceClicked()")
self.sigReplaceSelection.emit()
def configurationChanged(self):
- if DEBUG:
- print("configurationChanged(object)")
+ _logger.debug("configurationChanged(object)")
ddict = self.getConfiguration()
self.sigActionsConfigurationChanged.emit(ddict)
diff --git a/PyMca5/PyMcaGui/math/FFTAlignmentWindow.py b/PyMca5/PyMcaGui/math/FFTAlignmentWindow.py
index 11ebabb..9d9d125 100644
--- a/PyMca5/PyMcaGui/math/FFTAlignmentWindow.py
+++ b/PyMca5/PyMcaGui/math/FFTAlignmentWindow.py
@@ -33,7 +33,6 @@ import numpy
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import ExternalImagesWindow
from PyMca5.PyMcaGui import PyMcaFileDialogs
-DEBUG = 0
class ParametersWidget(qt.QWidget):
parametersWidgetSignal = qt.pyqtSignal(object)
diff --git a/PyMca5/PyMcaGui/math/NNMADialog.py b/PyMca5/PyMcaGui/math/NNMADialog.py
index 9cb8b79..a71c7d8 100644
--- a/PyMca5/PyMcaGui/math/NNMADialog.py
+++ b/PyMca5/PyMcaGui/math/NNMADialog.py
@@ -31,10 +31,14 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
import time
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from . import NNMAWindow
NNMA = True
-DEBUG = 0
+
+
+_logger = logging.getLogger(__name__)
+
class SimpleThread(qt.QThread):
def __init__(self, function, *var, **kw):
@@ -46,13 +50,12 @@ class SimpleThread(qt.QThread):
self._result = None
def run(self):
- if DEBUG:
+ try:
self._result = self._function(*self._var, **self._kw )
- else:
- try:
- self._result = self._function(*self._var, **self._kw )
- except:
- self._result = ("Exception",) + sys.exc_info()
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ self._result = ("Exception",) + sys.exc_info()
class NNMADialog(qt.QDialog):
def __init__(self, parent=None, rgbwidget=None, selection=False):
@@ -106,8 +109,7 @@ class NNMADialog(qt.QDialog):
self.nnmaParametersDialog.setParameters(ddict)
ret = self.nnmaParametersDialog.exec_()
if ret:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
nnmaParameters = self.nnmaParametersDialog.getParameters()
self.nnmaParametersDialog.close()
function = nnmaParameters['function']
@@ -116,7 +118,7 @@ class NNMADialog(qt.QDialog):
kw = nnmaParameters['kw']
data = self._data
old_shape = self._data.shape
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
images, eigenvalues, eigenvectors = function(data,
npc,
binning=binning,
@@ -143,8 +145,7 @@ class NNMADialog(qt.QDialog):
return
if isinstance(self._data, numpy.ndarray):
self._data.shape = old_shape
- if DEBUG:
- print("NNMA Elapsed = ", time.time() - t0)
+ _logger.debug("NNMA Elapsed = %s", time.time() - t0)
self.nnmaWindow.setPCAData(images,
eigenvalues,
eigenvectors)
diff --git a/PyMca5/PyMcaGui/math/PCADialog.py b/PyMca5/PyMcaGui/math/PCADialog.py
index b3b57b8..aa26ad8 100644
--- a/PyMca5/PyMcaGui/math/PCADialog.py
+++ b/PyMca5/PyMcaGui/math/PCADialog.py
@@ -31,6 +31,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import time
import numpy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
try:
from . import PCAWindow
@@ -39,7 +40,10 @@ try:
except ImportError:
PCA = False
MDP = False
-DEBUG = 0
+
+
+_logger = logging.getLogger(__name__)
+
class SimpleThread(qt.QThread):
@@ -53,13 +57,12 @@ class SimpleThread(qt.QThread):
self._result = None
def run(self):
- if DEBUG:
+ try:
self._result = self._function(*self._var, **self._kw)
- else:
- try:
- self._result = self._function(*self._var, **self._kw)
- except:
- self._result = ("Exception",) + sys.exc_info()
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ self._result = ("Exception",) + sys.exc_info()
class PCADialog(qt.QDialog):
@@ -120,8 +123,7 @@ class PCADialog(qt.QDialog):
self.pcaParametersDialogInitialized = True
ret = self.pcaParametersDialog.exec_()
if ret:
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
pcaParameters = self.pcaParametersDialog.getParameters()
self.pcaParametersDialog.close()
function = pcaParameters['function']
@@ -139,7 +141,7 @@ class PCADialog(qt.QDialog):
msg.setText("Number of components too high")
msg.exec_()
return
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
images, eigenvalues, eigenvectors = function(data,
npc,
binning=binning,
@@ -169,8 +171,7 @@ class PCADialog(qt.QDialog):
return
if isinstance(self._data, numpy.ndarray):
self._data.shape = old_shape
- if DEBUG:
- print("PCA Elapsed = ", time.time() - t0)
+ _logger.debug("PCA Elapsed = %s", time.time() - t0)
methodlabel = pcaParameters.get('methodlabel', "")
imagenames = None
vectornames = None
@@ -279,7 +280,7 @@ class PCADialog(qt.QDialog):
return result
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
import os
from PyMca5.PyMcaIO import EdfFile
app = qt.QApplication([])
diff --git a/PyMca5/PyMcaGui/math/PCAWindow.py b/PyMca5/PyMcaGui/math/PCAWindow.py
index 59e8ec1..a6004f0 100644
--- a/PyMca5/PyMcaGui/math/PCAWindow.py
+++ b/PyMca5/PyMcaGui/math/PCAWindow.py
@@ -162,7 +162,7 @@ class PCAParametersDialog(qt.QDialog):
self.graph.sigPlotSignal.connect(self._graphSlot)
if not self.__regions:
#I am adding after instantiation
- self.mainLayout.insertWidget(2,self.regionsWidget)
+ self.mainLayout.insertWidget(2, self.regionsWidget)
self.mainLayout.addWidget(self.graph)
self.__regions = True
@@ -172,17 +172,16 @@ class PCAParametersDialog(qt.QDialog):
toValue = ddict['to']
self.graph.setEnabled(True)
self.graph.clearMarkers()
- self.graph.insertXMarker(fromValue,
- 'From',
- text='From',
- color='blue',
- draggable=True)
- self.graph.insertXMarker(toValue,
- 'To',
- text= 'To',
- color='blue',
- draggable=True)
- self.graph.replot()
+ self.graph.addXMarker(fromValue,
+ 'From',
+ text='From',
+ color='blue',
+ draggable=True)
+ self.graph.addXMarker(toValue,
+ 'To',
+ text='To',
+ color='blue',
+ draggable=True)
else:
self.graph.clearMarkers()
self.graph.setEnabled(False)
diff --git a/PyMca5/PyMcaGui/math/SGWindow.py b/PyMca5/PyMcaGui/math/SGWindow.py
index 1a59e96..0449645 100644
--- a/PyMca5/PyMcaGui/math/SGWindow.py
+++ b/PyMca5/PyMcaGui/math/SGWindow.py
@@ -27,11 +27,10 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-from PyMca5.PyMcaGui import MaskImageWidget
from PyMca5.PyMcaGui import ScanWindow
from PyMca5.PyMcaMath import SGModule
@@ -111,8 +110,9 @@ class SGWindow(qt.QWidget):
self.spectrum = spectrum
self.parametersWidget = SGParametersWidget(self, length=len(spectrum))
self.graph = ScanWindow.ScanWindow(self)
- self.graph.newCurve(self.xValues,
- spectrum, "Spectrum", replace=True)
+ self.graph.addCurve(self.xValues,
+ spectrum, "Spectrum",
+ replace=True)
self.mainLayout.addWidget(self.parametersWidget)
self.mainLayout.addWidget(self.graph)
self.getParameters = self.parametersWidget.getParameters
@@ -129,13 +129,13 @@ class SGWindow(qt.QWidget):
degree=degree,
order=order)
if order > 0:
- maptoy2 = True
+ yaxis = "right"
else:
- maptoy2 = False
- self.graph.newCurve(self.xValues,
- self.background, "Filtered Spectrum",
- replace=False,
- maptoy2=maptoy2)
+ yaxis = "left"
+ self.graph.addCurve(self.xValues,
+ self.background, "Filtered Spectrum",
+ replace=False,
+ yaxis=yaxis)
#Force information update
legend = self.graph.getActiveCurve(just_legend=True)
@@ -190,10 +190,11 @@ if __name__ == "__main__":
import numpy
app = qt.QApplication([])
if 1:
- noise = numpy.random.randn(1000.)
- y=numpy.arange(1000.)
- w = SGDialog(None, y+numpy.sqrt(y)* noise)
+ noise = numpy.random.randn(1000)
+ y = numpy.arange(1000.)
+ w = SGDialog(None,
+ y + numpy.sqrt(y) * noise)
w.show()
- ret=w.exec_()
+ ret = w.exec_()
if ret:
print(w.getParameters())
diff --git a/PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py b/PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py
index 2e963cc..d164ec5 100644
--- a/PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py
+++ b/PyMca5/PyMcaGui/math/SIFTAlignmentWindow.py
@@ -29,20 +29,20 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
-import sys
import numpy
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import ExternalImagesWindow
from PyMca5.PyMcaGui import PyMcaFileDialogs
-from PyMca5.PyMcaMath import sift
+import silx.opencl
+from silx.image import sift
DEBUG = 0
if DEBUG:
print("SIFT coming from %s" % os.path.abspath(sift.__file__))
-__doc__ ="""The SIFT algorithm belongs to the University of British Columbia. It is
-protected by patent US6711293. If you are on a country where this pattent
+__doc__ = """The SIFT algorithm belongs to the University of British Columbia. It is
+protected by patent US6711293. If you are in a country where this patent
applies (like the USA), please check if you are allowed to use it. The
University of British Columbia does not require a license for its use for
non-commercial research applications.
@@ -50,7 +50,7 @@ non-commercial research applications.
This SIFT implementation uses the code developed by Jerome Kieffer and
Pierre Paleo. The project is hosted at:
-https://github.com/kif/sift_pyocl
+https://github.com/silx-kit/silx/tree/master/silx/opencl/sift
This algorithm should provide better results than FFT based algorithms
provided the images to be aligned provide enough registration points
@@ -72,7 +72,7 @@ Please note that introduces an additional dependency of PyMca on PyOpenCL.
sift_pyocl license follows:
-Copyright(C) 2013 European Synchrotron Radiation Facility, Grenoble, France
+Copyright (C) 2013-2017 European Synchrotron Radiation Facility, Grenoble, France
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
@@ -146,8 +146,8 @@ class ParametersWidget(qt.QWidget):
def getOpenCLDevices(self):
devices = []
- if sift.opencl.ocl is not None:
- for platformid, platform in enumerate(sift.opencl.ocl.platforms):
+ if silx.opencl.ocl is not None:
+ for platformid, platform in enumerate(silx.opencl.ocl.platforms):
for deviceid, dev in enumerate(platform.devices):
devices.append((platformid, deviceid, dev.name))
return devices
diff --git a/PyMca5/PyMcaGui/math/SNIPWindow.py b/PyMca5/PyMcaGui/math/SNIPWindow.py
index ece019a..0e5a612 100644
--- a/PyMca5/PyMcaGui/math/SNIPWindow.py
+++ b/PyMca5/PyMcaGui/math/SNIPWindow.py
@@ -244,8 +244,8 @@ class SNIPWindow(qt.QWidget):
length=len(spectrum),
smooth=smooth)
self.graph = ScanWindow.ScanWindow(self)
- self.graph.newCurve(self.xValues,
- spectrum, "Spectrum", replace=True)
+ self.graph.addCurve(self.xValues,
+ spectrum, "Spectrum", replace=True)
self.mainLayout.addWidget(self.parametersWidget)
self.mainLayout.addWidget(self.graph)
self.xMarkers = []
@@ -267,31 +267,31 @@ class SNIPWindow(qt.QWidget):
yMin, yMax = self.graph.getGraphYLimits()
xMean = 0.5 * (xMin + xMax)
yMean = 0.5 * (yMin + yMax)
- self.xMarkers.append(self.graph.insertXMarker(roi_min[1],
- legend='C Min',
- text='C Min'))
- self.xMarkers.append(self.graph.insertXMarker(roi_max[1],
- legend='C Max',
- text='C Max'))
- self.yMarkers.append(self.graph.insertYMarker(roi_min[0],
- legend='R Min',
- text='R Min'))
- self.yMarkers.append(self.graph.insertYMarker(roi_max[0],
- legend='R Max',
- text='R Max'))
+ self.xMarkers.append(self.graph.addXMarker(roi_min[1],
+ legend='C Min',
+ text='C Min'))
+ self.xMarkers.append(self.graph.addXMarker(roi_max[1],
+ legend='C Max',
+ text='C Max'))
+ self.yMarkers.append(self.graph.addYMarker(roi_min[0],
+ legend='R Min',
+ text='R Min'))
+ self.yMarkers.append(self.graph.addYMarker(roi_max[0],
+ legend='R Max',
+ text='R Max'))
else:
- self.graph.insertXMarker(roi_min[1],
- legend='C Min',
- text='C Min')
- self.graph.insertXMarker(roi_max[1],
- legend='C Max',
- text='C Max')
- self.graph.insertYMarker(roi_min[0],
- legend='R Min',
- text='R Min')
- self.graph.insertYMarker(roi_max[0],
- legend='R Max',
- text='R Max')
+ self.graph.addXMarker(roi_min[1],
+ legend='C Min',
+ text='C Min')
+ self.graph.addXMarker(roi_max[1],
+ legend='C Max',
+ text='C Max')
+ self.graph.addYMarker(roi_min[0],
+ legend='R Min',
+ text='R Min')
+ self.graph.addYMarker(roi_max[0],
+ legend='R Max',
+ text='R Max')
self.background = SNIPModule.getImageBackground(self.image, width,
roi_min=roi_min,
roi_max=roi_max,
@@ -319,8 +319,8 @@ class SNIPWindow(qt.QWidget):
legend0 = "Smoothed Spectrum"
else:
legend0 = "Background"
- self.graph.addCurve(self.xValues,
- self.background, legend0, replace=False)
+ self.graph.addCurve(self.xValues, self.background,
+ legend0, replace=False)
#Force information update
legend = self.graph.getActiveCurve(just_legend=True)
@@ -398,8 +398,8 @@ if __name__ == "__main__":
import numpy
app = qt.QApplication([])
if 0:
- noise = numpy.random.randn(1000.)
- y=numpy.arange(1000.)
+ noise = numpy.random.randn(1000)
+ y = numpy.arange(1000.)
w = SNIPDialog(None, y+numpy.sqrt(y)* noise)
elif len(sys.argv) > 1:
from PyMca5.PyMcaIO import EdfFile
@@ -413,6 +413,6 @@ if __name__ == "__main__":
100 * numpy.exp(-(1./20) * ((x-64)*(x-64) + (y-128)*(y-128)))
w = SNIPDialog(None, data)
w.show()
- ret=w.exec_()
+ ret = w.exec_()
if ret:
print(w.getParameters())
diff --git a/PyMca5/PyMcaGui/math/SimpleActions.py b/PyMca5/PyMcaGui/math/SimpleActions.py
new file mode 100644
index 0000000..a94119a
--- /dev/null
+++ b/PyMca5/PyMcaGui/math/SimpleActions.py
@@ -0,0 +1,322 @@
+#/*##########################################################################
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""This module defines a set of simple plot actions processing one or all
+plotted curves in a ScanWindow:
+
+ - :class:`AverageAction`
+ - :class:`DerivativeAction`
+ - :class:`SmoothAction`
+ - :class:`SwapSignAction`
+ - :class:`SubtractAction`
+ - :class:`YMinToZeroAction`
+
+"""
+import copy
+
+from silx.gui.plot.actions import PlotAction
+
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from PyMca5.PyMcaMath import SimpleMath
+from PyMca5.PyMcaGui.plotting.PyMca_Icons import IconDict
+
+if hasattr(qt, 'QString'):
+ QString = qt.QString
+else:
+ QString = qt.safe_str
+
+_simpleMath = SimpleMath.SimpleMath()
+
+
+def _getOneCurve(plot, qwarning=True):
+ """Return active curve if any,
+ else if there is a single curve return it,
+ else return None.
+
+ :param plot: Plot instance
+ :param bool qwarning: If True, display a warning popup to
+ inform that a curve must be selected when function is not
+ successful.
+ """
+ curve = plot.getActiveCurve()
+ if curve is None:
+ curves = plot.getAllCurves()
+ if not curves or len(curves) > 1:
+ if qwarning:
+ _QWarning(msg="You must select a curve.",
+ parent=plot)
+ return None
+ return curves[0]
+ return curve
+
+
+def _QWarning(msg, parent=None):
+ """Print a warning message in a QMessageBox"""
+ mb = qt.QMessageBox(parent)
+ mb.setIcon(qt.QMessageBox.Warning)
+ mb.setText(msg)
+ mb.exec_()
+
+#
+# def _isActive(legend, plot):
+# """
+#
+# :param legend: curve legend
+# :param plot: plot instance
+# :return: True or False
+# """
+# active_legend = plot.getActiveCurve(just_legend=True)
+# if active_legend is None:
+# # No active curve
+# return False
+# return legend == active_legend
+
+
+def _updated_info(info0, sourcename, operation):
+ info1 = copy.deepcopy(info0)
+ if not 'operations' in info1:
+ info1['operations'] = []
+ info1['operations'].append(operation)
+ info1['SourceName'] = sourcename
+ if 'selectionlegend' in info1:
+ del info1['selectionlegend']
+ return info1
+
+
+class AverageAction(PlotAction):
+ """Average all curves, clear plot, add average curve
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["average16"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ text='Average Plotted Curves',
+ tooltip='Replace all curves by the average curve',
+ triggered=self._averageAllCurves,
+ parent=parent)
+
+ def _averageAllCurves(self):
+ curves = self.plot.getAllCurves()
+ if not curves:
+ return
+ x0, y0, legend0, info0, _params0 = curves[0]
+ avg_legend = legend0
+ all_x = [x0]
+ all_y = [y0]
+ for x, y, legend, info, params in curves[1:]:
+ avg_legend += " + " + legend
+ all_x.append(x)
+ all_y.append(y)
+
+ avg_info = _updated_info(info0, avg_legend, "average")
+
+ xavg, yavg = _simpleMath.average(all_x, all_y)
+ avg_legend = "(%s)/%d" % (avg_legend, len(curves))
+
+ self.plot.clearCurves()
+ self.plot.addCurve(xavg, yavg, avg_legend,
+ info=avg_info)
+
+
+class SmoothAction(PlotAction):
+ """Plot smooth of the active curve if any,
+ else plot smooth of the only existing curve if any.
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["smooth"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ text='Smooth Active Curve',
+ tooltip='Smooth Active Curve',
+ triggered=self._smoothActiveCurve,
+ parent=parent)
+
+ def _smoothActiveCurve(self):
+ curve = _getOneCurve(self.plot)
+ if curve is None:
+ return
+ x0, y0, legend0, info0, _params = curve
+
+ x1 = x0 * 1
+ y1 = _simpleMath.smooth(y0)
+
+ if info0.get("operations") is None or \
+ info0["operations"][-1] != "smooth":
+ legend1 = "%s Smooth" % legend0
+ else:
+ # don't repeat "smooth"
+ legend1 = legend0
+
+ info1 = _updated_info(info0, legend0, "smooth")
+
+ self.plot.addCurve(x1, y1, legend1,
+ info=info1)
+
+
+class DerivativeAction(PlotAction):
+ """Plot derivative of the active curve if any,
+ else the derivative of the only existing curve.
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["derive"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ tooltip='Plot Derivative of Active Curve',
+ text='Derivate Active Curve',
+ triggered=self._derivateActiveCurve,
+ parent=parent)
+
+ def _derivateActiveCurve(self):
+ curve = _getOneCurve(self.plot)
+ if curve is None:
+ return
+ x0, y0, legend0, info0, params0 = curve
+
+ x1, y1 = _simpleMath.derivate(x0, y0)
+ legend1 = legend0 + "'"
+
+ info1 = _updated_info(info0, legend0, "derivate")
+ info1['plot_yaxis'] = "right"
+
+ ylabel1 = params0.get("ylabel")
+ if ylabel1 is None:
+ ylabel1 = "Y"
+
+ self.plot.addCurve(x1, y1, legend1,
+ ylabel=ylabel1 + "'",
+ info=info1,
+ yaxis="right")
+
+
+class SwapSignAction(PlotAction):
+ """Plot the active curve multiplied by -1
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["swapsign"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ text='Multiply Active Curve by -1',
+ tooltip='Multiply Active Curve by -1',
+ triggered=self._swapSignCurve,
+ parent=parent)
+
+ def _swapSignCurve(self):
+ curve = _getOneCurve(self.plot)
+ if curve is None:
+ return
+ x0, y0, legend0, info0, _params = curve
+
+ x1 = 1 * x0
+ y1 = -y0
+ legend1 = "-(%s)" % legend0
+
+ info1 = _updated_info(info0, legend0, "swapsign")
+
+ self.plot.addCurve(x1, y1, legend1,
+ info=info1)
+
+
+class YMinToZeroAction(PlotAction):
+ """
+
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["ymintozero"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ text='Y Min to Zero',
+ tooltip='Shift curve vertically to put min value at 0',
+ triggered=self._yMinToZeroCurve,
+ parent=parent)
+
+ def _yMinToZeroCurve(self):
+ curve = _getOneCurve(self.plot)
+ if curve is None:
+ return
+ x0, y0, legend0, info0, _params = curve
+
+ x1 = x0 * 1
+ y1 = y0 - min(y0)
+ legend1 = "(%s) - ymin" % legend0
+
+ info1 = _updated_info(info0, legend0, "forceymintozero")
+
+ self.plot.addCurve(x1, y1, legend1,
+ info=info1)
+
+
+class SubtractAction(PlotAction):
+ """Subtract active curve from all curves.
+
+ """
+ def __init__(self, plot, parent=None):
+ self.icon = qt.QIcon(qt.QPixmap(IconDict["subtract"]))
+ PlotAction.__init__(self,
+ plot,
+ icon=self.icon,
+ text='Subtract Active Curve',
+ tooltip='Subtract active curve from all curves',
+ triggered=self._subtractCurve,
+ parent=parent)
+
+ def _subtractCurve(self):
+ active_curve = _getOneCurve(self.plot)
+ all_curves = self.plot.getAllCurves()
+
+ #############################################################
+ if active_curve is None:
+ return
+
+ x0, y0, legend0, info0, params0 = active_curve
+
+ ylabel0 = params0.get("ylabel", "Y0")
+ if ylabel0 is None:
+ ylabel0 = "Y0"
+
+ for x, y, legend, info, params in all_curves:
+ # (y1 - y0) is equivalent to 2 * average(-y0, y1)
+ XX = [x0, x]
+ YY = [-y0, y]
+ xplot, yplot = _simpleMath.average(XX, YY)
+ yplot *= 2
+ legend1 = "(%s - %s)" % (legend, legend0)
+
+ ylabel = params0.get("ylabel", "Y")
+ if ylabel is None:
+ ylabel = "Y"
+
+ ylabel1 = "(%s - %s)" % (ylabel, ylabel0)
+
+ info1 = _updated_info(info, legend, "subtract")
+ info1['LabelNames'] = [legend1]
+
+ self.plot.removeCurve(legend)
+ self.plot.addCurve(xplot, yplot, legend1,
+ info=info1, ylabel=ylabel1)
diff --git a/PyMca5/PyMcaGui/math/StripBackgroundWidget.py b/PyMca5/PyMcaGui/math/StripBackgroundWidget.py
index c3fe56a..4c2f104 100644
--- a/PyMca5/PyMcaGui/math/StripBackgroundWidget.py
+++ b/PyMca5/PyMcaGui/math/StripBackgroundWidget.py
@@ -1,5 +1,5 @@
#/*##########################################################################
-# Copyright (C) 2004-2014 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 V.A. Sole, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -30,9 +30,10 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
from PyMca5.PyMcaGui import PyMcaQt as qt
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaMath.fitting import SpecfitFuns
+from silx.gui.plot import PlotWindow
+
class StripParametersWidget(qt.QWidget):
sigStripParametersWidgetSignal = qt.pyqtSignal(object)
@@ -235,10 +236,13 @@ class StripBackgroundWidget(qt.QWidget):
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.setSpacing(2)
self.parametersWidget = StripParametersWidget(self)
- self.graphWidget = PlotWindow.PlotWindow(self,
- newplot=False,
- plugins=False,
- fit=False)
+ self.graphWidget = PlotWindow(self, position=False, aspectRatio=False,
+ colormap=False, yInverted=False,
+ roi=False, mask=False, fit=False)
+ toolBar = self.graphWidget.getInteractiveModeToolBar()
+ toolBar.getZoomModeAction().setVisible(False)
+ toolBar.getPanModeAction().setVisible(False)
+
self.mainLayout.addWidget(self.parametersWidget)
self.mainLayout.addWidget(self.graphWidget)
self.getParameters = self.parametersWidget.getParameters
@@ -252,6 +256,7 @@ class StripBackgroundWidget(qt.QWidget):
self._x = x
self._y = y
self.update()
+ self.graphWidget.resetZoom()
def _slot(self, ddict):
self.update()
@@ -319,16 +324,16 @@ class StripBackgroundWidget(qt.QWidget):
snipBackground[lastAnchor:] =\
SpecfitFuns.snip1d(ysmooth[lastAnchor:], width, 0)
- self.graphWidget.addCurve(x, y, \
- legend='Input Data',\
- replace=True,
- replot=False)
- self.graphWidget.addCurve(x, stripBackground,\
- legend='Strip Background',\
- replot=False)
- self.graphWidget.addCurve(x, snipBackground,\
- legend='SNIP Background',
- replot=True)
+ self.graphWidget.addCurve(x, y,
+ legend='Input Data',
+ resetzoom=False)
+ self.graphWidget.addCurve(x, stripBackground,
+ resetzoom=False,
+ legend='Strip Background')
+ self.graphWidget.addCurve(x, snipBackground,
+ resetzoom=False,
+ legend='SNIP Background')
+ self.graphWidget.setActiveCurve('Input Data')
class StripBackgroundDialog(qt.QDialog):
def __init__(self, parent=None):
diff --git a/PyMca5/PyMcaGui/math/fitting/McaTable.py b/PyMca5/PyMcaGui/math/fitting/McaTable.py
index 3e606ef..7e83c94 100644
--- a/PyMca5/PyMcaGui/math/fitting/McaTable.py
+++ b/PyMca5/PyMcaGui/math/fitting/McaTable.py
@@ -27,6 +27,7 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QString"):
QString = qt.QString
@@ -37,7 +38,8 @@ QTVERSION = qt.qVersion()
QTable = qt.QTableWidget
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
class McaTable(QTable):
sigMcaTableSignal = qt.pyqtSignal(object)
@@ -72,8 +74,8 @@ class McaTable(QTable):
self.regionlist=[]
self.regiondict={}
- if DEBUG:
- print("MCATABLE click on vertical header items?")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ _logger.debug("MCATABLE click on vertical header items?")
self.verticalHeader().sectionClicked[int].connect(self.__myslot)
self.cellClicked[int, int].connect(self.__myslot)
self.itemSelectionChanged[()].connect(self.__myslot)
diff --git a/PyMca5/PyMcaGui/math/fitting/MultiParameters.py b/PyMca5/PyMcaGui/math/fitting/MultiParameters.py
index bb0069c..0f8b7c9 100644
--- a/PyMca5/PyMcaGui/math/fitting/MultiParameters.py
+++ b/PyMca5/PyMcaGui/math/fitting/MultiParameters.py
@@ -29,12 +29,14 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from . import Parameters
QTVERSION = qt.qVersion()
from . import McaTable
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class ParametersTab(qt.QTabWidget):
sigMultiParametersSignal = qt.pyqtSignal(object)
@@ -77,7 +79,6 @@ class ParametersTab(qt.QTabWidget):
self.addTab(table,str(name))
if fitparameterslist is not None:
table.fillfromfit(fitparameterslist)
- #print "SHowing page ",name
if QTVERSION < '4.0.0':
self.showPage(self.views[name])
else:
@@ -188,8 +189,7 @@ class ParametersTab(qt.QTabWidget):
hb = table.horizontalHeader().paletteBackgroundColor()
hcolor = ("#%x%x%x" % (hb.red(), hb.green(), hb.blue())).upper()
else:
- if DEBUG:
- print("Actual color to ge got")
+ _logger.debug("Actual color to ge got")
hcolor = ("#%x%x%x" % (230,240,249)).upper()
text=""
text+=("<nobr>")
diff --git a/PyMca5/PyMcaGui/math/fitting/Parameters.py b/PyMca5/PyMcaGui/math/fitting/Parameters.py
index 101a116..4ec094e 100644
--- a/PyMca5/PyMcaGui/math/fitting/Parameters.py
+++ b/PyMca5/PyMcaGui/math/fitting/Parameters.py
@@ -28,6 +28,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if not hasattr(qt, "QString"):
QString = str
@@ -42,6 +43,9 @@ else:
QTVERSION = qt.qVersion()
QTable = qt.QTableWidget
+_logger = logging.getLogger(__name__)
+
+
class QComboTableItem(qt.QComboBox):
sigCellChanged = qt.pyqtSignal(int, int)
def __init__(self, parent=None, row=None, col=None):
@@ -51,8 +55,7 @@ class QComboTableItem(qt.QComboBox):
self.activated[int].connect(self._cellChanged)
def _cellChanged(self, idx):
- if DEBUG:
- print("cell changed", idx)
+ _logger.debug("cell changed %s", idx)
self.sigCellChanged.emit(self._row, self._col)
class QCheckBoxItem(qt.QCheckBox):
@@ -66,8 +69,6 @@ class QCheckBoxItem(qt.QCheckBox):
def _cellChanged(self):
self.sigCellChanged.emit(self._row, self._col)
-DEBUG = 0
-
class Parameters(QTable):
def __init__(self, parent=None, allowBackgroundAdd=False, **kw):
@@ -77,7 +78,7 @@ class Parameters(QTable):
self.setColumnCount(1)
self.labels = ['Parameter', 'Estimation', 'Fit Value', 'Sigma',
'Constraints', 'Min/Parame', 'Max/Factor/Delta/']
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.code_options = ["FREE", "POSITIVE", "QUOTED", "FIXED",
"FACTOR", "DELTA", "SUM", "IGNORE", "ADD",
"SHOW"]
@@ -267,9 +268,8 @@ class Parameters(QTable):
return fitparameterslist
def myslot(self, row, col):
- if DEBUG:
- print("Passing by myslot(%d, %d)" % (row, col))
- print("current(%d, %d)" % (self.currentRow(), self.currentColumn()))
+ _logger.debug("Passing by myslot(%d, %d)", row, col)
+ _logger.debug("current(%d, %d)", self.currentRow(), self.currentColumn())
if (col != 4) and (col != -1):
if row != self.currentRow():
return
@@ -290,17 +290,14 @@ class Parameters(QTable):
#this is the combobox
widget = self.cellWidget(row, col)
newvalue = widget.currentText()
- if DEBUG:
- print("old value = ", oldvalue)
- print("new value = ", newvalue)
+ _logger.debug("old value = %s", oldvalue)
+ _logger.debug("new value = %s", newvalue)
if self.validate(param, field, oldvalue, newvalue):
- if DEBUG:
- print("Change is valid")
+ _logger.debug("Change is valid")
exec("self.configure(name=param,%s=newvalue)" % field)
else:
- if DEBUG:
- print("Change is not valid")
- print("oldvalue ", oldvalue)
+ _logger.debug("Change is not valid")
+ _logger.debug("oldvalue %s", oldvalue)
if field == 'code':
index = self.code_options.index(oldvalue)
self.__configuring = True
@@ -460,15 +457,14 @@ class Parameters(QTable):
self.addgroup(i, group)
return 0
elif str(newvalue) == 'SHOW':
- print(self.cget(workparam))
+ _logger.info(self.cget(workparam))
return 0
else:
- print("None of the others!")
+ _logger.info("None of the others!")
def addgroup(self, newg, gtype):
- if DEBUG:
- print("addgroup called")
- print("newg = ", newg, "gtype = ", gtype)
+ _logger.debug("addgroup called")
+ _logger.debug("newg = %s gtype = %s", newg, gtype)
line = 0
newparam = []
oldparamlist = list(self.paramlist)
@@ -545,10 +541,9 @@ class Parameters(QTable):
return candidates[0], candidates
def setReadOnly(self, parameter, fields):
- if DEBUG:
- print("parameter ", parameter)
- print("fields = ", fields)
- print("asked to be read only")
+ _logger.debug("parameter %s", parameter)
+ _logger.debug("fields = %s", fields)
+ _logger.debug("asked to be read only")
if QTVERSION < '4.0.0':
self.setfield(parameter, fields, qttable.QTableItem.Never)
else:
@@ -556,10 +551,9 @@ class Parameters(QTable):
self.setfield(parameter, fields, editflags)
def setReadWrite(self, parameter, fields):
- if DEBUG:
- print("parameter ", parameter)
- print("fields = ", fields)
- print("asked to be read write")
+ _logger.debug("parameter %s", parameter)
+ _logger.debug("fields = %s", fields)
+ _logger.debug("asked to be read write")
if QTVERSION < '4.0.0':
self.setfield(parameter, fields, qttable.QTableItem.OnTyping)
else:
@@ -569,9 +563,8 @@ class Parameters(QTable):
self.setfield(parameter, fields, editflags)
def setfield(self, parameter, fields, EditType):
- if DEBUG:
- print("setfield. parameter =", parameter)
- print("fields = ", fields)
+ _logger.debug("setfield. parameter = %s", parameter)
+ _logger.debug("fields = %s", fields)
if isinstance(parameter, list) or \
isinstance(parameter, tuple):
paramlist = parameter
@@ -613,8 +606,7 @@ class Parameters(QTable):
self.__configuring = _oldvalue
def configure(self, *vars, **kw):
- if DEBUG:
- print("configure called with **kw = ", kw)
+ _logger.debug("configure called with **kw = %s", kw)
name = None
error = 0
if 'name' in kw:
@@ -655,8 +647,7 @@ class Parameters(QTable):
elif key in self.parameters[name].keys():
newvalue = QString(str(kw[key]))
self.parameters[name][key] = newvalue
- if DEBUG:
- print("error = ", error)
+ _logger.debug("error = %s", error)
if 'code' in kw.keys():
newvalue = QString(kw['code'])
self.parameters[name]['code'] = newvalue
@@ -756,7 +747,7 @@ class Parameters(QTable):
float(str(self.parameters[name]['val2']))
except:
error = 1
- print("Forcing factor to 1")
+ _logger.warning("Forcing factor to 1")
self.parameters[name]['cons2'] = 1.0
self.setReadWrite(name, ['estimation', 'val1', 'val2'])
self.setReadOnly(name, ['fitresult', 'sigma'])
@@ -770,7 +761,7 @@ class Parameters(QTable):
float(str(self.parameters[name]['val2']))
except:
error = 1
- print("Forcing delta to 0")
+ _logger.warning("Forcing delta to 0")
self.parameters[name]['cons2'] = 0.0
self.setReadWrite(name, ['estimation', 'val1', 'val2'])
self.setReadOnly(name, ['fitresult', 'sigma'])
@@ -784,7 +775,7 @@ class Parameters(QTable):
float(str(self.parameters[name]['val2']))
except:
error = 1
- print("Forcing sum to 0")
+ _logger.warning("Forcing sum to 0")
self.parameters[name]['cons2'] = 0.0
self.setReadWrite(name, ['estimation', 'val1', 'val2'])
self.setReadOnly(name, ['fitresult', 'sigma'])
diff --git a/PyMca5/PyMcaGui/math/fitting/RateLawWindow.py b/PyMca5/PyMcaGui/math/fitting/RateLawWindow.py
index 461e45d..73094ba 100644
--- a/PyMca5/PyMcaGui/math/fitting/RateLawWindow.py
+++ b/PyMca5/PyMcaGui/math/fitting/RateLawWindow.py
@@ -30,17 +30,16 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import os
+
import sys
import numpy
-import traceback
-import copy
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaMath.fitting import RateLaw
-DEBUG = 0
+from PyMca5.PyMcaGui.PluginsToolButton import PluginsToolButton
+
+from silx.gui.plot import PlotWindow
class RateLawWindow(qt.QMainWindow):
def __init__(self, parent=None, backend=None):
@@ -67,9 +66,12 @@ class RateLawMdiArea(qt.QMdiArea):
"First", "Second"]
self._windowList.reverse()
for title in self._windowList:
- plot = PlotWindow.PlotWindow(self,
- position=True,
- backend=backend)
+ plot = PlotWindow(self,
+ position=True, backend=backend,
+ colormap=False, aspectRatio=False,
+ yInverted=False, roi=False, mask=False)
+ self.pluginsToolButton = PluginsToolButton(plot=plot)
+ plot.toolBar().addWidget(self.pluginsToolButton)
plot.setWindowTitle(title)
self.addSubWindow(plot)
self._windowDict[title] = plot
@@ -89,16 +91,25 @@ class RateLawMdiArea(qt.QMdiArea):
ylabel=ylabel,
yerror=sigmay,
symbol="o")
+ self._windowDict["Original"].setActiveCurve(legend)
self.update()
def update(self):
plot = self._windowDict["Original"]
activeCurve = plot.getActiveCurve()
- if not len(activeCurve):
- return
- [x, y, legend, info] = activeCurve[:4]
- xmin, xmax = plot.getGraphXLimits()
- ymin, ymax = plot.getGraphYLimits()
+ if activeCurve is None:
+ allCurves = plot.getAllCurves()
+ if len(allCurves):
+ activeCurve = allCurves[0]
+ else:
+ return
+ x = activeCurve.getXData(copy=False)
+ y = activeCurve.getYData(copy=False)
+ xlabel = activeCurve.getXLabel()
+ ylabel = activeCurve.getYLabel()
+
+ # xmin, xmax = plot.getGraphXLimits()
+ # ymin, ymax = plot.getGraphYLimits()
result = RateLaw.rateLaw(x, y, sigmay=None)
labels = ["Zero", "First", "Second"]
@@ -117,8 +128,6 @@ class RateLawMdiArea(qt.QMdiArea):
stderr = workingResult["stderr"]
xw = workingResult["x"]
yw = workingResult["y"]
- xlabel = info["ylabel"]
- ylabel = info["ylabel"]
title = "r = %.5f slope = %.3E +/- %.2E" % (r_value, slope, sigma_slope)
fit_legend = "%.3g * x + %.3g" % (slope, intercept)
if key == "First":
@@ -127,7 +136,7 @@ class RateLawMdiArea(qt.QMdiArea):
ylabel = "1 / %s" % ylabel
plot.addCurve(xw, yw,
legend="Data",
- replace=True, replot=False,
+ replace=True, resetzoom=False,
symbol="o",
linestyle=" ",
ylabel=ylabel)
@@ -135,10 +144,11 @@ class RateLawMdiArea(qt.QMdiArea):
plot.addCurve(xw, intercept + slope * xw,
legend=fit_legend,
replace=False,
- replot=True,
+ resetzoom=True,
symbol=None,
color="red",
ylabel=ylabel)
+ plot.setActiveCurve("Data")
plot.resetZoom()
self.sigRateLawMdiAreaSignal.emit(result)
diff --git a/PyMca5/PyMcaGui/math/fitting/SimpleFitConfigurationGui.py b/PyMca5/PyMcaGui/math/fitting/SimpleFitConfigurationGui.py
index 9be0054..1091a79 100644
--- a/PyMca5/PyMcaGui/math/fitting/SimpleFitConfigurationGui.py
+++ b/PyMca5/PyMcaGui/math/fitting/SimpleFitConfigurationGui.py
@@ -30,6 +30,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import traceback
import os.path
+import logging
from . import SimpleFitControlWidget
if sys.version_info < (3,):
@@ -54,7 +55,8 @@ if h5py is not None:
from . import Parameters
from PyMca5.PyMcaGui.math.StripBackgroundWidget import StripBackgroundDialog
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class DummyWidget(qt.QWidget):
def __init__(self, parent=None, text="Automatically estimated function"):
@@ -194,8 +196,7 @@ class SimpleFitConfigurationGui(qt.QDialog):
self.initDir = None
def _fitControlSlot(self, ddict):
- if DEBUG:
- print("FitControlSignal", ddict)
+ _logger.debug("FitControlSignal %s", ddict)
event = ddict['event']
if event == "stripSetupCalled":
if self._stripDialog is None:
@@ -351,17 +352,15 @@ class SimpleFitConfigurationGui(qt.QDialog):
fileName = ddict['functions'][functionName]['file']
if fileName not in currentFiles:
try:
- if DEBUG:
- print("Adding file %s" % fileName)
+ _logger.debug("Adding file %s", fileName)
self.simpleFitInstance.importFunctions(fileName)
currentFiles.append(fileName)
except:
if "library.zip" in fileName:
- if DEBUG:
- print("Assuming PyMca supplied fit function")
+ _logger.debug("Assuming PyMca supplied fit function")
continue
- print("Cannot import file %s" % fileName)
- print(sys.exc_info()[1])
+ _logger.warning("Cannot import file %s", fileName)
+ _logger.warning(sys.exc_info()[1])
if 'fit' in ddict:
self.fitControlWidget.setConfiguration(ddict['fit'])
@@ -493,7 +492,7 @@ class SimpleFitConfigurationGui(qt.QDialog):
self.initDir = os.path.dirname(filename)
self.setConfiguration(cfg)
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
@@ -530,17 +529,15 @@ class SimpleFitConfigurationGui(qt.QDialog):
def saveConfiguration(self, filename):
cfg = ConfigDict.ConfigDict(self.getConfiguration())
- if DEBUG:
+ try:
cfg.write(filename)
self.initDir = os.path.dirname(filename)
- else:
- try:
- cfg.write(filename)
- self.initDir = os.path.dirname(filename)
- except:
- qt.QMessageBox.critical(self, "Save Parameters",
- "ERROR while saving parameters to\n%s"%filename,
- qt.QMessageBox.Ok, qt.QMessageBox.NoButton, qt.QMessageBox.NoButton)
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ qt.QMessageBox.critical(self, "Save Parameters",
+ "ERROR while saving parameters to\n%s"%filename,
+ qt.QMessageBox.Ok, qt.QMessageBox.NoButton, qt.QMessageBox.NoButton)
def test():
@@ -558,5 +555,5 @@ def test():
sys.exit()
if __name__=="__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
test()
diff --git a/PyMca5/PyMcaGui/math/fitting/SimpleFitGui.py b/PyMca5/PyMcaGui/math/fitting/SimpleFitGui.py
index 19d73b2..2009690 100644
--- a/PyMca5/PyMcaGui/math/fitting/SimpleFitGui.py
+++ b/PyMca5/PyMcaGui/math/fitting/SimpleFitGui.py
@@ -29,14 +29,16 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaMath.fitting import SimpleFitModule
from . import SimpleFitConfigurationGui
from PyMca5.PyMcaMath.fitting import SimpleFitUserEstimatedFunctions
from . import Parameters
-from PyMca5.PyMcaGui import PlotWindow
+from silx.gui.plot import PlotWindow
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class TopWidget(qt.QWidget):
def __init__(self, parent=None):
@@ -141,11 +143,15 @@ class SimpleFitGui(qt.QWidget):
self.fitModule = fit
if graph is None:
self.__useTab = True
- self.graph = PlotWindow.PlotWindow(newplot=False,
- plugins=False,
- fit=False,
- control=True,
- position=True)
+ self.graph = PlotWindow(self,
+ aspectRatio=False, colormap=False,
+ yInverted=False, roi=False, mask=False,
+ fit=False, control=True, position=True)
+ self.graph.getInteractiveModeToolBar().setVisible(False)
+ # No context menu by default, execute zoomBack on right click
+ plotArea = self.graph.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
else:
self.__useTab = False
self.graph = graph
@@ -221,14 +227,14 @@ class SimpleFitGui(qt.QWidget):
functionsfile= qt.safe_str(fn)
if not len(functionsfile):
return
- if DEBUG:
+
+ try:
self.fitModule.importFunctions(functionsfile)
- else:
- try:
- self.fitModule.importFunctions(functionsfile)
- except:
- qt.QMessageBox.critical(self, "ERROR",
- "Function not imported")
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ qt.QMessageBox.critical(self, "ERROR",
+ "Function not imported")
config = self.fitModule.getConfiguration()
self.topWidget.setFunctions(config['fit']['functions'])
@@ -253,8 +259,7 @@ class SimpleFitGui(qt.QWidget):
SimpleFitConfigurationGui.SimpleFitConfigurationGui()
self._configurationDialog.setSimpleFitInstance(self.fitModule)
if not self._configurationDialog.exec_():
- if DEBUG:
- print("NOT UPDATING CONFIGURATION")
+ _logger.debug("NOT UPDATING CONFIGURATION")
oldConfig = self.fitModule.getConfiguration()
self._configurationDialog.setConfiguration(oldConfig)
return
@@ -276,8 +281,7 @@ class SimpleFitGui(qt.QWidget):
idx = newConfig['fit']['functions'].index(fname) + 1
idx = self.topWidget.backgroundCombo.findText(fname)
self.topWidget.backgroundCombo.setCurrentIndex(idx)
- if DEBUG:
- print("TABLE TO BE CLEANED")
+ _logger.debug("TABLE TO BE CLEANED")
#self.estimate()
def setFitFunction(self, fname):
@@ -298,16 +302,18 @@ class SimpleFitGui(qt.QWidget):
returnValue = self.fitModule.setData(*var, **kw)
if self.__useTab:
if hasattr(self.graph, "addCurve"):
+ self.graph.clear()
self.graph.addCurve(self.fitModule._x,
self.fitModule._y,
- legend='Data',
- replace=True)
+ legend='Data')
+ self.graph.setActiveCurve('Data')
elif hasattr(self.graph, "newCurve"):
+ # TODO: remove if not used
self.graph.clearCurves()
self.graph.newCurve('Data',
self.fitModule._x,
self.fitModule._y)
- self.graph.replot()
+ self.graph.replot()
return returnValue
def estimate(self):
@@ -318,11 +324,12 @@ class SimpleFitGui(qt.QWidget):
y = self.fitModule._y
self.graph.clear()
self.graph.addCurve(x, y, 'Data')
+ self.graph.setActiveCurve('Data')
self.fitModule.estimate()
self.setStatus()
self.parametersTable.fillTableFromFit(self.fitModule.paramlist)
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
text = "%s:%s" % (sys.exc_info()[0], sys.exc_info()[1])
msg = qt.QMessageBox(self)
@@ -331,7 +338,6 @@ class SimpleFitGui(qt.QWidget):
msg.exec_()
self.setStatus("Ready (after estimate error)")
-
def setStatus(self, text=None):
if text is None:
text = "%s" % self.fitModule.getStatus()
@@ -345,7 +351,7 @@ class SimpleFitGui(qt.QWidget):
values,chisq,sigma,niter,lastdeltachi = self.fitModule.startFit()
self.setStatus()
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
text = "%s:%s" % (sys.exc_info()[0], sys.exc_info()[1])
msg = qt.QMessageBox(self)
@@ -376,10 +382,9 @@ class SimpleFitGui(qt.QWidget):
#ddict['yfit'] = self.evaluateDefinedFunction()
#ddict['background'] = self.fitModule._evaluateBackground()
self.graph.clear()
- self.graph.addCurve(ddict['x'], ddict['y'], 'Data', replot=False)
- self.graph.addCurve(ddict['x'], ddict['yfit'], 'Fit', replot=False)
- self.graph.addCurve(ddict['x'], ddict['background'], 'Background',
- replot=False)
+ self.graph.addCurve(ddict['x'], ddict['y'], 'Data')
+ self.graph.addCurve(ddict['x'], ddict['yfit'], 'Fit')
+ self.graph.addCurve(ddict['x'], ddict['background'], 'Background')
contributions = ddict['contributions']
if len(contributions) > 1:
background = ddict['background']
@@ -387,9 +392,8 @@ class SimpleFitGui(qt.QWidget):
for contribution in contributions:
i += 1
self.graph.addCurve(ddict['x'], background + contribution,
- legend='Contribution %d' % i,
- replot=False)
- self.graph.replot()
+ legend='Contribution %d' % i)
+ self.graph.setActiveCurve('Data')
self.graph.show()
def dismiss(self):
@@ -401,6 +405,9 @@ class SimpleFitGui(qt.QWidget):
def evaluateContributions(self, x=None):
return self.fitModule.evaluateContributions(x)
+ def _zoomBack(self, pos):
+ self.graph.getLimitsHistory().pop()
+
def test():
import numpy
@@ -433,7 +440,7 @@ def test():
return w
if __name__=="__main__":
- DEBUG = 0
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
w = test()
app.exec_()
diff --git a/PyMca5/PyMcaGui/math/fitting/SpecfitGui.py b/PyMca5/PyMcaGui/math/fitting/SpecfitGui.py
index aef8fe8..2fd140e 100644
--- a/PyMca5/PyMcaGui/math/fitting/SpecfitGui.py
+++ b/PyMca5/PyMcaGui/math/fitting/SpecfitGui.py
@@ -30,6 +30,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import traceback
+import logging
from PyMca5.PyMcaCore import EventHandler
from PyMca5.PyMcaMath.fitting import Specfit
from PyMca5.PyMcaGui import PyMcaQt as qt
@@ -41,7 +42,9 @@ from . import MultiParameters
from . import FitActionsGui
from . import FitStatusGui
from . import QScriptOption
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
class SpecfitGui(qt.QWidget):
sigSpecfitGuiSignal = qt.pyqtSignal(object)
@@ -173,8 +176,8 @@ class SpecfitGui(qt.QWidget):
self.guiconfig.FunComBox.setCurrentIndex(i)
self.funevent(self.specfit.fitconfig['fittheory'])
except:
- print("Function not in list %s" %\
- self.specfit.fitconfig['fittheory'])
+ _logger.warning("Function not in list %s",
+ self.specfit.fitconfig['fittheory'])
self.funevent(self.specfit.theorylist[0])
#current background
try:
@@ -182,8 +185,8 @@ class SpecfitGui(qt.QWidget):
i=1+list(self.specfit.bkgdict.keys()).index(self.specfit.fitconfig['fitbkg'])
self.guiconfig.BkgComBox.setCurrentIndex(i)
except:
- print("Background not in list %s" %\
- self.specfit.fitconfig['fitbkg'])
+ _logger.warning("Background not in list %s",
+ self.specfit.fitconfig['fitbkg'])
self.bkgevent(list(self.specfit.bkgdict.keys())[0])
#and all the rest
if configuration['McaMode']:
@@ -261,7 +264,7 @@ class SpecfitGui(qt.QWidget):
ddict={}
ddict['event'] = 'FitError'
self._emitSignal(ddict)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
return
self.guiparameters.fillfrommca(mcaresult)
@@ -285,7 +288,7 @@ class SpecfitGui(qt.QWidget):
msg.exec_()
return
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
@@ -313,7 +316,7 @@ class SpecfitGui(qt.QWidget):
msg.setIcon(qt.QMessageBox.Critical)
msg.setText("Error on mcafit: %s" % sys.exc_info()[1])
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
return
self.guiparameters.fillfrommca(mcaresult)
@@ -326,11 +329,11 @@ class SpecfitGui(qt.QWidget):
#for param in self.specfit.paramlist:
# print param['name'],param['group'],param['estimation']
self.specfit.paramlist=self.guiparameters.fillfitfromtable()
- if DEBUG:
- for param in self.specfit.paramlist:
- print(param['name'],param['group'],param['estimation'])
- print("TESTING")
- self.specfit.startfit()
+ for param in self.specfit.paramlist:
+ _logger.debug("name %s; group %s; estimation %s",
+ param['name'], param['group'], param['estimation'])
+ _logger.debug("TESTING")
+
try:
self.specfit.startfit()
except:
@@ -338,7 +341,7 @@ class SpecfitGui(qt.QWidget):
msg.setIcon(qt.QMessageBox.Critical)
msg.setText("Error on Fit")
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
return
self.guiparameters.fillfromfit(self.specfit.paramlist,current='Fit')
diff --git a/PyMca5/PyMcaGui/math/fitting/TextField.py b/PyMca5/PyMcaGui/math/fitting/TextField.py
index 1327a9e..ecbc7d1 100644
--- a/PyMca5/PyMcaGui/math/fitting/TextField.py
+++ b/PyMca5/PyMcaGui/math/fitting/TextField.py
@@ -27,11 +27,12 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class TextField(qt.QWidget):
def __init__(self,parent = None,name = None,fl = 0):
@@ -40,8 +41,7 @@ class TextField(qt.QWidget):
try:
self.setSizePolicy(qt.QSizePolicy(1,1,0,0,self.sizePolicy().hasHeightForWidth()))
except:
- if DEBUG:
- print("TextField Bad Size policy")
+ _logger.warning("TextField Bad Size policy")
TextFieldLayout = qt.QHBoxLayout(self)
Layout2 = qt.QHBoxLayout(None)
@@ -55,8 +55,7 @@ class TextField(qt.QWidget):
try:
self.TextLabel.setSizePolicy(qt.QSizePolicy(7,1,0,0,self.TextLabel.sizePolicy().hasHeightForWidth()))
except:
- if DEBUG:
- print("TextField Bad Size policy")
+ _logger.warning("TextField Bad Size policy")
self.TextLabel.setText(str("TextLabel"))
Layout2.addWidget(self.TextLabel)
diff --git a/PyMca5/PyMcaGui/misc/DoubleSlider.py b/PyMca5/PyMcaGui/misc/DoubleSlider.py
index 4d85105..36d2b7b 100644
--- a/PyMca5/PyMcaGui/misc/DoubleSlider.py
+++ b/PyMca5/PyMcaGui/misc/DoubleSlider.py
@@ -27,11 +27,12 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class DoubleSlider(qt.QWidget):
sigDoubleSliderValueChanged = qt.pyqtSignal(object)
@@ -68,8 +69,7 @@ class DoubleSlider(qt.QWidget):
return ddict
def _sliderChanged(self, value):
- if DEBUG:
- print("DoubleSlider._sliderChanged()")
+ _logger.debug("DoubleSlider._sliderChanged()")
ddict = self.__getDict()
self.sigDoubleSliderValueChanged.emit(ddict)
diff --git a/PyMca5/PyMcaGui/misc/SelectionTable.py b/PyMca5/PyMcaGui/misc/SelectionTable.py
index f121eb3..4332964 100644
--- a/PyMca5/PyMcaGui/misc/SelectionTable.py
+++ b/PyMca5/PyMcaGui/misc/SelectionTable.py
@@ -38,7 +38,6 @@ Each time one of the contained widgets changes, a sigSelectionTableSignal
is emitted indicating the current selection and the triggering cell.
"""
from PyMca5.PyMcaGui import PyMcaQt as qt
-DEBUG = 0
class SelectionTable(qt.QTableWidget):
diff --git a/PyMca5/PyMcaGui/physics/xas/XASFourierTransformParameters.py b/PyMca5/PyMcaGui/physics/xas/XASFourierTransformParameters.py
index 32b3aae..5a7cab4 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASFourierTransformParameters.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASFourierTransformParameters.py
@@ -30,13 +30,13 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import os
-import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class XASFourierTransformParameters(qt.QGroupBox):
sigFTParametersSignal = qt.pyqtSignal(object)
@@ -164,8 +164,7 @@ class XASFourierTransformParameters(qt.QGroupBox):
self.pointsSelector.activated[int].connect(self._pointsChanged)
def _windowChanged(self, value):
- if DEBUG:
- print("_windowChanged ", value)
+ _logger.debug("_windowChanged %s", value)
current = str(self.windowSelector.currentText())
if current.lower() in ["gaussian", "gauss", "tukey", "papul"]:
self.apodizationBox.setEnabled(False)
@@ -177,20 +176,17 @@ class XASFourierTransformParameters(qt.QGroupBox):
self.emitSignal("FTWindowChanged")
def _apodizationChanged(self, value):
- if DEBUG:
- print("_apodizationChanged ", value)
+ _logger.debug("_apodizationChanged %s", value)
if self.__connected:
self.emitSignal("FTApodizationChanged")
def _kMinChanged(self, value):
- if DEBUG:
- print("Current kMin Value =", value)
+ _logger.debug("Current kMin Value = %s", value)
if self.__connected:
self.emitSignal("FTKMinChanged")
def _kMaxChanged(self, value):
- if DEBUG:
- print("Current kMax Value =", value)
+ _logger.debug("Current kMax Value = %s", value)
if self.__connected:
if value > self.kMinBox.value():
self.emitSignal("FTKMaxChanged")
@@ -201,20 +197,17 @@ class XASFourierTransformParameters(qt.QGroupBox):
pass
def _kStepChanged(self, value):
- if DEBUG:
- print("Current kStep value = ", value)
+ _logger.debug("Current kStep value = %s", value)
if self.__connected:
self.emitSignal("FTKStepChanged")
def _rMaxChanged(self, value):
- if DEBUG:
- print("Current rMax Value =", value)
+ _logger.debug("Current rMax Value = %s", value)
if self.__connected:
self.emitSignal("FTRMaxChanged")
def _pointsChanged(self, value):
- if DEBUG:
- print("_pointsChanged ", value)
+ _logger.debug("_pointsChanged %s", value)
if self.__connected:
self.emitSignal("FTPointsChanged")
@@ -234,8 +227,8 @@ class XASFourierTransformParameters(qt.QGroupBox):
return ddict
def setParameters(self, ddict, signal=True):
- if DEBUG:
- print("setParameters called", ddict, signal)
+ _logger.debug("setParameters called, ddict %s, signal %s",
+ ddict, signal)
if "FT" in ddict:
ddict = ddict["FT"]
try:
@@ -295,7 +288,7 @@ class XASFourierTransformParameters(qt.QGroupBox):
self.setStyleSheet("QGroupBox {color: %s;}" % color)
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
def mySlot(ddict):
print("Signal received: ", ddict)
diff --git a/PyMca5/PyMcaGui/physics/xas/XASNormalizationParameters.py b/PyMca5/PyMcaGui/physics/xas/XASNormalizationParameters.py
index 7643541..8fbafdd 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASNormalizationParameters.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASNormalizationParameters.py
@@ -32,13 +32,15 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
from PyMca5.PyMcaGui import XASNormalizationWindow
from PyMca5.PyMca import XASNormalization
IconDict = PyMca_Icons.IconDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class XASNormalizationParameters(qt.QGroupBox):
sigNormalizationParametersSignal = qt.pyqtSignal(object)
@@ -172,8 +174,7 @@ class XASNormalizationParameters(qt.QGroupBox):
self.postEdgeEndBox.valueChanged[float].connect(self._postEdgeEndChanged)
def _normalizationChanged(self, value):
- if DEBUG:
- print("_normalizationChanged ", value)
+ _logger.debug("_normalizationChanged, %s ", value)
if self.__connected:
self._emitSignal("JumpNormalizationChanged")
@@ -204,8 +205,7 @@ class XASNormalizationParameters(qt.QGroupBox):
self.e0SpinBox.setEnabled(True)
def _e0Changed(self, value):
- if DEBUG:
- print("E0 CHANGED", value)
+ _logger.debug("E0 CHANGED, %s", value)
if self.__connected:
try:
self.__connected = False
@@ -215,14 +215,12 @@ class XASNormalizationParameters(qt.QGroupBox):
self._emitSignal("E0Changed")
def _preEdgeChanged(self, value):
- if DEBUG:
- print("Current pre-edge value = ", value)
+ _logger.debug("Current pre-edge value = %s", value)
if self.__connected:
self._emitSignal("PreEdgeChanged")
def _preEdgeStartChanged(self, value):
- if DEBUG:
- print("pre start changed", value)
+ _logger.debug("pre start changed: %s", value)
if self.__connected:
try:
self.__connected = False
@@ -232,8 +230,7 @@ class XASNormalizationParameters(qt.QGroupBox):
self._emitSignal("PreEdgeChanged")
def _preEdgeEndChanged(self, value):
- if DEBUG:
- print("pre end changed", value)
+ _logger.debug("pre end changed: %s", value)
if self.__connected:
try:
self.__connected = False
@@ -243,14 +240,12 @@ class XASNormalizationParameters(qt.QGroupBox):
self._emitSignal("PreEdgeChanged")
def _postEdgeChanged(self, value):
- if DEBUG:
- print("post-edge changed", value)
+ _logger.debug("post-edge changed: %s", value)
if self.__connected:
self._emitSignal("PostEdgeChanged")
def _postEdgeStartChanged(self, value):
- if DEBUG:
- print("post-edge start changed", value)
+ _logger.debug("post-edge start changed: %s", value)
if self.__connected:
try:
self.__connected = False
@@ -260,8 +255,7 @@ class XASNormalizationParameters(qt.QGroupBox):
self._emitSignal("PostEdgeChanged")
def _postEdgeEndChanged(self, value):
- if DEBUG:
- print("post-edge changed", value)
+ _logger.debug("post-edge changed: %s", value)
if self.__connected:
try:
self.__connected = False
@@ -343,8 +337,7 @@ class XASNormalizationParameters(qt.QGroupBox):
return ddict
def setParameters(self, ddict, signal=True):
- if DEBUG:
- print("setParameters called", ddict, signal)
+ _logger.debug("setParameters called, %s %s", ddict, signal)
if "Normalization" in ddict:
ddict = ddict["Normalization"]
try:
@@ -408,7 +401,7 @@ class XASNormalizationParameters(qt.QGroupBox):
self.setStyleSheet("QGroupBox {color: %s;}" % color)
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
def mySlot(ddict):
print("Signal received: ", ddict)
diff --git a/PyMca5/PyMcaGui/physics/xas/XASNormalizationWindow.py b/PyMca5/PyMcaGui/physics/xas/XASNormalizationWindow.py
index 882e1b8..60e97aa 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASNormalizationWindow.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASNormalizationWindow.py
@@ -37,10 +37,8 @@ import copy
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-from PyMca5.PyMcaGraph.backends.MatplotlibBackend \
- import MatplotlibBackend as backend
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaPhysics import XASNormalization
+from silx.gui.plot import PlotWindow
POLYNOM_OPTIONS = ['Modif. Victoreen',
'Victoreen',
@@ -278,12 +276,17 @@ class XASNormalizationWindow(qt.QWidget):
self.energy = energy
self.spectrum = spectrum
self.parametersWidget = XASNormalizationParametersWidget(self)
- self.graph = PlotWindow.PlotWindow(self, backend=backend,
- plugins=False, newplot=False)
+ self.graph = PlotWindow(self, position=False,
+ aspectRatio=False, colormap=False,
+ yInverted=False, roi=False, mask=False,
+ fit=False)
+ self.graph.zoomModeAction.setVisible(False)
+ self.graph.panModeAction.setVisible(False)
self.__lastDict = {}
self.graph.sigPlotSignal.connect(self._handleGraphSignal)
self.graph.addCurve(self.energy,
- spectrum, legend="Spectrum", replace=True)
+ spectrum, legend="Spectrum")
+ self.graph.setActiveCurve("Spectrum")
self.mainLayout.addWidget(self.parametersWidget)
self.mainLayout.addWidget(self.graph)
# initialize variables
@@ -307,11 +310,10 @@ class XASNormalizationWindow(qt.QWidget):
else:
self.energy = energy
self.graph.clearMarkers()
+ self.graph.clearCurves()
self.graph.addCurve(self.energy,
self.spectrum,
- legend="Spectrum",
- replot=True,
- replace=True)
+ legend="Spectrum")
edgeEnergy = XASNormalization.estimateXANESEdge(self.spectrum,
energy=self.energy,
full=False)
@@ -379,13 +381,10 @@ class XASNormalizationWindow(qt.QWidget):
yPost = postEdgeFunction(postEdgeParameters, x)
self.graph.addCurve(x,
yPre,
- legend="Pre-edge Polynomial",
- replace=False)
+ legend="Pre-edge Polynomial")
self.graph.addCurve(x,
yPost+yPre,
- legend="Post-edge Polynomial",
- replace=False,
- replot=True)
+ legend="Post-edge Polynomial")
def updateMarkers(self, edgeEnergy, preEdgeRegions, postEdgeRegions, edge_auto=True):
if edge_auto:
@@ -393,38 +392,33 @@ class XASNormalizationWindow(qt.QWidget):
else:
draggable = True
#self.graph.clearMarkers()
- self.graph.insertXMarker(edgeEnergy,
- 'EDGE',
- text='EDGE',
- color='pink',
- draggable=draggable,
- replot=False)
+ self.graph.addXMarker(edgeEnergy,
+ 'EDGE',
+ text='EDGE',
+ color='pink',
+ draggable=draggable)
for i in range(2):
x = preEdgeRegions[0][i] + edgeEnergy
if i == 0:
label = 'MIN'
else:
label = 'MAX'
- self.graph.insertXMarker(x,
- 'Pre-'+ label,
- text=label,
- color='blue',
- draggable=True,
- replot=False)
+ self.graph.addXMarker(x,
+ 'Pre-' + label,
+ text=label,
+ color='blue',
+ draggable=True)
for i in range(2):
x = postEdgeRegions[0][i] + edgeEnergy
if i == 0:
label = 'MIN'
- replot=False
else:
label = 'MAX'
- replot=True
- self.graph.insertXMarker(x,
- 'Post-'+ label,
- text=label,
- color='blue',
- draggable=True,
- replot=replot)
+ self.graph.addXMarker(x,
+ 'Post-' + label,
+ text=label,
+ color='blue',
+ draggable=True)
def _handleGraphSignal(self, ddict):
#print("ddict = ", ddict)
@@ -532,7 +526,7 @@ if __name__ == "__main__":
w = XASNormalizationDialog(None, spectrum, energy=energy)
else:
from PyMca5 import SpecfitFuns
- noise = numpy.random.randn(1500.)
+ noise = numpy.random.randn(1500)
x = 8000. + numpy.arange(1500.)
y = SpecfitFuns.upstep([100, 8500., 50], x)
w = XASNormalizationDialog(None, y + numpy.sqrt(y)* noise, energy=x)
diff --git a/PyMca5/PyMcaGui/physics/xas/XASParameters.py b/PyMca5/PyMcaGui/physics/xas/XASParameters.py
index acdfbfc..7a1055f 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASParameters.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASParameters.py
@@ -31,6 +31,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
@@ -40,7 +41,8 @@ from PyMca5.PyMcaGui import XASFourierTransformParameters
from PyMca5.PyMcaGui import PyMcaFileDialogs
from PyMca5.PyMcaIO import ConfigDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class XASParameters(qt.QWidget):
sigXASParametersSignal = qt.pyqtSignal(object)
@@ -145,8 +147,7 @@ class XASParameters(qt.QWidget):
self._emitSignal(ddict["event"])
def _postEdgeParameterSlot(self, ddict):
- if DEBUG:
- print("_postEdgeParameterSlot ", ddict)
+ _logger.debug("_postEdgeParameterSlot: %s", ddict)
# Should I change the event to "EXAFSChanged"?
self.fourierTransformWidget.setKRange([ddict["KMin"], ddict["KMax"]])
self._emitSignal(ddict["event"])
@@ -213,10 +214,10 @@ class XASParameters(qt.QWidget):
self.postEdgeWidget.setTitleColor(color)
self.fourierTransformWidget.setTitleColor(color)
except:
- print("Error setting title color", sys.exc_info())
+ _logger.error("Error setting title color: %s", sys.exc_info())
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
def testSlot(ddict):
print("Emitted signal = ", ddict)
diff --git a/PyMca5/PyMcaGui/physics/xas/XASPostEdgeParameters.py b/PyMca5/PyMcaGui/physics/xas/XASPostEdgeParameters.py
index 5bfe43b..6f537f5 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASPostEdgeParameters.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASPostEdgeParameters.py
@@ -30,11 +30,13 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
def myFloat(x):
try:
@@ -161,8 +163,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.__connected = True
def _knotNumberChanged(self, value):
- if DEBUG:
- print("Current number of knots = ", value)
+ _logger.debug("Current number of knots = %s", value)
oldValue = self.__connected
self.__connected = False
try:
@@ -181,8 +182,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.emitSignal("KnotNumberChanged")
def _kMinChanged(self, value):
- if DEBUG:
- print("Current kMin Value =", value)
+ _logger.debug("Current kMin Value = %s", value)
oldValue = self.__connected
self.__connected = False
try:
@@ -193,8 +193,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.emitSignal("KMinChanged")
def _kMaxChanged(self, value):
- if DEBUG:
- print("Current kMax Value =", value)
+ _logger.debug("Current kMax Value = %s", value)
if value <= self.kMinBox.value():
# I should check if we have the focus prior to
# raise any error.
@@ -210,14 +209,12 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.emitSignal("KMaxChanged")
def _kWeightChanged(self, value):
- if DEBUG:
- print("Current kWeight Value =", value)
+ _logger.debug("Current kWeight Value = %s", value)
if self.__connected:
self.emitSignal("KWeightChanged")
def _knotChanged(self, value):
- if DEBUG:
- print("One knot has been changed = ", value)
+ _logger.debug("One knot has been changed = %s", value)
# adjust limits
oldValue = self.__connected
self.__connected = False
@@ -242,8 +239,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.emitSignal("KnotPositionChanged")
def _degreeChanged(self, value):
- if DEBUG:
- print("One knot polynomial degree changed", value)
+ _logger.debug("One knot polynomial degree changed: %s", value)
if self.__connected:
self.emitSignal("KnotOrderChanged")
@@ -267,8 +263,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
return ddict
def setParameters(self, ddict, signal=True):
- if DEBUG:
- print("setParameters called", ddict, signal)
+ _logger.debug("setParameters called: ddict %s, signal%s", ddict, signal)
if "EXAFS" in ddict:
ddict = ddict["EXAFS"]
elif "PostEdge" in ddict:
@@ -362,7 +357,7 @@ class XASPostEdgeParameters(qt.QGroupBox):
self.setStyleSheet("QGroupBox {color: %s;}" % color)
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
def testSlot(ddict):
print("Emitted signal = ", ddict)
diff --git a/PyMca5/PyMcaGui/physics/xas/XASSelfattenuationWindow.py b/PyMca5/PyMcaGui/physics/xas/XASSelfattenuationWindow.py
index 0d0f387..bdb0b6b 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASSelfattenuationWindow.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASSelfattenuationWindow.py
@@ -31,8 +31,7 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import copy
-import numpy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMcaFileDialogs
from PyMca5.PyMcaPhysics.xrf import Elements
@@ -45,7 +44,8 @@ if hasattr(qt, "QString"):
else:
qstring = str
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class SampleConfiguration(qt.QWidget):
def __init__(self, parent=None,orientation="vertical"):
@@ -121,16 +121,13 @@ class SampleConfiguration(qt.QWidget):
def materialSignal(self, txt):
txt = str(txt)
if Elements.isValidFormula(txt):
- if DEBUG:
- print("validFormula")
+ _logger.debug("validFormula")
elementDict = Elements.getMaterialMassFractions([txt], [1.0])
elif Elements.isValidMaterial(txt):
- if DEBUG:
- print("ValidMaterial")
+ _logger.debug("ValidMaterial")
elementDict = Elements.getMaterialMassFractions([txt], [1.0])
else:
- if DEBUG:
- print("to be defined")
+ _logger.debug("to be defined")
msg=qt.QMessageBox.information(self,
"Invalid Material %s" % txt,
"The material %s is not a valid Formula " \
@@ -160,12 +157,10 @@ class SampleConfiguration(qt.QWidget):
qstring(ele + "(%d)" % (z[i])))
if currentElement in elementsList:
#selection does not need to be changed
- if DEBUG:
- print("Element widget up to date")
+ _logger.debug("Element widget up to date")
else:
#selection needs to be changed
- if DEBUG:
- print("Setting the highest Z as default")
+ _logger.debug("Setting the highest Z as default")
self.elementSignal(qstring(elementsList[iMaxZ]))
diff --git a/PyMca5/PyMcaGui/physics/xas/XASWindow.py b/PyMca5/PyMcaGui/physics/xas/XASWindow.py
index b4fa9a4..bea81ef 100644
--- a/PyMca5/PyMcaGui/physics/xas/XASWindow.py
+++ b/PyMca5/PyMcaGui/physics/xas/XASWindow.py
@@ -32,16 +32,17 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import sys
-import numpy
-import traceback
-import copy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaGui import XASParameters
from PyMca5.PyMca import XASClass
-DEBUG = 0
+from silx.gui.plot import PlotWindow
+from PyMca5.PyMcaGui.PluginsToolButton import PluginsToolButton
+
+_logger = logging.getLogger(__name__)
+
class XASDialog(qt.QDialog):
def __init__(self, parent=None, analyzer=None, backend=None):
@@ -116,15 +117,13 @@ class XASWindow(qt.QMainWindow):
return self.parametersWidget.getParameters()
def _parametersSlot(self, ddict):
- if DEBUG:
- print("XASWindow.parametersSlot", ddict)
+ _logger.debug("XASWindow.parametersSlot: %s", ddict)
analyzer = self.mdiArea.analyzer
if "XASParameters" in ddict:
ddict = ddict["XASParameters"]
analyzer.setConfiguration(ddict)
- if DEBUG:
- print("ANALYZER CONFIGURATION FINAL")
- print(analyzer.getConfiguration())
+ _logger.debug("ANALYZER CONFIGURATION FINAL")
+ _logger.debug(analyzer.getConfiguration())
self.update()
def update(self, ddict=None):
@@ -156,10 +155,14 @@ class XASMdiArea(qt.QMdiArea):
self._windowList = ["Spectrum", "Post-edge", "Signal", "FT"]
self._windowList.reverse()
for title in self._windowList:
- plot = PlotWindow.PlotWindow(self,
- #control=True,
- position=True,
- backend=backend)
+ plot = PlotWindow(self, position=True, aspectRatio=False,
+ colormap=False, yInverted=False,
+ roi=False, mask=False, fit=False,
+ backend=backend)
+ plot.zoomModeAction.setVisible(False)
+ plot.panModeAction.setVisible(False)
+ pluginsToolButton = PluginsToolButton(plot=plot)
+ plot.toolBar().addWidget(pluginsToolButton)
plot.setWindowTitle(title)
self.addSubWindow(plot)
self._windowDict[title] = plot
@@ -190,6 +193,7 @@ class XASMdiArea(qt.QMdiArea):
legend="Spectrum",
xlabel="Energy (eV)",
ylabel="Absorption (a.u.)")
+ self._windowDict["Spectrum"].setActiveCurve("Spectrum")
return self.analyzer.setSpectrum(energy, mu)
def update(self, ddict=None):
@@ -200,19 +204,17 @@ class XASMdiArea(qt.QMdiArea):
plot = self._windowDict["Spectrum"]
e0 = ddict["Edge"]
plot.addCurve(ddict["Energy"] - e0, ddict["Mu"], legend="Spectrum",
- xlabel="Energy (eV)", ylabel="Absorption (a.u.)",
- replot=False, replace=True)
- plot.addCurve(ddict["NormalizedEnergy"][idx] - e0,
+ xlabel="Energy (eV)", ylabel="Absorption (a.u.)")
+ plot.addCurve(ddict["NormalizedEnergy"][idx] - e0,
ddict["NormalizedMu"][idx],
legend="Normalized",
xlabel="Energy (eV)",
ylabel="Absorption (a.u.)",
- yaxis="right",
- replot=False)
+ yaxis="right")
plot.addCurve(ddict["NormalizedEnergy"] - e0,
- ddict["NormalizedSignal"], legend="Post", replot=False)
+ ddict["NormalizedSignal"], legend="Post", resetzoom=False)
plot.addCurve(ddict["NormalizedEnergy"] - e0,
- ddict["NormalizedBackground"], legend="Pre",replot=False)
+ ddict["NormalizedBackground"], legend="Pre", resetzoom=False)
plot.resetZoom()
#idxK = ddict["EXAFSKValues"] >= 0
idx = (ddict["EXAFSKValues"] >= ddict["KMin"]) & \
@@ -222,32 +224,28 @@ class XASMdiArea(qt.QMdiArea):
ddict["EXAFSSignal"][idx],
legend="EXAFSSignal",
xlabel="K",
- ylabel="Normalized Units",
- replace=True,
- replot=False)
+ ylabel="Normalized Units")
+ plot.setActiveCurve("EXAFSSignal")
plot.addCurve(ddict["EXAFSKValues"][idx],
ddict["PostEdgeB"][idx],
legend="PostEdge",
xlabel="K",
ylabel="Normalized Units",
- color="blue",
- replot=False)
+ color="blue")
if 0:
plot.clearMarkers()
for i in range(len(ddict["KnotsX"])):
- plot.insertMarker(ddict["KnotsX"][i],
- ddict["KnotsY"][i],
- legend="Knot %d" % (i+1),
- text="Knot %d" % (i+1),
- replot=False,
- draggable=False,
- selectable=False,
- color="orange")
+ plot.addMarker(ddict["KnotsX"][i],
+ ddict["KnotsY"][i],
+ legend="Knot %d" % (i+1),
+ text="Knot %d" % (i+1),
+ draggable=False,
+ selectable=False,
+ color="orange")
else:
plot.addCurve(ddict["KnotsX"],
ddict["KnotsY"],
legend="Knots",
- replot=False,
linestyle="",
symbol="o",
color="orange")
@@ -264,50 +262,41 @@ class XASMdiArea(qt.QMdiArea):
ddict["EXAFSNormalized"][idx],
legend="Normalized EXAFS",
xlabel="K",
- ylabel=ylabel,
- replace=True,
- replot=False)
+ ylabel=ylabel)
+ plot.setActiveCurve("Normalized EXAFS")
plot.addCurve(ddict["FT"]["K"],
ddict["FT"]["WindowWeight"],
legend="FT Window",
xlabel="K",
ylabel="Weight",
yaxis="right",
- color="red",
- replace=False,
- replot=False)
+ color="red")
plot.resetZoom()
plot = self._windowDict["FT"]
plot.addCurve(ddict["FT"]["FTRadius"],
ddict["FT"]["FTIntensity"],
legend="FT Intensity",
xlabel="R (Angstrom)",
- ylabel="Arbitrary Units",
- replace=True,
- replot=False)
+ ylabel="Arbitrary Units")
+ plot.setActiveCurve("FT Intensity")
"""
plot.addCurve(ddict["FT"]["FTRadius"],
ddict["FT"]["FTReal"],
legend="FT Real",
xlabel="R (Angstrom)",
ylabel="Arbitrary Units",
- color="green",
- replace=False,
- replot=False)
+ color="green")
"""
plot.addCurve(ddict["FT"]["FTRadius"],
ddict["FT"]["FTImaginary"],
legend="FT Imaginary",
xlabel="R (Angstrom)",
ylabel="Arbitrary Units",
- color="red",
- replace=False,
- replot=False)
- plot.resetZoom()
+ color="red")
self.sigXASMdiAreaSignal.emit(ddict)
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
app = qt.QApplication([])
from PyMca5.PyMcaIO import specfilewrapper as specfile
from PyMca5.PyMcaDataDir import PYMCA_DATA_DIR
diff --git a/PyMca5/PyMcaGui/physics/xrf/AttenuatorsTable.py b/PyMca5/PyMcaGui/physics/xrf/AttenuatorsTable.py
index d230a68..370ff06 100644
--- a/PyMca5/PyMcaGui/physics/xrf/AttenuatorsTable.py
+++ b/PyMca5/PyMcaGui/physics/xrf/AttenuatorsTable.py
@@ -31,6 +31,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
@@ -46,7 +47,8 @@ from PyMca5.PyMcaPhysics import Elements
from . import MaterialEditor
from . import MatrixEditor
import re
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
class MyQLabel(qt.QLabel):
@@ -342,9 +344,8 @@ class AttenuatorsTableWidget(QTable):
self.matrixMode = matrixmode
self.attenuators = attenuators
self.verticalHeader().hide()
- if DEBUG:
- print("margin to adjust")
- print("focus style")
+ _logger.debug("margin to adjust")
+ _logger.debug("focus style")
self.setFrameShape(qt.QTableWidget.NoFrame)
self.setSelectionMode(qt.QTableWidget.NoSelection)
self.setColumnCount(len(labels))
@@ -544,14 +545,12 @@ class AttenuatorsTableWidget(QTable):
self.setCellWidget(idx, 2, self.combo)
self.combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
- def mySlot(self,row,col):
- if DEBUG:
- print("Value changed row = %d cole = &d" % (row, col))
- print("Text = %s" % self.text(row, col))
+ def mySlot(self, row, col):
+ _logger.debug("Value changed row = %d cole = &d", row, col)
+ _logger.debug("Text = %s", self.text(row, col))
def _comboSlot(self, ddict):
- if DEBUG:
- print("_comboSlot", ddict)
+ _logger.debug("_comboSlot %s", ddict)
row = ddict['row']
col = ddict['col']
text = ddict['text']
@@ -564,8 +563,8 @@ class AttenuatorsTableWidget(QTable):
return self.cellWidget(row, col).currentText()
else:
if col not in [1, 3, 4, 5]:
- print("row, col = %d, %d" % (row, col))
- print("I should not be here")
+ _logger.info("row, col = %d, %d", row, col)
+ _logger.info("I should not be here")
else:
item = self.item(row, col)
return item.text()
@@ -575,7 +574,7 @@ class AttenuatorsTableWidget(QTable):
self.cellWidget(row, 0).setText(text)
return
if col not in [1, 3, 4, 5]:
- print("only compatible columns 1, 3 and 4")
+ _logger.debug("only compatible columns 1, 3 and 4")
raise ValueError("method for column > 2")
item = self.item(row, col)
if item is None:
diff --git a/PyMca5/PyMcaGui/physics/xrf/ConcentrationsWidget.py b/PyMca5/PyMcaGui/physics/xrf/ConcentrationsWidget.py
index 8d31dd9..5392291 100644
--- a/PyMca5/PyMcaGui/physics/xrf/ConcentrationsWidget.py
+++ b/PyMca5/PyMcaGui/physics/xrf/ConcentrationsWidget.py
@@ -31,6 +31,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, 'QString'):
@@ -49,9 +50,10 @@ QTable = qt.QTableWidget
from PyMca5.PyMcaPhysics.xrf import ConcentrationsTool
from PyMca5.PyMcaPhysics.xrf import Elements
import time
-DEBUG = 0
-if DEBUG:
- print("ConcentrationsWidget is in debug mode")
+
+_logger = logging.getLogger(__name__)
+
+_logger.debug("ConcentrationsWidget is in debug mode")
class Concentrations(qt.QWidget):
@@ -127,7 +129,7 @@ class Concentrations(qt.QWidget):
if 'addinfo' in kw:
if kw['addinfo']:
addInfo = True
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if addInfo:
ddict, info = self.concentrationsTool.processFitResult(*var, **kw)
self.concentrationsTable.fillFromResult(ddict)
@@ -217,13 +219,12 @@ class SimpleThread(qt.QThread):
self._result = None
def run(self):
- if DEBUG:
+ try:
self._result = self._function(*self._var, **self._kw)
- else:
- try:
- self._result = self._function(*self._var, **self._kw)
- except:
- self._result = ("Exception",) + sys.exc_info()
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ self._result = ("Exception",) + sys.exc_info()
class ConcentrationsWidget(qt.QWidget):
diff --git a/PyMca5/PyMcaGui/physics/xrf/ElementsInfo.py b/PyMca5/PyMcaGui/physics/xrf/ElementsInfo.py
index e16fd12..aa7b7a6 100644
--- a/PyMca5/PyMcaGui/physics/xrf/ElementsInfo.py
+++ b/PyMca5/PyMcaGui/physics/xrf/ElementsInfo.py
@@ -30,6 +30,7 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaPhysics.xrf import ElementHtml
from PyMca5.PyMcaPhysics.xrf import Elements
@@ -37,7 +38,8 @@ from PyMca5.PyMcaGui.physics.xrf.QPeriodicTable import QPeriodicTable
__revision__ = "$Revision: 1.15 $"
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
CLOSE_ICON =[
"16 16 18 1",
". c None",
@@ -193,8 +195,7 @@ class ElementsInfo(qt.QWidget):
self.infoWidget.setFocus()
def infoToggle(self,**kw):
- if DEBUG:
- print("toggleSource called")
+ _logger.debug("toggleSource called")
if self.infoWidget.isHidden():
self.infoWidget.show()
self.infoWidget.raiseW()
@@ -238,8 +239,7 @@ class ElementsInfo(qt.QWidget):
class Line(qt.QFrame):
sigLineDoubleClickEvent = qt.pyqtSignal(object)
def mouseDoubleClickEvent(self,event):
- if DEBUG:
- print("Double Click Event")
+ _logger.debug("Double Click Event")
ddict={}
ddict['event']="DoubleClick"
ddict['data'] = event
@@ -248,8 +248,7 @@ class Line(qt.QFrame):
class PixmapLabel(qt.QLabel):
sigPixmapLabelMousePressEvent = qt.pyqtSignal(object)
def mousePressEvent(self,event):
- if DEBUG:
- print("Mouse Press Event")
+ _logger.debug("Mouse Press Event")
ddict={}
ddict['event']="MousePress"
ddict['data'] = event
@@ -276,6 +275,7 @@ class MyQLineEdit(qt.QLineEdit):
self.sigFocusOut.emit()
def main():
+ logging.basicConfig(level=logging.INFO)
app = qt.QApplication([])
winpalette = qt.QPalette(qt.QColor(230,240,249),qt.QColor(238,234,238))
app.setPalette(winpalette)
diff --git a/PyMca5/PyMcaGui/physics/xrf/EnergyTable.py b/PyMca5/PyMcaGui/physics/xrf/EnergyTable.py
index 7c07cb9..fac83c8 100644
--- a/PyMca5/PyMcaGui/physics/xrf/EnergyTable.py
+++ b/PyMca5/PyMcaGui/physics/xrf/EnergyTable.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -33,6 +33,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from . import QXTube
from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaGui import PyMca_Icons as Icons
@@ -41,7 +42,9 @@ qt = QXTube.qt
QTVERSION = qt.qVersion()
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
+
class EnergyTab(qt.QWidget):
def __init__(self,parent=None, name="Energy Tab"):
qt.QWidget.__init__(self, parent)
@@ -304,26 +307,25 @@ class EnergyTable(QTable):
self.setNumCols(3 * self.dataColumns)
self.setFocusStyle(qttable.QTable.FollowStyle)
else:
- if DEBUG:
- print("margin")
- print("frame shape")
- print("selection mode")
- print("focus style")
- print("all of them missing")
- self.setColumnCount(3 * self.dataColumns)
+ _logger.debug("margin\n"
+ "frame shape\n"
+ "selection mode\n"
+ "focus style\n"
+ "all of them missing")
+ self.setColumnCount(3 * self.dataColumns)
labels = []
for i in range(self.dataColumns):
- labels.append("Use" + i * " ")
- labels.append("Energy" + i * " ")
- labels.append("Weight" + i * " ")
+ labels.append("Use")
+ labels.append("Energy")
+ labels.append("Weight")
if QTVERSION < '4.0.0':
- for label in labels:
- self.horizontalHeader().setLabel(labels.index(label),label)
+ for i in range(len(labels)):
+ label = labels[i]
+ self.horizontalHeader().setLabel(i, label)
else:
- if DEBUG:
- print("margin to addjust")
- print("focus style")
+ _logger.debug("margin to adjust")
+ _logger.debug("focus style")
self.setFrameShape(qt.QTableWidget.NoFrame)
self.setSelectionMode(qt.QTableWidget.NoSelection)
self.setColumnCount(len(labels))
@@ -337,8 +339,7 @@ class EnergyTable(QTable):
self.__build(self.dataColumns * 20)
self.__disconnected = False
for i in range(self.dataColumns):
- if DEBUG:
- print("column adjustment missing")
+ _logger.debug("column adjustment missing")
self.cellChanged[int, int].connect(self.mySlot)
def _itemSlot(self, *var):
@@ -505,8 +506,7 @@ class EnergyTable(QTable):
if QTVERSION < '4.0.0':
self.adjustColumn(0 + 3*i)
else:
- if DEBUG:
- print("column adjustment missing")
+ _logger.debug("column adjustment missing")
except:
self.__disconnected = False
raise
@@ -520,9 +520,8 @@ class EnergyTable(QTable):
def mySlot(self,row,col):
if self.__disconnected:return
- if DEBUG:
- print("Value changed row = %d col = %d" % (row, col))
- print("Text = %s" % self.text(row,col))
+ _logger.debug("Value changed row = %d col = %d", row, col)
+ _logger.debug("Text = %s", self.text(row, col))
if (col != 0) and (col !=3) and (col != 6) and (col != 9):
try:
s = str(self.text(row, col))
@@ -561,8 +560,7 @@ class EnergyTable(QTable):
else:
item.setText(text)
else:
- if DEBUG:
- print("checkbox can be called?")
+ _logger.debug("checkbox can be called?")
pass
def _getDict(self):
diff --git a/PyMca5/PyMcaGui/physics/xrf/FastXRFLinearFitWindow.py b/PyMca5/PyMcaGui/physics/xrf/FastXRFLinearFitWindow.py
index dc7a169..71b0bf8 100644
--- a/PyMca5/PyMcaGui/physics/xrf/FastXRFLinearFitWindow.py
+++ b/PyMca5/PyMcaGui/physics/xrf/FastXRFLinearFitWindow.py
@@ -30,14 +30,12 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
-import numpy
+
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
from PyMca5.PyMcaGui import PyMcaFileDialogs
-DEBUG = 0
class FastXRFLinearFitWindow(qt.QWidget):
def __init__(self, parent=None):
diff --git a/PyMca5/PyMcaGui/physics/xrf/FitParam.py b/PyMca5/PyMcaGui/physics/xrf/FitParam.py
index 0235258..d998e53 100644
--- a/PyMca5/PyMcaGui/physics/xrf/FitParam.py
+++ b/PyMca5/PyMcaGui/physics/xrf/FitParam.py
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import traceback
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
@@ -48,19 +49,19 @@ from . import EnergyTable
from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaGui import PyMcaFileDialogs
XRFMC_FLAG = False
+_logger = logging.getLogger(__name__)
try:
from . import XRFMCPyMca
XRFMC_FLAG = True
except ImportError:
- print("XRFMC_TO_BE_IMPORTED")
+ _logger.warning("XRFMC_TO_BE_IMPORTED")
# no XRFMC support
pass
from PyMca5.PyMcaGui.math import StripBackgroundWidget
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaGui.physics.xrf import StrategyHandler
+from silx.gui.plot import PlotWindow
import numpy
-DEBUG = 0
FitParamSections= ["fit", "detector", "peaks", "peakshape", "attenuators","concentrations"]
FitParamHeaders= ["FIT", "DETECTOR","BEAM","PEAKS", "PEAK SHAPE", "ATTENUATORS","MATRIX","CONCENTRATIONS"]
@@ -84,12 +85,15 @@ class FitParamWidget(FitParamForm):
self.graphDialog.mainLayout = qt.QVBoxLayout(self.graphDialog)
self.graphDialog.mainLayout.setContentsMargins(0, 0, 0, 0)
self.graphDialog.mainLayout.setSpacing(0)
- self.graphDialog.graph = PlotWindow.PlotWindow(self.graphDialog,
- newplot=False,
- plugins=False, fit=False)
+ self.graphDialog.graph = PlotWindow(self.graphDialog,
+ position=False, colormap=False,
+ aspectRatio=False, yInverted=False,
+ roi=False, mask=False, fit=False)
self.graph = self.graphDialog.graph
- self.graph._togglePointsSignal()
- self.tabAttenuators = AttenuatorsTable.AttenuatorsTab(self.tabAtt,
+ self.graph.getInteractiveModeToolBar().getZoomModeAction().setVisible(False)
+ self.graph.getInteractiveModeToolBar().getPanModeAction().setVisible(False)
+ self.graph.setDefaultPlotPoints(True)
+ self.tabAttenuators = AttenuatorsTable.AttenuatorsTab(self.tabAtt,
graph=self.graphDialog)
self.graphDialog.mainLayout.addWidget(self.graph)
self.graphDialog.okButton = qt.QPushButton(self.graphDialog)
@@ -315,11 +319,11 @@ class FitParamWidget(FitParamForm):
efficiency *= (1.0 - numpy.exp(-coeffs))
self.graph.setGraphTitle('Filter (not beam filter) and detector correction')
- self.graph.addCurve(energies, efficiency,
- legend='Ta * (1.0 - Td)',
+ legend = 'Ta * (1.0 - Td)'
+ self.graph.addCurve(energies, efficiency, legend,
xlabel='Energy (keV)',
- ylabel='Efficiency Term',
- replace=True)
+ ylabel='Efficiency Term')
+ self.graph.setActiveCurve(legend)
self.graphDialog.exec_()
def __contComboActivated(self, idx):
@@ -365,8 +369,8 @@ class FitParamWidget(FitParamForm):
msg.setText("Error configuring strategy")
msg.setInformativeText("You need to specify incident beam energy")
msg.exec_()
- #print("TO check for matrix composition")
- #print("TO check for peaks")
+ #_logger.debug("TO check for matrix composition")
+ #_logger.debug("TO check for peaks")
def _strategySetupButtonClicked(self):
maxEnergy = qt.safe_str(self.peakTable.energy.text())
@@ -617,7 +621,7 @@ class FitParamWidget(FitParamForm):
combo.setOptions(matlist)
combo.lineEdit().setText(str(attpar[1]))
else:
- print("ERROR in __setAttPar")
+ _logger.warning("ERROR in __setAttPar")
if len(attpar) == 4:
attpar.append(1.0)
self.attTable.setText(row, 3, str(attpar[2]))
@@ -686,7 +690,7 @@ class FitParamWidget(FitParamForm):
combo.setOptions(matlist)
combo.lineEdit().setText(str(attpar[1]))
else:
- print("ERROR in __setAttPar")
+ _logger.warning("ERROR in __setAttPar")
self.multilayerTable.setText(row, 3, str(attpar[2]))
self.multilayerTable.setText(row, 4, str(attpar[3]))
@@ -1039,8 +1043,7 @@ class SectionFileDialog(qt.QFileDialog):
else:
self.setDir(qt.safe_str(initdir))
- if DEBUG:
- print("right to be added")
+ _logger.debug("right to be added")
if 0:
self.sectionWidget= SectionFileWidget(self,
sections=sections,
@@ -1362,6 +1365,7 @@ class FitParamDialog(qt.QDialog):
self.saveParameters(filename, None)
self.initDir = os.path.dirname(filename)
+
def openWidget():
app= qt.QApplication(sys.argv)
app.lastWindowClosed.connect(app.quit)
@@ -1370,6 +1374,7 @@ def openWidget():
wid.show()
app.exec_loop()
+
def openDialog():
app= qt.QApplication(sys.argv)
app.lastWindowClosed.connect(app.quit)
@@ -1381,6 +1386,8 @@ def openDialog():
del wid
app.quit()
+
if __name__=="__main__":
+ logging.basicConfig(level=logging.INFO)
#openWidget()
openDialog()
diff --git a/PyMca5/PyMcaGui/physics/xrf/FitPeakSelect.py b/PyMca5/PyMcaGui/physics/xrf/FitPeakSelect.py
index bbcb55a..c63e74d 100644
--- a/PyMca5/PyMcaGui/physics/xrf/FitPeakSelect.py
+++ b/PyMca5/PyMcaGui/physics/xrf/FitPeakSelect.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import copy
+import logging
from . import EnergyTable
from PyMca5.PyMcaPhysics import Elements
@@ -39,8 +40,8 @@ from .QPeriodicTable import QPeriodicTable
from PyMca5.PyMcaGui import PyMcaQt as qt
+_logger = logging.getLogger(__name__)
-DEBUG = 0
QTVERSION = qt.qVersion()
ElementList = Elements.ElementList
__revision__ = "$Revision: 1.12 $"
@@ -374,9 +375,7 @@ class FitPeakSelect(qt.QWidget):
self._energyClicked()
def _energyTableAction(self, ddict):
- if DEBUG:
- print("_energyTableAction called",)
- print("ddict = ",ddict.dict)
+ _logger.debug("_energyTableAction called, ddict = %s", ddict)
elist, wlist, flist, slist= self.energyTable.getParameters()
maxenergy = 0.0
for i in range(len(flist)):
diff --git a/PyMca5/PyMcaGui/physics/xrf/MaterialEditor.py b/PyMca5/PyMcaGui/physics/xrf/MaterialEditor.py
index 079e200..737189b 100644
--- a/PyMca5/PyMcaGui/physics/xrf/MaterialEditor.py
+++ b/PyMca5/PyMcaGui/physics/xrf/MaterialEditor.py
@@ -33,19 +33,20 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import copy
+import logging
import numpy
import traceback
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaPhysics import Elements
-from PyMca5.PyMcaGui import PlotWindow
-ScanWindow = PlotWindow.PlotWindow
+from silx.gui.plot import PlotWindow
if hasattr(qt, "QString"):
QString = qt.QString
else:
QString = str
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class MaterialEditor(qt.QWidget):
def __init__(self, parent=None, name="Material Editor",
@@ -105,13 +106,10 @@ class MaterialEditor(qt.QWidget):
if self.__toolMode:
self.materialGUI.setCurrent(a[0])
if (self.graph is None):
- self.graph = ScanWindow(self, newplot=False,
- fit=False,
- plugins=False,
- control=True,
- position=True)
- self.graph._togglePointsSignal()
- self.graph.enableOwnSave(True)
+ self.graph = PlotWindow(self, control=True, position=True,
+ colormap=False, aspectRatio=False,
+ yInverted=False, roi=False, mask=False)
+ self.graph.setDefaultPlotPoints(True)
layout.addWidget(self.materialGUI)
layout.addWidget(self.graph)
else:
@@ -146,7 +144,7 @@ class MaterialEditor(qt.QWidget):
#no message?
error = 1
del Elements.Material[material]
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
continue
return error
@@ -174,6 +172,8 @@ class MaterialEditor(qt.QWidget):
density=density, thickness=thickness, listoutput=False)
addButton = False
if self.graph is None:
+ # probably dead code (ScanWindow.ScanWindow not imported)
+ # TODO: if needed, this should be updated for silx based ScanWindow
self.graphDialog = qt.QDialog(self)
self.graphDialog.mainLayout = qt.QVBoxLayout(self.graphDialog)
self.graphDialog.mainLayout.setContentsMargins(0, 0, 0, 0)
@@ -216,6 +216,8 @@ class MaterialEditor(qt.QWidget):
energy)
addButton = False
if self.graph is None:
+ # probably dead code (ScanWindow.ScanWindow not imported)
+ # TODO: if needed, this should be updated for silx based ScanWindow
self.graphDialog = qt.QDialog(self)
self.graphDialog.mainLayout = qt.QVBoxLayout(self.graphDialog)
self.graphDialog.mainLayout.setContentsMargins(0, 0, 0, 0)
@@ -233,15 +235,13 @@ class MaterialEditor(qt.QWidget):
legend=legend,
xlabel='Energy (keV)',
ylabel='Mass Att. (cm2/g)',
- replace=True,
- replot=False)
+ replace=True)
for legend in ['Compton', 'Photo','Total']:
self.graph.addCurve(energy, numpy.array(data[legend.lower()]),
- legend=legend,
- xlabel='Energy (keV)',
- ylabel='Mass Att. (cm2/g)',
- replace=False,
- replot=False)
+ legend=legend,
+ xlabel='Energy (keV)',
+ ylabel='Mass Att. (cm2/g)',
+ replace=False)
self.graph.setActiveCurve(legend+' '+'Mass Att. (cm2/g)')
self.graph.setGraphTitle(ddict['Comment'])
if self.graphDialog is not None:
@@ -670,7 +670,7 @@ class MaterialGUI(qt.QWidget):
self.__massAttButton.clicked.connect(self.__massAttSlot)
def setCurrent(self, matkey0):
- if DEBUG:"setCurrent(self, matkey0) ", matkey0
+ _logger.debug("setCurrent(self, matkey0=%s)", matkey0)
matkey = Elements.getMaterialKey(matkey0)
if matkey is not None:
if self.__toolMode:
@@ -694,8 +694,7 @@ class MaterialGUI(qt.QWidget):
self.__fillingValues = False
def _fillValues(self):
- if DEBUG:
- print("fillValues(self)")
+ _logger.debug("fillValues(self)")
self.__fillingValues = True
if self.__comments:
self.__nameLine.setText("%s" % self._current['Comment'])
@@ -733,9 +732,8 @@ class MaterialGUI(qt.QWidget):
# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666503
def _updateCurrent(self):
- if DEBUG:
- print("updateCurrent(self)")
- print("self._current before = ", self._current)
+ _logger.debug("updateCurrent(self)")
+ _logger.debug("self._current before = %s", self._current)
self._current['CompoundList'] = []
self._current['CompoundFraction'] = []
@@ -755,8 +753,7 @@ class MaterialGUI(qt.QWidget):
self._current['CompoundFraction'].append(float(txt1))
self.__densitySlot(silent=True)
self.__thicknessSlot(silent=True)
- if DEBUG:
- print("self._current after = ", self._current)
+ _logger.debug("self._current after = %s", self._current)
def __densitySlot(self, silent=False):
try:
@@ -804,8 +801,7 @@ class MaterialGUI(qt.QWidget):
self.sigMaterialMassAttenuationSignal.emit(ddict)
def __nameLineSlot(self):
- if DEBUG:
- print("__nameLineSlot(self)")
+ _logger.debug("__nameLineSlot(self)")
qstring = self.__nameLine.text()
text = str(qstring)
if self.__toolMode:
@@ -857,8 +853,7 @@ class MaterialGUI(qt.QWidget):
return
item = self.__table.item(row, col)
if item is not None:
- if DEBUG:
- print("table item is None")
+ _logger.debug("table item is None")
qstring = item.text()
else:
qstring = ""
diff --git a/PyMca5/PyMcaGui/physics/xrf/McaAdvancedFit.py b/PyMca5/PyMcaGui/physics/xrf/McaAdvancedFit.py
index 7d67dfb..6e6b9f9 100644
--- a/PyMca5/PyMcaGui/physics/xrf/McaAdvancedFit.py
+++ b/PyMca5/PyMcaGui/physics/xrf/McaAdvancedFit.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -35,6 +35,7 @@ import os
import numpy
import time
import copy
+import logging
import tempfile
import shutil
import traceback
@@ -66,7 +67,6 @@ from . import McaAdvancedTable
from . import QtMcaAdvancedFitReport
from . import ConcentrationsWidget
from PyMca5.PyMcaPhysics.xrf import ConcentrationsTool
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
from . import McaCalWidget
@@ -75,25 +75,31 @@ from PyMca5.PyMcaGui import SubprocessLogWidget
from . import ElementsInfo
Elements = ElementsInfo.Elements
#import McaROIWidget
-from PyMca5.PyMcaGui import PyMcaPrintPreview
from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaIO import ConfigDict
from PyMca5.PyMcaGui import CalculationThread
-DEBUG = 0
-if DEBUG:
- print("############################################")
- print("# McaAdvancedFit is in DEBUG mode %s #" % DEBUG)
- print("############################################")
+from PyMca5.PyMcaGui.plotting import PyMca_Icons
+
+_logger = logging.getLogger(__name__)
+
+_logger.debug("############################################\n"
+ "# McaAdvancedFit is in DEBUG mode #\n"
+ "############################################")
XRFMC_FLAG = False
try:
from PyMca5.PyMcaPhysics.xrf.XRFMC import XRFMCHelper
XRFMC_FLAG = True
except ImportError:
- print("Cannot import XRFMCHelper module")
- if DEBUG:
+ _logger.warning("Cannot import XRFMCHelper module")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
USE_BOLD_FONT = True
+import silx
+from silx.gui.plot import PlotWindow
+from silx.gui.plot.PrintPreviewToolButton import SingletonPrintPreviewToolButton
+
+
class McaAdvancedFit(qt.QWidget):
"""
This class inherits QWidget.
@@ -162,7 +168,7 @@ class McaAdvancedFit(qt.QWidget):
self.graph = self.graphWindow
self.graph.setGraphXLabel('Channel')
self.graph.setGraphYLabel('Counts')
- self.mainTab.addTab(self.tabGraph,"GRAPH")
+ self.mainTab.addTab(self.tabGraph, "GRAPH")
self.graphWindow.sigPlotSignal.connect(self._mcaGraphSignalSlot)
#table
self.tabMca = qt.QWidget()
@@ -449,7 +455,6 @@ class McaAdvancedFit(qt.QWidget):
#del dialog
self.graph.clearMarkers()
- self.graph.replot()
self.__fitdone = False
self._concentrationsDict = None
self._concentrationsInfo = None
@@ -478,7 +483,7 @@ class McaAdvancedFit(qt.QWidget):
else:
self.matrixXRFMCSpectrumButton.show()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.mcafit.configure(config)
elif 1:
try:
@@ -550,8 +555,7 @@ class McaAdvancedFit(qt.QWidget):
self.mainTab.setCurrentIndex(0)
def __configureFromConcentrations(self,ddict):
- if DEBUG:
- print("McaAdvancedFit.__configureFromConcentrations", ddict)
+ _logger.debug("McaAdvancedFit.__configureFromConcentrations %s", ddict)
config = self.concentrationsWidget.getParameters()
self.mcafit.config['concentrations'].update(config)
if ddict['event'] == 'updated':
@@ -570,7 +574,6 @@ class McaAdvancedFit(qt.QWidget):
ele = dict['current']
items = []
if not (ele in dict):
- self.graph.replot()
return
for rays in dict[ele]:
for transition in Elements.Element[ele][rays +" xrays"]:
@@ -590,18 +593,15 @@ class McaAdvancedFit(qt.QWidget):
if (x < xmin) or (x > xmax):continue
if not self._energyAxis:
if abs(calib[1]) > 0.0000001:
- marker=self.graph.insertXMarker(x,
- legend=transition,
- text=transition,
- color='orange',
- replot=False)
+ marker=self.graph.addXMarker(x,
+ legend=transition,
+ text=transition,
+ color='orange')
else:
- marker=self.graph.insertXMarker(energy,
- legend=transition,
- text=transition,
- color='orange',
- replot=False)
- self.graph.replot()
+ marker=self.graph.addXMarker(energy,
+ legend=transition,
+ text=transition,
+ color='orange')
def _updateTop(self):
config = {}
@@ -619,11 +619,10 @@ class McaAdvancedFit(qt.QWidget):
def __updatefromtop(self,ndict):
config = self.mcafit.configure()
for key in ndict.keys():
- if DEBUG:
- keylist = ['stripflag','hypermetflag','sumflag','escapeflag',
- 'fitfunction', 'continuum']
- if key not in keylist:
- print("UNKNOWN key ",key)
+ if key not in ['stripflag', 'hypermetflag',
+ 'sumflag', 'escapeflag',
+ 'fitfunction', 'continuum']:
+ _logger.debug("UNKNOWN key %s", key)
config['fit'][key] = ndict[key]
self.__fitdone = False
#erase table
@@ -644,7 +643,7 @@ class McaAdvancedFit(qt.QWidget):
self.graph.removeCurve(key)
self.plot()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.mcafit.configure(config)
elif 1:
try:
@@ -689,8 +688,7 @@ class McaAdvancedFit(qt.QWidget):
return
def _tabChanged(self, value):
- if DEBUG:
- print("_tabChanged(self, value) called")
+ _logger.debug("_tabChanged(self, value) called")
if str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == "CONCENTRATIONS":
self.printButton.setEnabled(False)
w = self.concentrationsWidget
@@ -701,21 +699,19 @@ class McaAdvancedFit(qt.QWidget):
self.printButton.setEnabled(True)
#do not calculate again. It should be already updated
return
- if DEBUG:
+ try:
self.concentrations()
self.printButton.setEnabled(True)
- else:
- try:
- self.concentrations()
- self.printButton.setEnabled(True)
- except:
- #print "try to set"
- self.printButton.setEnabled(False)
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Concentrations error: %s" % sys.exc_info()[1])
- msg.exec_()
- self.mainTab.setCurrentIndex(0)
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ #print "try to set"
+ self.printButton.setEnabled(False)
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Concentrations error: %s" % sys.exc_info()[1])
+ msg.exec_()
+ self.mainTab.setCurrentIndex(0)
elif str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == "TABLE":
self.printButton.setEnabled(True)
w = self.mcatable
@@ -804,7 +800,8 @@ class McaAdvancedFit(qt.QWidget):
def printActiveTab(self):
txt = str(self.mainTab.tabText(self.mainTab.currentIndex())).upper()
if txt == "GRAPH":
- self.graph.printps()
+ # trigger the 2nd action in the PrintPreviewToolButton drop-down menu
+ self.graph.printPreviewTB.menu().actions()[1].trigger()
elif txt == "TABLE":
self.printps(True)
elif txt == "CONCENTRATIONS":
@@ -992,25 +989,21 @@ class McaAdvancedFit(qt.QWidget):
ddict = {}
ddict.update(config['concentrations'])
tool.setParameters(ddict, signal=False)
- if DEBUG:
- ddict, info = tool.processFitResult(config=ddict,fitresult=fitresult,
+ try:
+ ddict, info = tool.processFitResult(config=ddict, fitresult=fitresult,
elementsfrommatrix=False,
- fluorates = self.mcafit._fluoRates,
+ fluorates=self.mcafit._fluoRates,
addinfo=True)
- else:
- try:
- ddict, info = tool.processFitResult(config=ddict,fitresult=fitresult,
- elementsfrommatrix=False,
- fluorates = self.mcafit._fluoRates,
- addinfo=True)
- except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Error processing fit result: %s" % (sys.exc_info()[1]))
- msg.exec_()
- if str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == 'CONCENTRATIONS':
- self.mainTab.setCurrentIndex(0)
- return
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Error processing fit result: %s" % (sys.exc_info()[1]))
+ msg.exec_()
+ if str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == 'CONCENTRATIONS':
+ self.mainTab.setCurrentIndex(0)
+ return
self._concentrationsDict = ddict
self._concentrationsInfo = info
tool.show()
@@ -1043,7 +1036,7 @@ class McaAdvancedFit(qt.QWidget):
else:
delcurves.append(key)
for key in delcurves:
- self.graph.removeCurve(key, replot=False)
+ self.graph.removeCurve(key)
def matrixSpectrum(self):
@@ -1066,17 +1059,17 @@ class McaAdvancedFit(qt.QWidget):
ddict = {}
ddict.update(config['concentrations'])
tool.configure(ddict)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
ddict, info = tool.processFitResult(fitresult=fitresult,
- elementsfrommatrix=True,
- addinfo=True)
+ elementsfrommatrix=True,
+ addinfo=True)
elif 1:
try:
- thread = CalculationThread.CalculationThread( \
- calculation_method = tool.processFitResult,
- calculation_kw = {'fitresult':fitresult,
- 'elementsfrommatrix':True,
- 'addinfo':True},
+ thread = CalculationThread.CalculationThread(
+ calculation_method=tool.processFitResult,
+ calculation_kw={'fitresult': fitresult,
+ 'elementsfrommatrix': True,
+ 'addinfo': True},
expand_vars=True,
expand_kw=True)
thread.start()
@@ -1174,27 +1167,23 @@ class McaAdvancedFit(qt.QWidget):
self.dict['result']['ymatrix']= ddict['result']['ymatrix'] * 1.0
"""
if self.graph is not None:
- if self._logY:
- logfilter = 1
- else:
- logfilter = 0
if self._energyAxis:
xdata = dict['result']['energy'][:]
else:
xdata = dict['result']['xdata'][:]
- self.graph.newCurve("Matrix",xdata,dict['result']['ymatrix'],logfilter=logfilter)
+ self.graph.addCurve(xdata, dict['result']['ymatrix'], "Matrix")
"""
try:
self.__anasignal(ddict)
except:
- print("Error generating matrix output. ")
- print("Try to perform your fit again. ")
- print(sys.exc_info())
- print("If error persists, please report this error.")
- print("ymatrix shape = ", ddict['result']['ymatrix'].shape)
- print("xmatrix shape = ", xmatrix.shape)
- print("continuum shape = ", ddict['result']['continuum'].shape)
- print("zz shape = ", self.mcafit.zz.shape)
+ _logger.warning("Error generating matrix output. ")
+ _logger.warning("Try to perform your fit again. ")
+ _logger.warning("%s", sys.exc_info())
+ _logger.warning("If error persists, please report this error.")
+ _logger.warning("ymatrix shape = %s", ddict['result']['ymatrix'].shape)
+ _logger.warning("xmatrix shape = %s", xmatrix.shape)
+ _logger.warning("continuum shape = %s", ddict['result']['continuum'].shape)
+ _logger.warning("zz shape = %s", self.mcafit.zz.shape)
def fisxSpectrum(self):
if not self.__fitdone:
@@ -1327,7 +1316,7 @@ class McaAdvancedFit(qt.QWidget):
fileNamesDict = XRFMCHelper.getOutputFileNames(newFile,
outputDir=self.__tmpMatrixSpectrumDir)
if newFile != fileNamesDict['fit']:
- removeDirectory(self.__tmpMatrixSpectrumDir)
+ self.removeDirectory(self.__tmpMatrixSpectrumDir)
raise ValueError("Inconsistent internal behaviour!")
self._xrfmcFileNamesDict = fileNamesDict
@@ -1434,8 +1423,8 @@ class McaAdvancedFit(qt.QWidget):
try:
self.__anasignal(ddict)
except:
- print("Error generating Monte Carlo matrix output. ")
- print(sys.exc_info())
+ _logger.warning("Error generating Monte Carlo matrix output. ")
+ _logger.warning(sys.exc_info())
def peaksSpectrum(self):
if not self.__fitdone:
@@ -1477,14 +1466,14 @@ class McaAdvancedFit(qt.QWidget):
try:
self.__anasignal(ddict)
except:
- print("Error generating peaks output. ")
- print("Try to perform your fit again. ")
- print(sys.exc_info())
- print("If error persists, please report this error.")
- print("ymatrix shape = ", ddict['result']['ymatrix'].shape)
- print("xmatrix shape = ", xmatrix.shape)
- print("continuum shape = ", ddict['result']['continuum'].shape)
- print("zz shape = ", self.mcafit.zz.shape)
+ _logger.warning("Error generating peaks output. ")
+ _logger.warning("Try to perform your fit again. ")
+ _logger.warning("%s", sys.exc_info())
+ _logger.warning("If error persists, please report this error.")
+ _logger.warning("ymatrix shape = %s", ddict['result']['ymatrix'].shape)
+ _logger.warning("xmatrix shape = %s", xmatrix.shape)
+ _logger.warning("continuum shape = %s", ddict['result']['continuum'].shape)
+ _logger.warning("zz shape = %s", self.mcafit.zz.shape)
def __printps(self):
self.__printmenu.exec_(self.cursor().pos())
@@ -1534,7 +1523,7 @@ class McaAdvancedFit(qt.QWidget):
selection=self.info['legend'],
fitresult=self.dict,
concentrations=self._concentrationsDict,
- plotdict={'logy':self.graph.isYAxisLogarithmic()})
+ plotdict={'logy': self.graph.isYAxisLogarithmic()})
if 0:
#this forces to open and read the file
self.__lastreport = report.writeReport()
@@ -1709,8 +1698,8 @@ class McaAdvancedFit(qt.QWidget):
return h
# pyflakes http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666503
- def __print(self,text):
- print("__print not working yet")
+ def __print(self, text):
+ _logger.info("__print not working yet")
return
printer = qt.QPrinter()
printDialog = qt.QPrintDialog(printer, self)
@@ -1729,9 +1718,8 @@ class McaAdvancedFit(qt.QWidget):
document.print_(printer)
def setdata(self, *var, **kw):
- if DEBUG:
- print("McaAdvancedFit.setdata deprecated, use setData instead.")
- return self.setData( *var, **kw)
+ _logger.debug("McaAdvancedFit.setdata deprecated, use setData instead.")
+ return self.setData(*var, **kw)
def setData(self,*var,**kw):
"""
@@ -1841,8 +1829,7 @@ class McaAdvancedFit(qt.QWidget):
self.plot()
def setheader(self, *var, **kw):
- if DEBUG:
- print("McaAdvancedFit.setheader deprecated, use setHeader instead.")
+ _logger.debug("McaAdvancedFit.setheader deprecated, use setHeader instead.")
return self.setHeader( *var, **kw)
def setHeader(self,*var,**kw):
@@ -1886,18 +1873,14 @@ class McaAdvancedFit(qt.QWidget):
msg.setText("No peaks defined.\nPlease configure peaks")
msg.exec_()
return
- if DEBUG:
- if DEBUG:
- print("calling estimate")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ _logger.debug("calling estimate")
self.mcafit.estimate()
- if DEBUG:
- print("calling startfit")
- fitresult,result = self.mcafit.startfit(digest=1)
- if DEBUG:
- print("filling table")
+ _logger.debug("calling startfit")
+ fitresult, result = self.mcafit.startfit(digest=1)
+ _logger.debug("filling table")
self.mcatable.fillfrommca(result)
- if DEBUG:
- print("finished")
+ _logger.debug("finished")
elif 1:
try:
self.mcafit.estimate()
@@ -2001,17 +1984,16 @@ class McaAdvancedFit(qt.QWidget):
if (str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == 'CONCENTRATIONS') or \
(self.concentrationsWidget.parent() is None):
if not self.concentrationsWidget.isHidden():
- if DEBUG:
+ try:
self.concentrations()
- else:
- try:
- self.concentrations()
- except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Concentrations Error: %s" % (sys.exc_info()[1]))
- msg.exec_()
- return
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Concentrations Error: %s" % (sys.exc_info()[1]))
+ msg.exec_()
+ return
if str(self.mainTab.tabText(self.mainTab.currentIndex())).upper() == 'DIAGNOSTICS':
try:
self.diagnostics()
@@ -2067,10 +2049,7 @@ class McaAdvancedFit(qt.QWidget):
self.plot()
def plot(self, ddict=None):
- if self.graph.isYAxisLogarithmic():
- logfilter = 1
- else:
- logfilter = 0
+ self.graph.clearCurves()
config = self.mcafit.configure()
if ddict is None:
if not self.__fitdone:
@@ -2084,8 +2063,8 @@ class McaAdvancedFit(qt.QWidget):
ydata = self.mcafit.ydata * 1.0
xdata.shape= [len(xdata),]
ydata.shape= [len(ydata),]
- self.graph.addCurve(xdata, ydata, legend="Data", replot=True, replace=True)
- self.graph.updateLegends()
+ self.graph.addCurve(xdata, ydata, legend="Data", replace=True)
+ self.graph.setActiveCurve("Data")
return
else:
ddict = self.dict
@@ -2094,27 +2073,25 @@ class McaAdvancedFit(qt.QWidget):
else:
xdata = ddict['result']['xdata'][:]
self.graph.addCurve(xdata, ddict['result']['ydata'], legend="Data",
- replot=False)
+ replace=True, resetzoom=False)
self.graph.addCurve(xdata, ddict['result']['yfit'], legend="Fit",
- replot=False)
+ resetzoom=False)
self.graph.addCurve(xdata, ddict['result']['continuum'],
- legend="Continuum",
- replot=False)
+ legend="Continuum", resetzoom=False)
curveList = self.graph.getAllCurves(just_legend=True)
if config['fit']['sumflag']:
self.graph.addCurve(xdata, ddict['result']['pileup'] + \
ddict['result']['continuum'],
- legend="Pile-up", replot=False)
+ legend="Pile-up", resetzoom=False)
elif "Pile-up" in curveList:
- self.graph.removeCurve("Pile-up", replot=False)
+ self.graph.removeCurve("Pile-up")
if self.matrixSpectrumButton.isChecked():
if 'ymatrix' in ddict['result']:
- self.graph.addCurve(xdata,
- ddict['result']['ymatrix'],
- legend="Matrix")
+ self.graph.addCurve(xdata, ddict['result']['ymatrix'],
+ legend="Matrix", resetzoom=False)
else:
self.graph.removeCurve("Matrix")
else:
@@ -2128,14 +2105,13 @@ class McaAdvancedFit(qt.QWidget):
mcxdata = self._xrfmcMatrixSpectra[0]
mcydata0 = self._xrfmcMatrixSpectra[2]
mcydatan = self._xrfmcMatrixSpectra[-1]
- self.graph.addCurve(mcxdata,
- mcydata0,
+ self.graph.addCurve(mcxdata, mcydata0,
legend='MC Matrix 1',
- replot=False)
+ resetzoom=False)
self.graph.addCurve(mcxdata,
mcydatan,
legend='MC Matrix %d' % (len(self._xrfmcMatrixSpectra) - 2),
- replot=False)
+ resetzoom=False)
if self.peaksSpectrumButton.isChecked():
keep = ['Data','Fit','Continuum','Matrix','Pile-up']
@@ -2154,19 +2130,16 @@ class McaAdvancedFit(qt.QWidget):
self.graph.addCurve(xdata,
ddict['result'][label],
legend=label,
- replot=False)
+ resetzoom=False)
else:
if group in curveList:
- self.graph.removeCurve(label, replot=False)
+ self.graph.removeCurve(label)
else:
self.__clearPeaksSpectrum()
-
- self.graph.replot()
- self.graph.updateLegends()
+ self.graph.setActiveCurve("Data")
def _saveGraph(self, dict=None):
- curves = self.graph.getAllCurves()
- if not len(curves):
+ if not len(self.graph.getAllCurves(just_legend=True)):
return
if not self.__fitdone:
if False:
@@ -2205,7 +2178,7 @@ class McaAdvancedFit(qt.QWidget):
fitresult['result']['xdata'][-1]))
if MCLabels is not None:
if MCSpectra[2].size != fitresult['result']['xdata'].size:
- print("Monte Carlo Spectra not saved: Wrong spectrum length.")
+ _logger.warning("Monte Carlo Spectra not saved: Wrong spectrum length.")
MCLabels = None
MCSpectra = None
@@ -2855,14 +2828,14 @@ class Line(qt.QFrame):
def mouseDoubleClickEvent(self, event):
- if DEBUG:
- print("Double Click Event")
+ _logger.debug("Double Click Event")
ddict={}
ddict['event']="DoubleClick"
ddict['data'] = event
ddict['info'] = self.info
self.sigLineDoubleClickEvent.emit(ddict)
+
class SimpleThread(qt.QThread):
def __init__(self, function = None, kw = None):
if kw is None:
@@ -2882,65 +2855,113 @@ class SimpleThread(qt.QThread):
except:
self._result = ("Exception",) + sys.exc_info()
-class McaGraphWindow(PlotWindow.PlotWindow):
- def __init__(self, parent=None, backend=None, plugins=False,
- newplot=False, position=True, control=True, **kw):
+
+class McaGraphWindow(PlotWindow):
+ def __init__(self, parent=None, backend=None,
+ position=True, control=True, **kw):
super(McaGraphWindow, self).__init__(parent, backend=backend,
- plugins=plugins,
- newplot=newplot,
- energy=True,
- roi=True,
- logx=False,
- fit=True,
- position=position,
- control=control,
- **kw)
+ position=position, control=control,
+ roi=True, aspectRatio=False,
+ print_=False, colormap=False,
+ yInverted=False, mask=False,
+ fit=False, save=False,
+ **kw)
self.setDataMargins(0, 0, 0.025, 0.025)
self.setPanWithArrowKeys(True)
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
+
+ # No context menu by default, execute zoomBack on right click
+ plotArea = self.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
+ # toolbar
+ # hide unused actions and separators
+ self.getInteractiveModeToolBar().setVisible(False)
+ self.getXAxisLogarithmicAction().setVisible(False)
+ for action in self.toolBar().actions():
+ if action.isSeparator():
+ action.setVisible(False)
+
+ self.printPreviewTB = SingletonPrintPreviewToolButton(
+ parent=self.toolBar(), plot=self)
+ self.printPreviewTB.setIcon(
+ qt.QIcon(qt.QPixmap(IconDict["fileprint"])))
+
+ # self.fitIcon = qt.QIcon(qt.QPixmap(IconDict["fit"]))
+ self.fitButton = qt.QToolButton(self.toolBar())
+ self.fitButton.setIcon(qt.QIcon(qt.QPixmap(IconDict["fit"])))
+ self.fitButton.setToolTip('Fit of Active Curve')
+ self.fitButton.clicked.connect(self._fitIconSignal)
+
+ # self.energyIcon = qt.QIcon(qt.QPixmap(IconDict["energy"]))
+ self.energyButton = qt.QToolButton(self.toolBar())
+ self.energyButton.setCheckable(True)
+ self.energyButton.setIcon(qt.QIcon(qt.QPixmap(IconDict["energy"])))
+ self.energyButton.setToolTip('Toggle Energy Axis (On/Off)')
+ self.energyButton.clicked.connect(self._energyIconSignal)
+
+ self.saveButton = qt.QToolButton(self.toolBar())
+ self.saveButton.setIcon(qt.QIcon(qt.QPixmap(IconDict["filesave"])))
+ self.saveButton.setToolTip('Save plot snapshot or curves data')
+ self.saveButton.clicked.connect(self._saveIconSignal)
+
+ self.fitAction = self.toolBar().insertWidget(self.getCopyAction(),
+ self.fitButton)
+ self.energyAction = self.toolBar().insertWidget(self.getRoiAction(),
+ self.energyButton)
+
+ self.saveAction = self.getOutputToolBar().addWidget(self.saveButton)
+ self.getOutputToolBar().addWidget(qt.HorizontalSpacer(self.toolBar()))
+ self.printAction = self.getOutputToolBar().addWidget(self.printPreviewTB)
+
self.setGraphYLabel("Counts")
if self.energyButton.isChecked():
self.setGraphXLabel("Energy")
else:
self.setGraphXLabel("Channel")
- def printGraph(self):
- pixmap = qt.QPixmap.grabWidget(self.getWidgetHandle())
- self.printPreview.addPixmap(pixmap)
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
+ PyMca_Icons.change_icons(self)
def _energyIconSignal(self):
- legend = self.getActiveCurve(just_legend=True)
- ddict={}
- ddict['event'] = 'EnergyClicked'
- ddict['active'] = legend
- self.sigPlotSignal.emit(ddict)
+ self.sigPlotSignal.emit(
+ {'event': 'EnergyClicked',
+ 'active': self.getActiveCurve(just_legend=True)})
def _fitIconSignal(self):
- legend = self.getActiveCurve(just_legend=True)
- ddict={}
- ddict['event'] = 'FitClicked'
- ddict['active'] = legend
- self.sigPlotSignal.emit(ddict)
+ self.sigPlotSignal.emit(
+ {'event': 'FitClicked',
+ 'active': self.getActiveCurve(just_legend=True)})
def _saveIconSignal(self):
- legend = self.getActiveCurve(just_legend=True)
- ddict={}
- ddict['event'] = 'SaveClicked'
- ddict['active'] = legend
- self.sigPlotSignal.emit(ddict)
-
- def setActiveCurve(self, legend, replot=True):
- super(McaGraphWindow, self).setActiveCurve(legend, replot=False)
+ self.sigPlotSignal.emit(
+ {'event': 'SaveClicked',
+ 'active': self.getActiveCurve(just_legend=True)})
+
+ def setActiveCurve(self, legend, replot=None):
+ if legend is not None:
+ # see vasole/pymca#314
+ super(McaGraphWindow, self).setActiveCurve(legend, replot)
self.setGraphYLabel("Counts")
if self.energyButton.isChecked():
self.setGraphXLabel("Energy")
else:
self.setGraphXLabel("Channel")
- if replot:
- self.replot()
+
+ def _zoomBack(self, pos):
+ self.getLimitsHistory().pop()
+
+ if silx.version_info < (0, 9):
+ # overloaded to force dock widgets area to right
+ def addTabbedDockWidget(self, dock_widget):
+ if dock_widget not in self._dockWidgets:
+ self._dockWidgets.append(dock_widget)
+ if len(self._dockWidgets) == 1:
+ self.addDockWidget(qt.Qt.RightDockWidgetArea, dock_widget)
+ else:
+ # Other dock widgets are added as tabs to the same widget area
+ self.tabifyDockWidget(self._dockWidgets[0],
+ dock_widget)
+
def test(ffile='03novs060sum.mca', cfg=None):
from PyMca5.PyMcaIO import specfilewrapper as specfile
@@ -2977,6 +2998,7 @@ def main():
if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
if len(sys.argv) >1:
ffile = sys.argv[1]
else:
diff --git a/PyMca5/PyMcaGui/physics/xrf/McaAdvancedTable.py b/PyMca5/PyMcaGui/physics/xrf/McaAdvancedTable.py
index 67c9f38..dcfb0e8 100644
--- a/PyMca5/PyMcaGui/physics/xrf/McaAdvancedTable.py
+++ b/PyMca5/PyMcaGui/physics/xrf/McaAdvancedTable.py
@@ -30,13 +30,14 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QString"):
QString = qt.QString
else:
QString = str
QTVERSION = qt.qVersion()
-DEBUG=0
+_logger = logging.getLogger(__name__)
QTable = qt.QTableWidget
@@ -64,10 +65,11 @@ class McaTable(QTable):
self.regionlist=[]
self.regiondict={}
- if QTVERSION < '5.0.0':
- self.verticalHeader().setClickable(True)
- else:
+ verticalHeader = self.verticalHeader()
+ if hasattr(verticalHeader, "setSectionsClickable"):
self.verticalHeader().setSectionsClickable(True)
+ else:
+ self.verticalHeader().setClickable(True)
self.verticalHeader().sectionClicked.connect(self.__myslot)
self.itemSelectionChanged.connect(self.__myslot)
@@ -244,8 +246,7 @@ class McaTable(QTable):
hb = self.horizontalHeader().paletteBackgroundColor()
hcolor = ("#%x%x%x" % (hb.red(),hb.green(),hb.blue())).upper()
else:
- if DEBUG:
- print("color background to implement")
+ _logger.debug("color background to implement")
hcolor = ("#%x%x%x" % (230,240,249)).upper()
text = ""
text += ("<nobr>")
diff --git a/PyMca5/PyMcaGui/physics/xrf/McaCalWidget.py b/PyMca5/PyMcaGui/physics/xrf/McaCalWidget.py
index 9d28fd1..7477eb5 100644
--- a/PyMca5/PyMcaGui/physics/xrf/McaCalWidget.py
+++ b/PyMca5/PyMcaGui/physics/xrf/McaCalWidget.py
@@ -35,9 +35,11 @@ import sys
import numpy
from numpy.linalg import inv as inverse
import copy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
-from PyMca5.PyMcaGui import PlotWidget
+from silx.gui.plot import PlotWidget
+from silx.gui.plot.tools.toolbars import OutputToolBar
if hasattr(qt, "QString"):
QString = qt.QString
@@ -52,7 +54,7 @@ IconDict = PyMca_Icons.IconDict
from . import PeakTableWidget
if 0:
from PyMca5 import XRDPeakTableWidget
-DEBUG = 0
+_logger = logging.getLogger(__name__)
LOW_HEIGHT_THRESHOLD = 660
@@ -136,8 +138,8 @@ class McaCalWidget(qt.QDialog):
self.layout.addWidget(self.container)
#The graph
- self.graph= PlotWidget.PlotWidget(self.container,
- backend=None)
+ self.graph = PlotWidget(self.container,
+ backend=None)
self.graph.setGraphXLabel('Channel')
self.graph.setGraphYLabel('Counts')
self.graph.setDataMargins(0.0, 0.0, 0.0, 0.0)
@@ -220,6 +222,13 @@ class McaCalWidget(qt.QDialog):
self.manualsearch,
'Add a peak to the graph',
toggle=True)
+ # copy to clipboard
+ output_tb = OutputToolBar(parent=self.toolbar,
+ plot=self.graph)
+ output_tb.getPrintAction().setVisible(False)
+ output_tb.getSaveAction().setVisible(False)
+ self.toolbar.layout.addWidget(output_tb)
+
self.toolbar.layout.addWidget(qt.HorizontalSpacer(toolbar))
label=qt.QLabel(toolbar)
label.setText('<b>Channel:</b>')
@@ -249,7 +258,6 @@ class McaCalWidget(qt.QDialog):
self.epos.setFixedWidth(self.epos.fontMetrics().width('#########'))
self.toolbar.layout.addWidget(self.epos)
-
#rest
toolbar2 = qt.QWidget(self)
self.layout.addWidget(toolbar2)
@@ -289,8 +297,7 @@ class McaCalWidget(qt.QDialog):
return tb
def _toggleLogY(self):
- if DEBUG:
- print("_toggleLogY")
+ _logger.debug("_toggleLogY")
if self.graph.isYAxisLogarithmic():
self.setYAxisLogarithmic(False)
else:
@@ -311,19 +318,19 @@ class McaCalWidget(qt.QDialog):
self.okButton.clicked.connect(self.accept)
self.cancelButton.clicked.connect(self.reject)
- def plot(self,x,y,legend):
+ def plot(self, x, y, legend):
#clear graph
self.graph.clear()
- self.graph.addCurve(x, y , legend=legend, replot=True)
+ self.graph.addCurve(x, y, legend=legend)
self.dict['x'] = x
self.dict['y'] = y
self.dict['legend'] = legend
+ self.graph.setActiveCurve(legend)
#reset the zoom
self._resetZoom()
def peakSearch(self):
- if DEBUG:
- print("Peak search called")
+ _logger.debug("Peak search called")
if self.__manualsearch:
self.__manualsearch = 0
if QTVERSION < '4.0.0':
@@ -362,21 +369,18 @@ class McaCalWidget(qt.QDialog):
for idx in peaksidx:
self.foundPeaks.append(self.specfit.xdata[int(idx)])
#self.graph.insertx1marker(self.specfit.xdata[int(idx)],self.specfit.ydata[int(idx)])
- self.graph.insertXMarker(self.specfit.xdata[int(idx)],
- legend="%d" % i,
- text=None,
- selectable=True,
- draggable=False,
- replot=False)
+ self.graph.addXMarker(self.specfit.xdata[int(idx)],
+ legend="%d" % i,
+ text=None,
+ selectable=True,
+ draggable=False)
i += 1
- self.graph.replot()
#make sure marker mode is on
self.markermode = 0
self.__peakmarkermode()
-
def clearpeaks(self):
- print("DEPRECATED: Use clearPeaks")
+ _logger.info("DEPRECATED: Use clearPeaks")
return self.clearPeaks()
def clearPeaks(self):
@@ -384,7 +388,6 @@ class McaCalWidget(qt.QDialog):
self.graph.clearMarkers()
self.__destroylinewidgets()
self.peakTable.clearPeaks()
- self.graph.replot()
def manualsearch(self):
#disable peak selection
@@ -402,17 +405,16 @@ class McaCalWidget(qt.QDialog):
if self.markermode:
self.graph.setCursor(qt.QCursor(qt.Qt.CrossCursor))
self.markermode = 0
- self.graph.setZoomModeEnabled(False)
+ self.graph.setInteractiveMode('select')
else:
self.markermode = 1
self.nomarkercursor = self.graph.cursor().shape()
self.graph.setCursor(qt.QCursor(qt.Qt.PointingHandCursor))
- self.graph.setZoomModeEnabled(True)
+ self.graph.setInteractiveMode('zoom')
#self.markerButton.setOn(self.markermode == 1)
def __calparsignal(self,dict):
- if DEBUG:
- print("__calparsignal called dict = ",dict)
+ _logger.debug("__calparsignal called dict = %s", dict)
if dict['event'] == 'coeff':
current = dict['calname' ]
self.current = current
@@ -445,10 +447,9 @@ class McaCalWidget(qt.QDialog):
calenergy = deltat * (i + 1)
self.foundPeaks.append(channel)
name = "%d" % i
- marker = self.graph.insertXMarker(channel,
- legend=name,
- color="red",
- replot=False)
+ marker = self.graph.addXMarker(channel,
+ legend=name,
+ color="red")
if name in self.peakTable.peaks.keys():
self.peakTable.configure(number=name,
channel=channel,
@@ -466,7 +467,6 @@ class McaCalWidget(qt.QDialog):
#make sure we cannot select the peaks again
self.markermode = 1
self.__peakmarkermode()
- self.graph.replot()
else:
self.caldict[current]['A'] = dict['caldict'][current]['A']
self.caldict[current]['B'] = dict['caldict'][current]['B']
@@ -493,25 +493,20 @@ class McaCalWidget(qt.QDialog):
elif dict['boxname'] == 'Calibration':
pass
else:
- if DEBUG:
- print("Unknown combobox", dict['boxname'])
+ _logger.debug("Unknown combobox %s", dict['boxname'])
else:
- print("Unknown signal ", dict)
+ _logger.warning("Unknown signal %s", dict)
def __graphsignal(self, ddict):
- if DEBUG:
- print("__graphsignal called with dict = ", ddict)
+ _logger.debug("__graphsignal called with dict = %s", ddict)
if ddict['event'] in ['markerClicked', 'markerSelected']:
- if DEBUG:
- print("Setting marker color")
+ _logger.debug("Setting marker color")
marker = int(ddict['label'])
#The marker corresponds to the peak number
channel = self.foundPeaks[marker]
- self.graph.insertXMarker(channel,
- legend=ddict['label'],
- color='red',
- replot=False)
- self.graph.replot()
+ self.graph.addXMarker(channel,
+ legend=ddict['label'],
+ color='red')
current = self.current
calenergy = self.caldict[current]['A']+ \
self.caldict[current]['B'] * channel+ \
@@ -542,8 +537,7 @@ class McaCalWidget(qt.QDialog):
ret = linewidget.exec_()
if ret == qt.QDialog.Accepted:
ddict=linewidget.getDict()
- if DEBUG:
- print("dict got from dialog = ",ddict)
+ _logger.debug("dict got from dialog = %s", ddict)
if ddict != {}:
if name in self.peakTable.peaks.keys():
self.peakTable.configure(*ddict)
@@ -574,13 +568,10 @@ class McaCalWidget(qt.QDialog):
self.caldict[current]['C'] = newcal[2]
self.__peakTableSignal({'event':'use'}, calculate=False)
else:
- if DEBUG:
- print("Dialog cancelled or closed ")
- self.graph.insertXMarker(channel,
- legend=ddict['label'],
- color='black',
- replot=False)
- self.graph.replot()
+ _logger.debug("Dialog cancelled or closed ")
+ self.graph.addXMarker(channel,
+ legend=ddict['label'],
+ color='black')
del linewidget
elif ddict['event'] in ["mouseMoved", 'MouseAt']:
self.xpos.setText('%.1f' % ddict['x'])
@@ -602,19 +593,16 @@ class McaCalWidget(qt.QDialog):
self.foundPeaks.append(x)
legend = "%d" % (len(self.foundPeaks)-1)
#self.graph.insertx1marker(self.specfit.xdata[int(idx)],self.specfit.ydata[int(idx)])
- self.graph.insertXMarker(x, legend=legend,
- selectable=True, replot=False)
- self.graph.replot()
+ self.graph.addXMarker(x, legend=legend,
+ selectable=True)
self.markermode = 0
self.__peakmarkermode()
self.__msb.setChecked(0)
else:
- if DEBUG:
- print("Unhandled event ", ddict['event'])
+ _logger.debug("Unhandled event %s", ddict['event'])
def __peakTableSignal(self, ddict, calculate=True):
- if DEBUG:
- print("__peaktablesignal called dict = ",ddict)
+ _logger.debug("__peaktablesignal called dict = %s", ddict)
if (ddict['event'] == 'use') or (ddict['event'] == 'setenergy'):
#get table dictionary
peakdict = self.peakTable.getDict()
@@ -821,10 +809,9 @@ class McaCalWidget(qt.QDialog):
return self.calculateTOF(usedpeaks)
if len(usedpeaks) == 1:
if (usedpeaks[0][0] - 0.0) > 1.0E-20:
- return [0.0,usedpeaks[0][1]/usedpeaks[0][0],0.0]
+ return [0.0, usedpeaks[0][1]/usedpeaks[0][0], 0.0]
else:
- if DEBUG:
- print("Division by zero")
+ _logger.debug("Division by zero")
current = self.current
return [self.caldict[current]['A'],
self.caldict[current]['B'],
@@ -852,7 +839,7 @@ class McaCalWidget(qt.QDialog):
return result
def getdict(self):
- print("DEPRECATED. Use getDict")
+ _logger.info("DEPRECATED. Use getDict")
return self.getDict()
def getDict(self):
@@ -1079,6 +1066,7 @@ class CalibrationParameters(qt.QWidget):
self.CFixed.clicked.connect(self._CFixSlot)
self.orderbox.activated[str].connect(self.__orderbox)
+ self.savebox.lineEdit().editingFinished[()].connect(self.__savebox)
self.savebox.activated[str].connect(self.__savebox)
def setParameters(self, pars):
@@ -1107,7 +1095,7 @@ class CalibrationParameters(qt.QWidget):
return self.current
def getdict(self):
- print("DEPRECATED. Use getDict")
+ _logger.info("DEPRECATED. Use getDict")
return self.getDict()
def getDict(self):
@@ -1146,8 +1134,10 @@ class CalibrationParameters(qt.QWidget):
self.CFixed.hide()
self.myslot(event='order')
- def __savebox(self,qstring):
- key = str(qstring)
+ def __savebox(self, qstring=None):
+ if qstring is None:
+ qstring = self.savebox.currentText()
+ key = qt.safe_str(qstring)
if key not in self.caldict.keys():
self.caldict[key] = {}
if QTVERSION < '4.0.0':
@@ -1210,10 +1200,9 @@ class CalibrationParameters(qt.QWidget):
msg.exec_()
self.CText.setFocus()
- def myslot(self,*var,**kw):
- if DEBUG:
- print("Cal Parameters Slot ",var,kw)
- print(self.caldict[self.currentcal])
+ def myslot(self, *var, **kw):
+ _logger.debug("Cal Parameters Slot %s %s", var, kw)
+ _logger.debug("%s", self.caldict[self.currentcal])
if 'event' in kw:
ddict={}
if (kw['event'] == 'order'):
@@ -1361,8 +1350,9 @@ class InputLine(qt.QDialog):
setenergy=setenergy,
use=use,
calenergy=calenergy)
+
def getdict(self):
- print("DEPRECATED. Use getDict")
+ _logger.info("DEPRECATED. Use getDict")
return self.getDict()
def getDict(self):
@@ -1620,7 +1610,7 @@ class McaCalCopy(qt.QDialog):
self.CText.setText("%.7g" % self.caldict[text]['C'])
def getdict(self):
- print("DEPRECATED. Use getDict")
+ _logger.info("DEPRECATED. Use getDict")
return self.getDict()
def getDict(self):
diff --git a/PyMca5/PyMcaGui/physics/xrf/PeakIdentifier.py b/PyMca5/PyMcaGui/physics/xrf/PeakIdentifier.py
index d4b2d9c..fed357e 100644
--- a/PyMca5/PyMcaGui/physics/xrf/PeakIdentifier.py
+++ b/PyMca5/PyMcaGui/physics/xrf/PeakIdentifier.py
@@ -31,12 +31,14 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaPhysics import Elements
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
QTVERSION = qt.qVersion()
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
class PeakIdentifier(qt.QWidget):
@@ -158,7 +160,7 @@ class PeakIdentifier(qt.QWidget):
return
def myslot(self):
- print("PeakIdentifier.py myslot deprecated, use mySlot")
+ _logger.info("PeakIdentifier.py myslot deprecated, use mySlot")
return self.mySlot()
def _thresholdSlot(self, value):
@@ -281,6 +283,7 @@ class MyQLineEdit(qt.QLineEdit):
qt.QLineEdit.focusOutEvent(self, event)
def main():
+ logging.basicConfig(level=logging.INFO)
app = qt.QApplication(sys.argv)
winpalette = qt.QPalette(qt.QColor(230,240,249),qt.QColor(238,234,238))
app.setPalette(winpalette)
diff --git a/PyMca5/PyMcaGui/physics/xrf/PeakTableWidget.py b/PyMca5/PyMcaGui/physics/xrf/PeakTableWidget.py
index 4003c1e..78f815a 100644
--- a/PyMca5/PyMcaGui/physics/xrf/PeakTableWidget.py
+++ b/PyMca5/PyMcaGui/physics/xrf/PeakTableWidget.py
@@ -31,6 +31,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QStringList"):
QStringList = qt.QStringList
@@ -43,7 +44,8 @@ else:
QString = str
from PyMca5.PyMcaPhysics import Elements
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
QTable = qt.QTableWidget
class QComboTableItem(qt.QComboBox):
@@ -55,8 +57,7 @@ class QComboTableItem(qt.QComboBox):
self.activated[int].connect(self._cellChanged)
def _cellChanged(self, idx):
- if DEBUG:
- print("cell changed",idx)
+ _logger.debug("cell changed %s", idx)
self.sigCellChanged.emit(self._row, self._col)
class QCheckBoxItem(qt.QCheckBox):
@@ -178,14 +179,13 @@ class PeakTableWidget(QTable):
self.peaks[peak]['use_item'].setChecked(self.peaks[peak]['use'])
def myslot(self, row, col):
- if DEBUG:
- print("Passing by myslot",
- self.peaks[self.peaklist[row]]['fields'][col])
- peak=self.peaklist[row]
- field=self.peaks[peak]['fields'][col]
+ _logger.debug("Passing by myslot %s",
+ self.peaks[self.peaklist[row]]['fields'][col])
+ peak = self.peaklist[row]
+ field = self.peaks[peak]['fields'][col]
if (field == "element") or (field == "elementline"):
- key = field+"_item"
- newvalue=self.peaks[peak][key].currentText()
+ key = field + "_item"
+ newvalue = self.peaks[peak][key].currentText()
elif field == "use":
pass
else:
@@ -239,7 +239,7 @@ class PeakTableWidget(QTable):
energy = "%.5f " % (Elements.Element[ele][transition]['energy'])
break
if energy == "0.0":
- print("Something is wrong")
+ _logger.warning("Something is wrong")
else:
self.configure(name=peak,setenergy=energy)
self.setReadOnly(peak,'setenergy')
@@ -249,7 +249,7 @@ class PeakTableWidget(QTable):
try:
value = float(str(newvalue))
except:
- print(field, " newvalue = ", newvalue, "taking old value", oldvalue)
+ _logger.warning("%s newvalue = %s taking old value %s", field, newvalue, oldvalue)
item = self.item(row, col)
item.setText("%s" % oldvalue)
value = float(str(oldvalue))
@@ -263,7 +263,7 @@ class PeakTableWidget(QTable):
try:
value = float(str(newvalue))
except:
- print(field, " newvalue = ", newvalue, "taking old value", oldvalue)
+ _logger.warning("%s newvalue = %s taking old value%s", field, newvalue, oldvalue)
item = self.item(row, col)
item.setText("%s" % oldvalue)
value = float(str(oldvalue))
@@ -281,22 +281,18 @@ class PeakTableWidget(QTable):
ddict['event'] = 'use'
self.sigPeakTableWidgetSignal.emit(ddict)
- def setReadOnly(self,parameter,fields):
- if DEBUG:
- print("peak ",parameter,"fields = ",fields,"asked to be read only")
+ def setReadOnly(self, parameter, fields):
+ _logger.debug("peak %s fields = %s asked to be read only", parameter, fields)
self.setfield(parameter, fields,
- qt.Qt.ItemIsSelectable|qt.Qt.ItemIsEnabled)
-
+ qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled)
- def setReadWrite(self,parameter,fields):
- if DEBUG:
- print("peak ",parameter,"fields = ",fields,"asked to be read write")
+ def setReadWrite(self, parameter, fields):
+ _logger.debug("peak %s fields = %s asked to be read write", parameter, fields)
self.setfield(parameter, fields,
- qt.Qt.ItemIsEditable|qt.Qt.ItemIsSelectable|qt.Qt.ItemIsEnabled)
+ qt.Qt.ItemIsEditable | qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled)
def setfield(self,peak,fields,EditType):
- if DEBUG:
- print("setfield. peak =",peak,"fields = ",fields)
+ _logger.debug("setfield. peak = %s fields = %s",peak, fields)
if type(peak) == type (()) or \
type(peak) == type ([]):
peaklist=peak
@@ -331,10 +327,9 @@ class PeakTableWidget(QTable):
def configure(self,*vars,**kw):
- if DEBUG:
- print("configure called with **kw = ",kw)
- print("configure called with *vars = ",vars)
- name=None
+ _logger.debug("configure called with **kw = %s", kw)
+ _logger.debug("configure called with *vars = %s", vars)
+ name = None
error=0
if 'name' in kw:
name=kw['name']
@@ -371,13 +366,13 @@ class PeakTableWidget(QTable):
try:
self.myslot(row,col)
except:
- print("Error setting element")
+ _logger.warning("Error setting element")
elif key is 'elementline':
try:
iv = self.peaks[name][key+"_item"].findText(QString(kw[key]))
self.peaks[name][key+"_item"].setCurrentIndex(iv)
except:
- print("Error setting elementline")
+ _logger.warning("Error setting elementline")
elif key is 'use':
if kw[key]:
self.peaks[name][key] = 1
@@ -400,11 +395,10 @@ class PeakTableWidget(QTable):
else:
item.setText(text)
elif key == 'channel':
- if DEBUG:
- print("setting channel in configure")
+ _logger.debug("setting channel in configure")
if len(str(kw[key])):
- newvalue=float(str(kw[key]))
- newvalue= QString("%.3f" % newvalue)
+ newvalue = float(str(kw[key]))
+ newvalue = QString("%.3f" % newvalue)
self.peaks[name][key]=newvalue
else:
self.peaks[name][key]=oldvalue
@@ -454,7 +448,7 @@ class PeakTableWidget(QTable):
return 1
def getdict(self, *var):
- print("PeakTableWidget.getdict deprecated. Use getDict")
+ _logger.warning("PeakTableWidget.getdict deprecated. Use getDict")
return self.getDict(*var)
def getDict(self,*var):
diff --git a/PyMca5/PyMcaGui/physics/xrf/QXTube.py b/PyMca5/PyMcaGui/physics/xrf/QXTube.py
index cb9551d..a04e3b6 100644
--- a/PyMca5/PyMcaGui/physics/xrf/QXTube.py
+++ b/PyMca5/PyMcaGui/physics/xrf/QXTube.py
@@ -30,14 +30,16 @@ __author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaPhysics import Elements
from PyMca5.PyMcaPhysics import XRayTubeEbel
import numpy
-from PyMca5.PyMcaGui import PlotWindow
from PyMca5.PyMcaGui import PyMcaQt as qt
+from PyMca5.PyMcaGui.PluginsToolButton import PluginsToolButton
+from silx.gui.plot import PlotWindow
+_logger = logging.getLogger(__name__)
-DEBUG = 0
if qt.qVersion() > '4.0.0':
class QGridLayout(qt.QGridLayout):
@@ -86,8 +88,14 @@ class QXTube(qt.QWidget):
self.l.addWidget(label)
self.l.addWidget(hbox)
- self.graph = PlotWindow.PlotWindow(self,
- backend=None)
+ self.graph = PlotWindow(self, colormap=False, yInverted=False,
+ aspectRatio=False, control=False,
+ position=False, roi=False, mask=False,
+ fit=False)
+ self.pluginsToolButton = PluginsToolButton(plot=self.graph)
+ self.graph.toolBar().addWidget(self.pluginsToolButton)
+ self.graph.getInteractiveModeToolBar().getZoomModeAction().setVisible(False)
+ self.graph.getInteractiveModeToolBar().getPanModeAction().setVisible(False)
self.l.addWidget(self.graph)
self.graph.setGraphXLabel("Energy (keV)")
self.graph.setGraphYLabel("photons/sr/mA/keV/s")
@@ -133,11 +141,8 @@ class QXTube(qt.QWidget):
targetthickness=anodethickness,
filterlist=filterlist)
-
-
-
- self.graph.addCurve(e, continuumR, "continuumR", replot=False)
- self.graph.addCurve(e, continuumT, "continuumT", replot=False)
+ self.graph.addCurve(e, continuumR, "continuumR")
+ self.graph.addCurve(e, continuumT, "continuumT")
else:
continuum = XRayTubeEbel.continuumEbel([anode, anodedensity, anodethickness],
voltage, e,
@@ -146,10 +151,10 @@ class QXTube(qt.QWidget):
transmission=transmission,
targetthickness=anodethickness,
filterlist=filterlist)
- self.graph.addCurve(e, continuum, "continuum", replot=False)
+ self.graph.addCurve(e, continuum, "continuum")
+ self.graph.setActiveCurve("continuum")
self.graph.resetZoom()
- self.graph.replot()
def _export(self):
d = self.tubeWidget.getParameters()
@@ -192,19 +197,18 @@ class QXTube(qt.QWidget):
filterlist=filterlist)
d["characteristic"] = fllines
- if DEBUG:
- fsum = 0.0
- for l in fllines:
- print("%s %.4f %.3e" % (l[2],l[0],l[1]))
- fsum += l[1]
- print(fsum)
-
- energy, energyweight, energyscatter = XRayTubeEbel.generateLists([anode, anodedensity,
- anodethickness],
+ fsum = 0.0
+ for l in fllines:
+ _logger.debug("%s %.4f %.3e", l[2], l[0], l[1])
+ fsum += l[1]
+ _logger.debug("%s", fsum)
+
+ energy, energyweight, energyscatter = XRayTubeEbel.generateLists(
+ [anode, anodedensity, anodethickness],
voltage,
- window = [wele, wdensity, wthickness],
- alphae = alphae, alphax = alphax,
- transmission = transmission,
+ window=[wele, wdensity, wthickness],
+ alphae=alphae, alphax=alphax,
+ transmission=transmission,
targetthickness=anodethickness,
filterlist=filterlist)
@@ -412,23 +416,19 @@ class TubeWidget(qt.QWidget):
return d
def _anodeSlot(self, ddict):
- if DEBUG:
- print("_anodeSlot", ddict)
+ _logger.debug("_anodeSlot %s", ddict)
self.anodeDensity.setText("%f" % Elements.Element[ddict["element"]]["density"])
def _windowSlot(self, ddict):
- if DEBUG:
- print("_windowSlot", ddict)
+ _logger.debug("_windowSlot %s", ddict)
self.windowDensity.setText("%f" % Elements.Element[ddict["element"]]["density"])
def _filter1Slot(self, ddict):
- if DEBUG:
- print("_filter1Slot", ddict)
+ _logger.debug("_filter1Slot %s", ddict)
self.filter1Density.setText("%f" % Elements.Element[ddict["element"]]["density"])
def _transmissionSlot(self):
- if DEBUG:
- print("_transmissionSlot")
+ _logger.debug("_transmissionSlot")
if self.transmissionCheckBox.isChecked():
self.anodeThickness.setEnabled(1)
else:
@@ -460,8 +460,7 @@ class MyQComboBox(qt.QComboBox):
return self.currentIndex(),str(self.currentText())
def _mySignal(self, qstring0):
- if DEBUG:
- print("_mySignal ", qstring0)
+ _logger.debug("_mySignal %s", qstring0)
text = str(qstring0)
d = {}
d['event'] = 'activated'
@@ -470,6 +469,7 @@ class MyQComboBox(qt.QComboBox):
self.sigMyQComboBoxSignal.emit(d)
if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
app = qt.QApplication([])
w = QXTube()
w.show()
diff --git a/PyMca5/PyMcaGui/physics/xrf/StrategyHandler.py b/PyMca5/PyMcaGui/physics/xrf/StrategyHandler.py
index 710371f..07dfd6e 100644
--- a/PyMca5/PyMcaGui/physics/xrf/StrategyHandler.py
+++ b/PyMca5/PyMcaGui/physics/xrf/StrategyHandler.py
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import copy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMcaFileDialogs
from PyMca5.PyMcaPhysics import Elements
@@ -41,7 +42,8 @@ from .MaterialEditor import MaterialComboBox
IconDict = PyMca_Icons.IconDict
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
def _getPeakList(fitConfiguration):
elementsList = []
@@ -365,10 +367,9 @@ class IterationTable(qt.QTableWidget):
item.setEditText(material)
def mySlot(self,row,col):
- if DEBUG:
- print("Value changed row = %d col = %d" % (row, col))
- if col != 0:
- print("Text = %s" % self.cellWidget(row, col).currentText())
+ _logger.debug("Value changed row = %d col = %d", row, col)
+ if col != 0:
+ _logger.debug("Text = %s", self.cellWidget(row, col).currentText())
def _checkBoxSlot(self, ddict):
# check we do not have duplicates
@@ -461,8 +462,7 @@ class IterationTable(qt.QTableWidget):
materialItem.setCurrentIndex(0)
def _peakFamilySlot(self, ddict):
- if DEBUG:
- print("_peakFamilySlot", ddict)
+ _logger.debug("_peakFamilySlot %s", ddict)
# check we do not have duplicates
target = ddict["text"].split()[0]
row = ddict['row']
@@ -486,8 +486,7 @@ class IterationTable(qt.QTableWidget):
self.sigValueChanged.emit(row, col)
def _comboSlot(self, ddict):
- if DEBUG:
- print("_comboSlot", ddict)
+ _logger.debug("_comboSlot %s", ddict)
row = ddict['row']
col = ddict['col']
text = ddict['text']
diff --git a/PyMca5/PyMcaGui/plotting/ColormapDialog.py b/PyMca5/PyMcaGui/plotting/ColormapDialog.py
index b42bac2..e0851ce 100644
--- a/PyMca5/PyMcaGui/plotting/ColormapDialog.py
+++ b/PyMca5/PyMcaGui/plotting/ColormapDialog.py
@@ -28,12 +28,14 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
-from . import PlotWidget
+from silx.gui.plot import PlotWidget
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class MyQLineEdit(qt.QLineEdit):
def __init__(self,parent=None,name=""):
@@ -47,8 +49,7 @@ class MyQLineEdit(qt.QLineEdit):
self.returnPressed[()].emit()
def setPaletteBackgroundColor(self, color):
- if DEBUG:
- print("setPalettebackgroundColor not implemented yet")
+ _logger.debug("setPalettebackgroundColor not implemented yet")
pass
"""
@@ -213,9 +214,9 @@ class ColormapDialog(qt.QDialog):
# Graph widget for color curve...
- self.c = PlotWidget.PlotWidget(self, backend=None)
+ self.c = PlotWidget(self, backend=None)
self.c.setGraphXLabel("Data Values")
- self.c.setZoomModeEnabled(False)
+ self.c.setInteractiveMode('select')
self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
self.minmd = self.dataMin - self.marge
@@ -244,11 +245,11 @@ class ColormapDialog(qt.QDialog):
color = "black"
#TODO symbol
legend = "%d" % i
- self.c.insertXMarker(x[i],
- legend=legend,
- text=labelList[i],
- draggable=draggable,
- color=color)
+ self.c.addXMarker(x[i],
+ legend=legend,
+ text=labelList[i],
+ draggable=draggable,
+ color=color)
self.markers.append((legend, ""))
self.c.setMinimumSize(qt.QSize(250,200))
@@ -267,16 +268,13 @@ class ColormapDialog(qt.QDialog):
bins, counts = self.histogramData
self.c.addCurve(bins, counts,
"Histogram",
- color='pink', # TODO: Change fill color
- symbol='s',
- linestyle='-', # Line style
- #fill=True,
- yaxis='right')
- # TODO: Do not use info!
+ color='darkYellow',
+ histogram='center',
+ yaxis='right',
+ fill=True)
def _update(self):
- if DEBUG:
- print("colormap _update called")
+ _logger.debug("colormap _update called")
self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
self.minmd = self.dataMin - self.marge
self.maxpd = self.dataMax + self.marge
@@ -300,17 +298,15 @@ class ColormapDialog(qt.QDialog):
color = "black"
key = self.markers[i][0]
label = self.markers[i][1]
- self.c.insertXMarker(self.__x[i],
- legend=key,
- text=label,
- draggable=draggable,
- color=color)
- self.c.replot()
+ self.c.addXMarker(self.__x[i],
+ legend=key,
+ text=label,
+ draggable=draggable,
+ color=color)
self.sendColormap()
def buttonGroupChange(self, val):
- if DEBUG:
- print("buttonGroup asking to update colormap")
+ _logger.debug("buttonGroup asking to update colormap")
self.setColormapType(val, update=True)
self._update()
@@ -327,8 +323,7 @@ class ColormapDialog(qt.QDialog):
self._update()
def chval(self, ddict):
- if DEBUG:
- print("Received ", ddict)
+ _logger.debug("Received %s", ddict)
if ddict['event'] == 'markerMoving':
diam = int(ddict['label'])
x = ddict['x']
@@ -368,8 +363,7 @@ class ColormapDialog(qt.QDialog):
self.sendColormap()
def setAutoscale(self, val):
- if DEBUG:
- print("setAutoscale called", val)
+ _logger.debug("setAutoscale called %s", val)
if val:
self.autoScaleButton.setChecked(True)
self.autoScale90Button.setChecked(False)
@@ -378,14 +372,14 @@ class ColormapDialog(qt.QDialog):
self.setMaxValue(self.dataMax)
self.maxText.setEnabled(0)
self.minText.setEnabled(0)
- self.c.setEnabled(0)
+ self.c.setEnabled(False)
#self.c.disablemarkermode()
else:
self.autoScaleButton.setChecked(False)
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
- self.c.setEnabled(1)
+ self.c.setEnabled(True)
#self.c.enablemarkermode()
"""
@@ -403,12 +397,12 @@ class ColormapDialog(qt.QDialog):
self.setMaxValue(self.dataMax - abs(self.dataMax/10))
self.minText.setEnabled(0)
self.maxText.setEnabled(0)
- self.c.setEnabled(0)
+ self.c.setEnabled(False)
else:
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
- self.c.setEnabled(1)
+ self.c.setEnabled(True)
self.c.setFocus()
@@ -424,7 +418,7 @@ class ColormapDialog(qt.QDialog):
self.__x[1] = v
key = self.markers[1][0]
label = self.markers[1][1]
- self.c.insertXMarker(v, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x,
self.__y,
legend="ConstrainedCurve",
@@ -455,7 +449,7 @@ class ColormapDialog(qt.QDialog):
self.__x[1] = val
key = self.markers[1][0]
label = self.markers[1][1]
- self.c.insertXMarker(val, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -472,7 +466,7 @@ class ColormapDialog(qt.QDialog):
self.__x[2] = v
key = self.markers[2][0]
label = self.markers[2][1]
- self.c.insertXMarker(v, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -501,7 +495,7 @@ class ColormapDialog(qt.QDialog):
self.__x[2] = val
key = self.markers[2][0]
label = self.markers[2][1]
- self.c.insertXMarker(val, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -542,8 +536,7 @@ class ColormapDialog(qt.QDialog):
send 'ColormapChanged' signal
"""
def sendColormap(self):
- if DEBUG:
- print("sending colormap")
+ _logger.debug("sending colormap")
try:
cmap = self.getColormap()
self.sigColormapChanged.emit(cmap)
diff --git a/PyMca5/PyMcaGui/plotting/ImageView.py b/PyMca5/PyMcaGui/plotting/ImageView.py
index 2f8bd11..3371533 100644
--- a/PyMca5/PyMcaGui/plotting/ImageView.py
+++ b/PyMca5/PyMcaGui/plotting/ImageView.py
@@ -31,25 +31,11 @@ __contact__ = "thomas.vincent@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
-QWidget displaying a 2D image with histograms on its sides.
+The classes in this module are deprecated. Use
+:class:`silx.gui.plot.ImageView` and
+:class:`silx.gui.plot.ImageViewMainWindow` instead.
-The :class:`ImageView` implements this widget, and
-:class:`ImageViewMainWindow` provides a main window with additional toolbar
-and status bar.
-
-Basic usage of :class:`ImageView` is through the following methods:
-
-- :meth:`ImageView.getColormap`, :meth:`ImageView.setColormap` to update the
- default colormap to use and update the currently displayed image.
-- :meth:`ImageView.setImage` to update the displayed image.
-
-The :class:`ImageView` uses :class:`PlotWindow` and also
-exposes :class:`PyMca5.PyMcaGraph.Plot` API for further control
-(plot title, axes labels, adding other images, ...).
-
-For an example of use, see the implementation of :class:`ImageViewMainWindow`.
-
-The ImageView module can also be used to open an EDF or TIFF file
+This module can be used to open an EDF or TIFF file
from the shell command line.
To view an image file:
``python -m PyMca5.PyMcaGui.plotting.ImageView <file to open>``
@@ -59,872 +45,50 @@ To get help:
# import ######################################################################
-
-import numpy as np
-
+import logging
+import traceback
try:
from .. import PyMcaQt as qt
except ImportError:
from PyMca5.PyMcaGui import PyMcaQt as qt
-from .PlotWindow import PlotWindow
-from .Toolbars import ProfileToolBar, LimitsToolBar
-
-from PyMca5.PyMcaGraph import Plot
-
-
-# utils #######################################################################
-
-_COLORMAP_CURSOR_COLORS = {
- 'gray': 'pink',
- 'reversed gray': 'pink',
- 'temperature': 'black',
- 'red': 'gray',
- 'green': 'gray',
- 'blue': 'gray'}
-
-
-def _cursorColorForColormap(colormapName):
- """Get a color suitable for overlay over a colormap.
-
- :param str colormapName: The name of the colormap.
- :return: Name of the color.
- :rtype: str
- """
- return _COLORMAP_CURSOR_COLORS.get(colormapName, 'black')
-
-
-# RadarView ###################################################################
-
-class RadarView(qt.QGraphicsView):
- """Widget presenting a synthetic view of a 2D area and
- the current visible area.
-
- Coordinates are as in QGraphicsView:
- x goes from left to right and y goes from top to bottom.
- This widget preserves the aspect ratio of the areas.
-
- The 2D area and the visible area can be set with :meth:`setDataRect`
- and :meth:`setVisibleRect`.
- When the visible area has been dragged by the user, its new position
- is signaled by the *visibleRectDragged* signal.
-
- It is possible to invert the direction of the axes by using the
- :meth:`scale` method of QGraphicsView.
- """
-
- visibleRectDragged = qt.pyqtSignal(float, float, float, float)
- """Signals that the visible rectangle has been dragged.
-
- It provides: left, top, width, height in data coordinates.
- """
-
- _DATA_PEN = qt.QPen(qt.QColor('white'))
- _DATA_BRUSH = qt.QBrush(qt.QColor('light gray'))
- _VISIBLE_PEN = qt.QPen(qt.QColor('red'))
- _VISIBLE_BRUSH = qt.QBrush(qt.QColor(0, 0, 0, 0))
- _TOOLTIP = 'Radar View:\nVisible area (in red)\nof the image (in gray).'
-
- _PIXMAP_SIZE = 256
-
- class _DraggableRectItem(qt.QGraphicsRectItem):
- """RectItem which signals its change through visibleRectDragged."""
- def __init__(self, *args, **kwargs):
- super(RadarView._DraggableRectItem, self).__init__(*args, **kwargs)
- self.setFlag(qt.QGraphicsItem.ItemIsMovable)
- self.setFlag(qt.QGraphicsItem.ItemSendsGeometryChanges)
- self._ignoreChange = False
- self._constraint = 0, 0, 0, 0
-
- def setConstraintRect(self, left, top, width, height):
- """Set the constraint rectangle for dragging.
-
- The coordinates are in the _DraggableRectItem coordinate system.
-
- This constraint only applies to modification through interaction
- (i.e., this constraint is not applied to change through API).
-
- If the _DraggableRectItem is smaller than the constraint rectangle,
- the _DraggableRectItem remains within the constraint rectangle.
- If the _DraggableRectItem is wider than the constraint rectangle,
- the constraint rectangle remains within the _DraggableRectItem.
- """
- self._constraint = left, left + width, top, top + height
-
- def setPos(self, *args, **kwargs):
- """Overridden to ignore changes from API in itemChange."""
- self._ignoreChange = True
- super(RadarView._DraggableRectItem, self).setPos(*args, **kwargs)
- self._ignoreChange = False
-
- def moveBy(self, *args, **kwargs):
- """Overridden to ignore changes from API in itemChange."""
- self._ignoreChange = True
- super(RadarView._DraggableRectItem, self).moveBy(*args, **kwargs)
- self._ignoreChange = False
-
- def itemChange(self, change, value):
- """Callback called before applying changes to the item."""
- if (change == qt.QGraphicsItem.ItemPositionChange and
- not self._ignoreChange):
- # Makes sure that the visible area is in the data
- # or that data is in the visible area if area is too wide
- x, y = value.x(), value.y()
- xMin, xMax, yMin, yMax = self._constraint
-
- if self.rect().width() <= (xMax - xMin):
- if x < xMin:
- value.setX(xMin)
- elif x > xMax - self.rect().width():
- value.setX(xMax - self.rect().width())
- else:
- if x > xMin:
- value.setX(xMin)
- elif x < xMax - self.rect().width():
- value.setX(xMax - self.rect().width())
-
- if self.rect().height() <= (yMax - yMin):
- if y < yMin:
- value.setY(yMin)
- elif y > yMax - self.rect().height():
- value.setY(yMax - self.rect().height())
- else:
- if y > yMin:
- value.setY(yMin)
- elif y < yMax - self.rect().height():
- value.setY(yMax - self.rect().height())
-
- if self.pos() != value:
- # Notify change through signal
- views = self.scene().views()
- assert len(views) == 1
- views[0].visibleRectDragged.emit(
- value.x() + self.rect().left(),
- value.y() + self.rect().top(),
- self.rect().width(),
- self.rect().height())
-
- return value
-
- return super(RadarView._DraggableRectItem, self).itemChange(
- change, value)
-
- def __init__(self, parent=None):
- self._scene = qt.QGraphicsScene()
- self._dataRect = self._scene.addRect(0, 0, 1, 1,
- self._DATA_PEN,
- self._DATA_BRUSH)
- self._visibleRect = self._DraggableRectItem(0, 0, 1, 1)
- self._visibleRect.setPen(self._VISIBLE_PEN)
- self._visibleRect.setBrush(self._VISIBLE_BRUSH)
- self._scene.addItem(self._visibleRect)
-
- super(RadarView, self).__init__(self._scene, parent)
- self.setHorizontalScrollBarPolicy(qt.Qt.ScrollBarAlwaysOff)
- self.setVerticalScrollBarPolicy(qt.Qt.ScrollBarAlwaysOff)
- self.setFocusPolicy(qt.Qt.NoFocus)
- self.setStyleSheet('border: 0px')
- self.setToolTip(self._TOOLTIP)
-
- def sizeHint(self):
- # """Overridden to avoid sizeHint to depend on content size."""
- return self.minimumSizeHint()
-
- def wheelEvent(self, event):
- # """Overridden to disable vertical scrolling with wheel."""
- event.ignore()
-
- def resizeEvent(self, event):
- # """Overridden to fit current content to new size."""
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
- super(RadarView, self).resizeEvent(event)
-
- def setDataRect(self, left, top, width, height):
- """Set the bounds of the data rectangular area.
-
- This sets the coordinate system.
- """
- self._dataRect.setRect(left, top, width, height)
- self._visibleRect.setConstraintRect(left, top, width, height)
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
-
- def setVisibleRect(self, left, top, width, height):
- """Set the visible rectangular area.
-
- The coordinates are relative to the data rect.
- """
- self._visibleRect.setRect(0, 0, width, height)
- self._visibleRect.setPos(left, top)
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
-
-
-# ImageView ###################################################################
-
-class ImageView(qt.QWidget):
- """Display a single image with horizontal and vertical histograms.
-
- Use :meth:`setImage` to control the displayed image.
- This class also provides the :class:`PyMca5.PyMcaGraph.Plot` API.
- """
-
- HISTOGRAMS_COLOR = 'blue'
- """Color to use for the side histograms."""
-
- HISTOGRAMS_HEIGHT = 200
- """Height in pixels of the side histograms."""
-
- IMAGE_MIN_SIZE = 200
- """Minimum size in pixels of the image area."""
-
- # Qt signals
- valueChanged = qt.pyqtSignal(float, float, float)
- """Signals that the data value under the cursor has changed.
-
- It provides: row, column, data value.
-
- When the cursor is over an histogram, either row or column is Nan
- and the provided data value is the histogram value
- (i.e., the sum along the corresponding row/column).
- Row and columns are either Nan or integer values.
- """
-
- def __init__(self, parent=None, windowFlags=qt.Qt.Widget, backend=None):
- self._imageLegend = '__ImageView__image' + str(id(self))
- self._cache = None # Store currently visible data information
- self._updatingLimits = False
-
- super(ImageView, self).__init__(parent, windowFlags)
- self.setStyleSheet('background-color: white;')
- self._initWidgets(backend)
-
- # Sync PlotBackend and ImageView
- self._updateYAxisInverted()
-
- # Set-up focus proxy to handle arrow key event
- self.setFocusProxy(self._imagePlot)
-
- def _initWidgets(self, backend):
- """Set-up layout and plots."""
- # Monkey-patch for histogram size
- # alternative: create a layout that does not use widget size hints
- def sizeHint():
- return qt.QSize(self.HISTOGRAMS_HEIGHT, self.HISTOGRAMS_HEIGHT)
-
- self._histoHPlot = Plot.Plot(backend=backend)
- self._histoHPlot.setZoomModeEnabled(True)
- self._histoHPlot.setCallback(self._histoHPlotCB)
- self._histoHPlot.getWidgetHandle().sizeHint = sizeHint
- self._histoHPlot.getWidgetHandle().minimumSizeHint = sizeHint
-
- self._imagePlot = PlotWindow(backend=backend, plugins=False,
- colormap=True, flip=True,
- grid=False, togglePoints=False,
- logx=False, logy=False,
- aspect=True)
- self._imagePlot.usePlotBackendColormap = True
- self._imagePlot.setPanWithArrowKeys(True)
-
- self._imagePlot.setZoomModeEnabled(True) # Color is set in setColormap
- self._imagePlot.sigPlotSignal.connect(self._imagePlotCB)
- self._imagePlot.hFlipToolButton.clicked.connect(
- self._updateYAxisInverted)
- self._imagePlot.sigColormapChangedSignal.connect(self.setColormap)
-
- self._histoVPlot = Plot.Plot(backend=backend)
- self._histoVPlot.setZoomModeEnabled(True)
- self._histoVPlot.setCallback(self._histoVPlotCB)
- self._histoVPlot.getWidgetHandle().sizeHint = sizeHint
- self._histoVPlot.getWidgetHandle().minimumSizeHint = sizeHint
-
- self._radarView = RadarView()
- self._radarView.visibleRectDragged.connect(self._radarViewCB)
-
- self._layout = qt.QGridLayout()
- self._layout.addWidget(self._imagePlot, 0, 0)
- self._layout.addWidget(self._histoVPlot.getWidgetHandle(), 0, 1)
- self._layout.addWidget(self._histoHPlot.getWidgetHandle(), 1, 0)
- self._layout.addWidget(self._radarView, 1, 1)
-
- self._layout.setColumnMinimumWidth(0, self.IMAGE_MIN_SIZE)
- self._layout.setColumnStretch(0, 1)
- self._layout.setColumnMinimumWidth(1, self.HISTOGRAMS_HEIGHT)
- self._layout.setColumnStretch(1, 0)
-
- self._layout.setRowMinimumHeight(0, self.IMAGE_MIN_SIZE)
- self._layout.setRowStretch(0, 1)
- self._layout.setRowMinimumHeight(1, self.HISTOGRAMS_HEIGHT)
- self._layout.setRowStretch(1, 0)
-
- self._layout.setSpacing(0)
- self._layout.setContentsMargins(0, 0, 0, 0)
-
- self.setLayout(self._layout)
-
- def _dirtyCache(self):
- self._cache = None
-
- def _updateHistograms(self):
- """Update histograms content using current active image."""
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- wasUpdatingLimits = self._updatingLimits
- self._updatingLimits = True
-
- data, legend, info, pixmap = activeImage
- xScale, yScale = info['plot_xScale'], info['plot_yScale']
- height, width = data.shape
-
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
-
- # Convert plot area limits to image coordinates
- # and work in image coordinates (i.e., in pixels)
- xMin = int((xMin - xScale[0]) / xScale[1])
- xMax = int((xMax - xScale[0]) / xScale[1])
- yMin = int((yMin - yScale[0]) / yScale[1])
- yMax = int((yMax - yScale[0]) / yScale[1])
-
- if (xMin < width and xMax >= 0 and
- yMin < height and yMax >= 0):
- # The image is at least partly in the plot area
- # Get the visible bounds in image coords (i.e., in pixels)
- subsetXMin = 0 if xMin < 0 else xMin
- subsetXMax = (width if xMax >= width else xMax) + 1
- subsetYMin = 0 if yMin < 0 else yMin
- subsetYMax = (height if yMax >= height else yMax) + 1
-
- if (self._cache is None or
- subsetXMin != self._cache['dataXMin'] or
- subsetXMax != self._cache['dataXMax'] or
- subsetYMin != self._cache['dataYMin'] or
- subsetYMax != self._cache['dataYMax']):
- # The visible area of data has changed, update histograms
-
- # Rebuild histograms for visible area
- visibleData = data[subsetYMin:subsetYMax,
- subsetXMin:subsetXMax]
- histoHVisibleData = np.sum(visibleData, axis=0)
- histoVVisibleData = np.sum(visibleData, axis=1)
-
- self._cache = {
- 'dataXMin': subsetXMin,
- 'dataXMax': subsetXMax,
- 'dataYMin': subsetYMin,
- 'dataYMax': subsetYMax,
-
- 'histoH': histoHVisibleData,
- 'histoHMin': np.min(histoHVisibleData),
- 'histoHMax': np.max(histoHVisibleData),
-
- 'histoV': histoVVisibleData,
- 'histoVMin': np.min(histoVVisibleData),
- 'histoVMax': np.max(histoVVisibleData)
- }
-
- # Convert to histogram curve and update plots
- # Taking into account origin and scale
- coords = np.arange(2 * histoHVisibleData.size)
- xCoords = (coords + 1) // 2 + subsetXMin
- xCoords = xScale[0] + xScale[1] * xCoords
- xData = np.take(histoHVisibleData, coords // 2)
- self._histoHPlot.addCurve(xCoords, xData,
- xlabel='', ylabel='',
- replace=False, replot=False,
- color=self.HISTOGRAMS_COLOR,
- linestyle='-',
- selectable=False)
- vMin = self._cache['histoHMin']
- vMax = self._cache['histoHMax']
- vOffset = 0.1 * (vMax - vMin)
- if vOffset == 0.:
- vOffset = 1.
- self._histoHPlot.setGraphYLimits(vMin - vOffset,
- vMax + vOffset)
-
- coords = np.arange(2 * histoVVisibleData.size)
- yCoords = (coords + 1) // 2 + subsetYMin
- yCoords = yScale[0] + yScale[1] * yCoords
- yData = np.take(histoVVisibleData, coords // 2)
- self._histoVPlot.addCurve(yData, yCoords,
- xlabel='', ylabel='',
- replace=False, replot=False,
- color=self.HISTOGRAMS_COLOR,
- linestyle='-',
- selectable=False)
- vMin = self._cache['histoVMin']
- vMax = self._cache['histoVMax']
- vOffset = 0.1 * (vMax - vMin)
- if vOffset == 0.:
- vOffset = 1.
- self._histoVPlot.setGraphXLimits(vMin - vOffset,
- vMax + vOffset)
- else:
- self._dirtyCache()
- self._histoHPlot.clearCurves()
- self._histoVPlot.clearCurves()
+from silx.gui.plot.ImageView import ImageView as SilxImageView
+from silx.gui.plot.ImageView import ImageViewMainWindow as SilxImageViewMainWindow
- self._updatingLimits = wasUpdatingLimits
- def _updateRadarView(self):
- """Update radar view visible area.
+_logger = logging.getLogger(__name__)
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.ImageView instead",
+ __name__)
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
- Takes care of y coordinate conversion.
- """
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
- self._radarView.setVisibleRect(xMin, yMin, xMax - xMin, yMax - yMin)
-
- # Plots event listeners
-
- def _imagePlotCB(self, eventDict):
- """Callback for imageView plot events."""
- if eventDict['event'] == 'mouseMoved':
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- data = activeImage[0]
- height, width = data.shape
- x, y = int(eventDict['x']), int(eventDict['y'])
- if x >= 0 and x < width and y >= 0 and y < height:
- self.valueChanged.emit(float(x), float(y),
- data[y][x])
- elif eventDict['event'] == 'limitsChanged':
- # Do not handle histograms limitsChanged while
- # updating their limits from here.
- self._updatingLimits = True
-
- # Refresh histograms
- self._updateHistograms()
-
- # could use eventDict['xdata'], eventDict['ydata'] instead
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
-
- # Set horizontal histo limits
- self._histoHPlot.setGraphXLimits(xMin, xMax)
- self._histoHPlot.replot()
-
- # Set vertical histo limits
- self._histoVPlot.setGraphYLimits(yMin, yMax)
- self._histoVPlot.replot()
-
- self._updateRadarView()
-
- self._updatingLimits = False
-
- # Replot in case limitsChanged due to set*Limits
- # called from console.
- # This results in an extra replot call in other cases.
- self._imagePlot.replot()
-
- def _histoHPlotCB(self, eventDict):
- """Callback for horizontal histogram plot events."""
- if eventDict['event'] == 'mouseMoved':
- if self._cache is not None:
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- xOrigin, xScaleFactor = activeImage[2]['plot_xScale']
-
- minValue = xOrigin + xScaleFactor * self._cache['dataXMin']
- data = self._cache['histoH']
- width = data.shape[0]
- x = int(eventDict['x'])
- if x >= minValue and x < minValue + width:
- self.valueChanged.emit(float('nan'), float(x),
- data[x - minValue])
- elif eventDict['event'] == 'limitsChanged':
- if (not self._updatingLimits and
- eventDict['xdata'] != self._imagePlot.getGraphXLimits()):
- xMin, xMax = eventDict['xdata']
- self._imagePlot.setGraphXLimits(xMin, xMax)
- self._imagePlot.replot()
-
- def _histoVPlotCB(self, eventDict):
- """Callback for vertical histogram plot events."""
- if eventDict['event'] == 'mouseMoved':
- if self._cache is not None:
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- yOrigin, yScaleFactor = activeImage[2]['plot_yScale']
-
- minValue = yOrigin + yScaleFactor * self._cache['dataYMin']
- data = self._cache['histoV']
- height = data.shape[0]
- y = int(eventDict['y'])
- if y >= minValue and y < minValue + height:
- self.valueChanged.emit(float(y), float('nan'),
- data[y - minValue])
- elif eventDict['event'] == 'limitsChanged':
- if (not self._updatingLimits and
- eventDict['ydata'] != self._imagePlot.getGraphYLimits()):
- yMin, yMax = eventDict['ydata']
- self._imagePlot.setGraphYLimits(yMin, yMax)
- self._imagePlot.replot()
-
- def _radarViewCB(self, left, top, width, height):
- """Slot for radar view visible rectangle changes."""
- if not self._updatingLimits:
- # Takes care of Y axis conversion
- self._imagePlot.setLimits(left, left + width, top, top + height)
- self._imagePlot.replot()
-
- def _updateYAxisInverted(self):
- """Sync image, vertical histogram and radar view axis orientation."""
- inverted = self._imagePlot.isYAxisInverted()
-
- self._imagePlot.invertYAxis(inverted)
- self._histoVPlot.invertYAxis(inverted)
-
- # Use scale to invert radarView
- # RadarView default Y direction is from top to bottom
- # As opposed to Plot. So invert RadarView when Plot is NOT inverted.
- self._radarView.resetTransform()
- if not inverted:
- self._radarView.scale(1., -1.)
- self._updateRadarView()
-
- self._imagePlot.replot()
- self._histoVPlot.replot()
- self._radarView.update()
-
- def getHistogram(self, axis):
- """Return the histogram and corresponding row or column extent.
-
- The returned value when an histogram is available is a dict with keys:
-
- - 'data': numpy array of the histogram values.
- - 'extent': (start, end) row or column index.
- end index is not included in the histogram.
- :param str axis: 'x' for horizontal, 'y' for vertical
- :return: The histogram and its extent as a dict or None.
- :rtype: dict
+class ImageView(SilxImageView):
+ def __init__(self, parent=None, windowFlags=None, backend=None):
"""
- assert axis in ('x', 'y')
- if self._cache is None:
- return None
- else:
- if axis == 'x':
- return dict(
- data=np.array(self._cache['histoH'], copy=True),
- extent=(self._cache['dataXMin'], self._cache['dataXMax']))
- else:
- return dict(
- data=np.array(self._cache['histoV'], copy=True),
- extent=(self._cache['dataYMin'], self._cache['dataYMax']))
- def radarView(self):
- """Get the lower right radarView widget."""
- return self._radarView
-
- def setRadarView(self, radarView):
- """Change the lower right radarView widget.
-
- :param RadarView radarView: Widget subclassing RadarView to replace
- the lower right corner widget.
- """
- self._radarView.visibleRectDragged.disconnect(self._radarViewCB)
- self._radarView = radarView
- self._radarView.visibleRectDragged.connect(self._radarViewCB)
- self._layout.addWidget(self._radarView, 1, 1)
-
- self._updateYAxisInverted()
-
- # PlotWindow toolbar
-
- def toolBar(self):
- """Returns the tool bar associated with the image plot.
-
- This is the toolBar provided by :class:`PlotWindow`.
-
- :return: The toolBar associated to the image plot.
- :rtype: QToolBar
- """
- return self._imagePlot.toolBar
-
- # High-level API
-
- def getColormap(self):
- """Get the default colormap description.
-
- :return: A description of the current colormap.
- See :meth:`setColormap` for details.
- :rtype: dict
+ :param parent:
+ :param windowFlags: windowFlags (e.g. qt.Qt.Widget, qt.Qt.Window...)
+ If None, the silx default behavior is used: behave as a widget if
+ parent is not None, else behave as a Window.
+ :param backend:
"""
- return self._imagePlot.getDefaultColormap()
-
- def setColormap(self, colormap=None, normalization=None,
- autoscale=None, vmin=None, vmax=None, colors=256):
- """Set the default colormap and update active image.
-
- Parameters that are not provided are taken from the current colormap.
-
- The colormap parameter can also be a dict with the following keys:
-
- - *name*: string. The colormap to use:
- 'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
- - *normalization*: string. The mapping to use for the colormap:
- either 'linear' or 'log'.
- - *autoscale*: bool. Whether to use autoscale (True)
- or range provided by keys 'vmin' and 'vmax' (False).
- - *vmin*: float. The minimum value of the range to use if 'autoscale'
- is False.
- - *vmax*: float. The maximum value of the range to use if 'autoscale'
- is False.
-
- :param colormap: Name of the colormap in
- 'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
- Or the description of the colormap as a dict.
- :type colormap: dict or str.
- :param str normalization: Colormap mapping: 'linear' or 'log'.
- :param bool autoscale: Whether to use autoscale (True)
- or [vmin, vmax] range (False).
- :param float vmin: The minimum value of the range to use if
- 'autoscale' is False.
- :param float vmax: The maximum value of the range to use if
- 'autoscale' is False.
- """
- cmapDict = self._imagePlot.getDefaultColormap()
-
- if isinstance(colormap, dict):
- # Support colormap parameter as a dict
- assert normalization is None
- assert autoscale is None
- assert vmin is None
- assert vmax is None
- assert colors == 256
- for key, value in colormap.items():
- cmapDict[key] = value
-
- else:
- if colormap is not None:
- cmapDict['name'] = colormap
- if normalization is not None:
- cmapDict['normalization'] = normalization
- if autoscale is not None:
- cmapDict['autoscale'] = autoscale
- if vmin is not None:
- cmapDict['vmin'] = vmin
- if vmax is not None:
- cmapDict['vmax'] = vmax
-
- if 'colors' not in cmapDict:
- cmapDict['colors'] = 256
-
- cursorColor = _cursorColorForColormap(cmapDict['name'])
- self._imagePlot.setZoomModeEnabled(True, color=cursorColor)
+ super(ImageView, self).__init__(parent=parent, backend=backend)
- self._imagePlot.setDefaultColormap(cmapDict)
+ # SilxImageView does not have a windowFlags parameter.
+ # A silx PlotWidget behaves as a Widget if parent is not None,
+ # else it behaves as a QMainWindow.
+ if windowFlags is not None:
+ self.setWindowFlags(windowFlags)
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None: # Refresh image with new colormap
- data, legend, info, pixmap = activeImage
-
- self._imagePlot.addImage(data, legend=legend, info=info,
- colormap=self.getColormap(),
- replace=False, replot=False)
- self._imagePlot.replot()
-
- def setImage(self, image, origin=(0, 0), scale=(1., 1.),
- copy=True, reset=True):
- """Set the image to display.
-
- :param image: A 2D array representing the image or None to empty plot.
- :type image: numpy.ndarray-like with 2 dimensions or None.
- :param origin: The (x, y) position of the origin of the image.
- Default: (0, 0).
- The origin is the lower left corner of the image when
- the Y axis is not inverted.
- :type origin: Tuple of 2 floats: (origin x, origin y).
- :param scale: The scale factor to apply to the image on X and Y axes.
- Default: (1, 1).
- It is the size of a pixel in the coordinates of the axes.
- Scales must be positive numbers.
- :type scale: Tuple of 2 floats: (scale x, scale y).
- :param bool copy: Whether to copy image data (default) or not.
- :param bool reset: Whether to reset zoom and ROI (default) or not.
- """
- self._dirtyCache()
-
- assert len(origin) == 2
- assert len(scale) == 2
- assert scale[0] > 0
- assert scale[1] > 0
-
- if image is None:
- self._imagePlot.removeImage(self._imageLegend, replot=False)
- return
-
- data = np.array(image, order='C', copy=copy)
- assert data.size != 0
- assert len(data.shape) == 2
- height, width = data.shape
-
- self._imagePlot.addImage(data,
- legend=self._imageLegend,
- xScale=(origin[0], scale[0]),
- yScale=(origin[1], scale[1]),
- colormap=self.getColormap(),
- replace=False,
- replot=False)
- self._imagePlot.setActiveImage(self._imageLegend)
- self._updateHistograms()
-
- self._radarView.setDataRect(origin[0],
- origin[1],
- width * scale[0],
- height * scale[1])
-
- if reset:
- self.resetZoom()
- else:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
- self._imagePlot.replot()
-
- ####################
- # Plot API proxies #
- ####################
-
- # Rebuild side histograms if active image gets changed through the Plot API
-
- def addImage(self, data, legend=None, info=None,
- replace=True, replot=True,
- xScale=None, yScale=None, z=0,
- selectable=False, draggable=False,
- colormap=None, **kw):
- if legend == self._imagePlot.getActiveImage(just_legend=True):
- # Updating active image, resets side histograms cache
- self._dirtyCache()
-
- result = self._imagePlot.addImage(data, legend, info, replace, replot,
- xScale, yScale, z,
- selectable, draggable,
- colormap, **kw)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
-
- return result
-
- def clear(self):
- self._dirtyCache()
- return self._imagePlot.clear()
-
- def clearImages(self):
- self._dirtyCache()
- return self._imagePlot.clearImages()
-
- def removeImage(self, legend, replot=True):
- if legend == self._imagePlot.getActiveImage(just_legend=True):
- # Removing active image, resets side histograms cache
- self._dirtyCache()
-
- result = self._imageView.removeImage(legend, replot)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
-
- return result
-
- def setActiveImage(self, legend, replot=True):
- # Active image changes, resets side histogram cache
- self._dirtyCache()
-
- result = self._imagePlot.setActiveImage(legend, replot)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
- return result
-
- # Invert axes
-
- def invertYAxis(self, flag=True):
- result = self._imagePlot.invertYAxis(flag)
- self._updateYAxisInverted() # To sync vert. histo and radar view
- return result
-
- # Ugly yet simple proxy for the Plot API
-
- def __getattr__(self, name):
- """Proxy to expose image plot API."""
- return getattr(self._imagePlot, name)
-
-
-# ImageViewMainWindow #########################################################
-
-class ImageViewMainWindow(qt.QMainWindow):
- """QMainWindow embedding an ImageView.
-
- Surrounds the ImageView with an associated toolbar and status bar.
- """
+class ImageViewMainWindow(SilxImageViewMainWindow):
def __init__(self, parent=None, windowFlags=qt.Qt.Widget, backend=None):
- self._dataInfo = None
- super(ImageViewMainWindow, self).__init__(parent, windowFlags)
-
- # Create the ImageView widget and add it to the QMainWindow
- self.imageView = ImageView(backend=backend)
- self.imageView.setGraphXLabel('X')
- self.imageView.setGraphYLabel('Y')
- self.imageView.setGraphTitle('Image')
- self.imageView._imagePlot.sigColormapChangedSignal.connect(
- self._colormapUpdated)
- self.setCentralWidget(self.imageView)
-
- # Using PlotWindow's toolbar
- self.addToolBar(self.imageView.toolBar())
- self.profileToolBar = ProfileToolBar(self.imageView._imagePlot)
- self.addToolBar(self.profileToolBar)
- self.addToolBar(qt.Qt.BottomToolBarArea, LimitsToolBar(self.imageView))
-
- self.statusBar()
-
- # Connect to ImageView's signal
- self.imageView.valueChanged.connect(self._statusBarSlot)
-
- def _colormapUpdated(self, colormap):
- """Sync ROI color with current colormap"""
- self.profileToolBar.overlayColor = _cursorColorForColormap(
- colormap['name'])
-
- def _statusBarSlot(self, row, column, value):
- """Update status bar with coordinates/value from plots."""
- if np.isnan(row):
- msg = 'Column: %d, Sum: %g' % (int(column), value)
- elif np.isnan(column):
- msg = 'Row: %d, Sum: %g' % (int(row), value)
- else:
- msg = 'Position: (%d, %d), Value: %g' % (int(row), int(column),
- value)
- if self._dataInfo is not None:
- msg = self._dataInfo + ', ' + msg
-
- self.statusBar().showMessage(msg)
-
- def setImage(self, image, *args, **kwargs):
- """Set the displayed image.
-
- See :meth:`ImageView.setImage` for details.
- """
- if hasattr(image, 'dtype') and hasattr(image, 'shape'):
- assert len(image.shape) == 2
- height, width = image.shape
- self._dataInfo = 'Data: %dx%d (%s)' % (width, height,
- str(image.dtype))
- self.statusBar().showMessage(self._dataInfo)
- else:
- self._dataInfo = None
+ super(ImageViewMainWindow, self).__init__(parent, backend)
+ if windowFlags is not None:
+ self.setWindowFlags(windowFlags)
- # Set the new image in ImageView widget
- self.imageView.setImage(image, *args, **kwargs)
- self.profileToolBar.updateProfile()
- self.setStatusBar(None)
# main ########################################################################
diff --git a/PyMca5/PyMcaGui/plotting/MaskImageTools.py b/PyMca5/PyMcaGui/plotting/MaskImageTools.py
index 61466f7..5c6394f 100644
--- a/PyMca5/PyMcaGui/plotting/MaskImageTools.py
+++ b/PyMca5/PyMcaGui/plotting/MaskImageTools.py
@@ -30,8 +30,6 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
Common tools to deal with common graphics operations on images.
"""
-import sys
-import os
import numpy
from PyMca5 import spslut
@@ -253,9 +251,9 @@ def applyMaskToImage(pixmap, mask=None, colors=None, copy=True):
if __name__ == "__main__":
from PyMca5.PyMcaGui import PyMcaQt as qt
- from PyMca5.PyMcaGui import PlotWidget
+ from silx.gui.plot import PlotWidget
app = qt.QApplication([])
- w = PlotWidget.PlotWidget()
+ w = PlotWidget()
data = numpy.arange(10000.).reshape(100, 100)
mask = numpy.zeros(data.shape, dtype=numpy.uint8)
mask[25:75, 25:75] = 1
diff --git a/PyMca5/PyMcaGui/plotting/MaskImageWidget.py b/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
index 5116c8b..5be6bae 100644
--- a/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
+++ b/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
@@ -30,6 +30,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaGraph.ctools import pnpoly
from . import RGBCorrelatorGraph
from . import ColormapDialog
@@ -61,7 +62,8 @@ OVERLAY_DRAW = True
DEFAULT_COLORMAP_INDEX = 2
DEFAULT_COLORMAP_LOG_FLAG = False
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
USE_PICKER = False
@@ -85,7 +87,6 @@ class MaskImageWidget(qt.QWidget):
self.setMaximumWidth(int(screenWidth)-5)
self.setMinimumWidth(min(int(0.5*screenWidth),800))
- self._y1AxisInverted = False
self.__selectionMask = None
self._selectionColors = None
self.__imageData = None
@@ -185,13 +186,12 @@ class MaskImageWidget(qt.QWidget):
self.buildStandaloneSaveMenu()
self.graphWidget.zoomResetToolButton.clicked.connect(self._zoomResetSignal)
- self.graphWidget.graph.setDrawModeEnabled(False)
- self.graphWidget.graph.setZoomModeEnabled(True)
+ self.graphWidget.graph.setInteractiveMode('zoom')
if self.__selectionFlag:
if self.__imageIconsFlag:
self.setSelectionMode(False)
self._toggleSelectionMode()
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode('draw',
shape="rectangle",
label="mask")
else:
@@ -323,9 +323,8 @@ class MaskImageWidget(qt.QWidget):
self._profileSignalSlot(ddict)
def _profileSignalSlot(self, ddict):
- if DEBUG:
- print("_profileSignalSLot, event = %s" % ddict['event'])
- print("Received ddict = ", ddict)
+ _logger.debug("_profileSignalSLot, event = %s", ddict['event'])
+ _logger.debug("Received ddict = %s", ddict)
if ddict['event'] in [None, "NONE"]:
#Nothing to be made
@@ -333,10 +332,10 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == "profileWidthChanged":
if self.__lastOverlayLegend is not None:
- legend = self.__lastOverlayLegend
- #TODO: Find a better way to deal with this
- if legend in self.graphWidget.graph._itemDict:
- info = self.graphWidget.graph._itemDict[legend]['info']
+ shape = self.graphWidget.graph._getItem(kind='item',
+ legend=self.__lastOverlayLegend)
+ if shape is not None:
+ info = shape.getInfo(copy=False)
if info['mode'] == ddict['mode']:
newDict = {}
newDict['event'] = "updateProfile"
@@ -344,7 +343,6 @@ class MaskImageWidget(qt.QWidget):
newDict['ydata'] = info['ydata'] * 1
newDict['mode'] = info['mode'] * 1
newDict['pixelwidth'] = ddict['pixelwidth'] * 1
- info = None
#self._updateProfileCurve(newDict)
self._profileSignalSlot(newDict)
return
@@ -355,13 +353,13 @@ class MaskImageWidget(qt.QWidget):
self._profileSelectionWindow = ProfileScanWidget.ProfileScanWidget(actions=False)
else:
self._profileSelectionWindow = ProfileScanWidget.ProfileScanWidget(actions=True)
- self._profileSelectionWindow.sigAddClicked.connect( \
+ self._profileSelectionWindow.sigAddClicked.connect(
self._profileSelectionSlot)
- self._profileSelectionWindow.sigRemoveClicked.connect( \
+ self._profileSelectionWindow.sigRemoveClicked.connect(
self._profileSelectionSlot)
self._profileSelectionWindow.sigReplaceClicked.connect(
self._profileSelectionSlot)
- self._interpolate = SpecfitFuns.interpol
+ self._interpolate = SpecfitFuns.interpol
#if I do not return here and the user interacts with the graph while
#the profileSelectionWindow is not shown, I get crashes under Qt 4.5.3 and MacOS X
#when calling _getProfileCurve
@@ -376,16 +374,14 @@ class MaskImageWidget(qt.QWidget):
if curve is None:
return
xdata, ydata, legend, info = curve
- replot=True
- replace=True
idx = numpy.isfinite(ydata)
xdata = xdata[idx]
ydata = ydata[idx]
self._profileSelectionWindow.addCurve(xdata, ydata,
legend=legend,
info=info,
- replot=replot,
- replace=replace)
+ resetzoom=True,
+ replace=True)
def getGraphTitle(self):
try:
@@ -438,7 +434,7 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == 'profileModeChanged':
if self.__lastOverlayLegend:
- self.graphWidget.graph.removeItem(self.__lastOverlayLegend, replot=True)
+ self.graphWidget.graph.removeItem(self.__lastOverlayLegend)
return
#if I show the image here it does not crash, but it is not nice because
@@ -476,13 +472,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[row, :]
legend = "Row = %d" % row
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([0.0, shape[1], shape[1], 0.0],
[row, row, row+1, row+1],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
row0 = int(int(ddict['row'][0]) - 0.5 * width)
if row0 < 0:
@@ -497,13 +492,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[row0:row1+1, :].sum(axis=0)
legend = "Row = %d to %d" % (row0, row1)
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([0.0, 0.0, shape[1], shape[1]],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
xdata = numpy.arange(shape[1]).astype(numpy.float)
if self._xScale is not None:
xdata = self._xScale[0] + xdata * self._xScale[1]
@@ -519,13 +513,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[:, column]
legend = "Column = %d" % column
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([column, column, column+1, column+1],
[0.0, shape[0], shape[0], 0.0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
col0 = int(int(ddict['column'][0]) - 0.5 * width)
if col0 < 0:
@@ -540,13 +533,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[:, col0:col1+1].sum(axis=1)
legend = "Col = %d to %d" % (col0, col1)
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[0, shape[0], shape[0], 0.],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
xdata = numpy.arange(shape[0]).astype(numpy.float)
if self._yScale is not None:
xdata = self._yScale[0] + xdata * self._yScale[1]
@@ -577,8 +569,7 @@ class MaskImageWidget(qt.QWidget):
if npoints == 1:
#all points are the same
- if DEBUG:
- print("START AND END POINT ARE THE SAME!!")
+ _logger.debug("START AND END POINT ARE THE SAME!!")
return
if width < 0: # width = pixelwidth - 1
@@ -591,13 +582,12 @@ class MaskImageWidget(qt.QWidget):
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col1],
[row0, row1],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
elif deltaCol == 0:
#vertical line
col0 = int(int(ddict['column'][0]) - 0.5 * width)
@@ -624,13 +614,12 @@ class MaskImageWidget(qt.QWidget):
npoints = max(ydata.shape)
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
elif deltaRow == 0:
#horizontal line
row0 = int(int(ddict['row'][0]) - 0.5 * width)
@@ -657,13 +646,12 @@ class MaskImageWidget(qt.QWidget):
npoints = max(ydata.shape)
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
#restore original value of width
width = ddict['pixelwidth']
@@ -687,9 +675,8 @@ class MaskImageWidget(qt.QWidget):
newRow0 = 0.0
newRow1 = -(col1-col0) * sinalpha + (row1-row0) * cosalpha
- if DEBUG:
- print("new X0 Y0 = %f, %f " % (newCol0, newRow0))
- print("new X1 Y1 = %f, %f " % (newCol1, newRow1))
+ _logger.debug("new X0 Y0 = %f, %f ", newCol0, newRow0)
+ _logger.debug("new X1 Y1 = %f, %f ", newCol1, newRow1)
tmpX = numpy.linspace(newCol0, newCol1, npoints).astype(numpy.float)
rotMatrix = numpy.zeros((2,2), numpy.float)
@@ -697,19 +684,19 @@ class MaskImageWidget(qt.QWidget):
rotMatrix[0,1] = - sinalpha
rotMatrix[1,0] = sinalpha
rotMatrix[1,1] = cosalpha
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
#test if I recover the original points
- testX = numpy.zeros((2, 1) , numpy.float)
+ testX = numpy.zeros((2, 1), numpy.float)
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X0 = %f" % (colRow[0,0] + col0))
- print("Recovered Y0 = %f" % (colRow[1,0] + row0))
- print("It should be = %f, %f" % (col0, row0))
- testX[0,0] = newCol1
- testX[1,0] = newRow1
+ _logger.debug("Recovered X0 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y0 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col0, row0)
+ testX[0, 0] = newCol1
+ testX[1, 0] = newRow1
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X1 = %f" % (colRow[0,0] + col0))
- print("Recovered Y1 = %f" % (colRow[1,0] + row0))
- print("It should be = %f, %f" % (col1, row1))
+ _logger.debug("Recovered X1 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y1 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col1, row1)
#find the drawing limits
testX = numpy.zeros((2, 4) , numpy.float)
@@ -727,21 +714,18 @@ class MaskImageWidget(qt.QWidget):
for a in rowLimits0:
if (a >= shape[0]) or (a < 0):
- if DEBUG:
- print("outside row limits",a)
+ _logger.debug("outside row limits %s", a)
return
for a in colLimits0:
if (a >= shape[1]) or (a < 0):
- if DEBUG:
- print("outside column limits",a)
+ _logger.debug("outside column limits %s", a)
return
r0 = rowLimits0[0]
r1 = rowLimits0[1]
if r0 > r1:
- if DEBUG:
- print("r0 > r1", r0, r1)
+ _logger.debug("r0 > r1 %s %s", r0, r1)
raise ValueError("r0 > r1")
x = numpy.zeros((2, npoints) , numpy.float)
@@ -809,8 +793,7 @@ class MaskImageWidget(qt.QWidget):
rowLimits0,
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
if self.__lineProjectionMode == 'X':
xLabel = self.getXLabel()
xdata += col0
@@ -831,8 +814,7 @@ class MaskImageWidget(qt.QWidget):
float(deltaRow) * deltaRow)/(npoints-1.0)
xdata *= deltaDistance
else:
- if DEBUG:
- print("Mode %s not supported yet" % ddict['mode'])
+ _logger.debug("Mode %s not supported yet", ddict['mode'])
return
self.__lastOverlayWidth = ddict['pixelwidth']
@@ -842,8 +824,7 @@ class MaskImageWidget(qt.QWidget):
return xdata, ydata, legend, info
def _profileSelectionSlot(self, ddict):
- if DEBUG:
- print(ddict)
+ _logger.debug("%s", ddict)
# the curves as [[x0, y0, legend0, info0], ...]
curveList = ddict['curves']
label = ddict['label']
@@ -851,25 +832,17 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == 'ADD':
for i in range(n):
x, y, legend, info = curveList[i]
- info['profilelabel'] = label
- if i == (n-1):
- replot = True
+ resetzoom = (i == (n-1))
self._profileScanWindow.addCurve(x, y, legend=legend, info=info,
- replot=replot, replace=False)
+ resetzoom=resetzoom, replace=False)
elif ddict['event'] == 'REPLACE':
for i in range(n):
x, y, legend, info = curveList[i]
info['profilelabel'] = label
- if i in [0, n-1]:
- replace = True
- else:
- replace = False
- if i == (n-1):
- replot = True
- else:
- replot = False
+ replace = (i in [0, n-1])
+ resetzoom = (i == (n-1))
self._profileScanWindow.addCurve(x, y, legend=legend, info=info,
- replot=replot, replace=replace)
+ resetzoom=resetzoom, replace=replace)
elif ddict['event'] == 'REMOVE':
curveList = self._profileScanWindow.getAllCurves()
if curveList in [None, []]:
@@ -885,13 +858,10 @@ class MaskImageWidget(qt.QWidget):
n = len(toDelete)
for i in range(n):
legend = toDelete[i]
- if i == (n-1):
- replot = True
- else:
- replot = False
- self._profileScanWindow.removeCurve(legend, replot=replot)
+ resetzoom = (i == (n-1))
+ self._profileScanWindow.removeCurve(legend, resetzoom=resetzoom)
- def drawOverlayItem(self, x, y, legend=None, info=None, replace=False, replot=True):
+ def drawOverlayItem(self, x, y, legend=None, info=None, replace=False):
#same call as the plot1D addCurve command
if legend is None:
legend="UnnamedOverlayItem"
@@ -911,31 +881,22 @@ class MaskImageWidget(qt.QWidget):
for i in y:
yList.append(self._yScale[0] + i * self._yScale[1])
self.graphWidget.graph.addItem(xList, yList, legend=legend, info=info,
- replace=replace, replot=replot,
- shape="polygon", fill=True)
+ replace=replace, shape="polygon", fill=True)
self.__lastOverlayLegend = legend
def _hFlipIconSignal(self):
- self._y1AxisInverted = self.graphWidget.graph.isYAxisInverted()
- if self._y1AxisInverted:
- self._y1AxisInverted = False
- else:
- self._y1AxisInverted = True
- #self.graphWidget.graph.zoomReset()
- self.graphWidget.graph.invertYAxis(self._y1AxisInverted)
- self._y1AxisInverted = self.graphWidget.graph.isYAxisInverted()
- self.graphWidget.graph.replot()
+ yaxis = self.graphWidget.graph.getYAxis()
+ yaxis.setInverted(not yaxis.isInverted())
#inform the other widgets
ddict = {}
ddict['event'] = "hFlipSignal"
- ddict['current'] = self._y1AxisInverted * 1
+ ddict['current'] = yaxis.isInverted() * 1
ddict['id'] = id(self)
self.emitMaskImageSignal(ddict)
def setY1AxisInverted(self, value):
- self._y1AxisInverted = value
- self.graphWidget.graph.invertYAxis(self._y1AxisInverted)
+ self.graphWidget.graph.getYAxis().setInverted(value)
def setXLabel(self, label="Column"):
return self.graphWidget.setXLabel(label)
@@ -988,38 +949,34 @@ class MaskImageWidget(qt.QWidget):
self._replaceImageClicked)
def _setEraseSelectionMode(self):
- if DEBUG:
- print("_setEraseSelectionMode")
+ _logger.debug("_setEraseSelectionMode")
self.__eraseMode = True
self.__brushMode = True
- self.graphWidget.graph.setDrawModeEnabled(False)
+ self.graphWidget.graph.setInteractiveMode('select')
def _setRectSelectionMode(self):
- if DEBUG:
- print("_setRectSelectionMode")
+ _logger.debug("_setRectSelectionMode")
self.__eraseMode = False
self.__brushMode = False
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode("draw",
shape="rectangle",
label="mask")
def _setPolygonSelectionMode(self):
self.__eraseMode = False
self.__brushMode = False
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode('draw',
shape="polygon",
label="mask")
def _setBrushSelectionMode(self):
- if DEBUG:
- print("_setBrushSelectionMode")
+ _logger.debug("_setBrushSelectionMode")
self.__eraseMode = False
self.__brushMode = True
- self.graphWidget.graph.setDrawModeEnabled(False)
+ self.graphWidget.graph.setInteractiveMode('select')
def _setBrush(self):
- if DEBUG:
- print("_setBrush")
+ _logger.debug("_setBrush")
if self.__brushMenu is None:
self.__brushMenu = qt.QMenu()
self.__brushMenu.addAction(QString(" 1 Image Pixel Width"),
@@ -1055,25 +1012,25 @@ class MaskImageWidget(qt.QWidget):
self.__brushWidth = 20
def _toggleSelectionMode(self):
- drawMode = self.graphWidget.graph.getDrawMode()
- if drawMode is None:
+ mode = self.graphWidget.graph.getInteractiveMode()
+ if mode['mode'] != 'draw':
# we are not drawing anything
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
# we have to pass to mask mode
self.setSelectionMode(True)
else:
# we set zoom mode and show the line icons
self.setSelectionMode(False)
- elif drawMode['label'] is not None:
- if drawMode['label'].startswith('mask'):
- #we set the zoom mode and show the line icons
+ elif mode['label'] is not None:
+ if mode['label'].startswith('mask'):
+ # we set the zoom mode and show the line icons
self.setSelectionMode(False)
else:
# we disable zoom and drawing and set mask mode
self.setSelectionMode(True)
- elif drawMode['label'] in [None]:
+ elif mode['label'] in [None]:
# we are not drawing anything
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
# we have to pass to mask mode
self.setSelectionMode(True)
else:
@@ -1085,17 +1042,17 @@ class MaskImageWidget(qt.QWidget):
#if not self.__imageIconsFlag:
# mode = False
if mode:
- self.graphWidget.graph.setDrawModeEnabled(True,
- 'rectangle',
+ self.graphWidget.graph.setInteractiveMode('draw',
+ shape='rectangle',
label='mask')
- self.__brushMode = False
+ self.__brushMode = False
self.graphWidget.hideProfileSelectionIcons()
self.graphWidget.selectionToolButton.setChecked(True)
self.graphWidget.selectionToolButton.setDown(True)
self.graphWidget.showImageIcons()
else:
self.graphWidget.showProfileSelectionIcons()
- self.graphWidget.graph.setZoomModeEnabled(True)
+ self.graphWidget.graph.setInteractiveMode('zoom')
self.graphWidget.selectionToolButton.setChecked(False)
self.graphWidget.selectionToolButton.setDown(False)
self.graphWidget.hideImageIcons()
@@ -1169,8 +1126,7 @@ class MaskImageWidget(qt.QWidget):
self._resetSelection(True)
def _resetSelection(self, owncall=True):
- if DEBUG:
- print("_resetSelection")
+ _logger.debug("_resetSelection")
self.__selectionMask = None
if self.__imageData is None:
return
@@ -1210,8 +1166,8 @@ class MaskImageWidget(qt.QWidget):
if data is None:
self.__imageData = data
self.__selectionMask = None
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
return
else:
self.__imageData = data
@@ -1226,8 +1182,8 @@ class MaskImageWidget(qt.QWidget):
self.colormapDialog.setDisplayedMaxValue(maxData)
self.colormapDialog.setDataMinMax(minData, maxData, update=True)
else:
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
def getImageData(self):
return self.__imageData
@@ -1282,8 +1238,8 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap0 = pixmap
if clearmask:
self.__selectionMask = None
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
def plotImage(self, update=True):
if self.__imageData is None:
@@ -1295,13 +1251,14 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap0 = self.__pixmap.copy()
self.__applyMaskToImage()
- # replot=False as it triggers a zoom reset in Plot.py
+ origin, scale = None, None
+ if self._xScale is not None:
+ origin = (self._xScale[0], self._yScale[0])
+ scale = (self._xScale[1], self._yScale[1])
self.graphWidget.graph.addImage(self.__pixmap,
- "image",
- xScale=self._xScale,
- yScale=self._yScale,
- replot=False)
- self.graphWidget.graph.replot()
+ "image", resetzoom=False,
+ origin=origin,
+ scale=scale)
self.updateProfileSelectionWindow()
def getPixmapFromData(self):
@@ -1535,18 +1492,15 @@ class MaskImageWidget(qt.QWidget):
alteration = (1 - (0.2 * (self.__selectionMask > 0))) - \
0.1 * (self.__selectionMask == self._roiTags[self._nRoi - 1])
if self.colormap is None:
- if DEBUG:
- print("Colormap is None")
+ _logger.debug("Colormap is None")
if self.__image is not None:
if self.__image.format() == qt.QImage.Format_ARGB32:
- if DEBUG:
- print("__applyMaskToImage CASE 1")
+ _logger.debug("__applyMaskToImage CASE 1")
for i in range(4):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] *\
alteration).astype(numpy.uint8)
else:
- if DEBUG:
- print("__applyMaskToImage CASE 2")
+ _logger.debug("__applyMaskToImage CASE 2")
self.__pixmap = self.__pixmap0.copy()
tmp = self.__selectionMask > 0
self.__pixmap[tmp, 0] = 0x40
@@ -1559,8 +1513,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[roiTag, 3] = 2*0x40
else:
if self.__defaultColormap > 1:
- if DEBUG:
- print("__applyMaskToImage CASE 3")
+ _logger.debug("__applyMaskToImage CASE 3")
self.__pixmap = self.__pixmap0.copy()
for i in range(3):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] *\
@@ -1573,8 +1526,7 @@ class MaskImageWidget(qt.QWidget):
for i in range(3):
self.__pixmap[:,:,i] *= tmpMask
else:
- if DEBUG:
- print("__applyMaskToImage CASE 4")
+ _logger.debug("__applyMaskToImage CASE 4")
self.__pixmap = self.__pixmap0.copy()
self.__pixmap[self.__selectionMask>0,0] = 0x40
self.__pixmap[self.__selectionMask>0,2] = 0x70
@@ -1594,8 +1546,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[tmpMask,2] = 0xff
self.__pixmap[tmpMask,3] = 0xff
elif int(str(self.colormap[0])) > 1: #color
- if DEBUG:
- print("__applyMaskToImage CASE 5")
+ _logger.debug("__applyMaskToImage CASE 5")
for i in range(3):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] * alteration)
if 0:
@@ -1606,8 +1557,7 @@ class MaskImageWidget(qt.QWidget):
for i in range(3):
self.__pixmap[:,:,i] *= tmpMask
elif self._maxNRois > 1:
- if DEBUG:
- print("__applyMaskToImage CASE 6")
+ _logger.debug("__applyMaskToImage CASE 6")
tmp = 1 - (self.__selectionMask>0)
tmp2 = (self.__selectionMask == self._roiTags[self._nRoi - 1])
self.__pixmap[:, :, 2] = (0x70 * (self.__selectionMask>0) + \
@@ -1616,8 +1566,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[:,:, 3] = (0x40 * (self.__selectionMask>0) + 0x40 * tmp2) +\
tmp * self.__pixmap0[:,:,3]
else:
- if DEBUG:
- print("__applyMaskToImage CASE 7")
+ _logger.debug("__applyMaskToImage CASE 7")
self.__pixmap = self.__pixmap0.copy()
tmp = 1 - self.__selectionMask
self.__pixmap[:, :, 2] = (0x70 * self.__selectionMask) +\
@@ -1802,7 +1751,7 @@ class MaskImageWidget(qt.QWidget):
elif self.__pixmap0 is not None:
imageShape = self.__pixmap0.shape[0:2]
else:
- print("Cannot handle polygon mask")
+ _logger.warning("Cannot handle polygon mask")
return
x = self._xScale[0] + self._xScale[1] * numpy.arange(imageShape[1])
y = self._yScale[0] + self._yScale[1] * numpy.arange(imageShape[0])
@@ -1888,8 +1837,7 @@ class MaskImageWidget(qt.QWidget):
if ownsignal:
pass
if None in [ddict['x'], ddict['y']]:
- if DEBUG:
- print("Signal from outside region", ddict)
+ _logger.debug("Signal from outside region %s", ddict)
return
if self.graphWidget.infoWidget.isHidden() or self.__brushMode:
@@ -1948,7 +1896,7 @@ class MaskImageWidget(qt.QWidget):
self.setMouseText("%g, %g, %g" % (x, y, self.__imageData[row, column]))
if self.__brushMode:
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
return
if ddict['button'] != "left":
return
@@ -1982,9 +1930,8 @@ class MaskImageWidget(qt.QWidget):
self.sigMaskImageWidgetSignal.emit(ddict)
def _zoomResetSignal(self):
- if DEBUG:
- print("_zoomResetSignal")
- self.graphWidget._zoomReset(replot=False)
+ _logger.debug("_zoomResetSignal")
+ self.graphWidget.graph.resetZoom()
self.plotImage(True)
def getOutputFileName(self):
@@ -1996,7 +1943,8 @@ class MaskImageWidget(qt.QWidget):
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setAcceptMode(qt.QFileDialog.AcceptSave)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict["gioconda16"])))
- formatlist = ["ASCII Files *.dat",
+ formatlist = ["TIFF Files *.tif",
+ "ASCII Files *.dat",
"EDF Files *.edf",
'CSV(, separated) Files *.csv',
'CSV(; separated) Files *.csv',
@@ -2008,7 +1956,7 @@ class MaskImageWidget(qt.QWidget):
for f in formatlist:
strlist.append(f)
if self._saveFilter is None:
- self._saveFilter =formatlist[0]
+ self._saveFilter = formatlist[0]
if hasattr(filedialog, "setFilters"):
filedialog.setFilters(strlist)
filedialog.selectFilter(self._saveFilter)
@@ -2027,12 +1975,12 @@ class MaskImageWidget(qt.QWidget):
self._saveFilter = qt.safe_str(filedialog.selectedFilter())
else:
self._saveFilter = qt.safe_str(filedialog.selectedNameFilter())
- filterused = "."+self._saveFilter[-3:]
+ filterused = "." + self._saveFilter[-3:]
PyMcaDirs.outputDir = os.path.dirname(filename)
if len(filename) < 4:
- filename = filename+ filterused
+ filename = filename + filterused
elif filename[-4:] != filterused :
- filename = filename+ filterused
+ filename = filename + filterused
else:
filename = ""
return filename
@@ -2063,10 +2011,15 @@ class MaskImageWidget(qt.QWidget):
return
if filename is None:
filename = self.getOutputFileName()
- if not len(filename):return
+ if not len(filename):
+ return
if filename.lower().endswith(".edf"):
ArraySave.save2DArrayListAsEDF(imageList, filename, labels)
+ elif filename.lower().endswith(".tif"):
+ ArraySave.save2DArrayListAsMonochromaticTiff(imageList,
+ filename,
+ labels)
elif filename.lower().endswith(".csv"):
if "," in self._saveFilter:
csvseparator = ","
diff --git a/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py b/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
index d9ece40..09fff5c 100644
--- a/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
+++ b/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
@@ -37,70 +37,109 @@ ___doc__ = """
- Final layer containing the selected points with the selected colors.
"""
-import sys
-import os
import numpy
+import logging
from PyMca5.PyMcaGraph.ctools import pnpoly
-DEBUG = 0
+_logger = logging.getLogger(__name__)
-from . import PlotWindow
from . import MaskImageWidget
from . import MaskImageTools
-qt = PlotWindow.qt
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from .MaskToolBar import MaskToolBar
+from . import ColormapDialog
+from .PyMca_Icons import IconDict
+
+from silx.gui.plot import PlotWindow
+
if hasattr(qt, "QString"):
QString = qt.QString
else:
QString = qt.safe_str
-IconDict = PlotWindow.IconDict
-class MaskScatterWidget(PlotWindow.PlotWindow):
+
+class MaskScatterWidget(PlotWindow):
sigMaskScatterWidgetSignal = qt.pyqtSignal(object)
DEFAULT_COLORMAP_INDEX = 2
DEFAULT_COLORMAP_LOG_FLAG = True
- def __init__(self, parent=None, backend=None, plugins=False, newplot=False,
- control=False, position=False, maxNRois=1, grid=False,
- logx=False, logy=False, togglePoints=False, normal=True,
- polygon=True, colormap=True, aspect=True,
- imageIcons=True, bins=None, **kw):
+ def __init__(self, parent=None, backend=None, control=False,
+ position=False, maxNRois=1, grid=False, logScale=False,
+ curveStyle=False, resetzoom=True,
+ aspectRatio=True, imageIcons=True, polygon=True, bins=None):
super(MaskScatterWidget, self).__init__(parent=parent,
backend=backend,
- plugins=plugins,
- newplot=newplot,
control=control,
position=position,
grid=grid,
- logx=logx,
- logy=logy,
- togglePoints=togglePoints,
- normal=normal,
- aspect=aspect,
- colormap=colormap,
- imageIcons=imageIcons,
- polygon=polygon,
- **kw)
- self._buildAdditionalSelectionMenuDict()
+ logScale=logScale,
+ curveStyle=curveStyle,
+ resetzoom=resetzoom,
+ aspectRatio=aspectRatio,
+ colormap=False,
+ mask=False,
+ yInverted=False,
+ roi=False,
+ copy=True,
+ print_=False)
+ if parent is None:
+ self.setWindowTitle("MaskScatterWidget")
+ self.setActiveCurveHandling(False)
+
+ # No context menu by default, execute zoomBack on right click
+ plotArea = self.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
+ self.colormapIcon = qt.QIcon(qt.QPixmap(IconDict["colormap"]))
+ self.colormapToolButton = qt.QToolButton(self.toolBar())
+ self.colormapToolButton.setIcon(self.colormapIcon)
+ self.colormapToolButton.setToolTip('Change Colormap')
+ self.colormapToolButton.clicked.connect(self._colormapIconSignal)
+ self.colormapAction = self.toolBar().insertWidget(self.getSaveAction(),
+ self.colormapToolButton)
+
+ self.maskToolBar = None
+ if polygon or imageIcons:
+ self.maskToolBar = MaskToolBar(parent=self,
+ plot=self,
+ imageIcons=imageIcons,
+ polygon=polygon)
+ self.addToolBar(self.maskToolBar)
+
self._selectionCurve = None
self._selectionMask = None
- self._selectionColors = numpy.zeros((len(self.colorList), 4), numpy.uint8)
self._alphaLevel = None
- for i in range(len(self.colorList)):
- self._selectionColors[i, 0] = eval("0x" + self.colorList[i][-2:])
- self._selectionColors[i, 1] = eval("0x" + self.colorList[i][3:-2])
- self._selectionColors[i, 2] = eval("0x" + self.colorList[i][1:3])
- self._selectionColors[i, 3] = 0xff
+ self._xScale = None
+ self._yScale = None
+
self._maxNRois = maxNRois
self._nRoi = 1
self._zoomMode = True
self._eraseMode = False
self._brushMode = False
self._brushWidth = 5
- self._brushMenu = None
self._bins = bins
self._densityPlotWidget = None
self._pixmap = None
+ self._imageData = None
+ self.colormapDialog = None
+ self.colormap = None
self.setPlotViewMode("scatter", bins=bins)
- self.setDrawModeEnabled(False)
+
+ def _colormapIconSignal(self):
+ image = self.getActiveImage()
+ if image is None:
+ return
+
+ if hasattr(image, "getColormap"):
+ if self.colormapDialog is None:
+ self._initColormapDialog(image.getData(),
+ image.getColormap()._toDict())
+ self.colormapDialog.show()
+ else:
+ # RGBA image
+ _logger.info("No colormap to be handled")
+ return
def setPlotViewMode(self, mode="scatter", bins=None):
if mode.lower() != "density":
@@ -110,41 +149,24 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def _activateScatterPlotView(self):
self._plotViewMode = "scatter"
- for key in ["colormap", "brushSelection", "brush"]:
- self.setToolBarActionVisible(key, False)
- if hasattr(self, "eraseSelectionToolButton"):
- self.eraseSelectionToolButton.setToolTip("Set erase mode if checked")
- self.eraseSelectionToolButton.setCheckable(True)
- if self._eraseMode:
- self.eraseSelectionToolButton.setChecked(True)
- else:
- self.eraseSelectionToolButton.setChecked(False)
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setCheckable(True)
- if hasattr(self, "rectSelectionToolButton"):
- self.rectSelectionToolButton.setCheckable(True)
- if hasattr(self, "brushSelectionToolButton"):
- if self.brushSelectionToolButton.isChecked():
- self.brushSelectionToolButton.setChecked(False)
- self._brushMode = False
- self.setZoomModeEnabled(True)
+ self.colormapAction.setVisible(False)
+ self._brushMode = False
+ self.setInteractiveMode("select")
+
+ if hasattr(self, "maskToolBar"):
+ self.maskToolBar.activateScatterPlotView()
+
self.clearImages()
self._updatePlot()
def _activateDensityPlotView(self, bins=None):
self._plotViewMode = "density"
- for key in ["colormap", "brushSelection", "brush", "rectangle"]:
- self.setToolBarActionVisible(key, True)
- if hasattr(self, "eraseSelectionToolButton"):
- self.eraseSelectionToolButton.setCheckable(True)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setCheckable(True)
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setCheckable(True)
- if hasattr(self, "rectSelectionToolButton"):
- self.rectSelectionToolButton.setCheckable(True)
-
- if DEBUG:
+ self.colormapAction.setVisible(True)
+
+ if hasattr(self, "maskToolBar"):
+ self.maskToolBar.activateDensityPlotView()
+
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._densityPlotWidget is None:
self._densityPlotWidget = MaskImageWidget.MaskImageWidget(
imageicons=True,
@@ -166,7 +188,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y, = curve[0:2]
if bins is not None:
if type(bins) == type(1):
bins = (bins, bins)
@@ -175,7 +197,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
else:
bins = bins[0:2]
elif self._bins is None:
- bins = [int(x.size/ 10), int(y.size/10)]
+ bins = [int(x.size / 10), int(y.size/10)]
if bins[0] > 100:
bins[0] = 100
elif bins[0] < 2:
@@ -198,15 +220,14 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
#print("shape", image[0].shape, "image max min ", image[0].max(), image[0].min())
#print("deltaxmin and max", (self._binsX[1:] - self._binsX[:-1]).min(),
# (self._binsX[1:] - self._binsX[:-1]).max())
- deltaX = (self._binsX[1:]- self._binsX[:-1]).mean()
- deltaY = (self._binsY[1:]- self._binsY[:-1]).mean()
+ deltaX = (self._binsX[1:] - self._binsX[:-1]).mean()
+ deltaY = (self._binsY[1:] - self._binsY[:-1]).mean()
self._xScale = (x0, deltaX)
self._yScale = (y0, deltaY)
return image[0]
def _updateDensityPlot(self, bins=None):
- if DEBUG:
- print("_updateDensityPlot called")
+ _logger.debug("_updateDensityPlot called")
if self._densityPlotWidget is None:
return
curve = self.getCurve(self._selectionCurve)
@@ -234,8 +255,8 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
bins = self._bins
x0 = x.min()
y0 = y.min()
- deltaX = (x.max() - x0)/float(bins[0] - 1)
- deltaY = (y.max() - y0)/float(bins[1] - 1)
+ deltaX = (x.max() - x0) / float(bins[0] - 1)
+ deltaY = (y.max() - y0) / float(bins[1] - 1)
self.xScale = (x0, deltaX)
self.yScale = (y0, deltaY)
binsX = numpy.arange(bins[0]) * deltaX
@@ -244,27 +265,27 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._binsX = image[2]
self._binsY = image[1]
self._bins = bins
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
# this does not work properly
# update mask levels
if self._selectionMask is not None:
weights = self._selectionMask[:]
weights.shape = x.shape
if self._maxNRois > 1:
- print("BAD PATH")
+ _logger.debug("BAD PATH")
# this does not work properly yet
weightsSum = weights.sum(dtype=numpy.float64)
volume = (binsY[1] - binsY[0]) * (binsX[1] - binsX[0])
- mask = numpy.round(numpy.histogram2d(y, x,
- bins=(binsY, binsX),
- weights=weights,
- normed=True)[0] * weightsSum * volume).astype(numpy.uint8)
+ mask = numpy.round(numpy.histogram2d(y, x,
+ bins=(binsY, binsX),
+ weights=weights,
+ normed=True)[0] * weightsSum * volume).astype(numpy.uint8)
else:
#print("GOOD PATH")
- mask = numpy.histogram2d(y, x,
- bins=(binsY, binsX),
- weights=weights,
- normed=False)[0]
+ mask = numpy.histogram2d(y, x,
+ bins=(binsY, binsX),
+ weights=weights,
+ normed=False)[0]
mask[mask > 0] = 1
#print(mask.min(), mask.max())
self._densityPlotWidget.setSelectionMask(mask, plot=False)
@@ -275,7 +296,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
xScale=self.xScale,
yScale=self.yScale)
- # do not ovelay plot (yet)
+ # do not overlay plot (yet)
pixmap = self._densityPlotWidget.getPixmap() * 1
#pixmap[:, :, 3] = 128
#self.addImage(pixmap,
@@ -285,10 +306,84 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._imageData = image[0]
#raise NotImplemented("Density plot view not implemented yet")
+ def _initColormapDialog(self, imageData, colormap=None):
+ """Set-up the colormap dialog default values.
+
+ :param numpy.ndarray imageData: data used to init dialog.
+ :param dict colormap: Description of the colormap as a dict.
+ See :class:`PlotBackend` for details.
+ If None, use default values.
+ """
+ goodData = imageData[numpy.isfinite(imageData)]
+ if goodData.size > 0:
+ maxData = goodData.max()
+ minData = goodData.min()
+ else:
+ qt.QMessageBox.critical(self, "No Data",
+ "Image data does not contain any real value")
+ return
+
+ self.colormapDialog = ColormapDialog.ColormapDialog(self)
+
+ if colormap is None:
+ colormapIndex = self.DEFAULT_COLORMAP_INDEX
+ if colormapIndex == 6:
+ colormapIndex = 1
+ self.colormapDialog.setColormap(colormapIndex)
+ self.colormapDialog.setDataMinMax(minData, maxData)
+ self.colormapDialog.setAutoscale(1)
+ self.colormapDialog.setColormap(self.colormapDialog.colormapIndex)
+ # linear or logarithmic
+ self.colormapDialog.setColormapType(self.DEFAULT_COLORMAP_LOG_FLAG,
+ update=False)
+ else:
+ # Set-up colormap dialog from provided colormap dict
+ cmapList = ColormapDialog.colormapDictToList(colormap)
+ index, autoscale, vMin, vMax, dataMin, dataMax, cmapType = cmapList
+ self.colormapDialog.setColormap(index)
+ self.colormapDialog.setAutoscale(autoscale)
+ self.colormapDialog.setMinValue(vMin)
+ self.colormapDialog.setMaxValue(vMax)
+ self.colormapDialog.setDataMinMax(minData, maxData)
+ self.colormapDialog.setColormapType(cmapType, update=False)
+
+ self.colormap = self.colormapDialog.getColormap() # Is it used?
+ self.colormapDialog.setWindowTitle("Colormap Dialog")
+ self.colormapDialog.sigColormapChanged.connect(
+ self.updateActiveImageColormap)
+ self.colormapDialog._update()
+
+ def updateActiveImageColormap(self, colormap):
+ if len(colormap) == 1:
+ colormap = colormap[0]
+ # TODO: Once everything is ready to work with dict instead of
+ # list, we can remove this translation
+ plotBackendColormap = ColormapDialog.colormapListToDict(colormap)
+ self.setDefaultColormap(plotBackendColormap)
+
+ image = self.getActiveImage()
+ if image is None:
+ if self.colormapDialog is not None:
+ self.colormapDialog.hide()
+ return
+
+ if not hasattr(image, "getColormap"):
+ if self.colormapDialog is not None:
+ self.colormapDialog.hide()
+ return
+ pixmap = MaskImageTools.getPixmapFromData(image.getData(), colormap)
+ self.addImage(image.getData(), legend=image.getLegend(),
+ info=image.getInfo(),
+ pixmap=pixmap)
+
def setSelectionCurveData(self, x, y, legend=None, info=None,
- replot=True, replace=True, linestyle=" ", color=None,
- symbol=None, selectable=None, **kw):
- self.enableActiveCurveHandling(False)
+ replace=True, linestyle=" ", resetzoom=True,
+ color=None, symbol=None, selectable=None,
+ **kw):
+ if "replot" in kw:
+ _logger.warning("MaskScatterWidget.setSelectionCurveData: deprecated replot parameter")
+ resetzoom = kw["replot"] and resetzoom
+ self.setActiveCurveHandling(False)
if legend is None:
legend = "MaskScatterWidget"
if symbol is None:
@@ -309,9 +404,9 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
# the basic curve is drawn
self.addCurve(x=x, y=y, legend=legend, info=info,
- replace=replace, replot=False, linestyle=linestyle,
- color=color, symbol=symbol, selectable=selectable,z=0,
- **kw)
+ replace=replace, resetzoom=False, linestyle=linestyle,
+ color=color, symbol=symbol, selectable=selectable,
+ z=0, **kw)
self._selectionCurve = legend
# if view mode, draw the image
@@ -322,14 +417,18 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if self.colormapDialog is None:
self._initColormapDialog(imageData)
cmap = self.colormapDialog.getColormap()
- pixmap=MaskImageTools.getPixmapFromData(imageData,
- colormap=cmap)
+ pixmap = MaskImageTools.getPixmapFromData(imageData,
+ colormap=cmap)
+ origin, scale = (0., 0.), (1., 1.)
+ if self._xScale is not None and self._yScale is not None:
+ origin = self._xScale[0], self._yScale[0]
+ scale = self._xScale[1], self._yScale[1]
+
self.addImage(imageData, legend=legend + "density",
- xScale=self._xScale,
- yScale=self._yScale,
+ origin=origin, scale=scale,
z=0,
pixmap=pixmap,
- replot=False)
+ resetzoom=False)
self._imageData = imageData
self._pixmap = pixmap
@@ -339,26 +438,26 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if self._selectionMask.max():
hasMaskedData = True
- if hasMaskedData or (replace==False):
- self._updatePlot(replot=False)
+ if hasMaskedData or not replace:
+ self._updatePlot(resetzoom=False)
- # update the plot if it was requested
- if replot:
- self.replot()
+ # update the limits if it was requested
+ if resetzoom:
+ self.resetZoom()
if 0 :#or self._plotViewMode == "density":
# get the binned data
imageData = self.getDensityData()
# get the associated pixmap
- pixmap=MaskImageTools.getPixmapFromData(imageData)
+ pixmap = MaskImageTools.getPixmapFromData(imageData)
if 0:
self.addImage(imageData, legend=legend + "density",
- xScale=self._xScale,
- yScale=self._yScale,
- z=0,
- pixmap=pixmap,
- replot=True)
- if DEBUG:
+ xScale=self._xScale,
+ yScale=self._yScale,
+ z=0,
+ pixmap=pixmap,
+ resetzoom=True)
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._densityPlotWidget is None:
self._densityPlotWidget = MaskImageWidget.MaskImageWidget(
imageicons=True,
@@ -367,8 +466,8 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
aspect=True,
polygon=True)
self._updateDensityPlot()
- print("CLOSE = ", numpy.allclose(imageData, self._imageData))
- print("CLOSE PIXMAP = ", numpy.allclose(pixmap, self._pixmap))
+ _logger.debug("CLOSE = %s", numpy.allclose(imageData, self._imageData))
+ _logger.debug("CLOSE PIXMAP = %s", numpy.allclose(pixmap, self._pixmap))
self._imageData = imageData
self._pixmap = pixmap
#self._updatePlot()
@@ -403,14 +502,14 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def getSelectionMask(self):
if self._selectionMask is None:
if self._selectionCurve is not None:
- x, y, legend, info = self.getCurve(self._selectionCurve)
+ x, y = self.getCurve(self._selectionCurve)[0:2]
self._selectionMask = numpy.zeros(x.shape, numpy.uint8)
return self._selectionMask
- def _updatePlot(self, replot=True, replace=True):
+ def _updatePlot(self, resetzoom=False, replace=True):
if self._selectionCurve is None:
return
- x0, y0, legend, info = self.getCurve(self._selectionCurve)
+ x0, y0, legend, info = self.getCurve(self._selectionCurve)[0:4]
# make sure we work with views
x = x0[:]
y = y0[:]
@@ -423,16 +522,16 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
tmpMask = self._selectionMask[:]
tmpMask.shape = -1
for i in range(0, self._maxNRois + 1):
- colors[tmpMask == i, :] = self._selectionColors[i]
+ colors[tmpMask == i, :] = self.maskToolBar._selectionColors[i]
self.setSelectionCurveData(x, y, legend=legend, info=info,
#color=colors,
color="k",
linestyle=" ",
- replot=replot, replace=replace)
+ resetzoom=resetzoom, replace=replace)
else:
if self._selectionMask is None:
for i in range(1, self._maxNRois + 1):
- self.removeCurve(legend=legend + " %02d" % i, replot=False)
+ self.removeCurve(legend=legend + " %02d" % i)
else:
tmpMask = self._selectionMask[:]
tmpMask.shape = -1
@@ -446,77 +545,38 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
xMask = x[tmpMask == i]
yMask = y[tmpMask == i]
if xMask.size < 1:
- self.removeCurve(legend=legend + " %02d" % i,
- replot=False)
+ self.removeCurve(legend=legend + " %02d" % i)
continue
- color = self._selectionColors[i].copy()
+ color = self.maskToolBar._selectionColors[i].copy()
if useAlpha:
if len(color) == 4:
if type(color[3]) in [numpy.uint8, numpy.int]:
color[3] = self._alphaLevel
# a copy of the input info is needed in order not
# to set the main curve to that color
+
self.addCurve(xMask, yMask, legend=legend + " %02d" % i,
- info=info.copy(), color=color, linestyle=" ",
+ info=info.copy(), color=color,
+ ylabel=legend + " %02d" % i,
+ linestyle=" ", symbol="o",
selectable=False,
z=1,
- replot=False, replace=False)
- if replot:
- self.replot()
- #self.resetZoom()
+ resetzoom=False, replace=False)
+ if resetzoom:
+ self.resetZoom()
def setActiveRoiNumber(self, intValue):
if (intValue < 0) or (intValue > self._maxNRois):
raise ValueError("Value %d outside the interval [0, %d]" % (intValue, self._maxNRois))
self._nRoi = intValue
-
- def _eraseSelectionIconSignal(self):
- if self.eraseSelectionToolButton.isChecked():
- self._eraseMode = True
- else:
- self._eraseMode = False
-
- def _polygonIconSignal(self):
- if self.polygonSelectionToolButton.isChecked():
- self.setPolygonSelectionMode()
- else:
- self.setZoomModeEnabled(True)
-
- def _rectSelectionIconSignal(self):
- if DEBUG:
- print("_rectSelectionIconSignal")
- if self.rectSelectionToolButton.isChecked():
- self.setRectangularSelectionMode()
- else:
- self.setZoomModeEnabled(True)
-
- def setZoomModeEnabled(self, flag, color=None):
- if color is None:
- if hasattr(self, "colormapDialog"):
- if self.colormapDialog is None:
- color = "#00FFFF"
- else:
- cmap = self.colormapDialog.getColormap()
- if cmap[0] < 2:
- color = "#00FFFF"
- else:
- color = "black"
- super(MaskScatterWidget, self).setZoomModeEnabled(flag, color=color)
- if flag:
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- if hasattr(self,"brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
-
def _handlePolygonMask(self, points):
- if DEBUG:
- print("_handlePolygonMask called")
+ _logger.debug("_handlePolygonMask called")
if self._eraseMode:
value = 0
else:
value = self._nRoi
- x, y, legend, info = self.getCurve(self._selectionCurve)
+ x, y = self.getCurve(self._selectionCurve)[0:2]
x.shape = -1
y.shape = -1
currentMask = self.getSelectionMask()
@@ -533,12 +593,21 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setSelectionMask(currentMask, plot=True)
self._emitMaskChangedSignal()
+ def setMouseText(self, text=""):
+ try:
+ if text:
+ qt.QToolTip.showText(self.cursor().pos(),
+ text, self, qt.QRect())
+ else:
+ qt.QToolTip.hideText()
+ except:
+ _logger.warning("Error trying to show mouse text <%s>" % text)
+
def graphCallback(self, ddict):
- if DEBUG:
- print("MaskScatterWidget graphCallback", ddict)
+ _logger.debug("MaskScatterWidget graphCallback %s", ddict)
if ddict["event"] == "drawingFinished":
if ddict["parameters"]["shape"].lower() == "rectangle":
- points = numpy.zeros((5,2), dtype=ddict["points"].dtype)
+ points = numpy.zeros((5, 2), dtype=ddict["points"].dtype)
points[0] = ddict["points"][0]
points[1, 0] = ddict["points"][0, 0]
points[1, 1] = ddict["points"][1, 1]
@@ -553,7 +622,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if (self._plotViewMode == "density") and \
(self._imageData is not None):
shape = self._imageData.shape
- row, column = MaskImageTools.convertToRowAndColumn( \
+ row, column = MaskImageTools.convertToRowAndColumn(
ddict['x'],
ddict['y'],
shape,
@@ -601,7 +670,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
#self.setMouseText("%g, %g, %g" % (row, column, self.__imageData[rowMin, columnMin]))
#To show mouse coordinates:
#self.setMouseText("%g, %g, %g" % (ddict['x'], ddict['y'], self.__imageData[rowMin, columnMin]))
- if self._xScale is not None:
+ if self._xScale is not None and self._yScale is not None:
x = self._xScale[0] + column * self._xScale[1]
y = self._yScale[0] + row * self._yScale[1]
else:
@@ -610,7 +679,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setMouseText("%g, %g, %g" % (x, y, self._imageData[row, column]))
if self._brushMode:
- if self.isZoomModeEnabled():
+ if self.getInteractiveMode()['mode'] == 'zoom':
return
if ddict['button'] != "left":
return
@@ -632,103 +701,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
# the base implementation handles ROIs, mouse position and activeCurve
super(MaskScatterWidget, self).graphCallback(ddict)
- def _brushIconSignal(self):
- if DEBUG:
- print("brushIconSignal")
- if self._brushMenu is None:
- self._brushMenu = qt.QMenu()
- self._brushMenu.addAction(QString(" 1 Image Pixel Width"),
- self._setBrush1)
- self._brushMenu.addAction(QString(" 2 Image Pixel Width"),
- self._setBrush2)
- self._brushMenu.addAction(QString(" 3 Image Pixel Width"),
- self._setBrush3)
- self._brushMenu.addAction(QString(" 5 Image Pixel Width"),
- self._setBrush4)
- self._brushMenu.addAction(QString("10 Image Pixel Width"),
- self._setBrush5)
- self._brushMenu.addAction(QString("20 Image Pixel Width"),
- self._setBrush6)
- self._brushMenu.exec_(self.cursor().pos())
-
- def _brushSelectionIconSignal(self):
- if DEBUG:
- print("_setBrushSelectionMode")
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- self.setDrawModeEnabled(False)
- if self.brushSelectionToolButton.isChecked():
- self._brushMode = True
- self.setZoomModeEnabled(False)
- else:
- self._brushMode = False
- self.setZoomModeEnabled(True)
-
- def _setBrush1(self):
- self._brushWidth = 1
-
- def _setBrush2(self):
- self._brushWidth = 2
-
- def _setBrush3(self):
- self._brushWidth = 3
-
- def _setBrush4(self):
- self._brushWidth = 5
-
- def _setBrush5(self):
- self._brushWidth = 10
-
- def _setBrush6(self):
- self._brushWidth = 20
-
- def setRectangularSelectionMode(self):
- """
- Resets zoom mode and enters selection mode with the current active ROI index
- """
- self._zoomMode = False
- self._brushMode = False
- color = self._selectionColors[self._nRoi]
- # make sure the selection is made with a non transparent color
- if len(color) == 4:
- if type(color[-1]) in [numpy.uint8, numpy.int8]:
- color = color.copy()
- color[-1] = 255
- self.setDrawModeEnabled(True,
- shape="rectangle",
- label="mask",
- color=color)
- self.setZoomModeEnabled(False)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- if hasattr(self,"rectSelectionToolButton"):
- self.rectSelectionToolButton.setChecked(True)
-
- def setPolygonSelectionMode(self):
- """
- Resets zoom mode and enters selection mode with the current active ROI index
- """
- self._zoomMode = False
- self._brushMode = False
- color = self._selectionColors[self._nRoi]
- # make sure the selection is made with a non transparent color
- if len(color) == 4:
- if type(color[-1]) in [numpy.uint8, numpy.int8]:
- color = color.copy()
- color[-1] = 255
- self.setDrawModeEnabled(True, shape="polygon", label="mask",
- color=color)
- self.setZoomModeEnabled(False)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
- if hasattr(self,"rectSelectionToolButton"):
- self.rectSelectionToolButton.setChecked(False)
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(True)
-
- def setEraseSelectionMode(self, erase=True):
+ def setEraseSelectionMode(self, erase=True): # TODO: unused?
if erase:
self._eraseMode = True
else:
@@ -751,54 +724,11 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def emitMaskScatterWidgetSignal(self, ddict):
self.sigMaskScatterWidgetSignal.emit(ddict)
- def _imageIconSignal(self):
- self.__resetSelection()
-
- def _buildAdditionalSelectionMenuDict(self):
- self._additionalSelectionMenu = {}
- #scatter view menu
- menu = qt.QMenu()
- menu.addAction(QString("Density plot view"), self.__setDensityPlotView)
- menu.addAction(QString("Reset Selection"), self.__resetSelection)
- menu.addAction(QString("Invert Selection"), self._invertSelection)
- self._additionalSelectionMenu["scatter"] = menu
-
- # density view menu
- menu = qt.QMenu()
- menu.addAction(QString("Scatter plot view"), self.__setScatterPlotView)
- menu.addAction(QString("Reset Selection"), self.__resetSelection)
- menu.addAction(QString("Invert Selection"), self._invertSelection)
- menu.addAction(QString("I >= Colormap Max"), self._selectMax)
- menu.addAction(QString("Colormap Min < I < Colormap Max"),
- self._selectMiddle)
- menu.addAction(QString("I <= Colormap Min"), self._selectMin)
- menu.addAction(QString("Increase mask alpha"), self._increaseMaskAlpha)
- menu.addAction(QString("Decrease mask alpha"), self._decreaseMaskAlpha)
- self._additionalSelectionMenu["density"] = menu
-
- def __setScatterPlotView(self):
- self.setPlotViewMode(mode="scatter")
-
- def __setDensityPlotView(self):
- self.setPlotViewMode(mode="density")
-
- def _additionalIconSignal(self):
- if self._plotViewMode == "density": # and imageData is not none ...
- self._additionalSelectionMenu["density"].exec_(self.cursor().pos())
- else:
- self._additionalSelectionMenu["scatter"].exec_(self.cursor().pos())
-
- def __resetSelection(self):
- # Needed because receiving directly in _resetSelection it was passing
- # False as argument
- self._resetSelection(True)
-
def _resetSelection(self, owncall=True):
- if DEBUG:
- print("_resetSelection")
+ _logger.debug("_resetSelection")
if self._selectionMask is None:
- print("Selection mask is None, doing nothing")
+ _logger.info("Selection mask is None, doing nothing")
return
else:
self._selectionMask[:] = 0
@@ -870,19 +800,18 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._emitMaskChangedSignal()
def _setSelectionMaskFromDensityMask(self, densityPlotMask, update=None):
- if DEBUG:
- print("_setSelectionMaskFromDensityMask called")
+ _logger.debug("_setSelectionMaskFromDensityMask called")
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y = curve[0:2]
bins = self._bins
x0 = x.min()
y0 = y.min()
deltaX = (x.max() - x0)/float(bins[0])
deltaY = (y.max() - y0)/float(bins[1])
columns = numpy.digitize(x, self._binsX, right=True)
- columns[columns>=densityPlotMask.shape[1]] = \
+ columns[columns >= densityPlotMask.shape[1]] = \
densityPlotMask.shape[1] - 1
rows = numpy.digitize(y, self._binsY, right=True)
rows[rows>=densityPlotMask.shape[0]] = densityPlotMask.shape[0] - 1
@@ -907,8 +836,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setSelectionMask(view, plot=True)
def _densityPlotSlot(self, ddict):
- if DEBUG:
- print("_densityPlotSlot called")
+ _logger.debug("_densityPlotSlot called")
if ddict["event"] == "resetSelection":
self.__resetSelection()
return
@@ -918,13 +846,13 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y = curve[0:2]
bins = self._bins
x0 = x.min()
y0 = y.min()
deltaX = (x.max() - x0)/float(bins[0])
deltaY = (y.max() - y0)/float(bins[1])
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._selectionMask is None:
view = numpy.zeros(x.size, dtype=numpy.uint8)
else:
@@ -960,7 +888,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
view2[:] = values[:]
if self._selectionMask is not None:
view2.shape = self._selectionMask.shape
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if not numpy.allclose(view, view2):
a = view[:]
b = view2[:]
@@ -969,15 +897,15 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
c = 0
for i in range(a.size):
if a[i] != b[i]:
- print(i, "a = ", a[i], "b = ", b[i], "(x, y) = ", x[i], y[i])
+ _logger.debug("%d a = %s, b = %s, (x, y) = (%s, %s)",
+ i, a[i], b[i], x[i], y[i])
c += 1
if c > 10:
break
else:
- print("OK!!!")
+ _logger.debug("OK!!!")
self.setSelectionMask(view2)
-
def _initializeAlpha(self):
self._alphaLevel = 128
@@ -998,6 +926,15 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._alphaLevel = 2
self._updatePlot()
+ def setPolygonSelectionMode(self):
+ """
+ Resets zoom mode and enters selection mode with the current active ROI index
+ """
+ self.maskToolBar.setPolygonSelectionMode()
+
+ def _zoomBack(self, pos):
+ self.getLimitsHistory().pop()
+
if __name__ == "__main__":
backend = "matplotlib"
#backend = "opengl"
@@ -1006,7 +943,8 @@ if __name__ == "__main__":
print("Received: ", ddict)
x = numpy.arange(100.)
y = x * 1
- w = MaskScatterWidget(maxNRois=10, bins=(100,100), backend=backend)
+ w = MaskScatterWidget(maxNRois=10, bins=(100, 100), backend=backend,
+ control=True)
w.setSelectionCurveData(x, y, color="k", selectable=False)
import numpy.random
w.setSelectionMask(numpy.random.permutation(100) % 10)
diff --git a/PyMca5/PyMcaGui/plotting/MaskToolBar.py b/PyMca5/PyMcaGui/plotting/MaskToolBar.py
new file mode 100644
index 0000000..b53e81a
--- /dev/null
+++ b/PyMca5/PyMcaGui/plotting/MaskToolBar.py
@@ -0,0 +1,331 @@
+#/*##########################################################################
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""This module implements a plot toolbar with buttons to draw and erase masks.
+"""
+
+__author__ = "P. Knobel"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
+import numpy
+
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from .PyMca_Icons import IconDict
+
+from silx.gui import colors
+
+if hasattr(qt, "QString"):
+ QString = qt.QString
+else:
+ QString = qt.safe_str
+
+
+_COLORDICT = colors.COLORDICT
+# these are color RGBA strings '#0000ff'
+_COLORLIST = [_COLORDICT['black'],
+ _COLORDICT['blue'],
+ _COLORDICT['red'],
+ _COLORDICT['green'],
+ _COLORDICT['pink'],
+ _COLORDICT['yellow'],
+ _COLORDICT['brown'],
+ _COLORDICT['cyan'],
+ _COLORDICT['magenta'],
+ _COLORDICT['orange'],
+ _COLORDICT['violet'],
+ #_COLORDICT['bluegreen'],
+ _COLORDICT['grey'],
+ _COLORDICT['darkBlue'],
+ _COLORDICT['darkRed'],
+ _COLORDICT['darkGreen'],
+ _COLORDICT['darkCyan'],
+ _COLORDICT['darkMagenta'],
+ _COLORDICT['darkYellow'],
+ _COLORDICT['darkBrown']]
+
+
+class MaskToolBar(qt.QToolBar):
+ """Toolbar with buttons controlling the mask drawing and erasing
+ interactions on a :class:`MaskScatterWidget`, to select or deselect
+ data."""
+ # sigIconSignal = qt.pyqtSignal(object)
+ colorList = _COLORLIST
+
+ def __init__(self, parent=None, plot=None, title="Mask tools",
+ imageIcons=True, polygon=True):
+ super(MaskToolBar, self).__init__(title, parent)
+ assert plot is not None
+ assert imageIcons or polygon,\
+ "It makes no sense to build an empty mask toolbar"
+ self.plot = plot
+ self._brushMenu = None
+
+ self.polygonIcon = qt.QIcon(qt.QPixmap(IconDict["polygon"]))
+ self.imageIcon = qt.QIcon(qt.QPixmap(IconDict["image"]))
+ self.eraseSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["eraseselect"]))
+ self.rectSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["boxselect"]))
+ self.brushSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["brushselect"]))
+ self.brushIcon = qt.QIcon(qt.QPixmap(IconDict["brush"]))
+ self.additionalIcon = qt.QIcon(qt.QPixmap(IconDict["additionalselect"]))
+
+ self.polygonSelectionToolButton = qt.QToolButton(self)
+ self.imageToolButton = qt.QToolButton(self)
+ self.eraseSelectionToolButton = qt.QToolButton(self)
+ self.rectSelectionToolButton = qt.QToolButton(self)
+ self.brushSelectionToolButton = qt.QToolButton(self)
+ self.brushToolButton = qt.QToolButton(self)
+ self.additionalSelectionToolButton = qt.QToolButton(self)
+
+ self.polygonSelectionToolButton.setIcon(self.polygonIcon)
+ self.imageToolButton.setIcon(self.imageIcon)
+ self.eraseSelectionToolButton.setIcon(self.eraseSelectionIcon)
+ self.rectSelectionToolButton.setIcon(self.rectSelectionIcon)
+ self.brushSelectionToolButton.setIcon(self.brushSelectionIcon)
+ self.brushToolButton.setIcon(self.brushIcon)
+ self.additionalSelectionToolButton.setIcon(self.additionalIcon)
+
+ self.polygonSelectionToolButton.setToolTip('Polygon selection\n'
+ 'Click first point to finish')
+ self.imageToolButton.setToolTip('Reset')
+ self.eraseSelectionToolButton.setToolTip('Erase Selection')
+ self.rectSelectionToolButton.setToolTip('Rectangular Selection')
+ self.brushSelectionToolButton.setToolTip('Brush Selection')
+ self.brushToolButton.setToolTip('Brush Size')
+ self.additionalSelectionToolButton.setToolTip('Additional Selections Menu')
+
+ self.eraseSelectionToolButton.setCheckable(True)
+ self.polygonSelectionToolButton.setCheckable(True)
+ self.rectSelectionToolButton.setCheckable(True)
+ self.brushSelectionToolButton.setCheckable(True)
+
+ self.imageAction = self.addWidget(self.imageToolButton)
+ self.eraseSelectionAction = self.addWidget(self.eraseSelectionToolButton)
+ self.rectSelectionAction = self.addWidget(self.rectSelectionToolButton)
+ self.brushSelectionAction = self.addWidget(self.brushSelectionToolButton)
+ self.brushAction = self.addWidget(self.brushToolButton)
+ self.polygonSelectionAction = self.addWidget(self.polygonSelectionToolButton)
+ self.additionalSelectionAction = self.addWidget(self.additionalSelectionToolButton)
+
+ self.imageToolButton.clicked.connect(self._imageIconSignal)
+ self.eraseSelectionToolButton.clicked.connect(self._eraseSelectionIconSignal)
+ self.rectSelectionToolButton.clicked.connect(self._rectSelectionIconSignal)
+ self.brushSelectionToolButton.clicked.connect(self._brushSelectionIconSignal)
+ self.brushToolButton.clicked.connect(self._brushIconSignal)
+ self.polygonSelectionToolButton.clicked.connect(self._polygonIconSignal)
+ self.additionalSelectionToolButton.clicked.connect(self._additionalIconSignal)
+
+ if not imageIcons:
+ self.imageAction.setVisible(False)
+ self.eraseSelectionAction.setVisible(False)
+ self.rectSelectionAction.setVisible(False)
+ self.brushSelectionAction.setVisible(False)
+ self.brushAction.setVisible(False)
+ self.polygonSelectionAction.setVisible(False)
+ self.additionalSelectionAction.setVisible(False)
+
+ if not polygon:
+ self.polygonSelectionAction.setVisible(False)
+
+ self._buildAdditionalSelectionMenuDict()
+
+ # selection colors as a RBGA (uint8) array
+ self._selectionColors = numpy.zeros((len(self.colorList), 4), numpy.uint8)
+ for i in range(len(self.colorList)):
+ self._selectionColors[i, 0] = eval("0x" + self.colorList[i][-2:])
+ self._selectionColors[i, 1] = eval("0x" + self.colorList[i][3:-2])
+ self._selectionColors[i, 2] = eval("0x" + self.colorList[i][1:3])
+ self._selectionColors[i, 3] = 0xff
+
+ self.plot.sigInteractiveModeChanged.connect(self._interactiveModeChanged)
+
+ def activateScatterPlotView(self):
+ self.brushSelectionAction.setVisible(False)
+ self.brushAction.setVisible(False)
+ self.eraseSelectionAction.setToolTip("Set erase mode if checked")
+
+ self.eraseSelectionToolButton.setChecked(self.plot._eraseMode)
+ self.brushSelectionToolButton.setChecked(False)
+
+ def activateDensityPlotView(self):
+ self.brushSelectionAction.setVisible(True)
+ self.brushAction.setVisible(True)
+ self.rectSelectionAction.setVisible(True)
+
+ def _imageIconSignal(self, checked=False):
+ self.plot._resetSelection(owncall=True)
+
+ def _eraseSelectionIconSignal(self, checked=False):
+ self.plot._eraseMode = checked
+
+ def _getSelectionColor(self):
+ """Return a selection color as hex "#RRGGBBAA" string"""
+ rgba_color_array = self._selectionColors[self.plot._nRoi]
+ # make sure the selection is made with a non transparent color
+ if len(rgba_color_array) == 4:
+ rgba_color_array = rgba_color_array.copy()
+ rgba_color_array[-1] = 255
+
+ # convert to string
+ s = "#"
+ for channel_uint8_value in rgba_color_array:
+ s += "{:02x}".format(channel_uint8_value)
+ return s
+
+ def _polygonIconSignal(self, checked=False):
+ if checked:
+ self.plot.setInteractiveMode("draw", shape="polygon",
+ label="mask",
+ color=self._getSelectionColor())
+ self.plot._zoomMode = False
+ self.plot._brushMode = False
+
+ self.brushSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(True)
+ else:
+ self.plot.setInteractiveMode("select")
+ self._uncheckAllSelectionButtons()
+
+ def setPolygonSelectionMode(self):
+ """
+ Resets zoom mode and enters selection mode with the current active ROI index
+ """
+ self.polygonSelectionToolButton.setChecked(True)
+ self.polygonSelectionAction.trigger() # calls _polygonIconSignal
+
+ def _rectSelectionIconSignal(self, checked=False):
+ if checked:
+ self.plot._zoomMode = False
+ self.plot._brushMode = False
+ self.brushSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(True)
+
+ self.plot.setInteractiveMode("draw",
+ shape="rectangle",
+ label="mask",
+ color=self._getSelectionColor())
+ else:
+ self.plot.setInteractiveMode("select")
+ self._uncheckAllSelectionButtons()
+
+ def _brushSelectionIconSignal(self, checked=False):
+ self.polygonSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(False)
+ if checked:
+ self.plot._brushMode = True
+ self.plot.setInteractiveMode('select')
+ else:
+ self._brushMode = False
+
+ def _brushIconSignal(self, checked=False):
+ if self._brushMenu is None:
+ self._brushMenu = qt.QMenu()
+ self._brushMenu.addAction(QString(" 1 Image Pixel Width"),
+ self._setBrush1)
+ self._brushMenu.addAction(QString(" 2 Image Pixel Width"),
+ self._setBrush2)
+ self._brushMenu.addAction(QString(" 3 Image Pixel Width"),
+ self._setBrush3)
+ self._brushMenu.addAction(QString(" 5 Image Pixel Width"),
+ self._setBrush4)
+ self._brushMenu.addAction(QString("10 Image Pixel Width"),
+ self._setBrush5)
+ self._brushMenu.addAction(QString("20 Image Pixel Width"),
+ self._setBrush6)
+ self._brushMenu.exec_(self.cursor().pos())
+
+ def _setBrush1(self):
+ self.plot._brushWidth = 1
+
+ def _setBrush2(self):
+ self.plot._brushWidth = 2
+
+ def _setBrush3(self):
+ self.plot._brushWidth = 3
+
+ def _setBrush4(self):
+ self.plot._brushWidth = 5
+
+ def _setBrush5(self):
+ self.plot._brushWidth = 10
+
+ def _setBrush6(self):
+ self.plot._brushWidth = 20
+
+ def _buildAdditionalSelectionMenuDict(self):
+ self._additionalSelectionMenu = {}
+ #scatter view menu
+ menu = qt.QMenu()
+ menu.addAction(QString("Density plot view"), self.__setDensityPlotView)
+ menu.addAction(QString("Reset Selection"), self.__resetSelection)
+ menu.addAction(QString("Invert Selection"), self.plot._invertSelection)
+ self._additionalSelectionMenu["scatter"] = menu
+
+ # density view menu
+ menu = qt.QMenu()
+ menu.addAction(QString("Scatter plot view"), self.__setScatterPlotView)
+ menu.addAction(QString("Reset Selection"), self.__resetSelection)
+ menu.addAction(QString("Invert Selection"), self.plot._invertSelection)
+ menu.addAction(QString("I >= Colormap Max"), self.plot._selectMax)
+ menu.addAction(QString("Colormap Min < I < Colormap Max"),
+ self.plot._selectMiddle)
+ menu.addAction(QString("I <= Colormap Min"), self.plot._selectMin)
+ menu.addAction(QString("Increase mask alpha"), self.plot._increaseMaskAlpha)
+ menu.addAction(QString("Decrease mask alpha"), self.plot._decreaseMaskAlpha)
+
+ self._additionalSelectionMenu["density"] = menu
+
+ def __setScatterPlotView(self):
+ self.plot.setPlotViewMode(mode="scatter")
+
+ def __setDensityPlotView(self):
+ self.plot.setPlotViewMode(mode="density")
+
+ def __resetSelection(self):
+ self.plot._resetSelection(owncall=True)
+
+ def _additionalIconSignal(self, checked=False):
+ if self.plot._plotViewMode == "density": # and imageData is not none ...
+ self._additionalSelectionMenu["density"].exec_(self.cursor().pos())
+ else:
+ self._additionalSelectionMenu["scatter"].exec_(self.cursor().pos())
+
+ def _uncheckAllSelectionButtons(self):
+ self.brushSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(False)
+ self.brushSelectionToolButton.setChecked(False)
+
+ def _interactiveModeChanged(self, source):
+ if self.plot.getInteractiveMode()['mode'] != "draw":
+ self._uncheckAllSelectionButtons()
+
+ # def emitIconSignal(self, key, event="iconClicked"):
+ # ddict = {"key": key,
+ # "event": event}
+ # self.sigIconSignal.emit(ddict)
+
+
diff --git a/PyMca5/PyMcaGui/plotting/McaROIWidget.py b/PyMca5/PyMcaGui/plotting/McaROIWidget.py
index e49948e..5a2c663 100644
--- a/PyMca5/PyMcaGui/plotting/McaROIWidget.py
+++ b/PyMca5/PyMcaGui/plotting/McaROIWidget.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QString"):
@@ -41,7 +42,9 @@ QTVERSION = qt.qVersion()
from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaIO import ConfigDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
class McaROIWidget(qt.QWidget):
sigMcaROIWidgetSignal = qt.pyqtSignal(object)
@@ -109,8 +112,7 @@ class McaROIWidget(qt.QWidget):
self.mcaROITable.sigMcaROITableSignal.connect(self._forward)
def _add(self):
- if DEBUG:
- print("McaROIWidget._add")
+ _logger.debug("McaROIWidget._add")
ddict={}
ddict['event'] = "AddROI"
roilist, roidict = self.mcaROITable.getROIListAndDict()
@@ -409,8 +411,7 @@ class McaROITable(qt.QTableWidget):
else:
if currentroi in self.roidict.keys():
self.selectRow(self.roidict[currentroi]['line'])
- if DEBUG:
- print("Qt4 ensureCellVisible to be implemented")
+ _logger.debug("Qt4 ensureCellVisible to be implemented")
self.building = False
def addROI(self, roi, key=None):
@@ -472,8 +473,7 @@ class McaROITable(qt.QTableWidget):
ddict['row' ] = row
ddict['col' ] = col
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
row = 0
item = self.item(row, 0)
@@ -492,8 +492,7 @@ class McaROITable(qt.QTableWidget):
self._emitSelectionChangedSignal(row, 0)
def _cellChangedSlot(self, row, col):
- if DEBUG:
- print("_cellChangedSlot(%d, %d)" % (row, col))
+ _logger.debug("_cellChangedSlot(%d, %d)", row, col)
if self.building:
return
if col == 0:
@@ -513,8 +512,7 @@ class McaROITable(qt.QTableWidget):
except:
return
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
if QTVERSION < '4.0.0':
text = str(self.text(row, 0))
@@ -535,8 +533,7 @@ class McaROITable(qt.QTableWidget):
def nameSlot(self, row, col):
if col != 0: return
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
item = self.item(row, col)
if item is None:
@@ -572,8 +569,7 @@ class McaROITable(qt.QTableWidget):
col = var[1]
if col == 0:
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
row = 0
item = self.item(row, col)
diff --git a/PyMca5/PyMcaGui/plotting/PlotWidget.py b/PyMca5/PyMcaGui/plotting/PlotWidget.py
index d6282a8..4619feb 100644
--- a/PyMca5/PyMcaGui/plotting/PlotWidget.py
+++ b/PyMca5/PyMcaGui/plotting/PlotWidget.py
@@ -28,7 +28,9 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
+import logging
+import traceback
+
from PyMca5.PyMcaGraph import Plot
SVG = True
@@ -82,10 +84,21 @@ else:
if not hasattr(QtCore, "Signal"):
QtCore.Signal = QtCore.pyqtSignal
+
+_logger = logging.getLogger(__name__)
+
DEBUG = 0
if DEBUG:
+ _logger.setLevel(logging.DEBUG)
Plot.DEBUG = DEBUG
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.PlotWidget instead",
+ __name__)
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
+
+
class PlotWidget(QtGui.QMainWindow, Plot.Plot):
sigPlotSignal = QtCore.Signal(object)
diff --git a/PyMca5/PyMcaGui/plotting/PlotWindow.py b/PyMca5/PyMcaGui/plotting/PlotWindow.py
index 8dc46f7..b100f3e 100644
--- a/PyMca5/PyMcaGui/plotting/PlotWindow.py
+++ b/PyMca5/PyMcaGui/plotting/PlotWindow.py
@@ -1474,7 +1474,10 @@ class PlotWindow(PlotWidget.PlotWidget):
os.remove(filename)
if filterused[0].upper() == "WIDGET":
fformat = filename[-3:].upper()
- pixmap = qt.QPixmap.grabWidget(self)
+ if hasattr(qt.QPixmap,"grabWidget"):
+ pixmap = qt.QPixmap.grabWidget(self)
+ else:
+ pixmap = self.grab()
if not pixmap.save(filename, fformat):
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
diff --git a/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py b/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
index 93cc866..6b3d95a 100644
--- a/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
+++ b/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
@@ -34,7 +34,7 @@ if 1:
# if not, we miss profile fitting ...
from PyMca5.PyMcaGui.pymca.ScanWindow import ScanWindow as Window
else:
- from .PlotWindow import PlotWindow as Window
+ from silx.gui.plot import PlotWindow as Window
DEBUG = 0
class ProfileScanWidget(Window):
@@ -118,7 +118,7 @@ class ProfileScanWidget(Window):
elif action == 'REMOVE':
self.sigRemoveClicked.emit(ddict)
else:
- self.replaceAddClicked.emit(ddict)
+ self.sigReplaceClicked.emit(ddict)
def test():
app = qt.QApplication([])
diff --git a/PyMca5/PyMcaGui/plotting/PyMca_Icons.py b/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
index 56fdc97..ebb3f37 100644
--- a/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
+++ b/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
@@ -4177,9 +4177,22 @@ class _PatchedIconDict(MutableMapping):
# we also need to remove the key from internal translation table
del self._translation_table[key]
+
IconDict = _PatchedIconDict(IconDict0)
+def change_icons(plot):
+ """Replace some of the silx icons with PyMca icons.
+
+ :param plot: Silx plot window, or ScanWindow, or McaWindow
+ :return:
+ """
+ from PyMca5.PyMcaGui import PyMcaQt as qt
+ plot.getRoiAction().setIcon(qt.QIcon(qt.QPixmap(IconDict["roi"])))
+ if hasattr(plot, "printPreview"):
+ plot.printPreview.setIcon(qt.QIcon(qt.QPixmap(IconDict["fileprint"])))
+
+
def showIcons():
w = qt.QWidget()
g = qt.QGridLayout(w)
diff --git a/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py b/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
index 1a4608b..3734a52 100644
--- a/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
+++ b/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
@@ -28,7 +28,8 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
+import logging
+import traceback
from PyMca5.PyMcaGui import PyMcaQt as qt
DEBUG = 0
__revision__="$Revision: 1.7 $"
@@ -39,6 +40,14 @@ __revision__="$Revision: 1.7 $"
QTVERSION = qt.qVersion()
+_logger = logging.getLogger(__name__)
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.widgets.PrintPreview instead",
+ __name__)
+
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
+
################################################################################
################## PyMcaPrintPreview ###################
diff --git a/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py b/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
index bcaf7ae..24d874c 100644
--- a/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
+++ b/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
@@ -30,14 +30,24 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
-from . import PlotWidget
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
+from silx.gui.plot import PlotWidget
+from silx.gui.plot.PrintPreviewToolButton import SingletonPrintPreviewToolButton
from .PyMca_Icons import IconDict
-from . import PyMcaPrintPreview
from PyMca5.PyMcaCore import PyMcaDirs
+from silx.gui import icons as silx_icons
+
+if sys.version_info[0] == 3:
+ from io import BytesIO
+else:
+ import cStringIO as _StringIO
+ BytesIO = _StringIO.StringIO
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
def convertToRowAndColumn(x, y, shape, xScale=None, yScale=None, safe=True):
if xScale is None:
@@ -59,6 +69,7 @@ def convertToRowAndColumn(x, y, shape, xScale=None, yScale=None, safe=True):
r = int(r)
return r, c
+
class RGBCorrelatorGraph(qt.QWidget):
sigProfileSignal = qt.pyqtSignal(object)
@@ -71,17 +82,22 @@ class RGBCorrelatorGraph(qt.QWidget):
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.setSpacing(0)
self._keepDataAspectRatioFlag = False
+ self.graph = PlotWidget(parent=self, backend=backend)
+ self.graph.setGraphXLabel("Column")
+ self.graph.setGraphYLabel("Row")
+ self.graph.setYAxisAutoScale(True)
+ self.graph.setXAxisAutoScale(True)
+ plotArea = self.graph.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
self._buildToolBar(selection, colormap, imageicons,
standalonesave,
standalonezoom=standalonezoom,
profileselection=profileselection,
aspect=aspect,
polygon=polygon)
- self.graph = PlotWidget.PlotWidget(self, backend=backend, aspect=aspect)
- self.graph.setGraphXLabel("Column")
- self.graph.setGraphYLabel("Row")
- self.graph.setYAxisAutoScale(True)
- self.graph.setXAxisAutoScale(True)
+
if profileselection:
if len(self._pickerSelectionButtons):
self.graph.sigPlotSignal.connect(\
@@ -91,9 +107,6 @@ class RGBCorrelatorGraph(qt.QWidget):
self.saveDirectory = os.getcwd()
self.mainLayout.addWidget(self.graph)
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
- if DEBUG:
- print("printPreview id = %d" % id(self.printPreview))
def sizeHint(self):
return qt.QSize(1.5 * qt.QWidget.sizeHint(self).width(),
@@ -123,6 +136,7 @@ class RGBCorrelatorGraph(qt.QWidget):
self.hLineIcon = qt.QIcon(qt.QPixmap(IconDict["horizontal"]))
self.vLineIcon = qt.QIcon(qt.QPixmap(IconDict["vertical"]))
self.lineIcon = qt.QIcon(qt.QPixmap(IconDict["diagonal"]))
+ self.copyIcon = silx_icons.getQIcon("edit-copy")
self.toolBar = qt.QWidget(self)
self.toolBarLayout = qt.QHBoxLayout(self.toolBar)
@@ -160,16 +174,16 @@ class RGBCorrelatorGraph(qt.QWidget):
#Aspect ratio
if aspect:
self.aspectButton = self._addToolButton(self.solidCircleIcon,
- self._aspectButtonSignal,
- 'Keep data aspect ratio',
- toggle = False)
+ self._aspectButtonSignal,
+ 'Keep data aspect ratio',
+ toggle=False)
self.aspectButton.setChecked(False)
#colormap
if colormap:
tb = self._addToolButton(self.colormapIcon,
None,
- 'Change Colormap')
+ 'Change Colormap')
self.colormapToolButton = tb
#flip
@@ -190,6 +204,10 @@ class RGBCorrelatorGraph(qt.QWidget):
'Save')
self.saveToolButton = tb
+ self.copyToolButton = self._addToolButton(self.copyIcon,
+ self._copyIconSignal,
+ "Copy graph to clipboard")
+
#Selection
if selection:
tb = self._addToolButton(self.selectionIcon,
@@ -221,7 +239,6 @@ class RGBCorrelatorGraph(qt.QWidget):
'Brush Selection')
self.brushSelectionToolButton = tb
-
tb = self._addToolButton(self.brushIcon,
None,
'Select Brush')
@@ -292,7 +309,7 @@ class RGBCorrelatorGraph(qt.QWidget):
#self.lineWidthProfileButton = tb
#self._pickerSelectionButtons.append(tb)
if self._polygonSelection:
- print("Polygon selection not implemented yet")
+ _logger.info("Polygon selection not implemented yet")
#hide profile selection buttons
if imageicons:
for button in self._pickerSelectionButtons:
@@ -311,13 +328,13 @@ class RGBCorrelatorGraph(qt.QWidget):
self.toolBarLayout.addWidget(qt.HorizontalSpacer(self.toolBar))
# ---print
- tb = self._addToolButton(self.printIcon,
- self.printGraph,
- 'Prints the Graph')
+ self.printPreview = SingletonPrintPreviewToolButton(parent=self,
+ plot=self.graph)
+ self.printPreview.setIcon(self.printIcon)
+ self.toolBarLayout.addWidget(self.printPreview)
def _aspectButtonSignal(self):
- if DEBUG:
- print("_aspectButtonSignal")
+ _logger.debug("_aspectButtonSignal")
if self._keepDataAspectRatioFlag:
self.keepDataAspectRatio(False)
else:
@@ -332,7 +349,7 @@ class RGBCorrelatorGraph(qt.QWidget):
self._keepDataAspectRatioFlag = False
self.aspectButton.setIcon(self.solidCircleIcon)
self.aspectButton.setToolTip("Keep data aspect ratio")
- self.graph.keepDataAspectRatio(self._keepDataAspectRatioFlag)
+ self.graph.setKeepDataAspectRatio(self._keepDataAspectRatioFlag)
def showInfo(self):
self.infoWidget.show()
@@ -351,7 +368,7 @@ class RGBCorrelatorGraph(qt.QWidget):
else:
qt.QToolTip.hideText()
except:
- print("Error trying to show mouse text <%s>" % text)
+ _logger.warning("Error trying to show mouse text <%s>" % text)
def focusOutEvent(self, ev):
qt.QToolTip.hideText()
@@ -447,8 +464,8 @@ class RGBCorrelatorGraph(qt.QWidget):
button.hide()
self._pickerSelectionWidthLabel.hide()
self._pickerSelectionWidthValue.hide()
- #self.graph.setPickerSelectionModeOff()
- self.graph.setDrawModeEnabled(False)
+ if self.graph.getInteractiveMode()['mode'] == 'draw':
+ self.graph.setInteractiveMode('select')
def showProfileSelectionIcons(self):
if not len(self._pickerSelectionButtons):
@@ -471,8 +488,7 @@ class RGBCorrelatorGraph(qt.QWidget):
def _setPickerSelectionMode(self, mode=None):
if mode is None:
- self.graph.setDrawModeEnabled(False)
- self.graph.setZoomModeEnabled(True)
+ self.graph.setInteractiveMode('zoom')
else:
if mode == "HORIZONTAL":
shape = "hline"
@@ -480,8 +496,7 @@ class RGBCorrelatorGraph(qt.QWidget):
shape = "vline"
else:
shape = "line"
- self.graph.setZoomModeEnabled(False)
- self.graph.setDrawModeEnabled(True,
+ self.graph.setInteractiveMode('draw',
shape=shape,
label=mode)
ddict = {}
@@ -492,15 +507,14 @@ class RGBCorrelatorGraph(qt.QWidget):
self.sigProfileSignal.emit(ddict)
def _graphPolygonSignalReceived(self, ddict):
- if DEBUG:
- print("PolygonSignal Received")
- for key in ddict.keys():
- print(key, ddict[key])
+ _logger.debug("PolygonSignal Received")
+ for key in ddict.keys():
+ _logger.debug("%s: %s", key, ddict[key])
if ddict['event'] not in ['drawingProgress', 'drawingFinished']:
return
label = ddict['parameters']['label']
- if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']:
+ if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']:
return
ddict['mode'] = label
ddict['pixelwidth'] = self._pickerSelectionWidthValue.value()
@@ -531,32 +545,33 @@ class RGBCorrelatorGraph(qt.QWidget):
self._zoomReset()
def _zoomReset(self, replot=None):
- if DEBUG:
- print("_zoomReset")
- if replot is None:
- replot = True
+ _logger.debug("_zoomReset")
if self.graph is not None:
self.graph.resetZoom()
- if replot:
- self.graph.replot()
def _yAutoScaleToggle(self):
if self.graph is not None:
- if self.graph.isYAxisAutoScale():
- self.graph.setYAxisAutoScale(False)
- self.yAutoScaleToolButton.setDown(False)
- else:
- self.graph.setYAxisAutoScale(True)
- self.yAutoScaleToolButton.setDown(True)
+ self.yAutoScaleToolButton.setDown(
+ not self.graph.isYAxisAutoScale())
+ self.graph.setYAxisAutoScale(
+ not self.graph.isYAxisAutoScale())
def _xAutoScaleToggle(self):
if self.graph is not None:
- if self.graph.isXAxisAutoScale():
- self.graph.setXAxisAutoScale(False)
- self.xAutoScaleToolButton.setDown(False)
- else:
- self.graph.setXAxisAutoScale(True)
- self.xAutoScaleToolButton.setDown(True)
+ self.xAutoScaleToolButton.setDown(
+ not self.graph.isXAxisAutoScale())
+ self.graph.setXAxisAutoScale(
+ not self.graph.isXAxisAutoScale())
+
+ def _copyIconSignal(self):
+ pngFile = BytesIO()
+ self.graph.saveGraph(pngFile, fileFormat='png')
+ pngFile.flush()
+ pngFile.seek(0)
+ pngData = pngFile.read()
+ pngFile.close()
+ image = qt.QImage.fromData(pngData, 'png')
+ qt.QApplication.clipboard().setImage(image)
def _saveIconSignal(self):
self.saveDirectory = PyMcaDirs.outputDir
@@ -620,25 +635,26 @@ class RGBCorrelatorGraph(qt.QWidget):
return
if filetype.upper() == "IMAGE":
- self.saveGraphImage(outputFile, original = True)
+ self.saveGraphImage(outputFile, original=True)
elif filetype.upper() == "ZOOMEDIMAGE":
- self.saveGraphImage(outputFile, original = False)
+ self.saveGraphImage(outputFile, original=False)
else:
self.saveGraphWidget(outputFile)
- def saveGraphImage(self, filename, original = False):
+ def saveGraphImage(self, filename, original=False):
format_ = filename[-3:].upper()
- #This is the whole image, not the zoomed one ...
- rgbData, legend, info, pixmap = self.graph.getActiveImage()
+ activeImage = self.graph.getActiveImage()
+ rgbdata = activeImage.getRgbaImageData()
+ # silx to pymca scale convention (a + b x)
+ xScale = activeImage.getOrigin()[0], activeImage.getScale()[0]
+ yScale = activeImage.getOrigin()[1], activeImage.getScale()[1]
if original:
# save whole image
- bgrData = numpy.array(rgbData, copy=True)
- bgrData[:,:,0] = rgbData[:, :, 2]
- bgrData[:,:,2] = rgbData[:, :, 0]
+ bgradata = numpy.array(rgbdata, copy=True)
+ bgradata[:, :, 0] = rgbdata[:, :, 2]
+ bgradata[:, :, 2] = rgbdata[:, :, 0]
else:
- xScale = info.get("plot_xScale", None)
- yScale = info.get("plot_yScale", None)
- shape = rgbData.shape[:2]
+ shape = rgbdata.shape[:2]
xmin, xmax = self.graph.getGraphXLimits()
ymin, ymax = self.graph.getGraphYLimits()
# save zoomed image, for that we have to get the limits
@@ -652,16 +668,16 @@ class RGBCorrelatorGraph(qt.QWidget):
row1 += 1
if col1 < shape[1]:
col1 += 1
- tmpArray = rgbData[row0:row1, col0:col1, :]
- bgrData = numpy.array(tmpArray, copy=True, dtype=rgbData.dtype)
- bgrData[:,:,0] = tmpArray[:, :, 2]
- bgrData[:,:,2] = tmpArray[:, :, 0]
+ tmpArray = rgbdata[row0:row1, col0:col1, :]
+ bgradata = numpy.array(tmpArray, copy=True, dtype=rgbdata.dtype)
+ bgradata[:, :, 0] = tmpArray[:, :, 2]
+ bgradata[:, :, 2] = tmpArray[:, :, 0]
if self.graph.isYAxisInverted():
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32)
else:
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32).mirrored(False, True)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32).mirrored(False, True)
pixmap = qt.QPixmap.fromImage(qImage)
if pixmap.save(filename, format_):
return
@@ -669,10 +685,10 @@ class RGBCorrelatorGraph(qt.QWidget):
qt.QMessageBox.critical(self, "Save Error",
"%s" % sys.exc_info()[1])
return
-
+
def saveGraphWidget(self, filename):
format_ = filename[-3:].upper()
- if hasattr(qt.QPixmap, "graphWidget"):
+ if hasattr(qt.QPixmap, "grabWidget"):
# Qt4
pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle())
else:
@@ -691,20 +707,12 @@ class RGBCorrelatorGraph(qt.QWidget):
else:
return False
- def printGraph(self):
- if hasattr(qt.QPixmap, "grabWidget"):
- pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle())
- else:
- pixmap = self.graph.getWidgetHandle().grab()
- self.printPreview.addPixmap(pixmap)
- if self.printPreview.isReady():
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
-
def selectColormap(self):
qt.QMessageBox.information(self, "Open", "Not implemented (yet)")
+ def _zoomBack(self, pos):
+ self.graph.getLimitsHistory().pop()
+
class MyQLabel(qt.QLabel):
def __init__(self,parent=None,name=None,fl=0,bold=True, color= qt.Qt.red):
qt.QLabel.__init__(self,parent)
diff --git a/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py b/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
index e55aff9..8d95a0d 100644
--- a/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
+++ b/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
@@ -141,12 +141,12 @@ class ScatterPlotCorrelatorWidget(MaskScatterWidget.MaskScatterWidget):
self.setSelectionCurveData(x, y, legend=None,
color="k",
symbol=".",
- replot=False,
+ resetzoom=False,
replace=True,
xlabel=xLabel,
ylabel=yLabel,
selectable=False)
- self._updatePlot(replot=False, replace=True)
+ self._updatePlot(resetzoom=False, replace=True)
#matplotlib needs a zoom reset to update the scales
# that problem does not seem to be present with OpenGL
self.resetZoom()
diff --git a/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py b/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
index c8345ea..6df787a 100644
--- a/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
+++ b/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
@@ -1,5 +1,5 @@
# /*#########################################################################
-# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -112,7 +112,8 @@ def convertToRowAndColumn(x, y, shape,
class MyMaskToolsWidget(MaskToolsWidget):
"""Backport of the setSelectionMask behavior implemented in silx 0.6.0,
- to synchronize mask parameters with the active image."""
+ to synchronize mask parameters with the active image.
+ This widget must not be used with silx >= 0.6"""
def setSelectionMask(self, mask, copy=True):
"""Set the mask to a new array.
:param numpy.ndarray mask: The array to use for the mask.
@@ -157,7 +158,7 @@ class MyMaskToolsDockWidget(MaskToolsDockWidget):
"""
def __init__(self, parent=None, plot=None, name='Mask'):
super(MyMaskToolsDockWidget, self).__init__(parent, plot, name)
- if silx.version < "0.6":
+ if silx.version_info < (0, 6):
self.setWidget(MyMaskToolsWidget(plot=plot))
self.widget().sigMaskChanged.connect(self._emitSigMaskChanged)
@@ -206,6 +207,10 @@ class SaveImageListAction(qt.QAction):
if filename.lower().endswith(".edf"):
ArraySave.save2DArrayListAsEDF(imageList, filename, labels)
+ elif filename.lower().endswith(".tif"):
+ ArraySave.save2DArrayListAsMonochromaticTiff(imageList,
+ filename,
+ labels)
elif filename.lower().endswith(".csv"):
assert csvseparator is not None
ArraySave.save2DArrayListAsASCII(imageList, filename, labels,
@@ -267,7 +272,8 @@ class SaveImageListAction(qt.QAction):
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setAcceptMode(qt.QFileDialog.AcceptSave)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict["gioconda16"])))
- formatlist = ["ASCII Files *.dat",
+ formatlist = ["TIFF Files *.tif",
+ "ASCII Files *.dat",
"EDF Files *.edf",
'CSV(, separated) Files *.csv',
'CSV(; separated) Files *.csv',
@@ -307,8 +313,7 @@ class SaveImageListAction(qt.QAction):
class SaveMatplotlib(qt.QAction):
- """Save current image and mask (if any) in a :class:`MaskImageWidget`
- to EDF or CSV"""
+ """Save current image ho high quality graphics using matplotlib"""
def __init__(self, title, maskImageWidget):
super(SaveMatplotlib, self).__init__(QString(title),
maskImageWidget)
@@ -756,15 +761,16 @@ class SilxMaskImageWidget(qt.QMainWindow):
The mask can be cropped or padded to fit active image,
the returned shape is that of the active image.
"""
- if mask is None:
- mask = numpy.zeros_like(self._getMaskToolsDockWidget().getSelectionMask())
- if not len(mask):
- return
# disconnect temporarily to avoid infinite loop
self._getMaskToolsDockWidget().sigMaskChanged.disconnect(
self._emitMaskImageWidgetSignal)
- ret = self._getMaskToolsDockWidget().setSelectionMask(mask,
- copy=copy)
+ if mask is None and silx.version_info <= (0, 7, 0):
+ self._getMaskToolsDockWidget().resetSelectionMask()
+ ret = None
+ else:
+ # from silx 0.8 onwards, setSelectionMask(None) is supported
+ ret = self._getMaskToolsDockWidget().setSelectionMask(mask,
+ copy=copy)
self._getMaskToolsDockWidget().sigMaskChanged.connect(
self._emitMaskImageWidgetSignal)
return ret
@@ -775,7 +781,7 @@ class SilxMaskImageWidget(qt.QMainWindow):
:param bool copy: True (default) to get a copy of the mask.
If False, the returned array MUST not be modified.
:return: The array of the mask with dimension of the 'active' image.
- If there is no active image, an empty array is returned.
+ If there is no active image, None is returned.
:rtype: 2D numpy.ndarray of uint8
"""
return self._getMaskToolsDockWidget().getSelectionMask(copy=copy)
diff --git a/PyMca5/PyMcaGui/plotting/_ImageProfile.py b/PyMca5/PyMcaGui/plotting/_ImageProfile.py
index e57986c..0943317 100644
--- a/PyMca5/PyMcaGui/plotting/_ImageProfile.py
+++ b/PyMca5/PyMcaGui/plotting/_ImageProfile.py
@@ -37,9 +37,10 @@ Functions to extract a profile curve of a region of interest in an image.
# import ######################################################################
import numpy
+import logging
from PyMca5.PyMcaMath.fitting import SpecfitFuns
-DEBUG = 0
+_logger = logging.getLogger(__name__)
# utils #######################################################################
@@ -209,8 +210,7 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
coordsRange = row0, row1
if nPoints == 1: # all points are the same
- if DEBUG:
- print("START AND END POINT ARE THE SAME!!")
+ _logger.debug("START AND END POINT ARE THE SAME!!")
return None
# the coordinates of the reference points
@@ -249,9 +249,8 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
newRow0 = 0.0
newRow1 = - (col1 - col0) * sinalpha + (row1 - row0) * cosalpha
- if DEBUG:
- print("new X0 Y0 = %f, %f " % (newCol0, newRow0))
- print("new X1 Y1 = %f, %f " % (newCol1, newRow1))
+ _logger.debug("new X0 Y0 = %f, %f ", newCol0, newRow0)
+ _logger.debug("new X1 Y1 = %f, %f ", newCol1, newRow1)
tmpX = numpy.linspace(newCol0, newCol1,
nPoints).astype(numpy.float)
@@ -260,19 +259,19 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
rotMatrix[0, 1] = - sinalpha
rotMatrix[1, 0] = sinalpha
rotMatrix[1, 1] = cosalpha
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
# test if I recover the original points
testX = numpy.zeros((2, 1), numpy.float)
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X0 = %f" % (colRow[0, 0] + col0))
- print("Recovered Y0 = %f" % (colRow[1, 0] + row0))
- print("It should be = %f, %f" % (col0, row0))
+ _logger.debug("Recovered X0 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y0 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col0, row0)
testX[0, 0] = newCol1
testX[1, 0] = newRow1
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X1 = %f" % (colRow[0, 0] + col0))
- print("Recovered Y1 = %f" % (colRow[1, 0] + row0))
- print("It should be = %f, %f" % (col1, row1))
+ _logger.debug("Recovered X1 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y1 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col1, row1)
# find the drawing limits
testX = numpy.zeros((2, 4), numpy.float)
@@ -290,21 +289,18 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
for a in rowLimits0:
if (a >= image.shape[0]) or (a < 0):
- if DEBUG:
- print("outside row limits", a)
+ _logger.debug("outside row limits %s", a)
return None
for a in colLimits0:
if (a >= image.shape[1]) or (a < 0):
- if DEBUG:
- print("outside column limits", a)
+ _logger.debug("outside column limits %s", a)
return None
r0 = rowLimits0[0]
r1 = rowLimits0[1]
if r0 > r1:
- if DEBUG:
- print("r0 > r1", r0, r1)
+ _logger.debug("r0 > r1 %s %s", r0, r1)
raise ValueError("r0 > r1")
x = numpy.zeros((2, nPoints), numpy.float)
diff --git a/PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py b/PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py
index c03127c..3a6538e 100644
--- a/PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py
+++ b/PyMca5/PyMcaGui/pymca/EdfFileSimpleViewer.py
@@ -28,10 +28,11 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
from PyMca5.PyMcaGui import QSourceSelector
from PyMca5.PyMcaGui.pymca import QDataSource
@@ -59,9 +60,8 @@ class EdfFileSimpleViewer(qt.QWidget):
self._sourceSelectorSlot)
def _sourceSelectorSlot(self, ddict):
- if DEBUG:
- print("_sourceSelectorSlot(self, ddict)")
- print("ddict = ",ddict)
+ _logger.debug("_sourceSelectorSlot(self, ddict)")
+ _logger.debug("ddict = %s", ddict)
if ddict["event"] == "NewSourceSelected":
source = QDataSource.QDataSource(ddict["sourcelist"])
self.sourceList.append(source)
@@ -74,8 +74,7 @@ class EdfFileSimpleViewer(qt.QWidget):
found = 1
break
if not found:
- if DEBUG:
- print("WARNING: source not found")
+ _logger.debug("WARNING: source not found")
return
sourceType = source.sourceType
self.selectorWidget[sourceType].setDataSource(source)
@@ -86,8 +85,7 @@ class EdfFileSimpleViewer(qt.QWidget):
found = 1
break
if not found:
- if DEBUG:
- print("WARNING: source not found")
+ _logger.debug("WARNING: source not found")
return
sourceType = source.sourceType
del self.sourceList[self.sourceList.index(source)]
@@ -111,18 +109,19 @@ class EdfFileSimpleViewer(qt.QWidget):
def main():
import sys
import getopt
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
app=qt.QApplication(sys.argv)
winpalette = qt.QPalette(qt.QColor(230,240,249),qt.QColor(238,234,238))
app.setPalette(winpalette)
options=''
- longoptions=[]
+ longoptions=['logging=', 'debug=']
opts, args = getopt.getopt(
sys.argv[1:],
options,
longoptions)
- for opt,arg in opts:
- pass
- filelist=args
+
+ logging.basicConfig(level=getLoggingLevel(opts))
+ filelist = args
app.lastWindowClosed.connect(app.quit)
w=EdfFileSimpleViewer()
if len(filelist):
@@ -130,5 +129,6 @@ def main():
w.show()
app.exec_()
+
if __name__ == "__main__":
main()
diff --git a/PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py b/PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py
index ab104d7..4f2035c 100644
--- a/PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py
+++ b/PyMca5/PyMcaGui/pymca/ExternalImagesWindow.py
@@ -378,16 +378,13 @@ class ExternalImagesWindow(MaskImageWidget.MaskImageWidget):
if i == 0:
overlay = MaskImageWidget.OVERLAY_DRAW
replace = True
- if len(self.imageNames) == 1:
- replot = True
- else:
- replot = False
- elif i == (nImages -1):
+ replot = len(self.imageNames) == 1
+ elif i == (nImages - 1):
replot = True
- replace=False
+ replace = False
else:
replot = False
- replace= False
+ replace = False
curve = self._getProfileCurve(ddict, image=image, overlay=overlay)
if curve is None:
return
@@ -396,7 +393,7 @@ class ExternalImagesWindow(MaskImageWidget.MaskImageWidget):
self._profileSelectionWindow.addCurve(xdata, ydata,
legend=newLegend,
info=info,
- replot=replot,
+ resetzoom=replot,
replace=replace)
def getCurrentIndex(self):
diff --git a/PyMca5/PyMcaGui/pymca/LegacyScanWindow.py b/PyMca5/PyMcaGui/pymca/LegacyScanWindow.py
new file mode 100644
index 0000000..db1053c
--- /dev/null
+++ b/PyMca5/PyMcaGui/pymca/LegacyScanWindow.py
@@ -0,0 +1,1591 @@
+#/*##########################################################################
+# Copyright (C) 2004-2018 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""Legacy PyMca ScanWindow, to be replaced by a ScanWindow based on a
+silx PlotWidget.
+This module should not be used anywhere, it will no longer be maintained."""
+__author__ = "V.A. Sole - ESRF Data Analysis"
+__contact__ = "sole@esrf.fr"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import sys
+import os
+import numpy
+#from numpy import argsort, nonzero, take
+import time
+import traceback
+from PyMca5.PyMcaGui import PyMcaQt as qt
+if hasattr(qt, 'QString'):
+ QString = qt.QString
+else:
+ QString = qt.safe_str
+if __name__ == "__main__":
+ app = qt.QApplication([])
+
+from PyMca5.PyMcaGui.io import PyMcaFileDialogs
+from PyMca5.PyMcaGui.plotting import PlotWindow
+from . import ScanFit
+from PyMca5.PyMcaMath import SimpleMath
+from PyMca5.PyMcaCore import DataObject
+import copy
+from PyMca5.PyMcaGui.plotting import PyMcaPrintPreview
+from PyMca5.PyMcaCore import PyMcaDirs
+from . import ScanWindowInfoWidget
+#implement the plugins interface
+from PyMca5.PyMcaGui import QPyMcaMatplotlibSave1D
+MATPLOTLIB = True
+#force understanding of utf-8 encoding
+#otherways it cannot generate svg output
+try:
+ import encodings.utf_8
+except:
+ #not a big problem
+ pass
+
+PLUGINS_DIR = None
+try:
+ import PyMca5
+ if os.path.exists(os.path.join(os.path.dirname(PyMca5.__file__), "PyMcaPlugins")):
+ from PyMca5 import PyMcaPlugins
+ PLUGINS_DIR = os.path.dirname(PyMcaPlugins.__file__)
+ else:
+ directory = os.path.dirname(__file__)
+ while True:
+ if os.path.exists(os.path.join(directory, "PyMcaPlugins")):
+ PLUGINS_DIR = os.path.join(directory, "PyMcaPlugins")
+ break
+ directory = os.path.dirname(directory)
+ if len(directory) < 5:
+ break
+ userPluginsDirectory = PyMca5.getDefaultUserPluginsDirectory()
+ if userPluginsDirectory is not None:
+ if PLUGINS_DIR is None:
+ PLUGINS_DIR = userPluginsDirectory
+ else:
+ PLUGINS_DIR = [PLUGINS_DIR, userPluginsDirectory]
+except:
+ pass
+
+DEBUG = 0
+
+class ScanWindow(PlotWindow.PlotWindow):
+ def __init__(self, parent=None, name="Scan Window", specfit=None, backend=None,
+ plugins=True, newplot=True, roi=True, fit=True,
+ control=True, position=True, info=False, **kw):
+
+ super(ScanWindow, self).__init__(parent,
+ newplot=newplot,
+ plugins=plugins,
+ backend=backend,
+ roi=roi,
+ fit=fit,
+ control=control,
+ position=position,
+ **kw)
+ self.setDataMargins(0, 0, 0.025, 0.025)
+ #self._togglePointsSignal()
+ self.setPanWithArrowKeys(True)
+ self.setWindowType("SCAN")
+ # this two objects are the same
+ self.dataObjectsList = self._curveList
+ # but this is tricky
+ self.dataObjectsDict = {}
+
+ self.setWindowTitle(name)
+ self.matplotlibDialog = None
+
+ if PLUGINS_DIR is not None:
+ if type(PLUGINS_DIR) == type([]):
+ pluginDir = PLUGINS_DIR
+ else:
+ pluginDir = [PLUGINS_DIR]
+ self.getPlugins(method="getPlugin1DInstance",
+ directoryList=pluginDir)
+
+ if info:
+ self.scanWindowInfoWidget = ScanWindowInfoWidget.\
+ ScanWindowInfoWidget()
+ self.infoDockWidget = qt.QDockWidget(self)
+ self.infoDockWidget.layout().setContentsMargins(0, 0, 0, 0)
+ self.infoDockWidget.setWidget(self.scanWindowInfoWidget)
+ self.infoDockWidget.setWindowTitle(self.windowTitle()+(" Info"))
+ self.addDockWidget(qt.Qt.BottomDockWidgetArea,
+ self.infoDockWidget)
+ controlMenu = qt.QMenu()
+ controlMenu.addAction(QString("Show/Hide Legends"),
+ self.toggleLegendWidget)
+ controlMenu.addAction(QString("Show/Hide Info"),
+ self._toggleInfoWidget)
+ controlMenu.addAction(QString("Toggle Crosshair"),
+ self.toggleCrosshairCursor)
+ controlMenu.addAction(QString("Toggle Arrow Keys Panning"),
+ self.toggleArrowKeysPanning)
+ self.setControlMenu(controlMenu)
+ else:
+ self.scanWindowInfoWidget = None
+ #self.fig = None
+ if fit:
+ self.scanFit = ScanFit.ScanFit(specfit=specfit)
+ self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
+ self.simpleMath = SimpleMath.SimpleMath()
+ self.outputDir = None
+ self.outputFilter = None
+
+ #signals
+ # this one was made in the base class
+ #self.setCallback(self.graphCallback)
+ if fit:
+ from PyMca5.PyMcaGui.math.fitting import SimpleFitGui
+ self.customFit = SimpleFitGui.SimpleFitGui()
+ self.scanFit.sigScanFitSignal.connect(self._scanFitSignalReceived)
+ self.customFit.sigSimpleFitSignal.connect( \
+ self._customFitSignalReceived)
+
+ self.fitButtonMenu = qt.QMenu()
+ self.fitButtonMenu.addAction(QString("Simple Fit"),
+ self._simpleFitSignal)
+ self.fitButtonMenu.addAction(QString("Customized Fit") ,
+ self._customFitSignal)
+
+ def _toggleInfoWidget(self):
+ if self.infoDockWidget.isHidden():
+ self.infoDockWidget.show()
+ legend = self.getActiveCurve(just_legend=True)
+ if legend is not None:
+ ddict ={}
+ ddict['event'] = "curveClicked"
+ ddict['label'] = legend
+ ddict['legend'] = legend
+ self.graphCallback(ddict)
+ else:
+ self.infoDockWidget.hide()
+
+ def _buildLegendWidget(self):
+ if self.legendWidget is None:
+ super(ScanWindow, self)._buildLegendWidget()
+ if hasattr(self, "infoDockWidget") and \
+ hasattr(self, "roiDockWidget"):
+ self.tabifyDockWidget(self.infoDockWidget,
+ self.roiDockWidget,
+ self.legendDockWidget)
+ elif hasattr(self, "infoDockWidget"):
+ self.tabifyDockWidget(self.infoDockWidget,
+ self.legendDockWidget)
+
+ def _toggleROI(self, position=None):
+ super(ScanWindow, self)._toggleROI(position=position)
+ if hasattr(self, "infoDockWidget"):
+ self.tabifyDockWidget(self.infoDockWidget,
+ self.roiDockWidget)
+
+ def setDispatcher(self, w):
+ w.sigAddSelection.connect(self._addSelection)
+ w.sigRemoveSelection.connect(self._removeSelection)
+ w.sigReplaceSelection.connect(self._replaceSelection)
+
+ def _addSelection(self, selectionlist, replot=True):
+ if DEBUG:
+ print("_addSelection(self, selectionlist)",selectionlist)
+ if type(selectionlist) == type([]):
+ sellist = selectionlist
+ else:
+ sellist = [selectionlist]
+
+ if len(self._curveList):
+ activeCurve = self.getActiveCurve(just_legend=True)
+ else:
+ activeCurve = None
+ nSelection = len(sellist)
+ for selectionIndex in range(nSelection):
+ sel = sellist[selectionIndex]
+ if selectionIndex == (nSelection - 1):
+ actualReplot = replot
+ else:
+ actualReplot = False
+ source = sel['SourceName']
+ key = sel['Key']
+ legend = sel['legend'] #expected form sourcename + scan key
+ if not ("scanselection" in sel): continue
+ if sel['scanselection'] == "MCA":
+ continue
+ if not sel["scanselection"]:continue
+ if len(key.split(".")) > 2: continue
+ dataObject = sel['dataobject']
+ #only one-dimensional selections considered
+ if dataObject.info["selectiontype"] != "1D": continue
+
+ #there must be something to plot
+ if not hasattr(dataObject, 'y'):
+ continue
+ if not hasattr(dataObject, 'x'):
+ ylen = len(dataObject.y[0])
+ if ylen:
+ xdata = numpy.arange(ylen).astype(numpy.float)
+ else:
+ #nothing to be plot
+ continue
+ if dataObject.x is None:
+ ylen = len(dataObject.y[0])
+ if ylen:
+ xdata = numpy.arange(ylen).astype(numpy.float)
+ else:
+ #nothing to be plot
+ continue
+ elif len(dataObject.x) > 1:
+ if DEBUG:
+ print("Mesh plots")
+ continue
+ else:
+ xdata = dataObject.x[0]
+ sps_source = False
+ if 'SourceType' in sel:
+ if sel['SourceType'] == 'SPS':
+ sps_source = True
+
+ if sps_source:
+ ycounter = -1
+ if 'selection' not in dataObject.info:
+ dataObject.info['selection'] = copy.deepcopy(sel['selection'])
+ for ydata in dataObject.y:
+ xlabel = None
+ ylabel = None
+ ycounter += 1
+ if dataObject.m is None:
+ mdata = [numpy.ones(len(ydata)).astype(numpy.float)]
+ elif len(dataObject.m[0]) > 0:
+ if len(dataObject.m[0]) == len(ydata):
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ #A priori the graph only knows about plots
+ ydata = ydata/mdata
+ else:
+ raise ValueError("Monitor data length different than counter data")
+ else:
+ mdata = [numpy.ones(len(ydata)).astype(numpy.float)]
+ ylegend = 'y%d' % ycounter
+ if dataObject.info['selection'] is not None:
+ if type(dataObject.info['selection']) == type({}):
+ if 'x' in dataObject.info['selection']:
+ #proper scan selection
+ ilabel = dataObject.info['selection']['y'][ycounter]
+ ylegend = dataObject.info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if sel['selection']['x'] is not None:
+ if len(dataObject.info['selection']['x']):
+ xlabel = dataObject.info['LabelNames'] \
+ [dataObject.info['selection']['x'][0]]
+ dataObject.info["xlabel"] = xlabel
+ dataObject.info["ylabel"] = ylabel
+ newLegend = legend + " " + ylegend
+ self.dataObjectsDict[newLegend] = dataObject
+ self.addCurve(xdata, ydata, legend=newLegend, info=dataObject.info,
+ xlabel=xlabel, ylabel=ylabel, replot=False)
+ # replot=actualReplot)
+ if self.scanWindowInfoWidget is not None:
+ if not self.infoDockWidget.isHidden():
+ activeLegend = self.getActiveCurve(just_legend=True)
+ if activeLegend is not None:
+ if activeLegend == newLegend:
+ self.scanWindowInfoWidget.updateFromDataObject\
+ (dataObject)
+ else:
+ dummyDataObject = DataObject.DataObject()
+ dummyDataObject.y=[numpy.array([])]
+ dummyDataObject.x=[numpy.array([])]
+ self.scanWindowInfoWidget.updateFromDataObject(dummyDataObject)
+ else:
+ #we have to loop for all y values
+ ycounter = -1
+ for ydata in dataObject.y:
+ ylen = len(ydata)
+ if ylen == 1:
+ if len(xdata) > 1:
+ ydata = ydata[0] * numpy.ones(len(xdata)).astype(numpy.float)
+ elif len(xdata) == 1:
+ xdata = xdata[0] * numpy.ones(ylen).astype(numpy.float)
+ ycounter += 1
+ newDataObject = DataObject.DataObject()
+ newDataObject.info = copy.deepcopy(dataObject.info)
+ if dataObject.m is None:
+ mdata = numpy.ones(len(ydata)).astype(numpy.float)
+ elif len(dataObject.m[0]) > 0:
+ if len(dataObject.m[0]) == len(ydata):
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ #A priori the graph only knows about plots
+ ydata = ydata/mdata
+ elif len(dataObject.m[0]) == 1:
+ mdata = numpy.ones(len(ydata)).astype(numpy.float)
+ mdata *= dataObject.m[0][0]
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ #A priori the graph only knows about plots
+ ydata = ydata/mdata
+ else:
+ raise ValueError("Monitor data length different than counter data")
+ else:
+ mdata = numpy.ones(len(ydata)).astype(numpy.float)
+ newDataObject.x = [xdata]
+ newDataObject.y = [ydata]
+ newDataObject.m = [mdata]
+ newDataObject.info['selection'] = copy.deepcopy(sel['selection'])
+ ylegend = 'y%d' % ycounter
+ xlabel = None
+ ylabel = None
+ if sel['selection'] is not None:
+ if type(sel['selection']) == type({}):
+ if 'x' in sel['selection']:
+ #proper scan selection
+ newDataObject.info['selection']['x'] = sel['selection']['x']
+ newDataObject.info['selection']['y'] = [sel['selection']['y'][ycounter]]
+ newDataObject.info['selection']['m'] = sel['selection']['m']
+ ilabel = newDataObject.info['selection']['y'][0]
+ ylegend = newDataObject.info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if len(newDataObject.info['selection']['x']):
+ ilabel = newDataObject.info['selection']['x'][0]
+ xlabel = newDataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = "Point number"
+ if ('operations' in dataObject.info) and len(dataObject.y) == 1:
+ newDataObject.info['legend'] = legend
+ symbol = 'x'
+ else:
+ symbol=None
+ newDataObject.info['legend'] = legend + " " + ylegend
+ newDataObject.info['selectionlegend'] = legend
+ yaxis = None
+ if "plot_yaxis" in dataObject.info:
+ yaxis = dataObject.info["plot_yaxis"]
+ elif 'operations' in dataObject.info:
+ if dataObject.info['operations'][-1] == 'derivate':
+ yaxis = 'right'
+ #print("sending legend = ", newDataObject.info['legend'], "replot = ", False)
+ self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
+ self.addCurve(xdata, ydata, legend=newDataObject.info['legend'],
+ info=newDataObject.info,
+ symbol=symbol,
+ yaxis=yaxis,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ replot=False)
+ self.dataObjectsList = self._curveList
+ try:
+ if activeCurve is None:
+ if len(self._curveList) > 0:
+ activeCurve = self._curveList[0]
+ ddict = {}
+ ddict['event'] = "curveClicked"
+ ddict['label'] = activeCurve
+ self.graphCallback(ddict)
+ finally:
+ if replot:
+ #self.replot()
+ self.resetZoom()
+ self.updateLegends()
+
+ def _removeSelection(self, selectionlist):
+ if DEBUG:
+ print("_removeSelection(self, selectionlist)",selectionlist)
+ if type(selectionlist) == type([]):
+ sellist = selectionlist
+ else:
+ sellist = [selectionlist]
+
+ removelist = []
+ for sel in sellist:
+ source = sel['SourceName']
+ key = sel['Key']
+ if not ("scanselection" in sel): continue
+ if sel['scanselection'] == "MCA":
+ continue
+ if not sel["scanselection"]:continue
+ if len(key.split(".")) > 2: continue
+
+ legend = sel['legend'] #expected form sourcename + scan key
+ if type(sel['selection']) == type({}):
+ if 'y' in sel['selection']:
+ for lName in ['cntlist', 'LabelNames']:
+ if lName in sel['selection']:
+ for index in sel['selection']['y']:
+ removelist.append(legend +" "+\
+ sel['selection'][lName][index])
+
+ if len(removelist):
+ self.removeCurves(removelist)
+
+ def removeCurves(self, removeList, replot=True):
+ for legend in removeList:
+ if legend == removeList[-1]:
+ self.removeCurve(legend, replot=replot)
+ else:
+ self.removeCurve(legend, replot=False)
+ if legend in self.dataObjectsDict:
+ del self.dataObjectsDict[legend]
+ self.dataObjectsList = self._curveList
+
+ def _replaceSelection(self, selectionlist):
+ if DEBUG:
+ print("_replaceSelection(self, selectionlist)",selectionlist)
+ if type(selectionlist) == type([]):
+ sellist = selectionlist
+ else:
+ sellist = [selectionlist]
+
+ doit = 0
+ for sel in sellist:
+ if not ("scanselection" in sel): continue
+ if sel['scanselection'] == "MCA":
+ continue
+ if not sel["scanselection"]:continue
+ if len(sel["Key"].split(".")) > 2: continue
+ dataObject = sel['dataobject']
+ if dataObject.info["selectiontype"] == "1D":
+ if hasattr(dataObject, 'y'):
+ doit = 1
+ break
+ if not doit:
+ return
+ self.clearCurves()
+ self.dataObjectsDict={}
+ self.dataObjectsList=self._curveList
+ self._addSelection(selectionlist, replot=True)
+
+ def _handleMarkerEvent(self, ddict):
+ if ddict['event'] == 'markerMoved':
+ label = ddict['label']
+ if label.startswith('ROI'):
+ return self._handleROIMarkerEvent(ddict)
+ else:
+ if DEBUG:
+ print("Unhandled marker %s" % label)
+ return
+
+ def graphCallback(self, ddict):
+ if DEBUG:
+ print("graphCallback", ddict)
+ if ddict['event'] in ['markerMoved', 'markerSelected']:
+ self._handleMarkerEvent(ddict)
+ elif ddict['event'] in ["mouseMoved", "MouseAt"]:
+ if self._toggleCounter > 0:
+ activeCurve = self.getActiveCurve()
+ if activeCurve in [None, []]:
+ self._handleMouseMovedEvent(ddict)
+ else:
+ x, y, legend, info = activeCurve[0:4]
+ # calculate the maximum distance
+ xMin, xMax = self.getGraphXLimits()
+ maxXDistance = abs(xMax - xMin)
+ yMin, yMax = self.getGraphYLimits()
+ maxYDistance = abs(yMax - yMin)
+ if (maxXDistance > 0.0) and (maxYDistance > 0.0):
+ closestIndex = (pow((x - ddict['x'])/maxXDistance, 2) + \
+ pow((y - ddict['y'])/maxYDistance, 2))
+ else:
+ closestIndex = (pow(x - ddict['x'], 2) + \
+ pow(y - ddict['y'], 2))
+ xText = '----'
+ yText = '----'
+ if len(closestIndex):
+ closestIndex = closestIndex.argmin()
+ xCurve = x[closestIndex]
+ if abs(xCurve - ddict['x']) < (0.05 * maxXDistance):
+ yCurve = y[closestIndex]
+ if abs(yCurve - ddict['y']) < (0.05 * maxYDistance):
+ xText = '%.7g' % xCurve
+ yText = '%.7g' % yCurve
+ if xText == '----':
+ if self.getGraphCursor():
+ self._xPos.setStyleSheet("color: rgb(255, 0, 0);")
+ self._yPos.setStyleSheet("color: rgb(255, 0, 0);")
+ xText = '%.7g' % ddict['x']
+ yText = '%.7g' % ddict['y']
+ else:
+ self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
+ self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
+ else:
+ self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
+ self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
+ self._xPos.setText(xText)
+ self._yPos.setText(yText)
+ else:
+ self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
+ self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
+ self._handleMouseMovedEvent(ddict)
+ elif ddict['event'] in ["curveClicked", "legendClicked"]:
+ legend = ddict["label"]
+ if legend is None:
+ if len(self.dataObjectsList):
+ legend = self.dataObjectsList[0]
+ else:
+ return
+ if legend not in self.dataObjectsList:
+ if DEBUG:
+ print("unknown legend %s" % legend)
+ return
+
+ #force the current x label to the appropriate value
+ dataObject = self.dataObjectsDict[legend]
+ if 'selection' in dataObject.info:
+ ilabel = dataObject.info['selection']['y'][0]
+ ylabel = dataObject.info['LabelNames'][ilabel]
+ if len(dataObject.info['selection']['x']):
+ ilabel = dataObject.info['selection']['x'][0]
+ xlabel = dataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = "Point Number"
+ if len(dataObject.info['selection']['m']):
+ ilabel = dataObject.info['selection']['m'][0]
+ ylabel += "/" + dataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = dataObject.info.get('xlabel', None)
+ ylabel = dataObject.info.get('ylabel', None)
+ if xlabel is not None:
+ self.setGraphXLabel(xlabel)
+ if ylabel is not None:
+ self.setGraphYLabel(ylabel)
+ self.setGraphTitle(legend)
+ self.setActiveCurve(legend)
+ #self.setGraphTitle(legend)
+ if self.scanWindowInfoWidget is not None:
+ if not self.infoDockWidget.isHidden():
+ self.scanWindowInfoWidget.updateFromDataObject\
+ (dataObject)
+ elif ddict['event'] == "removeCurveEvent":
+ legend = ddict['legend']
+ self.removeCurves([legend])
+ elif ddict['event'] == "renameCurveEvent":
+ legend = ddict['legend']
+ newlegend = ddict['newlegend']
+ if legend in self.dataObjectsDict:
+ self.dataObjectsDict[newlegend]= copy.deepcopy(self.dataObjectsDict[legend])
+ self.dataObjectsDict[newlegend].info['legend'] = newlegend
+ self.dataObjectsList.append(newlegend)
+ self.removeCurves([legend], replot=False)
+ self.newCurve(self.dataObjectsDict[newlegend].x[0],
+ self.dataObjectsDict[newlegend].y[0],
+ legend=self.dataObjectsDict[newlegend].info['legend'])
+
+ #make sure the plot signal is forwarded because we have overwritten
+ #its handling
+ self.sigPlotSignal.emit(ddict)
+
+
+ def _customFitSignalReceived(self, ddict):
+ if ddict['event'] == "FitFinished":
+ newDataObject = self.__customFitDataObject
+
+ xplot = ddict['x']
+ yplot = ddict['yfit']
+ newDataObject.x = [xplot]
+ newDataObject.y = [yplot]
+ newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
+
+ #here I should check the log or linear status
+ self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
+ self.addCurve(xplot,
+ yplot,
+ legend=newDataObject.info['legend'])
+
+ def _scanFitSignalReceived(self, ddict):
+ if DEBUG:
+ print("_scanFitSignalReceived", ddict)
+ if ddict['event'] == "EstimateFinished":
+ return
+ if ddict['event'] == "FitFinished":
+ newDataObject = self.__fitDataObject
+
+ xplot = self.scanFit.specfit.xdata * 1.0
+ yplot = self.scanFit.specfit.gendata(parameters=ddict['data'])
+ newDataObject.x = [xplot]
+ newDataObject.y = [yplot]
+ newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
+
+ self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
+ self.addCurve(x=xplot, y=yplot, legend=newDataObject.info['legend'])
+
+ def _fitIconSignal(self):
+ if DEBUG:
+ print("_fitIconSignal")
+ self.fitButtonMenu.exec_(self.cursor().pos())
+
+ def _simpleFitSignal(self):
+ if DEBUG:
+ print("_simpleFitSignal")
+ self._QSimpleOperation("fit")
+
+ def _customFitSignal(self):
+ if DEBUG:
+ print("_customFitSignal")
+ self._QSimpleOperation("custom_fit")
+
+ def _saveIconSignal(self):
+ if DEBUG:
+ print("_saveIconSignal")
+ self._QSimpleOperation("save")
+
+ def _averageIconSignal(self):
+ if DEBUG:
+ print("_averageIconSignal")
+ self._QSimpleOperation("average")
+
+ def _smoothIconSignal(self):
+ if DEBUG:
+ print("_smoothIconSignal")
+ self._QSimpleOperation("smooth")
+
+ def _getOutputFileName(self):
+ #get outputfile
+ self.outputDir = PyMcaDirs.outputDir
+ if self.outputDir is None:
+ self.outputDir = os.getcwd()
+ wdir = os.getcwd()
+ elif os.path.exists(self.outputDir):
+ wdir = self.outputDir
+ else:
+ self.outputDir = os.getcwd()
+ wdir = self.outputDir
+
+ filterlist = ['Specfile MCA *.mca',
+ 'Specfile Scan *.dat',
+ 'Specfile MultiScan *.dat',
+ 'Raw ASCII *.txt',
+ '","-separated CSV *.csv',
+ '";"-separated CSV *.csv',
+ '"tab"-separated CSV *.csv',
+ 'OMNIC CSV *.csv',
+ 'Widget PNG *.png',
+ 'Widget JPG *.jpg',
+ 'Graphics PNG *.png',
+ 'Graphics EPS *.eps',
+ 'Graphics SVG *.svg']
+ fileList, fileFilter = PyMcaFileDialogs.getFileList(self,
+ filetypelist=filterlist,
+ message="Output File Selection",
+ currentdir=wdir,
+ single=True,
+ mode="SAVE",
+ getfilter=True,
+ currentfilter=self.outputFilter)
+ if not len(fileList):
+ return
+ filterused = fileFilter.split()
+ filetype = filterused[1]
+ extension = filterused[2]
+ outdir = qt.safe_str(fileList[0])
+ try:
+ self.outputDir = os.path.dirname(outdir)
+ PyMcaDirs.outputDir = os.path.dirname(outdir)
+ except:
+ print("setting output directory to default")
+ self.outputDir = os.getcwd()
+ try:
+ outputFile = os.path.basename(outdir)
+ except:
+ outputFile = outdir
+ if len(outputFile) < 5:
+ outputFile = outputFile + extension[-4:]
+ elif outputFile[-4:] != extension[-4:]:
+ outputFile = outputFile + extension[-4:]
+ return os.path.join(self.outputDir, outputFile), filetype, filterused
+
+ def _QSimpleOperation(self, operation):
+ try:
+ self._simpleOperation(operation)
+ except:
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setInformativeText(str(sys.exc_info()[1]))
+ msg.setDetailedText(traceback.format_exc())
+ msg.exec_()
+
+ def _saveOperation(self, fileName, fileType, fileFilter):
+ filterused = fileFilter
+ filetype = fileType
+ filename = fileName
+ if os.path.exists(filename):
+ os.remove(filename)
+ if filterused[0].upper() == "WIDGET":
+ fformat = filename[-3:].upper()
+ if hasattr(qt.QPixmap,"grabWidget"):
+ pixmap = qt.QPixmap.grabWidget(self)
+ else:
+ pixmap = self.grab()
+ if not pixmap.save(filename, fformat):
+ qt.QMessageBox.critical(self,
+ "Save Error",
+ "%s" % sys.exc_info()[1])
+ return
+ try:
+ if filename[-3:].upper() in ['EPS', 'PNG', 'SVG']:
+ self.graphicsSave(filename)
+ return
+ except:
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Graphics Saving Error: %s" % (sys.exc_info()[1]))
+ msg.exec_()
+ return
+ systemline = os.linesep
+ os.linesep = '\n'
+ try:
+ if sys.version < "3.0":
+ ffile=open(filename, "wb")
+ else:
+ ffile=open(filename, "w", newline='')
+ except IOError:
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Input Output Error: %s" % (sys.exc_info()[1]))
+ msg.exec_()
+ return
+ x, y, legend, info = self.getActiveCurve()
+ xlabel = info.get("xlabel", "X")
+ ylabel = info.get("ylabel", "Y")
+ if 0:
+ if "selection" in info:
+ if type(info['selection']) == type({}):
+ if 'x' in info['selection']:
+ #proper scan selection
+ ilabel = info['selection']['y'][0]
+ ylegend = info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if info['selection']['x'] is not None:
+ if len(info['selection']['x']):
+ xlabel = info['LabelNames'] [info['selection']['x'][0]]
+ else:
+ xlabel = "Point number"
+ try:
+ if filetype in ['Scan', 'MultiScan']:
+ ffile.write("#F %s\n" % filename)
+ savingDate = "#D %s\n"%(time.ctime(time.time()))
+ ffile.write(savingDate)
+ ffile.write("\n")
+ ffile.write("#S 1 %s\n" % legend)
+ ffile.write(savingDate)
+ ffile.write("#N 2\n")
+ ffile.write("#L %s %s\n" % (xlabel, ylabel) )
+ for i in range(len(y)):
+ ffile.write("%.7g %.7g\n" % (x[i], y[i]))
+ ffile.write("\n")
+ if filetype == 'MultiScan':
+ scan_n = 1
+ curveList = self.getAllCurves()
+ for x, y, key, info in curveList:
+ if key == legend:
+ continue
+ xlabel = info.get("xlabel", "X")
+ ylabel = info.get("ylabel", "Y")
+ if 0:
+ if "selection" in info:
+ if type(info['selection']) == type({}):
+ if 'x' in info['selection']:
+ #proper scan selection
+ ilabel = info['selection']['y'][0]
+ ylegend = info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if info['selection']['x'] is not None:
+ if len(info['selection']['x']):
+ xlabel = info['LabelNames'] [info['selection']['x'][0]]
+ else:
+ xlabel = "Point number"
+ scan_n += 1
+ ffile.write("#S %d %s\n" % (scan_n, key))
+ ffile.write(savingDate)
+ ffile.write("#N 2\n")
+ ffile.write("#L %s %s\n" % (xlabel, ylabel) )
+ for i in range(len(y)):
+ ffile.write("%.7g %.7g\n" % (x[i], y[i]))
+ ffile.write("\n")
+ elif filetype == 'ASCII':
+ for i in range(len(y)):
+ ffile.write("%.7g %.7g\n" % (x[i], y[i]))
+ elif filetype == 'CSV':
+ if "," in filterused[0]:
+ csvseparator = ","
+ elif ";" in filterused[0]:
+ csvseparator = ";"
+ elif "OMNIC" in filterused[0]:
+ csvseparator = ","
+ else:
+ csvseparator = "\t"
+ if "OMNIC" not in filterused[0]:
+ ffile.write('"%s"%s"%s"\n' % (xlabel,csvseparator,ylabel))
+ for i in range(len(y)):
+ ffile.write("%.7E%s%.7E\n" % (x[i], csvseparator,y[i]))
+ else:
+ ffile.write("#F %s\n" % filename)
+ ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("\n")
+ ffile.write("#S 1 %s\n" % legend)
+ ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("#@MCA %16C\n")
+ ffile.write("#@CHANN %d %d %d 1\n" % (len(y), x[0], x[-1]))
+ ffile.write("#@CALIB %.7g %.7g %.7g\n" % (0, 1, 0))
+ ffile.write(self.array2SpecMca(y))
+ ffile.write("\n")
+ ffile.close()
+ os.linesep = systemline
+ except:
+ os.linesep = systemline
+ raise
+ return
+
+
+ def _simpleOperation(self, operation):
+ if operation == 'subtract':
+ self._subtractOperation()
+ return
+ if operation == "save":
+ #getOutputFileName
+ filename = self._getOutputFileName()
+ if filename is None:
+ return
+ self._saveOperation(filename[0], filename[1], filename[2])
+ return
+ if operation != "average":
+ #get active curve
+ legend = self.getActiveCurveLegend()
+ if legend is None:return
+
+ found = False
+ for key in self.dataObjectsList:
+ if key == legend:
+ found = True
+ break
+
+ if found:
+ dataObject = self.dataObjectsDict[legend]
+ else:
+ print("I should not be here")
+ print("active curve =",legend)
+ print("but legend list = ",self.dataObjectsList)
+ return
+ y = dataObject.y[0]
+ if dataObject.x is not None:
+ x = dataObject.x[0]
+ else:
+ x = numpy.arange(len(y)).astype(numpy.float)
+ ilabel = dataObject.info['selection']['y'][0]
+ ylabel = dataObject.info['LabelNames'][ilabel]
+ if len(dataObject.info['selection']['x']):
+ ilabel = dataObject.info['selection']['x'][0]
+ xlabel = dataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = "Point Number"
+ else:
+ x = []
+ y = []
+ legend = ""
+ i = 0
+ ndata = 0
+ for key in self._curveList:
+ if DEBUG:
+ print("key -> ", key)
+ if key in self.dataObjectsDict:
+ x.append(self.dataObjectsDict[key].x[0]) #only the first X
+ if len(self.dataObjectsDict[key].y) == 1:
+ y.append(self.dataObjectsDict[key].y[0])
+ else:
+ sel_legend = self.dataObjectsDict[key].info['legend']
+ ilabel = 0
+ #I have to get the proper y associated to the legend
+ if sel_legend in key:
+ if key.index(sel_legend) == 0:
+ label = key[len(sel_legend):]
+ while (label.startswith(' ')):
+ label = label[1:]
+ if not len(label):
+ break
+ if label in self.dataObjectsDict[key].info['LabelNames']:
+ ilabel = self.dataObjectsDict[key].info['LabelNames'].index(label)
+ if DEBUG:
+ print("LABEL = ", label)
+ print("ilabel = ", ilabel)
+ y.append(self.dataObjectsDict[key].y[ilabel])
+ if i == 0:
+ legend = key
+ firstcurve = key
+ i += 1
+ else:
+ legend += " + " + key
+ lastcurve = key
+ ndata += 1
+ if ndata == 0: return #nothing to average
+ dataObject = self.dataObjectsDict[firstcurve]
+
+ #create the output data object
+ newDataObject = DataObject.DataObject()
+ newDataObject.data = None
+ newDataObject.info = copy.deepcopy(dataObject.info)
+ if 'selectionlegend' in newDataObject.info:
+ del newDataObject.info['selectionlegend']
+ if not ('operations' in newDataObject.info):
+ newDataObject.info['operations'] = []
+ newDataObject.info['operations'].append(operation)
+
+ sel = {}
+ sel['SourceType'] = "Operation"
+ #get new x and new y
+ if operation == "derivate":
+ #xmin and xmax
+ xlimits=self.getGraphXLimits()
+ xplot, yplot = self.simpleMath.derivate(x, y, xlimits=xlimits)
+ ilabel = dataObject.info['selection']['y'][0]
+ ylabel = dataObject.info['LabelNames'][ilabel]
+ newDataObject.info['LabelNames'][ilabel] = ylabel+"'"
+ newDataObject.info['plot_yaxis'] = "right"
+ sel['SourceName'] = legend
+ sel['Key'] = "'"
+ sel['legend'] = legend + sel['Key']
+ outputlegend = legend + sel['Key']
+ elif operation == "average":
+ xplot, yplot = self.simpleMath.average(x, y)
+ if len(legend) < 80:
+ sel['SourceName'] = legend
+ sel['Key'] = ""
+ sel['legend'] = "(%s)/%d" % (legend, ndata)
+ outputlegend = "(%s)/%d" % (legend, ndata)
+ else:
+ sel['SourceName'] = legend
+ legend = "Average of %d from %s to %s" % (ndata, firstcurve, lastcurve)
+ sel['Key'] = ""
+ sel['legend'] = legend
+ outputlegend = legend
+ elif operation == "swapsign":
+ xplot = x * 1
+ yplot = -y
+ sel['SourceName'] = legend
+ sel['Key'] = ""
+ sel['legend'] = "-(%s)" % legend
+ outputlegend = "-(%s)" % legend
+ elif operation == "smooth":
+ xplot = x * 1
+ yplot = self.simpleMath.smooth(y)
+ sel['SourceName'] = legend
+ sel['Key'] = ""
+ sel['legend'] = "%s Smooth" % legend
+ outputlegend = "%s Smooth" % legend
+ if 'operations' in dataObject.info:
+ if len(dataObject.info['operations']):
+ if dataObject.info['operations'][-1] == "smooth":
+ sel['legend'] = legend
+ outputlegend = legend
+ elif operation == "forceymintozero":
+ xplot = x * 1
+ yplot = y - min(y)
+ sel['SourceName'] = legend
+ sel['Key'] = ""
+ sel['legend'] = "(%s) - ymin" % legend
+ outputlegend = "(%s) - ymin" % legend
+ elif operation == "fit":
+ #remove a existing fit if present
+ xmin,xmax=self.getGraphXLimits()
+ outputlegend = legend + " Fit"
+ for key in self._curveList:
+ if key == outputlegend:
+ self.removeCurves([outputlegend], replot=False)
+ break
+ self.scanFit.setData(x = x,
+ y = y,
+ xmin = xmin,
+ xmax = xmax,
+ legend = legend)
+ if self.scanFit.isHidden():
+ self.scanFit.show()
+ self.scanFit.raise_()
+ elif operation == "custom_fit":
+ #remove a existing fit if present
+ xmin, xmax=self.getGraphXLimits()
+ outputlegend = legend + "Custom Fit"
+ keyList = list(self._curveList)
+ for key in keyList:
+ if key == outputlegend:
+ self.removeCurves([outputlegend], replot=False)
+ break
+ self.customFit.setData(x = x,
+ y = y,
+ xmin = xmin,
+ xmax = xmax,
+ legend = legend)
+ if self.customFit.isHidden():
+ self.customFit.show()
+ self.customFit.raise_()
+ else:
+ raise ValueError("Unknown operation %s" % operation)
+ if operation not in ["fit", "custom_fit"]:
+ newDataObject.x = [xplot]
+ newDataObject.y = [yplot]
+ newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
+
+ #and add it to the plot
+ if True and (operation not in ['fit', 'custom_fit']):
+ sel['dataobject'] = newDataObject
+ sel['scanselection'] = True
+ sel['selection'] = copy.deepcopy(dataObject.info['selection'])
+ sel['selectiontype'] = "1D"
+ if operation == 'average':
+ self._replaceSelection([sel])
+ elif operation != 'fit':
+ self._addSelection([sel])
+ else:
+ self.__fitDataObject = newDataObject
+ return
+ else:
+ newDataObject.info['legend'] = outputlegend
+ if operation == 'fit':
+ self.__fitDataObject = newDataObject
+ return
+ if operation == 'custom_fit':
+ self.__customFitDataObject = newDataObject
+ return
+
+ self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
+ #here I should check the log or linear status
+ self.addCurve(x=xplot, y=yplot, legend=newDataObject.info['legend'], replot=False)
+ self.replot()
+
+ def graphicsSave(self, filename):
+ #use the plugin interface
+ x, y, legend, info = self.getActiveCurve()[:4]
+ curveList = self.getAllCurves()
+ size = (6, 3) #in inches
+ bw = False
+ if len(curveList) > 1:
+ legends = True
+ else:
+ legends = False
+ if self.matplotlibDialog is None:
+ self.matplotlibDialog = QPyMcaMatplotlibSave1D.\
+ QPyMcaMatplotlibSaveDialog(size=size,
+ logx=self._logX,
+ logy=self._logY,
+ legends=legends,
+ bw = bw)
+ mtplt = self.matplotlibDialog.plot
+ mtplt.setParameters({'logy':self._logY,
+ 'logx':self._logX,
+ 'legends':legends,
+ 'bw':bw})
+ xmin, xmax = self.getGraphXLimits()
+ ymin, ymax = self.getGraphYLimits()
+ mtplt.setLimits(xmin, xmax, ymin, ymax)
+
+ legend0 = legend
+ xdata = x
+ ydata = y
+ dataCounter = 1
+ alias = "%c" % (96+dataCounter)
+ mtplt.addDataToPlot( xdata, ydata, legend=legend0, alias=alias )
+ for curve in curveList:
+ xdata, ydata, legend, info = curve[0:4]
+ if legend == legend0:
+ continue
+ dataCounter += 1
+ alias = "%c" % (96+dataCounter)
+ mtplt.addDataToPlot( xdata, ydata, legend=legend, alias=alias )
+
+ if sys.version < '3.0':
+ self.matplotlibDialog.setXLabel(qt.safe_str(self.getGraphXLabel()))
+ self.matplotlibDialog.setYLabel(qt.safe_str(self.getGraphYLabel()))
+ else:
+ self.matplotlibDialog.setXLabel(self.getGraphXLabel())
+ self.matplotlibDialog.setYLabel(self.getGraphYLabel())
+
+ if legends:
+ mtplt.plotLegends()
+ ret = self.matplotlibDialog.exec_()
+ if ret == qt.QDialog.Accepted:
+ mtplt.saveFile(filename)
+ return
+
+ def getActiveCurveLegend(self):
+ return super(ScanWindow,self).getActiveCurve(just_legend=True)
+
+ def _deriveIconSignal(self):
+ if DEBUG:
+ print("_deriveIconSignal")
+ self._QSimpleOperation('derivate')
+
+ def _swapSignIconSignal(self):
+ if DEBUG:
+ print("_swapSignIconSignal")
+ self._QSimpleOperation('swapsign')
+
+ def _yMinToZeroIconSignal(self):
+ if DEBUG:
+ print("_yMinToZeroIconSignal")
+ self._QSimpleOperation('forceymintozero')
+
+ def _subtractIconSignal(self):
+ if DEBUG:
+ print("_subtractIconSignal")
+ self._QSimpleOperation('subtract')
+
+ def _subtractOperation(self):
+ #identical to twice the average with the negative active curve
+ #get active curve
+ legend = self.getActiveCurveLegend()
+ if legend is None:
+ return
+
+ found = False
+ for key in self.dataObjectsList:
+ if key == legend:
+ found = True
+ break
+
+ if found:
+ dataObject = self.dataObjectsDict[legend]
+ else:
+ print("I should not be here")
+ print("active curve =",legend)
+ print("but legend list = ",self.dataObjectsList)
+ return
+ x = dataObject.x[0]
+ y = dataObject.y[0]
+ ilabel = dataObject.info['selection']['y'][0]
+ ylabel = dataObject.info['LabelNames'][ilabel]
+ if len(dataObject.info['selection']['x']):
+ ilabel = dataObject.info['selection']['x'][0]
+ xlabel = dataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = "Point Number"
+
+ xActive = x
+ yActive = y
+ yActiveLegend = legend
+ yActiveLabel = ylabel
+ xActiveLabel = xlabel
+
+ operation = "subtract"
+ sel_list = []
+ i = 0
+ ndata = 0
+ keyList = list(self._curveList)
+ for key in keyList:
+ legend = ""
+ x = [xActive]
+ y = [-yActive]
+ if DEBUG:
+ print("key -> ", key)
+ if key in self.dataObjectsDict:
+ x.append(self.dataObjectsDict[key].x[0]) #only the first X
+ if len(self.dataObjectsDict[key].y) == 1:
+ y.append(self.dataObjectsDict[key].y[0])
+ ilabel = self.dataObjectsDict[key].info['selection']['y'][0]
+ else:
+ sel_legend = self.dataObjectsDict[key].info['legend']
+ ilabel = self.dataObjectsDict[key].info['selection']['y'][0]
+ #I have to get the proper y associated to the legend
+ if sel_legend in key:
+ if key.index(sel_legend) == 0:
+ label = key[len(sel_legend):]
+ while (label.startswith(' ')):
+ label = label[1:]
+ if not len(label):
+ break
+ if label in self.dataObjectsDict[key].info['LabelNames']:
+ ilabel = self.dataObjectsDict[key].info['LabelNames'].index(label)
+ if DEBUG:
+ print("LABEL = ", label)
+ print("ilabel = ", ilabel)
+ y.append(self.dataObjectsDict[key].y[ilabel])
+ outputlegend = "(%s - %s)" % (key, yActiveLegend)
+ ndata += 1
+ xplot, yplot = self.simpleMath.average(x, y)
+ yplot *= 2
+ #create the output data object
+ newDataObject = DataObject.DataObject()
+ newDataObject.data = None
+ newDataObject.info.update(self.dataObjectsDict[key].info)
+ if not ('operations' in newDataObject.info):
+ newDataObject.info['operations'] = []
+ newDataObject.info['operations'].append(operation)
+ newDataObject.info['LabelNames'][ilabel] = "(%s - %s)" % \
+ (newDataObject.info['LabelNames'][ilabel], yActiveLabel)
+ newDataObject.x = [xplot]
+ newDataObject.y = [yplot]
+ newDataObject.m = None
+ sel = {}
+ sel['SourceType'] = "Operation"
+ sel['SourceName'] = key
+ sel['Key'] = ""
+ sel['legend'] = outputlegend
+ sel['dataobject'] = newDataObject
+ sel['scanselection'] = True
+ sel['selection'] = copy.deepcopy(dataObject.info['selection'])
+ #sel['selection']['y'] = [ilabel]
+ sel['selectiontype'] = "1D"
+ sel_list.append(sel)
+ if True:
+ #The legend menu was not working with the next line
+ #but if works if I add the list
+ self._replaceSelection(sel_list)
+ else:
+ oldlist = list(self.dataObjectsDict)
+ self._addSelection(sel_list)
+ self.removeCurves(oldlist)
+
+ #The plugins interface
+ def getGraphYLimits(self):
+ #if the active curve is mapped to second axis
+ #I should give the second axis limits
+ return super(ScanWindow, self).getGraphYLimits()
+
+ #end of plugins interface
+ def addCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
+ color=None, symbol=None, linestyle=None,
+ xlabel=None, ylabel=None, yaxis=None,
+ xerror=None, yerror=None, **kw):
+ if legend in self._curveList:
+ if info is None:
+ info = {}
+ oldStuff = self.getCurve(legend)
+ if len(oldStuff):
+ oldX, oldY, oldLegend, oldInfo = oldStuff
+ else:
+ oldInfo = {}
+ if color is None:
+ color = info.get("plot_color", oldInfo.get("plot_color", None))
+ if symbol is None:
+ symbol = info.get("plot_symbol",oldInfo.get("plot_symbol", None))
+ if linestyle is None:
+ linestyle = info.get("plot_linestyle",oldInfo.get("plot_linestyle", None))
+ if yaxis is None:
+ yaxis = info.get("plot_yaxis",oldInfo.get("plot_yaxis", None))
+ else:
+ if info is None:
+ info = {}
+ if color is None:
+ color = info.get("plot_color", None)
+ if symbol is None:
+ symbol = info.get("plot_symbol", None)
+ if linestyle is None:
+ linestyle = info.get("plot_linestyle", None)
+ if yaxis is None:
+ yaxis = info.get("plot_yaxis", None)
+ if legend in self.dataObjectsDict:
+ # the info is changing
+ super(ScanWindow, self).addCurve(x, y, legend=legend, info=info,
+ replace=replace, replot=replot, color=color, symbol=symbol,
+ linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
+ xerror=xerror, yerror=yerror, **kw)
+ else:
+ # create the data object
+ self.newCurve(x, y, legend=legend, info=info,
+ replace=replace, replot=replot, color=color, symbol=symbol,
+ linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
+ xerror=xerror, yerror=yerror, **kw)
+
+ def newCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
+ color=None, symbol=None, linestyle=None,
+ xlabel=None, ylabel=None, yaxis=None,
+ xerror=None, yerror=None, **kw):
+ if legend is None:
+ legend = "Unnamed curve 1.1"
+ if xlabel is None:
+ xlabel = "X"
+ if ylabel is None:
+ ylabel = "Y"
+ if info is None:
+ info = {}
+ # this is awfull but I have no other way to pass the plot information ...
+ if color is not None:
+ info["plot_color"] = color
+ if symbol is not None:
+ info["plot_symbol"] = symbol
+ if linestyle is not None:
+ info["plot_linestyle"] = linestyle
+ if yaxis is not None:
+ info["plot_yaxis"] = yaxis
+
+ newDataObject = DataObject.DataObject()
+ newDataObject.x = [x]
+ newDataObject.y = [y]
+ newDataObject.m = None
+ newDataObject.info = copy.deepcopy(info)
+ newDataObject.info['legend'] = legend
+ newDataObject.info['SourceName'] = legend
+ newDataObject.info['Key'] = ""
+ newDataObject.info['selectiontype'] = "1D"
+ newDataObject.info['LabelNames'] = [xlabel, ylabel]
+ newDataObject.info['selection'] = {'x':[0], 'y':[1]}
+ sel_list = []
+ sel = {}
+ sel['SourceType'] = "Operation"
+ sel['SourceName'] = legend
+ sel['Key'] = ""
+ sel['legend'] = legend
+ sel['dataobject'] = newDataObject
+ sel['scanselection'] = True
+ sel['selection'] = {'x':[0], 'y':[1], 'm':[], 'cntlist':[xlabel, ylabel]}
+ #sel['selection']['y'] = [ilabel]
+ sel['selectiontype'] = "1D"
+ sel_list.append(sel)
+ if replace:
+ self._replaceSelection(sel_list)
+ else:
+ self._addSelection(sel_list, replot=replot)
+
+ def printGraph(self):
+ if self.printPreview.printer is None:
+ # setup needed
+ self.printPreview.setup()
+ self._printer = self.printPreview.printer
+ if self._printer is None:
+ # printer was not selected
+ return
+ #self._printer = None
+ if PlotWindow.PlotWidget.SVG:
+ svg = True
+ self._svgRenderer = self.getSvgRenderer()
+ else:
+ svg = False
+ if hasattr(self, "getWidgetHandle"):
+ widget = self.getWidgetHandle()
+ else:
+ widget = self.centralWidget()
+ if hasattr(widget, "grab"):
+ pixmap = widget.grab()
+ else:
+ pixmap = qt.QPixmap.grabWidget(widget)
+
+ title = None
+ comment = None
+ if self.scanWindowInfoWidget is not None:
+ if not self.infoDockWidget.isHidden():
+ info = self.scanWindowInfoWidget.getInfo()
+ title = info['scan'].get('source', None)
+ comment = info['scan'].get('scan', None)+"\n"
+ h, k, l = info['scan'].get('hkl')
+ if h != "----":
+ comment += "H = %s K = %s L = %s\n" % (h, k, l)
+ peak = info['graph']['peak']
+ peakAt = info['graph']['peakat']
+ fwhm = info['graph']['fwhm']
+ fwhmAt = info['graph']['fwhmat']
+ com = info['graph']['com']
+ mean = info['graph']['mean']
+ std = info['graph']['std']
+ minimum = info['graph']['min']
+ maximum = info['graph']['max']
+ delta = info['graph']['delta']
+ xLabel = self.getGraphXLabel()
+ comment += "Peak %s at %s = %s\n" % (peak, xLabel, peakAt)
+ comment += "FWHM %s at %s = %s\n" % (fwhm, xLabel, fwhmAt)
+ comment += "COM = %s Mean = %s STD = %s\n" % (com, mean, std)
+ comment += "Min = %s Max = %s Delta = %s\n" % (minimum,
+ maximum,
+ delta)
+
+ if hasattr(self, "scanFit"):
+ if not self.scanFit.isHidden():
+ if comment is None:
+ comment = ""
+ comment += "\n"
+ comment += self.scanFit.getText()
+
+ if svg:
+ self.printPreview.addSvgItem(self._svgRenderer,
+ title=None,
+ comment=comment,
+ commentPosition="LEFT")
+ else:
+ self.printPreview.addPixmap(pixmap,
+ title=None,
+ comment=comment,
+ commentPosition="LEFT")
+ if self.printPreview.isHidden():
+ self.printPreview.show()
+ self.printPreview.raise_()
+
+ def getSvgRenderer(self, printer=None):
+ if printer is None:
+ if self.printPreview.printer is None:
+ # setup needed
+ self.printPreview.setup()
+ self._printer = self.printPreview.printer
+ printer = self._printer
+ if printer is None:
+ # printer was not selected
+ # return a renderer without adjusting the viewbox
+ if sys.version < '3.0':
+ import cStringIO as StringIO
+ imgData = StringIO.StringIO()
+ else:
+ from io import StringIO
+ imgData = StringIO()
+ self.saveGraph(imgData, fileFormat='svg')
+ imgData.flush()
+ imgData.seek(0)
+ svgData = imgData.read()
+ imgData = None
+ svgRenderer = qt.QSvgRenderer()
+ svgRenderer._svgRawData = svgData
+ svgRenderer._svgRendererData = qt.QXmlStreamReader(svgData)
+ if not svgRenderer.load(svgRenderer._svgRendererData):
+ raise RuntimeError("Cannot interpret svg data")
+ return svgRenderer
+
+ # we have what is to be printed
+ if sys.version < '3.0':
+ import cStringIO as StringIO
+ imgData = StringIO.StringIO()
+ else:
+ from io import StringIO
+ imgData = StringIO()
+ self.saveGraph(imgData, fileFormat='svg')
+ imgData.flush()
+ imgData.seek(0)
+ svgData = imgData.read()
+ imgData = None
+ svgRenderer = qt.QSvgRenderer()
+
+ #svgRenderer = PlotWindow.PlotWindow.getSvgRenderer(self)
+
+ # we have to specify the bounding box
+ config = self.getPrintConfiguration()
+ width = config['width']
+ height = config['height']
+ xOffset = config['xOffset']
+ yOffset = config['yOffset']
+ units = config['units']
+ keepAspectRatio = config['keepAspectRatio']
+
+
+ dpix = printer.logicalDpiX()
+ dpiy = printer.logicalDpiY()
+
+ # get the available space
+ availableWidth = printer.width()
+ availableHeight = printer.height()
+
+ # convert the offsets to dpi
+ if units.lower() in ['inch', 'inches']:
+ xOffset = xOffset * dpix
+ yOffset = yOffset * dpiy
+ if width is not None:
+ width = width * dpix
+ if height is not None:
+ height = height * dpiy
+ elif units.lower() in ['cm', 'centimeters']:
+ xOffset = (xOffset/2.54) * dpix
+ yOffset = (yOffset/2.54) * dpiy
+ if width is not None:
+ width = (width/2.54) * dpix
+ if height is not None:
+ height = (height/2.54) * dpiy
+ else:
+ # page units
+ xOffset = availableWidth * xOffset
+ yOffset = availableHeight * yOffset
+ if width is not None:
+ width = availableWidth * width
+ if height is not None:
+ height = availableHeight * height
+
+ availableWidth -= xOffset
+ availableHeight -= yOffset
+
+ if width is not None:
+ if (availableWidth + 0.1) < width:
+ txt = "Available width %f is less than requested width %f" % \
+ (availableWidth, width)
+ raise ValueError(txt)
+ availableWidth = width
+ if height is not None:
+ if (availableHeight + 0.1) < height:
+ txt = "Available height %f is less than requested height %f" % \
+ (availableHeight, height)
+ raise ValueError(txt)
+ availableHeight = height
+
+ if keepAspectRatio:
+ #get the aspect ratio
+ widget = self.getWidgetHandle()
+ if widget is None:
+ # does this make sense?
+ graphWidth = availableWidth
+ graphHeight = availableHeight
+ else:
+ graphWidth = float(widget.width())
+ graphHeight = float(widget.height())
+
+ graphRatio = graphHeight / graphWidth
+ # that ratio has to be respected
+
+ bodyWidth = availableWidth
+ bodyHeight = availableWidth * graphRatio
+
+ if bodyHeight > availableHeight:
+ bodyHeight = availableHeight
+ bodyWidth = bodyHeight / graphRatio
+ else:
+ bodyWidth = availableWidth
+ bodyHeight = availableHeight
+
+ body = qt.QRectF(xOffset,
+ yOffset,
+ bodyWidth,
+ bodyHeight)
+ # this does not work if I set the svgData before
+ svgRenderer.setViewBox(body)
+ svgRenderer._viewBox = body
+ if not sys.version.startswith("2"):
+ svgData = svgData.encode(encoding="utf-8",
+ errors="replace")
+ svgRenderer._svgRawData = svgData
+ svgRenderer._svgRendererData = qt.QXmlStreamReader(svgData)
+
+ if not svgRenderer.load(svgRenderer._svgRendererData):
+ raise RuntimeError("Cannot interpret svg data")
+ return svgRenderer
+
+def test():
+ w = ScanWindow()
+ x = numpy.arange(1000.)
+ y = 10 * x + 10000. * numpy.exp(-0.5*(x-500)*(x-500)/400)
+ w.addCurve(x, y, legend="dummy", replot=True, replace=True)
+ w.resetZoom()
+ app.lastWindowClosed.connect(app.quit)
+ w.show()
+ app.exec_()
+
+
+if __name__ == "__main__":
+ test()
diff --git a/PyMca5/PyMcaGui/pymca/Mca2Edf.py b/PyMca5/PyMcaGui/pymca/Mca2Edf.py
index d9428a5..1b30a9d 100644
--- a/PyMca5/PyMcaGui/pymca/Mca2Edf.py
+++ b/PyMca5/PyMcaGui/pymca/Mca2Edf.py
@@ -533,9 +533,12 @@ class Mca2EdfWindow(qt.QWidget):
pass
def main():
+ import logging
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
import getopt
options = 'f'
- longoptions = ['outdir=', 'listfile=', 'mcastep=']
+ longoptions = ['outdir=', 'listfile=', 'mcastep=',
+ 'logging=', 'debug=']
filelist = None
outdir = None
listfile = None
@@ -544,13 +547,15 @@ def main():
sys.argv[1:],
options,
longoptions)
- for opt,arg in opts:
+ for opt, arg in opts:
if opt in ('--outdir'):
outdir = arg
elif opt in ('--listfile'):
listfile = arg
elif opt in ('--mcastep'):
mcastep = int(arg)
+
+ logging.basicConfig(level=getLoggingLevel(opts))
if listfile is None:
filelist=[]
for item in args:
diff --git a/PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py b/PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py
index 881e1c4..8df05ee 100644
--- a/PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py
+++ b/PyMca5/PyMcaGui/pymca/McaCalibrationControlGUI.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
@@ -39,7 +40,8 @@ else:
from PyMca5 import PyMcaDirs
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class McaCalibrationControlGUI(qt.QWidget):
sigMcaCalibrationControlGUISignal = qt.pyqtSignal(object)
@@ -82,29 +84,26 @@ class McaCalibrationControlGUI(qt.QWidget):
self.calbut.clicked.connect(self._calbuttonclicked)
def _calboxactivated(self, item=None):
- if DEBUG:
- item = qt.safe_str(item)
- print("Calibration box activated %s" % item)
+ _logger.debug("Calibration box activated %s", qt.safe_str(item))
comboitem, combotext = self.calbox.getCurrent()
- self._emitpysignal(box=[comboitem,combotext],
+ self._emitpysignal(box=[comboitem, combotext],
boxname='Calibration',
event='activated')
def _calbuttonclicked(self):
- if DEBUG:
- print("Calibration button clicked")
+ _logger.debug("Calibration button clicked")
self.calmenu.exec_(self.cursor().pos())
def _copysignal(self):
- comboitem,combotext = self.calbox.getCurrent()
+ comboitem, combotext = self.calbox.getCurrent()
self._emitpysignal(button="CalibrationCopy",
- box=[comboitem,combotext],
+ box=[comboitem, combotext],
event='clicked')
def _computesignal(self):
- comboitem,combotext = self.calbox.getCurrent()
+ comboitem, combotext = self.calbox.getCurrent()
self._emitpysignal(button="Calibration",
- box=[comboitem,combotext],
+ box=[comboitem, combotext],
event='clicked')
def _loadsignal(self):
@@ -118,7 +117,7 @@ class McaCalibrationControlGUI(qt.QWidget):
windir = self.lastInputDir
if windir is None:
windir = os.getcwd()
- filename= qt.safe_str(qt.QFileDialog.getOpenFileName(self,
+ filename = qt.safe_str(qt.QFileDialog.getOpenFileName(self,
"Load existing calibration file",
windir,
self.lastInputFilter))
@@ -225,8 +224,7 @@ class McaCalibrationControlGUI(qt.QWidget):
checkbox=None,
line_edit=None,
event=None):
- if DEBUG:
- print("_emitpysignal called ",button,box)
+ _logger.debug("_emitpysignal called %s %s", button, box)
data={}
data['button'] = button
data['box'] = box
diff --git a/PyMca5/PyMcaGui/pymca/McaLegendselector.py b/PyMca5/PyMcaGui/pymca/McaLegendselector.py
new file mode 100644
index 0000000..332e072
--- /dev/null
+++ b/PyMca5/PyMcaGui/pymca/McaLegendselector.py
@@ -0,0 +1,103 @@
+#/*##########################################################################
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+__author__ = "P. Knobel - ESRF Data Analysis"
+__contact__ = "sole@esrf.fr"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
+import copy
+import numpy
+from silx.gui.plot import LegendSelector
+
+
+class McaLegendsDockWidget(LegendSelector.LegendsDockWidget):
+ """Subclassing of the silx LegendsDockWidget to handle
+ curve renaming for McaWindow.
+ """
+ def renameCurve(self, oldLegend, newLegend):
+ """Change the name of a curve using remove and addCurve.
+ The name must also be changed in dataObjetsDict and calDict.
+
+ :param str oldLegend: The legend of the curve to be changed
+ :param str newLegend: The new legend of the curve
+ """
+ is_active = self.plot.getActiveCurve(just_legend=True) == oldLegend
+ xChannels, yOrig, infoOrig = self.plot.getDataAndInfoFromLegend(oldLegend)
+ curve = self.plot.getCurve(oldLegend)
+ x = curve.getXData()
+ y = curve.getYData()
+ info = curve.getInfo()
+ calib = info.get('McaCalib', [0.0, 1.0, 0.0])
+ calibrationOrder = info.get('McaCalibOrder', 2)
+ if calibrationOrder == 'TOF':
+ xFromChannels = calib[2] + calib[0] / pow(xChannels-calib[1], 2)
+ else:
+ xFromChannels = calib[0] + \
+ calib[1] * xChannels + calib[2] * xChannels * xChannels
+ if numpy.allclose(xFromChannels, x):
+ x = xChannels
+ newInfo = copy.deepcopy(info)
+ newInfo['legend'] = newLegend
+ newInfo['SourceName'] = newLegend
+ newInfo['Key'] = ""
+ newInfo['selectiontype'] = "1D"
+ self.plot.removeCurve(oldLegend)
+ self.plot.addCurve(x,
+ y,
+ legend=newLegend,
+ info=newInfo,
+ color=curve.getColor(),
+ symbol=curve.getSymbol(),
+ linewidth=curve.getLineWidth(),
+ linestyle=curve.getLineStyle(),
+ xlabel=curve.getXLabel(),
+ ylabel=curve.getYLabel(),
+ xerror=curve.getXErrorData(copy=False),
+ yerror=curve.getYErrorData(copy=False),
+ z=curve.getZValue(),
+ selectable=curve.isSelectable(),
+ fill=curve.isFill(),
+ resetzoom=False)
+ if is_active:
+ self.plot.setActiveCurve(newLegend)
+
+ # make sure the dicts are also renamed
+ self._renameInDataObjectsDict(oldLegend, newLegend)
+ self._renameInCalDict(oldLegend, newLegend)
+
+ def _renameInDataObjectsDict(self, oldLegend, newLegend):
+ # This seems to be useless but I don't know why.
+ # dataObjectDict is already properly renamed.
+ if oldLegend in self.plot.dataObjectsDict:
+ self.plot.dataObjectsDict[newLegend] = copy.deepcopy(
+ self.plot.dataObjectsDict[oldLegend])
+ self.plot.dataObjectsDict[newLegend].info['legend'] = newLegend
+ del self.plot.dataObjectsDict[oldLegend]
+
+ def _renameInCalDict(self, oldLegend, newLegend):
+ if oldLegend in self.plot.caldict:
+ self.plot.caldict[newLegend] = copy.deepcopy(self.plot.caldict[oldLegend])
+ del self.plot.caldict[oldLegend]
diff --git a/PyMca5/PyMcaGui/pymca/McaWindow.py b/PyMca5/PyMcaGui/pymca/McaWindow.py
index f965c13..7cc5814 100644
--- a/PyMca5/PyMcaGui/pymca/McaWindow.py
+++ b/PyMca5/PyMcaGui/pymca/McaWindow.py
@@ -27,12 +27,14 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
import sys
import os
import numpy
-#from numpy import argsort, nonzero, take
import time
import traceback
+import logging
+
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, 'QString'):
QString = qt.QString
@@ -44,113 +46,159 @@ if __name__ == "__main__":
import copy
from PyMca5.PyMcaGui.io import PyMcaFileDialogs
-from PyMca5.PyMcaGui import IconDict
from . import ScanWindow
from . import McaCalibrationControlGUI
from PyMca5.PyMcaIO import ConfigDict
-from PyMca5.PyMcaGui import McaAdvancedFit
-from PyMca5.PyMcaCore import DataObject
+from PyMca5.PyMcaGui.physics.xrf import McaAdvancedFit
from PyMca5.PyMcaGui.physics.xrf import McaCalWidget
+from PyMca5.PyMcaCore import DataObject
from . import McaSimpleFit
from PyMca5.PyMcaMath.fitting import Specfit
-from PyMca5.PyMcaMath.fitting import SpecfitFuns
-from PyMca5.PyMcaGui import PyMcaPrintPreview
from PyMca5 import PyMcaDirs
+from PyMca5.PyMcaGui.pymca.McaLegendselector import McaLegendsDockWidget
+
+import silx.gui.icons
+
-from PyMca5.PyMcaGui import QPyMcaMatplotlibSave1D
MATPLOTLIB = True
-#force understanding of utf-8 encoding
-#otherways it cannot generate svg output
+# force understanding of utf-8 encoding
+# otherwise it cannot generate svg output
try:
import encodings.utf_8
except:
- #not a big problem
+ # not a big problem
pass
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+# _logger.setLevel(logging.DEBUG)
+
+
class McaWindow(ScanWindow.ScanWindow):
- def __init__(self, parent=None, name="Mca Window", specfit=None, backend=None,
- plugins=True, newplot=False, roi=True, fit=True, **kw):
+ sigROISignal = qt.pyqtSignal(object)
+
+ def __init__(self, parent=None, name="Mca Window", fit=True, backend=None,
+ plugins=True, control=True, position=True, roi=True,
+ specfit=None, info=False):
ScanWindow.ScanWindow.__init__(self, parent,
- name=name,
- newplot=newplot,
- plugins=plugins,
- backend=backend,
- roi=roi,
- fit=fit,
- **kw)
- self.setWindowType("MCA")
- # these two objects are the same
- self.dataObjectsList = self._curveList
- # but this is tricky
+ name=name,
+ plugins=plugins,
+ backend=backend,
+ control=control,
+ position=position,
+ roi=roi,
+ fit=False, # we redefine this
+ save=False, # we redefine this
+ info=info)
+ self._plotType = "MCA" # needed by legacy plugins
+
+ # this is tricky
self.dataObjectsDict = {}
- #self.setWindowTitle(name)
self.outputDir = None
self.outputFilter = None
- self.matplotlibDialog = None
-
self.calibration = 'None'
- self.calboxoptions = ['None','Original (from Source)','Internal (from Source OR PyMca)']
- self.caldict={}
- self.calwidget = None
- self.currentROI = None
- self.peakmarker = None
- if specfit is None:
- self.specfit = Specfit.Specfit()
- else:
- self.specfit = specfit
- self.simplefit = McaSimpleFit.McaSimpleFit(specfit=self.specfit)
+ self.calboxoptions = ['None', 'Original (from Source)',
+ 'Internal (from Source OR PyMca)']
+ self.caldict = {}
+ self.calwidget = None
+ self.peakmarker = None
+
+ self.specfit = specfit if specfit is not None else Specfit.Specfit()
+ self.simplefit = McaSimpleFit.McaSimpleFit(specfit=self.specfit)
self.specfit.fitconfig['McaMode'] = 1
self.advancedfit = McaAdvancedFit.McaAdvancedFit()
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
- if DEBUG:
- print("printPreview id = %d" % id(self.printPreview))
-
self._buildCalibrationControlWidget()
- self._toggleCounter = 2
- self._togglePointsSignal()
+
+ self.setDefaultPlotLines(True)
+ self.setDefaultPlotPoints(False)
+
self._ownSignal = None
- self.changeGridLevel()
+ self.setGraphGrid('major')
self.connections()
self.setGraphYLabel('Counts')
- if 1:
- self.fitButtonMenu = qt.QMenu()
- self.fitButtonMenu.addAction(QString("Simple"),
- self.mcaSimpleFitSignal)
- self.fitButtonMenu.addAction(QString("Advanced") ,
- self.mcaAdvancedFitSignal)
- #self.fitButtonMenu.addAction(QString("Simple Fit"),
- # self._simpleFitSignal)
- #self.fitButtonMenu.addAction(QString("Customized Fit") ,
- # self._customFitSignal)
+ # custom save
+ self.mcaSaveButton = qt.QToolButton(self)
+ self.mcaSaveButton.setIcon(silx.gui.icons.getQIcon('document-save'))
+ self.mcaSaveButton.setToolTip('Save as')
+ self.mcaSaveButton.clicked.connect(self._saveIconSignal)
+ self.getOutputToolBar().addWidget(self.mcaSaveButton)
+
+ # Fit icon
+ self.fitToolButton = qt.QToolButton(self)
+ self.fitToolButton.setIcon(silx.gui.icons.getQIcon('math-fit'))
+ self.fitToolButton.setToolTip("Fit of Active Curve")
+ self.fitToolButton.clicked.connect(self._fitButtonClicked)
+
+ self.fitButtonMenu = qt.QMenu()
+ self.fitButtonMenu.addAction(QString("Simple"),
+ self.mcaSimpleFitSignal)
+ self.fitButtonMenu.addAction(QString("Advanced"),
+ self.mcaAdvancedFitSignal)
+
+ if fit:
+ self.toolBar().insertWidget(self.getMaskAction(),
+ self.fitToolButton)
+
+ # hide a bunch of PlotWindow and ScanWindow actions
+ self.getOutputToolBar().getSaveAction().setVisible(False)
+ self.getOutputToolBar().getPrintAction().setVisible(False)
+ self.avgAction.setVisible(False)
+ self.derivativeAction.setVisible(False)
+ self.smoothAction.setVisible(False)
+ self.swapSignAction.setVisible(False)
+ self.yMinToZero.setVisible(False)
+ self.subtractAction.setVisible(False)
+
+ def getLegendsDockWidget(self):
+ # customize the legendsdockwidget to handle curve renaming
+ if self._legendsDockWidget is None:
+ self._legendsDockWidget = McaLegendsDockWidget(plot=self)
+ self._legendsDockWidget.hide()
+ self.addTabbedDockWidget(self._legendsDockWidget)
+ return self._legendsDockWidget
+
+ def getCurvesRoiDockWidget(self):
+ """Reimplemented to add the dock widget to the right of the plot.
+ """
+ if self._curvesROIDockWidget is None:
+ self._curvesROIDockWidget =\
+ ScanWindow.ScanWindow.getCurvesRoiDockWidget(self)
+ self.addTabbedDockWidget(self._curvesROIDockWidget)
+ self.addDockWidget(qt.Qt.RightDockWidgetArea,
+ self._curvesROIDockWidget)
+ return self._curvesROIDockWidget
+
+ def _fitButtonClicked(self):
+ self.fitButtonMenu.exec_(self.cursor().pos())
def _buildCalibrationControlWidget(self):
widget = self.centralWidget()
- self.controlWidget = McaCalibrationControlGUI.McaCalibrationControlGUI(\
+ self.controlWidget = McaCalibrationControlGUI.McaCalibrationControlGUI(
widget)
widget.layout().addWidget(self.controlWidget)
- self.controlWidget.sigMcaCalibrationControlGUISignal.connect(\
+ self.controlWidget.sigMcaCalibrationControlGUISignal.connect(
self.__anasignal)
def connections(self):
self.simplefit.sigMcaSimpleFitSignal.connect(self.__anasignal)
self.advancedfit.sigMcaAdvancedFitSignal.connect(self.__anasignal)
+ self.getCurvesRoiDockWidget().sigROISignal.connect(self.emitCurrentROISignal)
def mcaSimpleFitSignal(self):
legend = self.getActiveCurve(just_legend=True)
if legend is None:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Please Select an active curve")
- msg.setWindowTitle('MCA Window Simple Fit')
- msg.exec_()
- return
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Please Select an active curve")
+ msg.setWindowTitle('MCA Window Simple Fit')
+ msg.exec_()
+ return
x, y, info = self.getDataAndInfoFromLegend(legend)
self.advancedfit.hide()
self.simplefit.show()
@@ -161,87 +209,42 @@ class McaWindow(ScanWindow.ScanWindow):
self.__simplefitcalmode = self.calibration
curveinfo = info
if self.calibration == 'None':
- calib = [0.0,1.0,0.0]
+ calib = [0.0, 1.0, 0.0]
else:
- if 'McaCalib' in curveinfo:
- calib = curveinfo['McaCalib']
- else:
- calib = [0.0, 1.0, 0.0]
+ calib = curveinfo.get('McaCalib', [0.0, 1.0, 0.0])
self.__simplefitcalibration = calib
- calibrationOrder = curveinfo.get('McaCalibOrder',2)
+ calibrationOrder = curveinfo.get('McaCalibOrder', 2)
if calibrationOrder == 'TOF':
- x = calib[2] + calib[0] / pow(x-calib[1],2)
+ x = calib[2] + calib[0] / pow(x - calib[1], 2)
else:
x = calib[0] + calib[1] * x + calib[2] * x * x
- self.simplefit.setdata(x=x,y=y,
- xmin=xmin,
- xmax=xmax,
- legend=legend)
- """
- if self.specfit.fitconfig['McaMode']:
- self.specfitGUI.guiparameters.fillfromfit(self.specfit.paramlist,
- current='Region 1')
- self.specfitGUI.guiparameters.removeallviews(keep='Region 1')
- else:
- self.specfitGUI.guiparameters.fillfromfit(self.specfit.paramlist,
- current='Fit')
- self.specfitGUI.guiparameters.removeallviews(keep='Fit')
- """
+ self.simplefit.setdata(x=x, y=y, xmin=xmin, xmax=xmax,
+ legend=legend)
+
if self.specfit.fitconfig['McaMode']:
self.simplefit.fit()
else:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Error. Trying to fit fitted data?")
- msg.setWindowTitle('MCA Window Simple Fit')
- msg.exec_()
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Error. Trying to fit fitted data?")
+ msg.setWindowTitle('MCA Window Simple Fit')
+ msg.exec_()
def getActiveCurve(self, just_legend=False):
- if DEBUG:
- print("Local MCA window getActiveCurve called!!!!")
- legend = super(McaWindow, self).getActiveCurve(just_legend)
+ _logger.debug("Local MCA window getActiveCurve called!!!!")
+ activeCurve = super(McaWindow, self).getActiveCurve(just_legend)
if just_legend:
- return legend
- activeCurve = legend
+ return activeCurve
if activeCurve in [None, []]:
return None
- x = activeCurve[0]
- y = activeCurve[1]
- legend = activeCurve[2]
- curveinfo = activeCurve[3]
+ curveinfo = activeCurve.getInfo()
xlabel = self.getGraphXLabel()
ylabel = self.getGraphYLabel()
- """
- if legend in self.dataObjectsDict.keys():
- info = self.dataObjectsDict[legend].info
- if str(xlabel.upper()) != "CHANNEL":
- x = self.dataObjectsDict[legend].x[0]
- else:
- info = None
- else:
- info = None
-
- if info is not None:
- if self.calibration == 'None':
- calib = [0.0,1.0,0.0]
- else:
- if 'McaCalib' in curveinfo:
- calib = curveinfo['McaCalib']
- else:
- calib = [0.0, 1.0, 0.0]
- calibrationOrder = curveinfo.get('McaCalibOrder',2)
- if calibrationOrder == 'TOF':
- x = calib[2] + calib[0] / pow(x - calib[1],2)
- else:
- x = calib[0] + calib[1] * x + calib[2] * x * x
- else:
- info = curveinfo
- """
- info = curveinfo
- info['xlabel'] = xlabel
- info['ylabel'] = ylabel
- return x, y, legend, info
+ curveinfo['xlabel'] = xlabel
+ curveinfo['ylabel'] = ylabel
+ activeCurve.setInfo(curveinfo)
+ return activeCurve
def getDataAndInfoFromLegend(self, legend):
"""
@@ -254,7 +257,7 @@ class McaWindow(ScanWindow.ScanWindow):
if legend in self.dataObjectsDict:
# The data as displayed
- x, y, legend, curveinfo = self.getCurve(legend)
+ x, y, legend, curveinfo = self.getCurve(legend)[:4]
# the data as first entered
info = self.dataObjectsDict[legend].info
if self.calibration == 'None':
@@ -301,15 +304,15 @@ class McaWindow(ScanWindow.ScanWindow):
return
x, y, info = self.getDataAndInfoFromLegend(legend)
- curveinfo = self.getCurve(legend)[3]
- xmin,xmax = self.getGraphXLimits()
+ curveinfo = self.getCurve(legend).getInfo()
+ xmin, xmax = self.getGraphXLimits()
if self.calibration == 'None':
if 'McaCalibSource' in curveinfo:
calib = curveinfo['McaCalibSource']
elif 'McaCalibSource' in info:
calib = info['McaCalibSource']
else:
- calib = [0.0,1.0,0.0]
+ calib = [0.0, 1.0, 0.0]
else:
calib = curveinfo['McaCalib']
energy = calib[0] + calib[1] * x + calib[2] * x * x
@@ -325,7 +328,7 @@ class McaWindow(ScanWindow.ScanWindow):
self.advancedfit.raise_()
if info is not None:
xlabel = 'Channel'
- self.advancedfit.setData(x=x,y=y,
+ self.advancedfit.setData(x=x, y=y,
xmin=xmin,
xmax=xmax,
legend=legend,
@@ -341,17 +344,15 @@ class McaWindow(ScanWindow.ScanWindow):
msg.exec_()
return
- def __anasignal(self,dict):
- if DEBUG:
- print("__anasignal called dict = ",dict)
+ def __anasignal(self, dict):
+ _logger.debug("__anasignal called dict = %s", dict)
if dict['event'] == 'clicked':
- # A button has been cicked
- if dict['button'] == 'Source':
+ # A button has been clicked
+ if dict['button'] == 'Source':
pass
elif dict['button'] == 'Calibration':
- #legend,x,y = self.graph.getactivecurve()
- legend = self.getActiveCurve(just_legend=1)
+ legend = self.getActiveCurve(just_legend=True)
if legend is None:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
@@ -362,15 +363,15 @@ class McaWindow(ScanWindow.ScanWindow):
x, y, info = self.getDataAndInfoFromLegend(legend)
if info is None:
return
- ndict = {}
- ndict[legend] = {'order':1,
- 'A':0.0,
- 'B':1.0,
- 'C':0.0}
+ ndict = {legend: {'order': 1,
+ 'A': 0.0,
+ 'B': 1.0,
+ 'C': 0.0}}
+
if legend in self.caldict:
ndict[legend].update(self.caldict[legend])
if abs(ndict[legend]['C']) > 0.0:
- ndict[legend]['order'] = self.caldict[legend].get('order', 2)
+ ndict[legend]['order'] = self.caldict[legend].get('order', 2)
elif 'McaCalib' in info:
if type(info['McaCalib'][0]) == type([]):
calib = info['McaCalib'][0]
@@ -380,16 +381,14 @@ class McaWindow(ScanWindow.ScanWindow):
if len(calib) > 1:
ndict[legend]['A'] = calib[0]
ndict[legend]['B'] = calib[1]
- if len(calib) >2:
- ndict[legend]['order'] = calibrationOrder
- ndict[legend]['C'] = calib[2]
+ if len(calib) > 2:
+ ndict[legend]['order'] = calibrationOrder
+ ndict[legend]['C'] = calib[2]
caldialog = McaCalWidget.McaCalWidget(legend=legend,
- x=x,
- y=y,
- modal=1,
- caldict=ndict)
- #info,x,y = self.getinfodatafromlegend(legend)
- #caldialog.graph.newCurve("fromlegend",x=x,y=y)
+ x=x,
+ y=y,
+ modal=1,
+ caldict=ndict)
ret = caldialog.exec_()
if ret == qt.QDialog.Accepted:
@@ -409,8 +408,7 @@ class McaWindow(ScanWindow.ScanWindow):
self.refresh()
del caldialog
elif dict['button'] == 'CalibrationCopy':
- #legend,x,y = self.graph.getactivecurve()
- legend = self.getActiveCurve(just_legend=1)
+ legend = self.getActiveCurve(just_legend=True)
if legend is None:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
@@ -421,52 +419,52 @@ class McaWindow(ScanWindow.ScanWindow):
x, y, info = self.getDataAndInfoFromLegend(legend)
if info is None:
return
- ndict=copy.deepcopy(self.caldict)
+ ndict = copy.deepcopy(self.caldict)
if 'McaCalib' in info:
if type(info['McaCalib'][0]) == type([]):
sourcecal = info['McaCalib'][0]
else:
sourcecal = info['McaCalib']
else:
- sourcecal = [0.0,1.0,0.0]
+ sourcecal = [0.0, 1.0, 0.0]
for curve in self.getAllCurves(just_legend=True):
curveinfo = self.getCurve(curve)[3]
if 'McaCalibSource' in curveinfo:
key = "%s (Source)" % curve
if key not in ndict:
- if curveinfo['McaCalibSource'] != [0.0,1.0,0.0]:
- ndict[key] = {'A':curveinfo['McaCalibSource'][0],
- 'B':curveinfo['McaCalibSource'][1],
- 'C':curveinfo['McaCalibSource'][2]}
+ if curveinfo['McaCalibSource'] != [0.0, 1.0, 0.0]:
+ ndict[key] = {'A': curveinfo['McaCalibSource'][0],
+ 'B': curveinfo['McaCalibSource'][1],
+ 'C': curveinfo['McaCalibSource'][2]}
if curveinfo['McaCalibSource'][2] != 0.0:
ndict[key]['order'] = 2
else:
ndict[key]['order'] = 1
if curve not in self.caldict.keys():
- if curveinfo['McaCalib'] != [0.0,1.0,0.0]:
+ if curveinfo['McaCalib'] != [0.0, 1.0, 0.0]:
if curveinfo['McaCalib'] != curveinfo['McaCalibSource']:
key = "%s (PyMca)" % curve
- ndict[key] = {'A':curveinfo['McaCalib'][0],
- 'B':curveinfo['McaCalib'][1],
- 'C':curveinfo['McaCalib'][2]}
+ ndict[key] = {'A': curveinfo['McaCalib'][0],
+ 'B': curveinfo['McaCalib'][1],
+ 'C': curveinfo['McaCalib'][2]}
if curveinfo['McaCalib'][2] != 0.0:
ndict[key]['order'] = 2
else:
ndict[key]['order'] = 1
else:
if curve not in self.caldict.keys():
- if curveinfo['McaCalib'] != [0.0,1.0,0.0]:
- key = "%s (PyMca)" % curve
- ndict[key] = {'A':curveinfo['McaCalib'][0],
- 'B':curveinfo['McaCalib'][1],
- 'C':curveinfo['McaCalib'][2]}
- if curveinfo['McaCalib'][2] != 0.0:
- ndict[key]['order'] = 2
- else:
- ndict[key]['order'] = 1
+ if curveinfo['McaCalib'] != [0.0, 1.0, 0.0]:
+ key = "%s (PyMca)" % curve
+ ndict[key] = {'A': curveinfo['McaCalib'][0],
+ 'B': curveinfo['McaCalib'][1],
+ 'C': curveinfo['McaCalib'][2]}
+ if curveinfo['McaCalib'][2] != 0.0:
+ ndict[key]['order'] = 2
+ else:
+ ndict[key]['order'] = 1
if not (legend in self.caldict):
- ndict[legend]={}
+ ndict[legend] = {}
ndict[legend]['A'] = sourcecal[0]
ndict[legend]['B'] = sourcecal[1]
ndict[legend]['C'] = sourcecal[2]
@@ -474,7 +472,7 @@ class McaWindow(ScanWindow.ScanWindow):
ndict[legend]['order'] = 2
else:
ndict[legend]['order'] = 1
- caldialog = McaCalWidget.McaCalCopy(legend=legend,modal=1,
+ caldialog = McaCalWidget.McaCalCopy(legend=legend, modal=1,
caldict=ndict,
sourcecal=sourcecal,
fl=0)
@@ -498,7 +496,7 @@ class McaWindow(ScanWindow.ScanWindow):
self.refresh()
del caldialog
elif dict['button'] == 'CalibrationLoad':
- item = dict['box'][0]
+ # item = dict['box'][0]
itemtext = dict['box'][1]
filename = dict['line_edit']
if not os.path.exists(filename):
@@ -557,15 +555,15 @@ class McaWindow(ScanWindow.ScanWindow):
elif dict['button'] == 'Search':
pass
elif dict['button'] == 'Fit':
- if dict['box'][1] == 'Simple':
+ if dict['box'][1] == 'Simple':
self.mcasimplefitsignal()
- elif dict['box'][1] == 'Advanced':
+ elif dict['box'][1] == 'Advanced':
self.mcaadvancedfitsignal()
else:
- print("Unknown Fit Event")
+ _logger.error("Unknown Fit Event")
elif dict['event'] == 'activated':
# A comboBox has been selected
- if dict['boxname'] == 'Source':
+ if dict['boxname'] == 'Source':
pass
elif dict['boxname'] == 'Calibration':
self.calibration = dict['box'][1]
@@ -593,31 +591,30 @@ class McaWindow(ScanWindow.ScanWindow):
"""
pass
else:
- if DEBUG:
- print("Unknown combobox",dict['boxname'])
+ _logger.debug("Unknown combobox %s", dict['boxname'])
- elif (dict['event'] == 'EstimateFinished'):
+ elif dict['event'] == 'EstimateFinished':
pass
elif (dict['event'] == 'McaAdvancedFitFinished') or \
- (dict['event'] == 'McaAdvancedFitMatrixFinished') :
- x = dict['result']['xdata']
- yb = dict['result']['continuum']
- legend0= dict['info']['legend']
+ (dict['event'] == 'McaAdvancedFitMatrixFinished'):
+ x = dict['result']['xdata']
+ yb = dict['result']['continuum']
+ legend0 = dict['info']['legend']
fitcalibration = [dict['result']['fittedpar'][0],
dict['result']['fittedpar'][1],
0.0]
if dict['event'] == 'McaAdvancedFitMatrixFinished':
legend = dict['info']['legend'] + " Fit"
legend3 = dict['info']['legend'] + " Matrix"
- ymatrix = dict['result']['ymatrix'] * 1.0
- #copy the original info from the curve
+ ymatrix = dict['result']['ymatrix'] * 1.0
+ # copy the original info from the curve
newDataObject = DataObject.DataObject()
newDataObject.info = copy.deepcopy(self.dataObjectsDict[legend0].info)
- newDataObject.info['SourceType']= 'AdvancedFit'
+ newDataObject.info['SourceType'] = 'AdvancedFit'
newDataObject.info['SourceName'] = 1 * self.dataObjectsDict[legend0].info['SourceName']
- newDataObject.info['legend'] = legend3
- newDataObject.info['Key'] = legend3
- newDataObject.info['McaCalib'] = fitcalibration * 1
+ newDataObject.info['legend'] = legend3
+ newDataObject.info['Key'] = legend3
+ newDataObject.info['McaCalib'] = fitcalibration * 1
newDataObject.x = [x]
newDataObject.y = [ymatrix]
newDataObject.m = None
@@ -625,16 +622,16 @@ class McaWindow(ScanWindow.ScanWindow):
#self.graph.newCurve(legend3,x=x,y=ymatrix,logfilter=1)
else:
legend = dict['info']['legend'] + " Fit"
- yfit = dict['result']['yfit'] * 1.0
+ yfit = dict['result']['yfit'] * 1.0
- #copy the original info from the curve
+ # copy the original info from the curve
newDataObject = DataObject.DataObject()
newDataObject.info = copy.deepcopy(self.dataObjectsDict[legend0].info)
- newDataObject.info['SourceType']= 'AdvancedFit'
+ newDataObject.info['SourceType'] = 'AdvancedFit'
newDataObject.info['SourceName'] = 1 * self.dataObjectsDict[legend0].info['SourceName']
newDataObject.info['legend'] = legend
- newDataObject.info['Key'] = legend
- newDataObject.info['McaCalib'] = fitcalibration * 1
+ newDataObject.info['Key'] = legend
+ newDataObject.info['McaCalib'] = fitcalibration * 1
newDataObject.data = numpy.reshape(numpy.concatenate((x,yfit,yb),0),(3,len(x)))
newDataObject.x = [x]
newDataObject.y = [yfit]
@@ -643,15 +640,15 @@ class McaWindow(ScanWindow.ScanWindow):
self.dataObjectsDict[legend] = newDataObject
#self.graph.newCurve(legend,x=x,y=yfit,logfilter=1)
- #the same for the background
+ # the same for the background
legend2 = dict['info']['legend'] + " Bkg"
newDataObject2 = DataObject.DataObject()
newDataObject2.info = copy.deepcopy(self.dataObjectsDict[legend0].info)
- newDataObject2.info['SourceType']= 'AdvancedFit'
+ newDataObject2.info['SourceType'] = 'AdvancedFit'
newDataObject2.info['SourceName'] = 1 * self.dataObjectsDict[legend0].info['SourceName']
newDataObject2.info['legend'] = legend2
- newDataObject2.info['Key'] = legend2
- newDataObject2.info['McaCalib'] = fitcalibration * 1
+ newDataObject2.info['Key'] = legend2
+ newDataObject2.info['McaCalib'] = fitcalibration * 1
newDataObject2.data = None
newDataObject2.x = [x]
newDataObject2.y = [yb]
@@ -659,12 +656,12 @@ class McaWindow(ScanWindow.ScanWindow):
self.dataObjectsDict[legend2] = newDataObject2
#self.graph.newCurve(legend2,x=x,y=yb,logfilter=1)
- if not (legend in self.caldict):
+ if legend not in self.caldict:
self.caldict[legend] = {}
- self.caldict[legend] ['order'] = 1
- self.caldict[legend] ['A'] = dict['result']['fittedpar'][0]
- self.caldict[legend] ['B'] = dict['result']['fittedpar'][1]
- self.caldict[legend] ['C'] = 0.0
+ self.caldict[legend]['order'] = 1
+ self.caldict[legend]['A'] = dict['result']['fittedpar'][0]
+ self.caldict[legend]['B'] = dict['result']['fittedpar'][1]
+ self.caldict[legend]['C'] = 0.0
options = []
for option in self.calboxoptions:
options.append(option)
@@ -673,59 +670,57 @@ class McaWindow(ScanWindow.ScanWindow):
options.append(key)
try:
self.controlWidget.calbox.setOptions(options)
- #I only reset the graph scale after a fit, not on a matrix spectrum
+ # I only reset the graph scale after a fit, not on a matrix spectrum
if dict['event'] == 'McaAdvancedFitFinished':
- #get current limits
+ # get current limits
if self.calibration == 'None':
- xmin, xmax =self.getGraphXLimits()
- emin = dict['result']['fittedpar'][0] + \
- dict['result']['fittedpar'][1] * xmin
- emax = dict['result']['fittedpar'][0] + \
- dict['result']['fittedpar'][1] * xmax
+ xmin, xmax = self.getGraphXLimits()
+ emin = dict['result']['fittedpar'][0] + \
+ dict['result']['fittedpar'][1] * xmin
+ emax = dict['result']['fittedpar'][0] + \
+ dict['result']['fittedpar'][1] * xmax
else:
- emin,emax = self.getGraphXLimits()
- ymin, ymax =self.getGraphYLimits()
+ emin, emax = self.getGraphXLimits()
+ ymin, ymax = self.getGraphYLimits()
self.controlWidget.calbox.setCurrentIndex(options.index(legend))
self.calibration = legend
self.controlWidget._calboxactivated(legend)
- self.setGraphYLimits(ymin, ymax, replot=False)
+ self.setGraphYLimits(ymin, ymax)
if emin < emax:
- self.setGraphXLimits(emin, emax, replot=True)
+ self.setGraphXLimits(emin, emax)
else:
- self.setGraphXLimits(emax, emin, replot=True)
+ self.setGraphXLimits(emax, emin)
except:
- if DEBUG:
- print("Refreshing due to exception", sys.exc_info()[1])
+ _logger.debug("Refreshing due to exception %s", sys.exc_info()[1])
self.refresh()
- #self.graph.replot()
elif dict['event'] == 'McaFitFinished':
mcaresult = dict['data']
- legend = dict['info']['legend'] + " "
i = 0
xfinal = []
yfinal = []
- ybfinal= []
+ ybfinal = []
regions = []
- legend0= dict['info']['legend']
+ legend0 = dict['info']['legend']
mcamode = True
for result in mcaresult:
i += 1
if result['chisq'] is not None:
- mcamode = result['fitconfig']['McaMode']
- idx=numpy.nonzero((self.specfit.xdata0>=result['xbegin']) & \
- (self.specfit.xdata0<=result['xend']))[0]
- x=numpy.take(self.specfit.xdata0,idx)
- y=self.specfit.gendata(x=x,parameters=result['paramlist'])
- nparb= len(self.specfit.bkgdict[self.specfit.fitconfig['fitbkg']][1])
- yb = self.specfit.gendata(x=x,parameters=result['paramlist'][0:nparb])
- xtoadd = numpy.take(self.dataObjectsDict[legend0].x[0],idx).tolist()
- if not len(xtoadd): continue
- xfinal = xfinal + xtoadd
- regions.append([xtoadd[0],xtoadd[-1]])
- yfinal = yfinal + y.tolist()
- ybfinal= ybfinal + yb.tolist()
- #self.graph.newCurve(legend + 'Region %d' % i,x=x,y=yfit,logfilter=1)
+ mcamode = result['fitconfig']['McaMode']
+ idx = numpy.nonzero((self.specfit.xdata0 >= result['xbegin']) &
+ (self.specfit.xdata0 <= result['xend']))[0]
+ x = numpy.take(self.specfit.xdata0, idx)
+ y = self.specfit.gendata(x=x, parameters=result['paramlist'])
+ nparb = len(self.specfit.bkgdict[self.specfit.fitconfig['fitbkg']][1])
+ yb = self.specfit.gendata(x=x, parameters=result['paramlist'][0:nparb])
+ xtoadd = numpy.take(self.dataObjectsDict[legend0].x[0], idx).tolist()
+ if not len(xtoadd):
+ continue
+ xfinal = xfinal + xtoadd
+ regions.append([xtoadd[0], xtoadd[-1]])
+ yfinal = yfinal + y.tolist()
+ ybfinal = ybfinal + yb.tolist()
+ # self.graph.newCurve(legend + 'Region %d' % i,x=x,y=yfit,logfilter=1)
legend = legend0 + " SFit"
if legend in self.dataObjectsDict.keys():
if legend in self.getAllCurves(just_legend=True):
@@ -735,44 +730,45 @@ class McaWindow(ScanWindow.ScanWindow):
else:
if 'baseline' in self.dataObjectsDict[legend].info:
self.removeCurve(legend)
- #copy the original info from the curve
+ # copy the original info from the curve
newDataObject = DataObject.DataObject()
newDataObject.info = copy.deepcopy(self.dataObjectsDict[legend0].info)
- newDataObject.info['SourceType']= 'SimpleFit'
+ newDataObject.info['SourceType'] = 'SimpleFit'
newDataObject.info['SourceName'] = 1 * self.dataObjectsDict[legend0].info['SourceName']
- newDataObject.info['legend'] = legend
- newDataObject.info['Key'] = legend
- newDataObject.info['CalMode'] = self.__simplefitcalmode
- newDataObject.info['McaCalib'] = self.__simplefitcalibration
- x = numpy.array(xfinal)
+ newDataObject.info['legend'] = legend
+ newDataObject.info['Key'] = legend
+ newDataObject.info['CalMode'] = self.__simplefitcalmode
+ newDataObject.info['McaCalib'] = self.__simplefitcalibration
+ x = numpy.array(xfinal)
yfit = numpy.array(yfinal)
yb = numpy.array(ybfinal)
newDataObject.x = [x]
newDataObject.y = [yfit]
newDataObject.m = [numpy.ones(len(yfit)).astype(numpy.float)]
if mcamode:
- newDataObject.info['regions'] = regions
+ newDataObject.info['regions'] = regions
newDataObject.info['baseline'] = yb
self.dataObjectsDict[legend] = newDataObject
self.refresh()
return
+
elif dict['event'] == 'McaTableFilled':
if self.peakmarker is not None:
- self.graph.removeMarker(self.peakmarker)
+ self.removeMarker(self.peakmarker)
self.peakmarker = None
elif dict['event'] == 'McaTableRowHeaderClicked':
- #I have to mark the peaks
+ # I have to mark the peaks
if dict['row'] >= 0:
pos = dict['Position']
label = 'PEAK %d' % (dict['row']+1)
if self.peakmarker is not None:
self.removeMarker(self.peakmarker)
- self.insertXMarker(pos,
- label,
- text=label,
- color='pink',
- draggable=False)
+ self.addXMarker(pos,
+ label,
+ text=label,
+ color='pink',
+ draggable=False)
self.peakmarker = label
else:
if self.peakmarker is not None:
@@ -782,13 +778,13 @@ class McaWindow(ScanWindow.ScanWindow):
if self.peakmarker is not None:
self.removeMarker(self.peakmarker)
self.peakmarker = None
- elif (dict['event'] == 'McaAdvancedFitElementClicked') or \
- (dict['event'] == 'ElementClicked'):
- #this has been moved to the fit window
+
+ elif (dict['event'] == 'McaAdvancedFitElementClicked' or
+ dict['event'] == 'ElementClicked'):
+ # this has been moved to the fit window
pass
elif dict['event'] == 'McaAdvancedFitPrint':
- #self.advancedfit.printps(doit=1)
self.printHtml(dict['text'])
elif dict['event'] == 'McaSimpleFitPrint':
@@ -798,95 +794,105 @@ class McaWindow(ScanWindow.ScanWindow):
if self.peakmarker is not None:
self.removeMarker(self.peakmarker)
self.peakmarker = None
- self.replot()
+
elif dict['event'] == 'ScanFitPrint':
self.printHtml(dict['text'])
- elif dict['event'] == 'AddROI':
- return super(McaWindow, self)._roiSignal(dict)
- elif dict['event'] == 'DelROI':
- return super(McaWindow, self)._roiSignal(dict)
-
- elif dict['event'] == 'ResetROI':
- return super(McaWindow, self)._roiSignal(dict)
-
- elif dict['event'] == 'ActiveROI':
- print("ActiveROI event")
- pass
elif dict['event'] == 'selectionChanged':
- print("Selection changed event not implemented any more")
+ _logger.error("Selection changed event not implemented any more")
else:
- if DEBUG:
- print("Unknown or ignored event",dict['event'])
-
-
- def emitCurrentROISignal(self):
- if self.currentROI is None:
+ _logger.debug("Unknown or ignored event %s", dict['event'])
+
+ def emitCurrentROISignal(self, ddict=None):
+ """Emit a custom ROISignal with calibration info.
+ Ignore the incoming signal emitted by CurvesRoiDockWidget"""
+ currentRoi = self.getCurvesRoiDockWidget().currentROI
+ if currentRoi is None:
+ # could be a silx <= 0.7.0 bug
+ if hasattr(self.getCurvesRoiDockWidget().roiWidget,
+ "currentROI"):
+ currentRoi = self.getCurvesRoiDockWidget().roiWidget.currentROI
+ if currentRoi is None:
+ _logger.debug("No current ROI")
return
- #I have to get the current calibration
+
+ # I have to get the current calibration
if self.getGraphXLabel().upper() != "CHANNEL":
- #I have to get the energy
+ # I have to get the energy
A = self.controlWidget.calinfo.caldict['']['A']
B = self.controlWidget.calinfo.caldict['']['B']
C = self.controlWidget.calinfo.caldict['']['C']
order = self.controlWidget.calinfo.caldict['']['order']
else:
A = 0.0
- try:
- legend = self.getActiveCurve(just_legend=True)
- if legend in self.dataObjectsDict.keys():
+ legend = self.getActiveCurve(just_legend=True)
+ if legend in self.dataObjectsDict:
+ try:
A = self.dataObjectsDict[legend].x[0][0]
- except:
- if DEBUG:
- print("X axis offset not found")
+ except:
+ _logger.debug("X axis offset not found")
B = 1.0
C = 0.0
order = 1
- key = self.currentROI
- roiList, roiDict = self.roiWidget.getROIListAndDict()
- fromdata = roiDict[key]['from' ]
- todata = roiDict[key]['to']
- ddict = {}
- ddict['event'] = "ROISignal"
- ddict['name'] = key
- ddict['from'] = fromdata
- ddict['to'] = todata
- ddict['type'] = roiDict[self.currentROI]["type"]
- ddict['calibration']= [A, B, C, order]
+
+ if hasattr(currentRoi, "getName"):
+ # TODO: double-check ROIWidget.currentROI API after merging silx#1714
+ # silx.gui.plot.CurvesROIWidget.ROI object
+ name = currentRoi.getName()
+ else:
+ # assume it is a string (silx <= 0.7.0)
+ name = currentRoi
+
+ roisDict = self.getCurvesRoiDockWidget().roiWidget.getRois()
+ assert name in roisDict, "roiWidget.currentRoi not found in roiDict!"
+ roi = roisDict[name]
+ if isinstance(roi, dict):
+ from_ = roi['from']
+ to_ = roi['to']
+ type_ = roi["type"]
+ else:
+ # silx >= 0.8.0
+ from_ = roi.getFrom()
+ to_ = roi.getTo()
+ type_ = roi.getType()
+
+ ddict = {
+ 'event': "ROISignal",
+ 'name': name,
+ 'from': from_,
+ 'to': to_,
+ 'type': type_,
+ 'calibration': [A, B, C, order]}
self.sigROISignal.emit(ddict)
- def setDispatcher(self, w):
- w.sigAddSelection.connect(self._addSelection)
- w.sigRemoveSelection.connect(self._removeSelection)
- w.sigReplaceSelection.connect(self._replaceSelection)
+ def _addSelection(self, selection, resetzoom=True, replot=None):
+ _logger.debug("__add, selection = %s", selection)
- def _addSelection(self, selection, replot=True):
- if DEBUG:
- print("__add, selection = ",selection)
+ if replot is not None:
+ _logger.warning(
+ 'deprecated replot argument, use resetzoom instead')
+ resetzoom = replot and resetzoom
- if type(selection) == type([]):
- sellist = selection
- else:
- sellist = [selection]
+ sellist = selection if isinstance(selection, list) else [selection]
for sel in sellist:
# force the selections to include their source for completeness?
# source = sel['SourceName']
- key = sel['Key']
- if "scanselection" in sel:
- if sel["scanselection"] not in [False, "MCA"]:
- continue
- mcakeys = [key]
+ key = sel['Key']
+ if sel.get("scanselection", False) not in [False, "MCA"]:
+ continue
+ mcakeys = [key]
for mca in mcakeys:
legend = sel['legend']
dataObject = sel['dataobject']
info = dataObject.info
- if "selectiontype" in dataObject.info:
- if dataObject.info["selectiontype"] != "1D": continue
+
+ if dataObject.info.get("selectiontype", "1D") != "1D":
+ continue
if numpy.isscalar(dataObject.y[0]):
dataObject.y[0] = numpy.array([dataObject.y[0]])
data = dataObject.y[0]
- curveinfo=copy.deepcopy(info)
+ curveinfo = copy.deepcopy(info)
curveinfo["ylabel"] = info.get("ylabel", "Counts")
if dataObject.x is None:
xhelp = None
@@ -900,7 +906,7 @@ class McaWindow(ScanWindow.ScanWindow):
if xhelp is None:
if 'Channel0' not in info:
info['Channel0'] = 0.0
- xhelp =info['Channel0'] + numpy.arange(len(data)).astype(numpy.float)
+ xhelp = info['Channel0'] + numpy.arange(len(data)).astype(numpy.float)
dataObject.x = [xhelp]
ylen = len(data)
@@ -930,13 +936,13 @@ class McaWindow(ScanWindow.ScanWindow):
xhelp = numpy.take(xhelp, index)
data = numpy.take(data, index)
mdata = numpy.take(mdata, index)
- data = data/mdata
+ data = data / mdata
dataObject.x = [xhelp * 1]
dataObject.m = [numpy.ones(len(data)).astype(numpy.float)]
elif (len(mdata) == 1) or (ylen == 1):
if mdata[0] == 0.0:
continue
- data = data/mdata
+ data = data / mdata
else:
raise ValueError("Cannot normalize data")
dataObject.y = [data]
@@ -946,14 +952,14 @@ class McaWindow(ScanWindow.ScanWindow):
else:
simplefitplot = False
try:
- calib = [0.0,1.0,0.0]
+ calib = [0.0, 1.0, 0.0]
for inputkey in ['baseline', 'regions', 'McaLiveTime']:
if inputkey in info:
curveinfo[inputkey] = info[inputkey]
curveinfo['McaCalib'] = calib
if 'McaCalib' in info:
if type(info['McaCalib'][0]) == type([]):
- calib0 = info['McaCalib'][info['McaDet']-1]
+ calib0 = info['McaCalib'][info['McaDet'] - 1]
else:
calib0 = info['McaCalib']
if 'McaCalibSource' in info:
@@ -965,29 +971,28 @@ class McaWindow(ScanWindow.ScanWindow):
calib = curveinfo['McaCalibSource']
elif 'McaCalib' in info:
if type(info['McaCalib'][0]) == type([]):
- calib = info['McaCalib'][info['McaDet']-1]
+ calib = info['McaCalib'][info['McaDet'] - 1]
else:
calib = info['McaCalib']
if len(calib) > 1:
- xdata=calib[0]+ \
- calib[1]* xhelp
+ xdata = calib[0] + calib[1] * xhelp
if len(calib) == 3:
- xdata = xdata + calib[2]* xhelp * xhelp
+ xdata = xdata + calib[2] * xhelp * xhelp
curveinfo['McaCalib'] = calib
if simplefitplot:
inforegions = []
for region in info['regions']:
- inforegions.append([calib[0] + \
- calib[1] * region[0] +\
+ inforegions.append([calib[0] +
+ calib[1] * region[0] +
calib[2] * region[0] * region[0],
- calib[0] + \
- calib[1] * region[1] +\
+ calib[0] +
+ calib[1] * region[1] +
calib[2] * region[1] * region[1]])
self.addCurve(xdata, data, legend=legend,
- info=curveinfo, own=True)
+ info=curveinfo, own=True)
else:
self.addCurve(xdata, data, legend=legend,
- info=curveinfo, own=True)
+ info=curveinfo, own=True)
self.setGraphXLabel('Energy')
elif self.calibration == self.calboxoptions[2]:
calibrationOrder = None
@@ -996,20 +1001,19 @@ class McaWindow(ScanWindow.ScanWindow):
B = self.caldict[legend]['B']
C = self.caldict[legend]['C']
calibrationOrder = self.caldict[legend]['order']
- calib = [A,B,C]
+ calib = [A, B, C]
elif 'McaCalib' in info:
if type(info['McaCalib'][0]) == type([]):
- calib = info['McaCalib'][info['McaDet']-1]
+ calib = info['McaCalib'][info['McaDet'] - 1]
else:
calib = info['McaCalib']
if len(calib) > 1:
- xdata=calib[0]+ \
- calib[1]* xhelp
+ xdata = calib[0] + calib[1] * xhelp
if len(calib) == 3:
if calibrationOrder == 'TOF':
- xdata = calib[2] + calib[0] / pow(xhelp-calib[1],2)
+ xdata = calib[2] + calib[0] / pow(xhelp - calib[1], 2)
else:
- xdata = xdata + calib[2]* xhelp * xhelp
+ xdata = xdata + calib[2] * xhelp * xhelp
curveinfo['McaCalib'] = calib
curveinfo['McaCalibOrder'] = calibrationOrder
if simplefitplot:
@@ -1019,61 +1023,60 @@ class McaWindow(ScanWindow.ScanWindow):
inforegions.append([calib[2] + calib[0] / pow(region[0]-calib[1],2),
calib[2] + calib[0] / pow(region[1]-calib[1],2)])
else:
- inforegions.append([calib[0] + \
- calib[1] * region[0] +\
- calib[2] * region[0] * region[0],
- calib[0] + \
- calib[1] * region[1] +\
- calib[2] * region[1] * region[1]])
+ inforegions.append([calib[0] +
+ calib[1] * region[0] +
+ calib[2] * region[0] * region[0],
+ calib[0] +
+ calib[1] * region[1] +
+ calib[2] * region[1] * region[1]])
self.addCurve(xdata, data,
- legend=legend,
- info=curveinfo,
- own=True)
+ legend=legend,
+ info=curveinfo,
+ own=True)
else:
self.addCurve(xdata, data,
- legend=legend,
- info=curveinfo,
- own=True)
+ legend=legend,
+ info=curveinfo,
+ own=True)
if calibrationOrder == 'ID18':
self.setGraphXLabel('Time')
else:
self.setGraphXLabel('Energy')
elif self.calibration == 'Fit':
- print("Not yet implemented")
+ _logger.error("Not yet implemented")
continue
- elif self.calibration in self.caldict.keys():
+ elif self.calibration in self.caldict.keys():
A = self.caldict[self.calibration]['A']
B = self.caldict[self.calibration]['B']
C = self.caldict[self.calibration]['C']
calibrationOrder = self.caldict[self.calibration]['order']
- calib = [A,B,C]
+ calib = [A, B, C]
if calibrationOrder == 'TOF':
- xdata = C + (A / ((xhelp - B) * (xhelp - B)))
+ xdata = C + (A / ((xhelp - B) * (xhelp - B)))
else:
- xdata=calib[0]+ \
- calib[1]* xhelp + \
- calib[2]* xhelp * xhelp
+ xdata = calib[0] + \
+ calib[1] * xhelp + \
+ calib[2] * xhelp * xhelp
curveinfo['McaCalib'] = calib
curveinfo['McaCalibOrder'] = calibrationOrder
if simplefitplot:
inforegions = []
for region in info['regions']:
if calibrationOrder == 'TOF':
- inforegions.append([calib[2] + calib[0] / pow(region[0]-calib[1],2),
- calib[2] + calib[0] / pow(region[1]-calib[1],2)])
+ inforegions.append(
+ [calib[2] + calib[0] / pow(region[0]-calib[1], 2),
+ calib[2] + calib[0] / pow(region[1]-calib[1], 2)])
else:
- inforegions.append([calib[0] + \
- calib[1] * region[0] +\
- calib[2] * region[0] * region[0],
- calib[0] + \
- calib[1] * region[1] +\
- calib[2] * region[1] * region[1]])
+ inforegions.append([calib[0] +
+ calib[1] * region[0] +
+ calib[2] * region[0] * region[0],
+ calib[0] +
+ calib[1] * region[1] +
+ calib[2] * region[1] * region[1]])
self.addCurve(xdata, data,
legend=legend,
info=curveinfo,
own=True)
- #baseline = info['baseline'],
- #regions = inforegions)
else:
self.addCurve(xdata, data,
legend=legend,
@@ -1089,8 +1092,6 @@ class McaWindow(ScanWindow.ScanWindow):
legend=legend,
info=curveinfo,
own=True)
- #baseline = info['baseline'],
- #regions = info['regions'])
else:
self.addCurve(xhelp, data,
legend=legend,
@@ -1100,14 +1101,11 @@ class McaWindow(ScanWindow.ScanWindow):
except:
del self.dataObjectsDict[legend]
raise
- if replot:
- #self.replot()
+ if resetzoom:
self.resetZoom()
- self.updateLegends()
def _removeSelection(self, selectionlist):
- if DEBUG:
- print("_removeSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_removeSelection(self, selectionlist) %d", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -1115,35 +1113,29 @@ class McaWindow(ScanWindow.ScanWindow):
legendlist = []
for sel in sellist:
- key = sel['Key']
+ key = sel['Key']
if "scanselection" in sel:
if sel['scanselection'] not in [False, "MCA"]:
continue
- mcakeys = [key]
+ mcakeys = [key]
for mca in mcakeys:
legend = sel['legend']
legendlist.append(legend)
- self.removeCurves(legendlist, replot=True)
+ self.removeCurves(legendlist)
- def removeCurves(self, removelist, replot=True):
+ def removeCurves(self, removelist):
for legend in removelist:
- self.removeCurve(legend, replot=False)
- if replot:
- self.replot()
+ self.removeCurve(legend)
- def removeCurve(self, legend, replot=True):
- super(McaWindow, self).removeCurve(legend, replot=False)
+ def removeCurve(self, legend):
+ super(McaWindow, self).removeCurve(legend)
if legend in self.dataObjectsDict.keys():
del self.dataObjectsDict[legend]
- self.dataObjectsList = self._curveList
- if replot:
- self.replot()
def _replaceSelection(self, selectionlist):
- if DEBUG:
- print("_replaceSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_replaceSelection(self, selectionlist) %s", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -1151,63 +1143,17 @@ class McaWindow(ScanWindow.ScanWindow):
doit = False
for sel in sellist:
- if "scanselection" in sel:
- if sel['scanselection'] not in [False, "MCA"]:
- continue
+ if sel.get('scanselection', False) not in [False, "MCA"]:
+ continue
doit = True
break
if not doit:
return
self.clearCurves()
- self.dataObjectsDict={}
- self.dataObjectsList=self._curveList
+ self.dataObjectsDict = {}
self._addSelection(selectionlist)
- def graphCallback(self, ddict):
- if DEBUG:
- print("McaWindow._graphCallback", ddict)
- if ddict['event'] in ['markerMoved', 'markerSelected']:
- return self._handleMarkerEvent(ddict)
- elif ddict['event'] in ["mouseMoved", "MouseAt"]:
- if self.calibration == self.calboxoptions[0]:
- self._xPos.setText('%.2f' % ddict['x'])
- self._yPos.setText('%.2f' % ddict['y'])
- else:
- self._xPos.setText('%.4f' % ddict['x'])
- self._yPos.setText('%.2f' % ddict['y'])
- elif ddict['event'] in ["curveClicked", "legendClicked"]:
- legend = ddict.get('legend', None)
- legend = ddict.get('label', legend)
- if legend is None:
- if len(self.dataObjectsList):
- legend = self.dataObjectsList[0]
- else:
- return
- self.setActiveCurve(legend)
- elif ddict['event'] == "renameCurveEvent":
- legend = ddict['legend']
- newlegend = ddict['newlegend']
- if legend in self.dataObjectsDict:
- self.dataObjectsDict[newlegend]= copy.deepcopy(\
- self.dataObjectsDict[legend])
- self.dataObjectsDict[newlegend].info['legend'] = newlegend
- self.removeCurve(legend)
- self.addCurve(self.dataObjectsDict[newlegend].x[0],
- self.dataObjectsDict[newlegend].y[0],
- legend=newlegend,
- info=self.dataObjectsDict[newlegend].info['legend'],
- own=True,
- replot=False)
- if legend in self.caldict:
- self.caldict[newlegend] = copy.deepcopy(self.caldict[legend])
- del self.dataObjectsDict[legend]
- self.replot()
- else:
- super(McaWindow, self).graphCallback(ddict)
- return
- self.sigPlotSignal.emit(ddict)
-
- def setActiveCurve(self, legend=None):
+ def setActiveCurve(self, legend):
if legend is None:
legend = self.getActiveCurve(just_legend=True)
if legend is None:
@@ -1215,84 +1161,49 @@ class McaWindow(ScanWindow.ScanWindow):
self.controlWidget.calinfo.BText.setText("?????")
self.controlWidget.calinfo.CText.setText("?????")
return
- if legend in self.dataObjectsDict.keys():
- x0 = self.dataObjectsDict[legend].x[0]
- y = self.dataObjectsDict[legend].y[0]
- #those are the actual data
- if str(self.getGraphXLabel()).upper() != "CHANNEL":
- #I have to get the energy
- A = self.controlWidget.calinfo.caldict['']['A']
- B = self.controlWidget.calinfo.caldict['']['B']
- C = self.controlWidget.calinfo.caldict['']['C']
- order = self.controlWidget.calinfo.caldict['']['order']
- else:
- A = 0.0
- B = 1.0
- C = 0.0
- order = 1
- calib = [A,B,C]
- if order == "TOF":
- x = calib[2] + calib[0] / pow(x0-calib[1],2)
- else:
- x = calib[0]+ \
- calib[1]* x0 + \
- calib[2]* x0 * x0
- else:
- print("Received legend = ", legend)
- print("legends recognized = ", self.dataObjectsDict.keys())
- print("Should not be here")
+ # if legend in self.dataObjectsDict.keys(): # todo: unused block
+ # x0 = self.dataObjectsDict[legend].x[0]
+ # y = self.dataObjectsDict[legend].y[0]
+ # # those are the actual data
+ # if str(self.getGraphXLabel()).upper() != "CHANNEL":
+ # # I have to get the energy
+ # A = self.controlWidget.calinfo.caldict['']['A']
+ # B = self.controlWidget.calinfo.caldict['']['B']
+ # C = self.controlWidget.calinfo.caldict['']['C']
+ # order = self.controlWidget.calinfo.caldict['']['order']
+ # else:
+ # A = 0.0
+ # B = 1.0
+ # C = 0.0
+ # order = 1
+ # calib = [A, B, C]
+ # if order == "TOF":
+ # x = calib[2] + calib[0] / pow(x0-calib[1], 2)
+ # else:
+ # x = calib[0] + \
+ # calib[1] * x0 + \
+ # calib[2] * x0 * x0
+ # else:
+ if legend not in self.dataObjectsDict.keys():
+ _logger.error("Received legend = %s\nlegends recognized = %s\n"
+ "Should not be here",
+ legend, self.dataObjectsDict.keys())
return
try:
info = self.getCurve(legend)[3]
calib = info['McaCalib']
- self.controlWidget.calinfo.setParameters({'A':calib[0],
- 'B':calib[1],
- 'C':calib[2]})
+ self.controlWidget.calinfo.setParameters({'A': calib[0],
+ 'B': calib[1],
+ 'C': calib[2]})
except KeyError:
self.controlWidget.calinfo.AText.setText("?????")
self.controlWidget.calinfo.BText.setText("?????")
self.controlWidget.calinfo.CText.setText("?????")
xlabel = self.getGraphXLabel()
ylabel = self.getGraphYLabel()
- super(McaWindow, self).setActiveCurve(legend, replot=False)
+ super(McaWindow, self).setActiveCurve(legend)
self.setGraphXLabel(xlabel)
self.setGraphYLabel(ylabel)
- self.replot()
-
- def _customFitSignalReceived(self, ddict):
- if ddict['event'] == "FitFinished":
- newDataObject = self.__customFitDataObject
-
- xplot = ddict['x']
- yplot = ddict['yfit']
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
-
- #here I should check the log or linear status
- self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
- self.addCurve(xplot,
- yplot,
- legend=newDataObject.info['legend'],
- own=True)
-
- def _scanFitSignalReceived(self, ddict):
- if DEBUG:
- print("_graphSignalReceived", ddict)
- if ddict['event'] == "EstimateFinished":
- return
- if ddict['event'] == "FitFinished":
- newDataObject = self.__fitDataObject
-
- xplot = self.scanFit.specfit.xdata * 1.0
- yplot = self.scanFit.specfit.gendata(parameters=ddict['data'])
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
-
- self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
- self.addCurve(x=xplot, y=yplot,
- legend=newDataObject.info['legend'], own=True)
def _saveIconSignal(self):
legend = self.getActiveCurve(just_legend=True)
@@ -1303,7 +1214,7 @@ class McaWindow(ScanWindow.ScanWindow):
msg.setWindowTitle('MCA window')
msg.exec_()
return
- #get outputfile
+ # get outputfile
self.outputDir = PyMcaDirs.outputDir
if self.outputDir is None:
self.outputDir = os.getcwd()
@@ -1329,7 +1240,8 @@ class McaWindow(ScanWindow.ScanWindow):
if self.outputFilter is None:
self.outputFilter = format_list[0]
- fileList, fileFilter = PyMcaFileDialogs.getFileList(self,
+ fileList, fileFilter = PyMcaFileDialogs.getFileList(
+ self,
filetypelist=format_list,
message="Output File Selection",
currentdir=wdir,
@@ -1341,34 +1253,33 @@ class McaWindow(ScanWindow.ScanWindow):
return
self.outputFilter = fileFilter
filterused = self.outputFilter.split()
- filetype = filterused[1]
+ filetype = filterused[1]
extension = filterused[2]
- outdir=qt.safe_str(fileList[0])
+ outdir = qt.safe_str(fileList[0])
try:
- self.outputDir = os.path.dirname(outdir)
+ self.outputDir = os.path.dirname(outdir)
PyMcaDirs.outputDir = os.path.dirname(outdir)
except:
- self.outputDir = "."
+ self.outputDir = "."
try:
outputFile = os.path.basename(outdir)
except:
- outputFile = outdir
+ outputFile = outdir
- #get active curve
- x, y, legend, info = self.getActiveCurve()
+ # get active curve
+ x, y, legend, info, params = self.getActiveCurve()
if info is None:
return
- ndict = {}
- ndict[legend] = {'order':1,'A':0.0,'B':1.0,'C':0.0}
+ ndict = {legend: {'order': 1, 'A': 0.0, 'B': 1.0, 'C': 0.0}}
if self.getGraphXLabel().upper() == "CHANNEL":
if legend in self.caldict:
calibrationOrder = self.caldict[legend].get('McaCalibOrder',2)
ndict[legend].update(self.caldict[legend])
if abs(ndict[legend]['C']) > 0.0:
- ndict[legend]['order'] = 2
+ ndict[legend]['order'] = 2
elif 'McaCalib' in info:
- calibrationOrder = info.get('McaCalibOrder',2)
+ calibrationOrder = info.get('McaCalibOrder', 2)
if type(info['McaCalib'][0]) == type([]):
calib = info['McaCalib'][0]
else:
@@ -1376,11 +1287,11 @@ class McaWindow(ScanWindow.ScanWindow):
if len(calib) > 1:
ndict[legend]['A'] = calib[0]
ndict[legend]['B'] = calib[1]
- if len(calib) >2:
- ndict[legend]['order'] = 2
- ndict[legend]['C'] = calib[2]
+ if len(calib) > 2:
+ ndict[legend]['order'] = 2
+ ndict[legend]['C'] = calib[2]
elif legend in self.dataObjectsDict:
- calibrationOrder = self.dataObjectsDict[legend].info.get('McaCalibOrder',2)
+ calibrationOrder = self.dataObjectsDict[legend].info.get('McaCalibOrder', 2)
if 'McaCalib' in self.dataObjectsDict[legend].info:
calib = self.dataObjectsDict[legend].info['McaCalib']
ndict[legend]['A'] = calib[0]
@@ -1388,16 +1299,16 @@ class McaWindow(ScanWindow.ScanWindow):
ndict[legend]['C'] = calib[2]
calib = [ndict[legend]['A'], ndict[legend]['B'], ndict[legend]['C']]
if calibrationOrder == 'TOF':
- energy = calib[2] + calib[0] / pow(x - calib[1],2)
+ energy = calib[2] + calib[0] / pow(x - calib[1], 2)
else:
energy = calib[0] + calib[1] * x + calib[2] * x * x
else:
- #I have it in energy
+ # I have it in energy
A = self.controlWidget.calinfo.caldict['']['A']
B = self.controlWidget.calinfo.caldict['']['B']
C = self.controlWidget.calinfo.caldict['']['C']
order = self.controlWidget.calinfo.caldict['']['order']
- ndict[legend] = {'order':order,'A':A,'B':B,'C':C}
+ ndict[legend] = {'order': order, 'A': A, 'B': B, 'C': C}
calib = [A, B, C]
energy = x * 1
if legend in self.dataObjectsDict.keys():
@@ -1409,9 +1320,9 @@ class McaWindow(ScanWindow.ScanWindow):
if numpy.allclose(energy, x0):
x = self.dataObjectsDict[legend].x[0]
else:
- ndict[legend] = {'order':1,'A': 0.0, 'B':1.0, 'C': 1.0}
+ ndict[legend] = {'order': 1, 'A': 0.0, 'B': 1.0, 'C': 1.0}
- #always overwrite for the time being
+ # always overwrite for the time being
if not outputFile.endswith(extension[1:]):
outputFile += extension[1:]
specFile = os.path.join(self.outputDir, outputFile)
@@ -1428,9 +1339,13 @@ class McaWindow(ScanWindow.ScanWindow):
os.linesep = '\n'
if filterused[0].upper() == "WIDGET":
fformat = specFile[-3:].upper()
- pixmap = qt.QPixmap.grabWidget(self.getWidgetHandle())
+ if hasattr(qt.QPixmap, "grabWidget"):
+ pixmap = qt.QPixmap.grabWidget(self.getWidgetHandle())
+ else:
+ pixmap = self.getWidgetHandle().grab()
if not pixmap.save(specFile, fformat):
- qt.QMessageBox.critical(self,
+ qt.QMessageBox.critical(
+ self,
"Save Error",
"%s" % "I could not save the file\nwith the desired format")
return
@@ -1438,13 +1353,13 @@ class McaWindow(ScanWindow.ScanWindow):
if MATPLOTLIB:
try:
if specFile[-3:].upper() in ['EPS', 'PNG', 'SVG']:
- self.graphicsSave(specFile)
+ self._graphicsSave(plot=self, filename=specFile)
return
except:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
msg.setWindowTitle("Save error")
- msg.setInformativeText("Graphics Saving Error: %s" % \
+ msg.setInformativeText("Graphics Saving Error: %s" %
(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
msg.exec_()
@@ -1461,18 +1376,16 @@ class McaWindow(ScanWindow.ScanWindow):
msg.setText("Input Output Error: %s" % (sys.exc_info()[1]))
msg.exec_()
return
- systemline = os.linesep
- os.linesep = '\n'
- #This was giving problems on legends with a leading b
- #legend = legend.strip('<b>')
- #legend = legend.strip('<\b>')
+ # This was giving problems on legends with a leading b
+ # legend = legend.strip('<b>')
+ # legend = legend.strip('<\b>')
try:
if filetype == 'Scan':
ffile.write("#F %s\n" % specFile)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("#D %s\n" % (time.ctime(time.time())))
ffile.write("\n")
ffile.write("#S 1 %s\n" % legend)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("#D %s\n" % (time.ctime(time.time())))
ffile.write("#N 3\n")
ffile.write("#L channel counts energy\n")
for i in range(len(y)):
@@ -1480,7 +1393,7 @@ class McaWindow(ScanWindow.ScanWindow):
ffile.write("\n")
elif filetype == 'ASCII':
for i in range(len(y)):
- ffile.write("%.7g %.7g %.7g\n" % (x[i], y[i], energy[i]))
+ ffile.write("%.7g %.7g %.7g\n" % (x[i], y[i], energy[i]))
elif filetype == 'CSV':
if "," in filterused[0]:
csv = ","
@@ -1492,24 +1405,24 @@ class McaWindow(ScanWindow.ScanWindow):
csv = "\t"
if "OMNIC" in filterused[0]:
for i in range(len(y)):
- ffile.write("%.7E%s%.7E\n" % \
- (energy[i], csv, y[i]))
+ ffile.write("%.7E%s%.7E\n" %
+ (energy[i], csv, y[i]))
else:
ffile.write('"channel"%s"counts"%s"energy"\n' % (csv, csv))
for i in range(len(y)):
- ffile.write("%.7E%s%.7E%s%.7E\n" % \
- (x[i], csv, y[i], csv, energy[i]))
+ ffile.write("%.7E%s%.7E%s%.7E\n" %
+ (x[i], csv, y[i], csv, energy[i]))
else:
ffile.write("#F %s\n" % specFile)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("#D %s\n" % (time.ctime(time.time())))
ffile.write("\n")
ffile.write("#S 1 %s\n" % legend)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
+ ffile.write("#D %s\n" % (time.ctime(time.time())))
ffile.write("#@MCA %16C\n")
- ffile.write("#@CHANN %d %d %d 1\n" % (len(y), x[0], x[-1]))
+ ffile.write("#@CHANN %d %d %d 1\n" % (len(y), x[0], x[-1]))
ffile.write("#@CALIB %.7g %.7g %.7g\n" % (ndict[legend]['A'],
- ndict[legend]['B'],
- ndict[legend]['C']))
+ ndict[legend]['B'],
+ ndict[legend]['C']))
ffile.write(self.array2SpecMca(y))
ffile.write("\n")
ffile.close()
@@ -1518,12 +1431,6 @@ class McaWindow(ScanWindow.ScanWindow):
raise
return
- def _simpleOperation(self, operation):
- if operation != "save":
- return super(McaWindow, self)._simpleOperation(operation)
- else:
- return self._saveIconSignal()
-
def getCalibrations(self):
return copy.deepcopy(self.caldict)
@@ -1545,56 +1452,57 @@ class McaWindow(ScanWindow.ScanWindow):
self.controlWidget.calbox.setCurrentIndex(item)
self.refresh()
- #The plugins interface
+ # The plugins interface
def _toggleLogY(self):
- if DEBUG:
- print("McaWindow _toggleLogY")
+ _logger.debug("McaWindow _toggleLogY")
+ # ensure call to addCurve does not change dataObjectsDict
self._ownSignal = True
try:
- super(McaWindow, self)._toggleLogY()
+ self.setYAxisLogarithmic(not self.isYAxisLogarithmic())
finally:
self._ownSignal = None
def _toggleLogX(self):
- if DEBUG:
- print("McaWindow _toggleLogX")
+ _logger.debug("McaWindow _toggleLogX")
+ # ensure call to addCurve does not change dataObjectsDict
self._ownSignal = True
try:
- super(McaWindow, self)._toggleLogX()
+ self.setXAxisLogarithmic(not self.isXAxisLogarithmic())
finally:
self._ownSignal = None
def getGraphYLimits(self):
- #if the active curve is mapped to second axis
- #I should give the second axis limits
+ # if the active curve is mapped to second axis
+ # I should give the second axis limits
return super(McaWindow, self).getGraphYLimits()
- #end of plugins interface
- def addCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
+ # end of plugins interface
+ def addCurve(self, x, y, legend=None, info=None, replace=False,
color=None, symbol=None, linestyle=None,
xlabel=None, ylabel=None, yaxis=None,
- xerror=None, yerror=None, own=None, **kw):
- if legend in self._curveList:
+ xerror=None, yerror=None, own=None,
+ resetzoom=True, **kw):
+ if "replot" in kw:
+ _logger.warning("addCurve deprecated replot argument, "
+ "use resetzoom instead")
+ resetzoom = kw["replot"] and resetzoom
+ all_legends = self.getAllCurves(just_legend=True)
+ if legend in all_legends:
if info is None:
info = {}
oldStuff = self.getCurve(legend)
if oldStuff not in [[], None]:
- oldX, oldY, oldLegend, oldInfo = oldStuff
+ oldX, oldY, oldLegend, oldInfo, oldParams = oldStuff
else:
oldInfo = {}
if color is None:
color = info.get("plot_color", oldInfo.get("plot_color", None))
if symbol is None:
- symbol = info.get("plot_symbol",oldInfo.get("plot_symbol", None))
+ symbol = info.get("plot_symbol", oldInfo.get("plot_symbol", None))
if linestyle is None:
- if self._plotLines:
- linestyle = info.get("plot_linestyle",oldInfo.get("plot_linestyle", None))
- if linestyle in [' ', None, '']:
- linestyle = '-'
- else:
- linestyle = ' '
+ linestyle = info.get("plot_linestyle", oldInfo.get("plot_linestyle", None))
if yaxis is None:
- yaxis = info.get("plot_yaxis",oldInfo.get("plot_yaxis", None))
+ yaxis = info.get("plot_yaxis", oldInfo.get("plot_yaxis", None))
if xlabel is None:
xlabel = self.getGraphXLabel()
if ylabel is None:
@@ -1604,14 +1512,16 @@ class McaWindow(ScanWindow.ScanWindow):
if own and (legend in self.dataObjectsDict):
# The curve is already registered
super(McaWindow, self).addCurve(x, y, legend=legend, info=info,
- replace=replace, replot=replot, color=color, symbol=symbol,
- linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
- xerror=xerror, yerror=yerror, **kw)
+ replace=replace, resetzoom=resetzoom,
+ color=color, symbol=symbol,
+ linestyle=linestyle, xlabel=xlabel,
+ ylabel=ylabel, yaxis=yaxis,
+ xerror=xerror, yerror=yerror, **kw)
else:
if legend in self.dataObjectsDict:
xChannels, yOrig, infoOrig = self.getDataAndInfoFromLegend(legend)
calib = info.get('McaCalib', [0.0, 1.0, 0.0])
- calibrationOrder = info.get('McaCalibOrder',2)
+ calibrationOrder = info.get('McaCalibOrder', 2)
if calibrationOrder == 'TOF':
xFromChannels = calib[2] + calib[0] / pow(xChannels-calib[1], 2)
else:
@@ -1621,14 +1531,21 @@ class McaWindow(ScanWindow.ScanWindow):
x = xChannels
# create the data object (Is this necessary????)
self.newCurve(x, y, legend=legend, info=info,
- replace=replace, replot=replot, color=color, symbol=symbol,
- linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
- xerror=xerror, yerror=yerror, **kw)
+ replace=replace, color=color, symbol=symbol, resetzoom=resetzoom,
+ linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
+ xerror=xerror, yerror=yerror, **kw)
+ # activate first curve
+ if not all_legends:
+ self.setActiveCurve(legend)
- def newCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
- color=None, symbol=None, linestyle=None,
+ def newCurve(self, x, y, legend=None, info=None, replace=False,
+ color=None, symbol=None, linestyle=None, resetzoom=True,
xlabel=None, ylabel=None, yaxis=None,
xerror=None, yerror=None, **kw):
+ if "replot" in kw:
+ _logger.warning("addCurve deprecated replot argument, "
+ "use resetzoom instead")
+ resetzoom = kw["replot"] and resetzoom
if info is None:
info = {}
if legend is None:
@@ -1655,23 +1572,22 @@ class McaWindow(ScanWindow.ScanWindow):
newDataObject.info['Key'] = ""
newDataObject.info['selectiontype'] = "1D"
sel_list = []
- sel = {}
- sel['SourceType'] = "Operation"
- sel['SourceName'] = legend
- sel['Key'] = legend
- sel['legend'] = legend
- sel['dataobject'] = newDataObject
- sel['scanselection'] = False
- sel['selectiontype'] = "1D"
+ sel = {
+ 'SourceType': "Operation",
+ 'SourceName': legend,
+ 'Key': legend,
+ 'legend': legend,
+ 'dataobject': newDataObject,
+ 'scanselection': False,
+ 'selectiontype': "1D"}
sel_list.append(sel)
if replace:
self._replaceSelection(sel_list)
else:
- self._addSelection(sel_list, replot=replot)
+ self._addSelection(sel_list, resetzoom=resetzoom)
def refresh(self):
- if DEBUG:
- print(" DANGEROUS REFRESH CALLED")
+ _logger.debug(" DANGEROUS REFRESH CALLED")
activeCurve = self.getActiveCurve(just_legend=True)
# try to keep the same curve order
legendList = self.getAllCurves(just_legend=True)
@@ -1679,52 +1595,29 @@ class McaWindow(ScanWindow.ScanWindow):
sellist = []
for key in legendList:
if key in dataObjectsKeyList:
- sel ={}
- sel['SourceName'] = self.dataObjectsDict[key].info['SourceName']
- sel['dataobject'] = self.dataObjectsDict[key]
- sel['legend'] = key
- sel['Key'] = self.dataObjectsDict[key].info['Key']
+ sel = {'SourceName': self.dataObjectsDict[key].info['SourceName'],
+ 'dataobject': self.dataObjectsDict[key],
+ 'legend': key,
+ 'Key': self.dataObjectsDict[key].info['Key']}
sellist.append(sel)
for key in dataObjectsKeyList:
if key not in legendList:
- sel ={}
- sel['SourceName'] = self.dataObjectsDict[key].info['SourceName']
- sel['dataobject'] = self.dataObjectsDict[key]
- sel['legend'] = key
- sel['Key'] = self.dataObjectsDict[key].info['Key']
+ sel = {'SourceName': self.dataObjectsDict[key].info['SourceName'],
+ 'dataobject': self.dataObjectsDict[key],
+ 'legend': key,
+ 'Key': self.dataObjectsDict[key].info['Key']}
sellist.append(sel)
self.clearCurves()
self._addSelection(sellist)
if activeCurve is not None:
self.setActiveCurve(activeCurve)
- self.replot()
-
- def renameCurve(self, oldLegend, newLegend, replot=True):
- xChannels, yOrig, infoOrig = self.getDataAndInfoFromLegend(oldLegend)
- x, y, legend, info = self.getCurve(oldLegend)[:4]
- calib = info.get('McaCalib', [0.0, 1.0, 0.0])
- calibrationOrder = info.get('McaCalibOrder',2)
- if calibrationOrder == 'TOF':
- xFromChannels = calib[2] + calib[0] / pow(xChannels-calib[1], 2)
- else:
- xFromChannels = calib[0] + \
- calib[1] * xChannels + calib[2] * xChannels * xChannels
- if numpy.allclose(xFromChannels, x):
- x = xChannels
- newInfo = copy.deepcopy(info)
- newInfo['legend'] = newLegend
- newInfo['SourceName'] = newLegend
- newInfo['Key'] = ""
- newInfo['selectiontype'] = "1D"
- # create the data object (Is this necessary????)
- self.removeCurve(oldLegend, replot=False)
- self.addCurve(x, y, legend=newLegend, info=newInfo, replot=replot)
- self.updateLegends()
+ self.resetZoom()
+
def test():
w = McaWindow()
x = numpy.arange(1000.)
- y = 10 * x + 10000. * numpy.exp(-0.5*(x-500)*(x-500)/400)
+ y = 10 * x + 10000. * numpy.exp(-0.5*(x-500)*(x-500)/400)
w.addCurve(x, y, legend="dummy", replot=True, replace=True)
w.resetZoom()
app.lastWindowClosed.connect(app.quit)
diff --git a/PyMca5/PyMcaGui/pymca/Median2DBrowser.py b/PyMca5/PyMcaGui/pymca/Median2DBrowser.py
index 021310a..583d053 100644
--- a/PyMca5/PyMcaGui/pymca/Median2DBrowser.py
+++ b/PyMca5/PyMcaGui/pymca/Median2DBrowser.py
@@ -28,15 +28,17 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
-DEBUG = 0
+import logging
+_logger = logging.getLogger(__name__)
+
try:
from PyMca5.PyMcaGui.pymca import StackBrowser
from PyMca5.PyMcaMath.PyMcaSciPy.signal import median
except ImportError:
- if DEBUG:
- import traceback
- print("Median2DBrowser problem!")
- print(traceback.format_exc())
+ _logger.warning("Median2DBrowser problem!")
+ import traceback
+ print(traceback.format_exc())
+
medfilt2d = median.medfilt2d
qt = StackBrowser.qt
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaBatch.py b/PyMca5/PyMcaGui/pymca/PyMcaBatch.py
index 6df8d78..984d29b 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaBatch.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaBatch.py
@@ -32,6 +32,7 @@ import sys
import os
import time
import subprocess
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
@@ -57,7 +58,8 @@ from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaCore import PyMcaBatchBuildOutput
ROIWIDTH = 100.
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class McaBatchGUI(qt.QWidget):
def __init__(self,parent=None,name="PyMca batch fitting",fl=None,
@@ -192,8 +194,7 @@ class McaBatchGUI(qt.QWidget):
if QTVERSION < '4.0.0':
palette.setDisabled(palette.active())
else:
- if DEBUG:
- print("palette set disabled")
+ _logger.debug("palette set disabled")
self.__imgBox.setChecked(True)
self.__imgBox.setEnabled(False)
vbox2.l.addWidget(self.__imgBox)
@@ -786,9 +787,8 @@ class McaBatchGUI(qt.QWidget):
allowSingleFileSplitProcesses = False
if HDF5SUPPORT:
if h5py.is_hdf5(self.fileList[0]):
- if DEBUG:
- print("Disallow single HDF5 process split")
- print("due to problems with concurrent access")
+ _logger.debug("Disallow single HDF5 process split")
+ _logger.debug("due to problems with concurrent access")
#allowSingleFileSplitProcesses = True
allowSingleFileSplitProcesses = False
if not allowSingleFileSplitProcesses:
@@ -1007,8 +1007,7 @@ class McaBatchGUI(qt.QWidget):
self.hide()
qApp = qt.QApplication.instance()
qApp.processEvents()
- if DEBUG:
- print("cmd = %s" % cmd)
+ _logger.debug("cmd = %s", cmd)
if self.__splitBox.isChecked():
nbatches = int(qt.safe_str(self.__splitSpin.text()))
if len(self.fileList) > 1:
@@ -1028,8 +1027,7 @@ class McaBatchGUI(qt.QWidget):
subprocess.Popen(cmd1.encode(sys.getfilesystemencoding()),
cwd=os.getcwd()))
- if DEBUG:
- print("cmd = %s" % cmd1)
+ _logger.debug("cmd = %s", cmd1)
else:
#f = open("CMD", 'wb')
processList = []
@@ -1037,8 +1035,7 @@ class McaBatchGUI(qt.QWidget):
#the mcastep has been dealt with above
cmd1 = cmd + " --mcaoffset=%d --chunk=%d" % (i, i)
processList.append(subprocess.Popen(cmd1, cwd=os.getcwd()))
- if DEBUG:
- print("CMD = %s" % cmd1)
+ _logger.debug("CMD = %s", cmd1)
#f.write(cmd1+"\n")
#f.close()
self._processList = processList
@@ -1048,7 +1045,7 @@ class McaBatchGUI(qt.QWidget):
if not self._timer.isActive():
self._timer.start(1000)
else:
- print("timer was already active")
+ _logger.info("timer was already active")
return
else:
try:
@@ -1135,8 +1132,7 @@ class McaBatchGUI(qt.QWidget):
self.outputDir, overwrite,
filestep, mcastep, html, htmlindex,
listfile, concentrations, table, fitfiles, selectionFlag)
- if DEBUG:
- print("cmd = %s" % cmd)
+ _logger.debug("cmd = %s", cmd)
if self.__splitBox.isChecked():
qApp = qt.QApplication.instance()
qApp.processEvents()
@@ -1168,11 +1164,11 @@ class McaBatchGUI(qt.QWidget):
if not self._timer.isActive():
self._timer.start(1000)
else:
- print("timer was already active")
+ _logger.info("timer was already active")
return
else:
os.system(cmd)
- print(" COMMAND = ", cmd)
+ _logger.info(" COMMAND = %s", cmd)
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Information)
text = "Your batch has been started as an independent process."
@@ -1184,7 +1180,7 @@ class McaBatchGUI(qt.QWidget):
try:
os.remove(listfile)
except:
- print("Cannot delete file %s" % listfile)
+ _logger.error("Cannot delete file %s", listfile)
raise
if config is None:
lst = self.fileList
@@ -1224,7 +1220,7 @@ class McaBatchGUI(qt.QWidget):
self.raise_()
work = PyMcaBatchBuildOutput.PyMcaBatchBuildOutput(os.path.join(self.outputDir, "IMAGES"))
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
a, b, c = work.buildOutput(delete=False)
else:
a, b, c = work.buildOutput(delete=True)
@@ -1245,7 +1241,7 @@ class McaBatchGUI(qt.QWidget):
else:
os.system("%s %s &" % (rgb, b[0]))
work = PyMcaBatchBuildOutput.PyMcaBatchBuildOutput(self.outputDir)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
work.buildOutput(delete=False)
else:
work.buildOutput(delete=True)
@@ -1301,8 +1297,7 @@ class McaBatch(McaAdvancedFitBatch.McaAdvancedFitBatch, qt.QThread):
qt.QApplication.postEvent(self.parent, McaCustomEvent.McaCustomEvent(ddict))
def onMca(self, mca, nmca, filename=None, key=None, info=None):
- if DEBUG:
- print("onMca key = %s" % key)
+ _logger.debug("onMca key = %s", key)
ddict = {'mca':mca,
'nmca':nmca,
'mcastep':self.mcaStep,
@@ -1322,8 +1317,7 @@ class McaBatch(McaAdvancedFitBatch.McaAdvancedFitBatch, qt.QThread):
if self.pleasePause:self.__pauseMethod()
def onEnd(self):
- if DEBUG:
- print("onEnd")
+ _logger.debug("onEnd")
ddict = {'event':'onEnd',
'filestep':self.fileStep,
@@ -1454,12 +1448,11 @@ class McaBatchWindow(qt.QWidget):
elif event.dict['event'] == 'reportWritten':self.onReportWritten()
else:
- print("Unhandled event %s" % event)
+ _logger.warning("Unhandled event %s", event)
def onNewFile(self, file, filelist, filestep, filebeginoffset =0, fileendoffset = 0):
- if DEBUG:
- print("onNewFile: %s" % file)
+ _logger.debug("onNewFile: %s", file)
indexlist = list(range(0,len(filelist),filestep))
index = indexlist.index(filelist.index(file)) - filebeginoffset
#print index + filebeginoffset
@@ -1474,7 +1467,7 @@ class McaBatchWindow(qt.QWidget):
try:
os.remove(self.htmlindex)
except:
- print("cannot delete file %s" % self.htmlindex)
+ _logger.warning("cannot delete file %s", self.htmlindex)
nfiles = len(indexlist)-filebeginoffset-fileendoffset
self.status.setText("Processing file %s" % file)
e = time.time()
@@ -1497,9 +1490,8 @@ class McaBatchWindow(qt.QWidget):
qApp = qt.QApplication.instance()
qApp.processEvents()
- def onImage(self,key,keylist):
- if DEBUG:
- print("onImage %s" % key)
+ def onImage(self, key, keylist):
+ _logger.debug("onImage %s", key)
i = keylist.index(key) + 1
n = len(keylist)
if QTVERSION < '4.0.0':
@@ -1516,8 +1508,7 @@ class McaBatchWindow(qt.QWidget):
#def onMca(self, mca, nmca, mcastep):
def onMca(self, ddict):
- if DEBUG:
- print("onMca ", ddict['mca'])
+ _logger.debug("onMca %s", ddict['mca'])
mca = ddict['mca']
nmca = ddict['nmca']
mcastep = ddict['mcastep']
@@ -1537,12 +1528,12 @@ class McaBatchWindow(qt.QWidget):
self.__htmlReport(filename, key, outputdir,
useExistingFiles, info, firstmca = False)
except:
- print("ERROR on REPORT",sys.exc_info())
- print(sys.exc_info()[1])
- print("filename = %s key =%s " % (filename, key))
- print("If your batch is stopped, please report this")
- print("error sending the above mentioned file and the")
- print("associated fit configuration file.")
+ _logger.warning("ERROR on REPORT %s", sys.exc_info())
+ _logger.warning("%s", sys.exc_info()[1])
+ _logger.warning("filename = %s key =%s ", (filename, key))
+ _logger.warning("If your batch is stopped, please report this")
+ _logger.warning("error sending the above mentioned file and the")
+ _logger.warning("associated fit configuration file.")
if QTVERSION < '4.0.0':
self.mcaBar.setTotalSteps(nmca)
self.mcaBar.setProgress(mca)
@@ -1566,20 +1557,20 @@ class McaBatchWindow(qt.QWidget):
try:
os.mkdir(fitdir)
except:
- print("I could not create directory %s" % fitdir)
+ _logger.warning("I could not create directory %s", fitdir)
return
- fitdir = os.path.join(fitdir,filename+"_HTMLDIR")
+ fitdir = os.path.join(fitdir, filename+"_HTMLDIR")
if not os.path.exists(fitdir):
try:
os.mkdir(fitdir)
except:
- print("I could not create directory %s" % fitdir)
+ _logger.warning("I could not create directory %s", fitdir)
return
localindex = os.path.join(fitdir, "index.html")
if not os.path.isdir(fitdir):
- print("%s does not seem to be a valid directory" % fitdir)
+ _logger.warning("%s does not seem to be a valid directory", fitdir)
else:
- outfile = filename +"_"+key+".html"
+ outfile = filename + "_" + key + ".html"
outfile = os.path.join(fitdir, outfile)
useExistingResult = useExistingFiles
if os.path.exists(outfile):
@@ -1587,7 +1578,7 @@ class McaBatchWindow(qt.QWidget):
try:
os.remove(outfile)
except:
- print("cannot delete file %s" % outfile)
+ _logger.warning("cannot delete file %s", outfile)
useExistingResult = 0
else:
useExistingResult = 0
@@ -1596,7 +1587,7 @@ class McaBatchWindow(qt.QWidget):
fitdir = os.path.join(fitdir,filename+"_FITDIR")
fitfile= os.path.join(fitdir, filename +"_"+key+".fit")
if not os.path.exists(fitfile):
- print("fit file %s does not exists!" % fitfile)
+ _logger.warning("fit file %s does not exists!", fitfile)
return
if self.report is None:
#first file
@@ -1704,8 +1695,7 @@ class McaBatchWindow(qt.QWidget):
if sys.executable in ["PyMcaMain", "PyMcaMain.exe",
"PyMcaBatch", "PyMcaBatch.exe"]:
frozen = True
- if DEBUG:
- print("final dirname = %s" % dirname)
+ _logger.debug("final dirname = %s", dirname)
if frozen:
# we are at level PyMca5\PyMcaGui\pymca
dirname = os.path.dirname(dirname)
@@ -1718,19 +1708,20 @@ class McaBatchWindow(qt.QWidget):
else:
myself = sys.executable+" "+os.path.join(dirname, "EdfFileSimpleViewer.py")
cmd = "%s %s &" % (myself, filelist)
- if DEBUG:
- print("cmd = %s" % cmd)
+ _logger.debug("cmd = %s", cmd)
os.system(cmd)
def main():
sys.excepthook = qt.exceptionHandler
import getopt
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
options = 'f'
longoptions = ['cfg=','outdir=','roifit=','roi=','roiwidth=',
'overwrite=', 'filestep=', 'mcastep=', 'html=','htmlindex=',
'listfile=','cfglistfile=', 'concentrations=', 'table=', 'fitfiles=',
'filebeginoffset=','fileendoffset=','mcaoffset=', 'chunk=',
- 'nativefiledialogs=','selection=', 'exitonend=']
+ 'nativefiledialogs=','selection=', 'exitonend=',
+ 'logging=', 'debug=']
filelist = None
outdir = None
cfg = None
@@ -1807,6 +1798,8 @@ def main():
elif opt in ('--exitonend'):
exitonend = int(arg)
+ logging.basicConfig(level=getLoggingLevel(opts))
+
if listfile is None:
filelist=[]
for item in args:
@@ -1859,8 +1852,8 @@ def main():
mcaoffset=mcaoffset, chunk=chunk, selection=selection)
except:
if exitonend:
- print("Error: " % sys.exc_info()[1])
- print("Quitting as requested")
+ _logger.warning("Error: ", sys.exc_info()[1])
+ _logger.warning("Quitting as requested")
qt.QApplication.instance().quit()
else:
msg = qt.QMessageBox()
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaGLWindow.py b/PyMca5/PyMcaGui/pymca/PyMcaGLWindow.py
index 100a221..76c8fd0 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaGLWindow.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaGLWindow.py
@@ -28,20 +28,20 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
-DEBUG = 0
+import logging
+_logger = logging.getLogger(__name__)
+
try:
from PyMca5 import Object3D
from PyMca5.Object3D import Object3DScene
except ImportError:
- if DEBUG:
- print("PyMcaGLWindow imports Object3D direcly. Frozen version?")
+ _logger.debug("PyMcaGLWindow imports Object3D direcly. Frozen version?")
import Object3D
from Object3D import Object3DScene
class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
def _addSelection(self, selectionlist, replot=True):
- if DEBUG:
- print("addSelection(self, selectionlist)",selectionlist)
+ _logger.debug("addSelection(self, selectionlist=%s)", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -68,8 +68,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
else:
numberOfXAxes = len(dataObject.x)
if numberOfXAxes > 1:
- if DEBUG:
- print("Mesh plots")
+ _logger.debug("Mesh plots")
else:
xdata = dataObject.x[0]
@@ -93,8 +92,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
def _removeSelection(self, selectionlist):
- if DEBUG:
- print("_removeSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_removeSelection(self, selectionlist=%s)", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -117,8 +115,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
def _replaceSelection(self, selectionlist):
- if DEBUG:
- print("_replaceSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_replaceSelection(self, selectionlist=%s)", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -165,8 +162,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
#or not
if ndim == ndata:
if len(data.shape) == 3:
- if DEBUG:
- print("CASE 1")
+ _logger.debug("CASE 1")
if (xDimList[0] != data.shape[0]) or\
(xDimList[1] != data.shape[1]) or\
(xDimList[2] != data.shape[2]):
@@ -185,8 +181,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
legend=legend,
update_scene=update_scene)
elif len(data.shape) == 2:
- if DEBUG:
- print("CASE 2")
+ _logger.debug("CASE 2")
object3D = self.mesh(data,
x=dataObject.x[0],
y=dataObject.x[1],
@@ -195,8 +190,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
legend=legend,
update_scene=update_scene)
elif len(data.shape) == 1:
- if DEBUG:
- print("CASE 3")
+ _logger.debug("CASE 3")
object3D = self.mesh(data,
x=dataObject.x[0],
y=numpy.zeros((1,1), numpy.float32),
@@ -205,9 +199,8 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
update_scene=update_scene)
return object3D
elif (len(data.shape) == 3) and (len(xDimList) == 2):
- print("WARNING Assuming last dimension")
- if DEBUG:
- print("CASE 1.1")
+ _logger.warning("Assuming last dimension")
+ _logger.debug("CASE 1.1")
if (xDimList[0] != data.shape[0]) or\
(xDimList[1] != data.shape[1]):
text = "Wrong dimensions:"
@@ -247,8 +240,7 @@ class SceneGLWindow(Object3D.Object3DScene.Object3DScene):
#I force a surface plot.
if ndata < 200000:
cfg = object3D.setConfiguration({'common':{'mode':3}})
- if DEBUG:
- print("DEFAULT CASE")
+ _logger.debug("DEFAULT CASE")
object3D.setData(values, xyz=xyzData)
self.addObject(object3D, legend, update_scene=update_scene)
return object3D
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaHKLImageWindow.py b/PyMca5/PyMcaGui/pymca/PyMcaHKLImageWindow.py
index 2ad4aac..651790c 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaHKLImageWindow.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaHKLImageWindow.py
@@ -29,12 +29,14 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
+import logging
from . import PyMcaImageWindow
from PyMca5.PyMcaPhysics import SixCircle
arctan = numpy.arctan
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class PyMcaHKLImageWindow(PyMcaImageWindow.PyMcaImageWindow):
def __init__(self, *var, **kw):
@@ -276,8 +278,7 @@ class PyMcaHKLImageWindow(PyMcaImageWindow.PyMcaImageWindow):
ddict['lambda'] = float(info[key])
continue
- if DEBUG:
- for key in ddict.keys():
- print(key, ddict[key])
+ for key in ddict.keys():
+ _logger.debug("%s: %s", key, ddict[key])
return ddict
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaImageWindow.py b/PyMca5/PyMcaGui/pymca/PyMcaImageWindow.py
index 67418c4..ee6535f 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaImageWindow.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaImageWindow.py
@@ -29,8 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
-import time
-from PyMca5.PyMcaGui import IconDict
+import logging
from . import RGBImageCalculator
qt = RGBImageCalculator.qt
QTVERSION = qt.qVersion()
@@ -38,7 +37,8 @@ from . import RGBCorrelator
from PyMca5.PyMcaGui import FrameBrowser
USE_BROWSER = True
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
def __init__(self, parent = None,
@@ -99,8 +99,7 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
w.sigReplaceSelection.connect(self._replaceSelection)
def _addSelection(self, selectionlist):
- if DEBUG:
- print("_addSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_addSelection(self, selectionlist=%s)", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -164,7 +163,7 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
tmpData.shape = int(nRows), int(nColumns)
dataObject.data[yIndex] = tmpData
else:
- print("Nothing to plot")
+ _logger.info("Nothing to plot")
elif hasattr(dataObject, "x") and (dataObject.x is not None):
shape = dataObject.data.shape
if len(dataObject.x) == 2:
@@ -176,7 +175,7 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
nColumns = numpy.argmin(abs(x0-x0[0]) < 1.0e-6)
nRows = x1.size / nColumns
if nRows!= int(nRows):
- print("%f != %d" % (nRows, int(nRows)))
+ _logger.warning("%f != %d", nRows, int(nRows))
raise ValueError("2D Selection not understood")
transpose = False
nColumns = int(nColumns)
@@ -186,7 +185,7 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
nRows = numpy.argmin(abs(x1-x1[0]) < 1.0e-6)
nColumns = x0.size / nRows
if nColumns != int(nColumns):
- print("%f != %d" % (nColumns, int(nColumns)))
+ _logger.warning("%f != %d", nColumns, int(nColumns))
raise ValueError("2D Selection not understood")
transpose = True
nRows = int(nRows)
@@ -299,8 +298,7 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
pass
def _removeSelection(self, selectionlist):
- if DEBUG:
- print("_removeSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_removeSelection(self, selectionlist=%s)", selectionlist)
if type(selectionlist) == type([]):
sellist = selectionlist
else:
@@ -316,8 +314,8 @@ class PyMcaImageWindow(RGBImageCalculator.RGBImageCalculator):
#self.plotImage(True)
def _replaceSelection(self, selectionlist):
- if DEBUG:
- print("_replaceSelection(self, selectionlist)",selectionlist)
+ _logger.debug("_replaceSelection(self, selectionlist=%s)",
+ selectionlist)
current = self.slider.value()
self._addSelection(selectionlist)
if current < self._nImages:
@@ -362,7 +360,7 @@ class TimerLoop:
self.__timer.start(period)
def test(self):
- print("Test function called")
+ _logger.info("Test function called")
if __name__ == "__main__":
from PyMca5 import DataObject
@@ -378,8 +376,7 @@ if __name__ == "__main__":
def buildSelection(dataObject, name = "image_data0"):
key = dataObject.info['Key']
def dataObjectDestroyed(ref, dataObjectKey=key):
- if DEBUG:
- print("dataObject distroyed key = %s" % key)
+ _logger.debug("dataObject distroyed key = %s", key)
dataObjectRef=weakref.proxy(dataObject, dataObjectDestroyed)
selection = {}
selection['SourceType'] = 'SPS'
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaMain.py b/PyMca5/PyMcaGui/pymca/PyMcaMain.py
index 991a8b1..02fa20e 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaMain.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaMain.py
@@ -30,11 +30,12 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys, getopt
import traceback
+import logging
if sys.platform == 'win32':
import ctypes
from ctypes.wintypes import MAX_PATH
nativeFileDialogs = None
-DEBUG = 0
+_logger = logging.getLogger(__name__)
backend=None
if __name__ == '__main__':
options = '-f'
@@ -45,14 +46,15 @@ if __name__ == '__main__':
'backend=',
'nativefiledialogs=',
'PySide=',
- 'binding=']
+ 'binding=',
+ 'logging=']
try:
opts, args = getopt.getopt(
sys.argv[1:],
options,
longoptions)
except getopt.error:
- print(sys.exc_info()[1])
+ print("%s" % sys.exc_info()[1])
sys.exit(1)
keywords={}
@@ -65,8 +67,10 @@ if __name__ == '__main__':
elif opt in ('--shm'):
keywords['shm'] = arg
elif opt in ('--debug'):
- debugreport = 1
- DEBUG = 1
+ if arg.lower() not in ['0', 'false']:
+ debugreport = 1
+ _logger.setLevel(logging.DEBUG)
+ # --debug is also parsed later for the global logging level
elif opt in ('-f'):
keywords['fresh'] = 1
elif opt in ('--qt'):
@@ -89,8 +93,13 @@ if __name__ == '__main__':
if sys.version_info < (3,):
try:
import sip
- sip.setapi("QString", 2)
- sip.setapi("QVariant", 2)
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ sip.setapi('QDate', 2)
+ sip.setapi('QDateTime', 2)
+ sip.setapi('QTextStream', 2)
+ sip.setapi('QTime', 2)
+ sip.setapi('QUrl', 2)
except:
print("Cannot set sip API")
import PyQt4.QtCore
@@ -115,6 +124,9 @@ if __name__ == '__main__':
elif qtversion == '5':
import PyQt5.QtCore
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
+ logging.basicConfig(level=getLoggingLevel(opts))
+
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
if sys.platform == 'darwin':
@@ -212,7 +224,6 @@ if __name__ == "__main__":
qApp = qt.QApplication.instance()
qApp.processEvents()
-from PyMca5.PyMcaGraph.Plot import Plot
from PyMca5.PyMcaGui.pymca import ScanWindow
from PyMca5.PyMcaGui.pymca import McaWindow
@@ -294,7 +305,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.sourceWidget.sourceSelector._openFileSlot)
self.openMenu.addAction("Load Training Data",
self.loadTrainingData)
-
+ self.trainingDataMenu = None
self.__useTabWidget = True
@@ -308,13 +319,14 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.mdi.addWindow(self.scanWindow)
else:
if backend is not None:
- Plot.defaultBackend = backend
+ import silx
+ silx.config.DEFAULT_PLOT_BACKEND = backend
self.mainTabWidget = qt.QTabWidget(self.mdi)
self.mainTabWidget.setWindowTitle("Main Window")
self.mcaWindow = McaWindow.McaWindow(backend=backend)
self.scanWindow = ScanWindow.ScanWindow(info=True,
backend=backend)
- self.scanWindow._togglePointsSignal()
+ self.scanWindow.getCurveStyleAction().trigger()
if OBJECT3D:
self.glWindow = SceneGLWindow.SceneGLWindow()
self.mainTabWidget.addTab(self.mcaWindow, "MCA")
@@ -380,7 +392,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self._startupSelection(source=kw['spec'],
selection=None)
- def connectDispatcher(self, viewer, dispatcher = None):
+ def connectDispatcher(self, viewer, dispatcher=None):
#I could connect sourceWidget to myself and then
#pass the selections to the active window!!
#That will be made in a next iteration I guess
@@ -447,22 +459,22 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
if self.mainTabWidget.isHidden():
#make sure it is visible in case of being closed
self.mainTabWidget.show()
- if DEBUG:
+
+ try:
self._dispatcherAddSelectionSlot(ddict)
- else:
- try:
- self._dispatcherAddSelectionSlot(ddict)
- except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Error: %s" % sys.exc_info()[1])
- msg.setInformativeText(str(sys.exc_info()[1]))
- msg.setDetailedText(traceback.format_exc())
- msg.exec_()
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Error: %s" % sys.exc_info()[1])
+ msg.setInformativeText(str(sys.exc_info()[1]))
+ msg.setDetailedText(traceback.format_exc())
+ msg.exec_()
def _dispatcherAddSelectionSlot(self, dictOrList):
- if DEBUG:
- print("self._dispatcherAddSelectionSlot(ddict), ddict = ", dictOrList)
+ _logger.debug("self._dispatcherAddSelectionSlot(ddict), ddict = %s",
+ dictOrList)
if type(dictOrList) == type([]):
ddict = dictOrList[0]
else:
@@ -470,8 +482,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
toadd = False
if self._is2DSelection(ddict):
- if DEBUG:
- print("2D selection")
+ _logger.debug("2D selection")
if self.imageWindowCorrelator is None:
self.imageWindowCorrelator = RGBCorrelator.RGBCorrelator()
#toadd = True
@@ -493,13 +504,15 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
except:
pass
if hkl:
- imageWindow = PyMcaHKLImageWindow.PyMcaHKLImageWindow(name = legend,
- correlator = self.imageWindowCorrelator,
- scanwindow=self.scanWindow)
+ imageWindow = PyMcaHKLImageWindow.PyMcaHKLImageWindow(
+ name=legend,
+ correlator=self.imageWindowCorrelator,
+ scanwindow=self.scanWindow)
else:
- imageWindow = PyMcaImageWindow.PyMcaImageWindow(name = legend,
- correlator = self.imageWindowCorrelator,
- scanwindow=self.scanWindow)
+ imageWindow = PyMcaImageWindow.PyMcaImageWindow(
+ name=legend,
+ correlator=self.imageWindowCorrelator,
+ scanwindow=self.scanWindow)
self.imageWindowDict[legend] = imageWindow
imageWindow.sigAddImageClicked.connect( \
@@ -527,8 +540,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
else:
self.imageWindowDict[legend]._addSelection(ddict)
elif self._isStackSelection(ddict):
- if DEBUG:
- print("Stack selection")
+ _logger.debug("Stack selection")
legend = ddict['legend']
widget = QStackWidget.QStackWidget()
widget.notifyCloseEventToWidget(self)
@@ -539,18 +551,15 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
else:
if OBJECT3D:
if ddict['dataobject'].info['selectiontype'] == "1D":
- if DEBUG:
- print("1D selection")
+ _logger.debug("1D selection")
self.mcaWindow._addSelection(dictOrList)
self.scanWindow._addSelection(dictOrList)
else:
- if DEBUG:
- print("3D selection")
+ _logger.debug("3D selection")
self.mainTabWidget.setCurrentWidget(self.glWindow)
self.glWindow._addSelection(dictOrList)
else:
- if DEBUG:
- print("1D selection")
+ _logger.debug("1D selection")
self.mcaWindow._addSelection(dictOrList)
self.scanWindow._addSelection(dictOrList)
@@ -565,8 +574,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
def _dispatcherRemoveSelectionSlot(self, dictOrList):
- if DEBUG:
- print("self.dispatcherRemoveSelectionSlot(ddict), ddict = ", dictOrList)
+ _logger.debug("self.dispatcherRemoveSelectionSlot(ddict), ddict = %s", dictOrList)
if type(dictOrList) == type([]):
ddict = dictOrList[0]
else:
@@ -597,8 +605,8 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
msg.exec_()
def _dispatcherReplaceSelectionSlot(self, dictOrList):
- if DEBUG:
- print("self.dispatcherReplaceSelectionSlot(ddict), ddict = ", dictOrList)
+ _logger.debug("self.dispatcherReplaceSelectionSlot(ddict), ddict = %s",
+ dictOrList)
if type(dictOrList) == type([]):
ddict = dictOrList[0]
else:
@@ -632,8 +640,8 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.scanWindow._replaceSelection(dictOrList)
def dispatcherOtherSignalsSlot(self, dictOrList):
- if DEBUG:
- print("self.dispatcherOtherSignalsSlot(ddict), ddict = ",dictOrList)
+ _logger.debug("self.dispatcherOtherSignalsSlot(ddict), ddict = %s",
+ dictOrList)
if type(dictOrList) == type([]):
ddict = dictOrList[0]
else:
@@ -652,8 +660,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
if ddict['event'] == "SourceTypeChanged":
pass
return
- if DEBUG:
- print("Unhandled dict")
+ _logger.debug("Unhandled dict")
def setConfig(self, configDict):
if 'PyMca' in configDict:
@@ -729,12 +736,8 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
d["PyMca"]["McaWindow"]["calibrations"] = self.mcaWindow.getCalibrations()
#ROIs
- d['ROI']={}
- if self.mcaWindow.roiWidget is None:
- roilist = []
- roidict = {}
- else:
- roilist, roidict = self.mcaWindow.roiWidget.getROIListAndDict()
+ d['ROI'] = {}
+ roilist, roidict = self.mcaWindow.getCurvesRoiDockWidget().roiWidget.getROIListAndDict()
d['ROI']['roilist'] = roilist
d['ROI']['roidict'] = {}
d['ROI']['roidict'].update(roidict)
@@ -763,15 +766,14 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
#ScanFit related
d['ScanSimpleFit'] = {}
d['ScanSimpleFit']['Configuration'] = {}
- if DEBUG:
- d['ScanSimpleFit']['Configuration'].update(\
- self.scanWindow.scanFit.getConfiguration())
- else:
- try:
- d['ScanSimpleFit']['Configuration'].update(\
- self.scanWindow.scanFit.getConfiguration())
- except:
- print("Error getting ScanFint configuration")
+
+ try:
+ d['ScanSimpleFit']['Configuration'].update(
+ self.scanWindow.scanFit.getConfiguration())
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ _logger.warning("Error getting ScanFit configuration")
return d
def saveConfig(self, config, filename = None):
@@ -792,6 +794,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
key = 'Splitter'
if key in ddict['Geometry'].keys():
self.splitter.setSizes(ddict['Geometry'][key])
+ # TODO: Recover this functionality with silx
if hasattr(self.mcaWindow, "graph"):
# this was the way of working of 4.x.x versions
key = 'McaWindow'
@@ -884,10 +887,10 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
if type(roilist) != type([]):
roilist=[roilist]
roidict = ddict['roidict']
- if self.mcaWindow.roiWidget is None:
- self.mcaWindow.showRoiWidget(qt.Qt.BottomDockWidgetArea)
- self.mcaWindow.roiWidget.fillFromROIDict(roilist=roilist,
- roidict=roidict)
+ # TODO: silx branch should show the ROI always with the McaWindow
+ roiWidget = self.mcaWindow.getCurvesRoiDockWidget().roiWidget
+ roiWidget.fillFromROIDict(roilist=roilist,
+ roidict=roidict)
def __configureElements(self, ddict):
if 'Material' in ddict:
@@ -930,8 +933,8 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
(d['LastFit']['ydata0'] != 'None'):
self.mcaWindow.advancedfit.setdata(x=d['LastFit']['xdata0'],
y=d['LastFit']['ydata0'],
- sigmay=d['LastFit']['sigmay0'],
- **d['Information'])
+ sigmay=d['LastFit']['sigmay0'],
+ **d['Information'])
if d['LastFit']['hidden'] == 'False':
self.mcaWindow.advancedfit.show()
self.mcaWindow.advancedfit.raiseW()
@@ -941,7 +944,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
except:
pass
else:
- print("hidden")
+ _logger.info("hidden")
def __configureScanCustomFit(self, ddict):
pass
@@ -1115,8 +1118,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
"""
def menuToolsAboutToShow(self):
- if DEBUG:
- print("menu ToolsAboutToShow")
+ _logger.debug("menu ToolsAboutToShow")
self.menuTools.clear()
if self.sourceFrame.isHidden():
self.menuTools.addAction("Show Source",self.toggleSource)
@@ -1139,8 +1141,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self._xrfmcPyMca)
if SUMRULES_FLAG:
self.menuTools.addAction("Sum Rules Tool", self._sumRules)
- if DEBUG:
- print("Fit to Specfile missing")
+ _logger.debug("Fit to Specfile missing")
if TOMOGUI_FLAG:
self.menuTools.addAction("Tomography reconstruction",
self.__tomoRecons)
@@ -1153,8 +1154,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
def toggleSource(self,**kw):
- if DEBUG:
- print("toggleSource called")
+ _logger.debug("toggleSource called")
if self.sourceFrame.isHidden():
self.sourceFrame.show()
self.sourceFrame.raise_()
@@ -1395,8 +1395,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
if widget.parent() is None:
widget.close()
except:
- if DEBUG:
- print("Error closing widget")
+ _logger.debug("Error closing widget")
return PyMcaMdi.PyMcaMdi.closeEvent(self, event)
def __xiaCorrect(self):
@@ -1430,8 +1429,10 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.saveMenu.addAction("Active Mca",
self.mcaWindow._saveIconSignal)
elif text.upper() == 'SCAN':
- self.saveMenu.addAction("Active Scan",
- self.scanWindow._saveIconSignal)
+ self.saveMenu.addAction(
+ "Active Scan",
+ self.scanWindow.getSaveAction().trigger)
+
elif text in self.imageWindowDict.keys():
self.saveMenu.addAction("Active Image",
self.imageWindowDict[text].graphWidget._saveIconSignal)
@@ -1505,10 +1506,27 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.saveConfig(self.getConfig(), filename)
def loadTrainingData(self):
+ if self.trainingDataMenu is None:
+ self.trainingDataMenu = qt.QMenu()
+ self.trainingSources = {"XRF Analysis": os.path.join(PyMcaDataDir.PYMCA_DATA_DIR, 'XRFSpectrum.mca'),
+ "Tertiary Excitation": os.path.join(PyMcaDataDir.PYMCA_DATA_DIR, 'Steel.spe')}
+ self.trainingActions = []
+ for key in ["XRF Analysis", "Tertiary Excitation"]:
+ action = qt.QAction(key, None)
+ self.trainingActions.append(action)
+ self.trainingDataMenu.addAction(action)
try:
- source = os.path.join(PyMcaDataDir.PYMCA_DATA_DIR,
- 'XRFSpectrum.mca')
+ selectedAction = self.trainingDataMenu.exec_(qt.QCursor.pos())
+ key = qt.safe_str(selectedAction.text())
+ source = self.trainingSources[key]
self.sourceWidget.sourceSelector.openSource(source)
+ # only in case of the steel sample we set the input dir to simplify accessing the supplied cfg file
+ if key in ["Tertiary Excitation"]:
+ # we do not change the input dir currently used by the source selector
+ #self.sourceWidget.sourceSelector.lastInputDir = os.path.dirname(source)
+ # but we change the input dir to allow easy loading of the config file from the
+ # fit configuration window
+ PyMcaDirs.inputDir = os.path.dirname(source)
except:
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
@@ -1519,8 +1537,7 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
msg.exec_()
def openSource(self,index=0):
- if DEBUG:
- print("index = %d " % index)
+ _logger.debug("index = %d ", index)
if index <= 0:
outfile = qt.QFileDialog(self)
outfile.setWindowTitle("Select PyMca Configuration File")
@@ -1635,18 +1652,19 @@ class PyMcaMain(PyMcaMdi.PyMcaMdi):
self.changeLog.show()
def onDebug(self):
- print("Module name PyQt ",qt.PYQT_VERSION_STR)
+ _logger.debug("Module name PyQt %s", qt.PYQT_VERSION_STR)
for module in sys.modules.values():
try:
if 'Revision' in module.__revision__:
if module.__name__ != "__main__":
- print("Module name = ",module.__name__,module.__revision__.replace("$",""))
+ _logger.debug("Module name = %s, %s",
+ module.__name__,
+ module.__revision__.replace("$", ""))
except:
pass
def onPrint(self):
- if DEBUG:
- print("onPrint called")
+ _logger.debug("onPrint called")
if not self.scanWindow.isHidden():
self.scanWindow.printGraph()
return
@@ -1671,7 +1689,7 @@ if 0:
#name= self.__getNewGraphName()
if name == "MCA Graph":
- graph= McaWindow.McaWindow(self.mdi, name=name)
+ graph = McaWindow.McaWindow(self.mdi, name=name)
graph.windowClosed[()].connect(self.closeGraph)
graph.show()
@@ -1704,7 +1722,7 @@ if 0:
"""
Called after a graph is closed
"""
- print("closeGraph", name)
+ _logger.info("closeGraph", name)
def __getGraphNames(self):
return [ str(window.caption()) for window in self.mdi.windowList() ]
@@ -1744,8 +1762,7 @@ class MyQTextBrowser(qt.QTextBrowser):
class Line(qt.QFrame):
sigLineDoubleClickEvent = qt.pyqtSignal(object)
def mouseDoubleClickEvent(self,event):
- if DEBUG:
- print("Double Click Event")
+ _logger.debug("Double Click Event")
ddict={}
ddict['event']="DoubleClick"
ddict['data'] = event
@@ -1754,8 +1771,7 @@ class Line(qt.QFrame):
class PixmapLabel(qt.QLabel):
sigPixmapLabelMousePressEvent = qt.pyqtSignal(object)
def mousePressEvent(self,event):
- if DEBUG:
- print("Mouse Press Event")
+ _logger.debug("Mouse Press Event")
ddict={}
ddict['event']="MousePress"
ddict['data'] = event
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaMdi.py b/PyMca5/PyMcaGui/pymca/PyMcaMdi.py
index c4d515a..4ec1955 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaMdi.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaMdi.py
@@ -28,6 +28,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys, getopt, string
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QString"):
QString = qt.QString
@@ -40,7 +41,7 @@ from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
IconDict0 = PyMca_Icons.IconDict0
from .PyMca_help import HelpDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
__version__ = "1.5"
@@ -174,8 +175,7 @@ class PyMcaMdi(qt.QMainWindow):
self.winToolBar = self.addToolBar("wintoolbar")
def onWinToolMenu(self, idx):
- if DEBUG:
- print("onWinToolMenu %d " % idx)
+ _logger.debug("onWinToolMenu %d ", idx)
for midx in self.winToolMenuIndex:
self.winToolMenu.setItemChecked(midx, midx==idx)
act= self.winToolMenuIndex.index(idx)
@@ -287,8 +287,7 @@ class PyMcaMdi(qt.QMainWindow):
self.menuBar().addMenu(self.menuHelp)
def menuWindowAboutToShow(self):
- if DEBUG:
- print("menuWindowAboutToShow")
+ _logger.debug("menuWindowAboutToShow")
self.menuWindow.clear()
if len(self.mdi.windowList())==0:
return
@@ -312,10 +311,10 @@ class PyMcaMdi(qt.QMainWindow):
def _windowMapperMapSlot(self):
return self.windowMapper.map()
- def menuWindowActivated(self, idx = None):
- if DEBUG:
- print("menuWindowActivated idx = ",idx)
- if idx is None:return
+ def menuWindowActivated(self, idx=None):
+ _logger.debug("menuWindowActivated idx = %s", idx)
+ if idx is None:
+ return
if self.menuWindowMap[idx].isHidden():
self.menuWindowMap[idx].show()
self.menuWindowMap[idx].raise_()
@@ -336,7 +335,7 @@ class PyMcaMdi(qt.QMainWindow):
self.followActiveWindow= follow
def onWindowActivated(self, win):
- print("Window activated")
+ _logger.info("Window activated")
pass
#
@@ -368,8 +367,7 @@ class PyMcaMdi(qt.QMainWindow):
pass
def menuToolsAboutToShow(self):
- if DEBUG:
- print("menuToolsAboutToShow")
+ _logger.debug("menuToolsAboutToShow")
self.menuTools.clear()
self.menuToolsMap= {}
"""
@@ -384,8 +382,7 @@ class PyMcaMdi(qt.QMainWindow):
self.menuTools.insertItem("Customize", self.customize)
def menuToolsActivated(self, idx):
- if DEBUG:
- print("menuToolsActivated idx = ",idx)
+ _logger.debug("menuToolsActivated idx = %s", idx)
if self.menuTools.isItemChecked(idx):
self.menuToolsMap[idx].hide()
else:
@@ -445,7 +442,7 @@ def main(args):
options,
longoptions)
except getopt.error:
- print(sys.exc_info()[1])
+ _logger.error(sys.exc_info()[1])
sys.exit(1)
# --- waiting widget
kw={}
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaNexusWidget.py b/PyMca5/PyMcaGui/pymca/PyMcaNexusWidget.py
index 9462fdc..b41012d 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaNexusWidget.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaNexusWidget.py
@@ -30,6 +30,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import posixpath
import h5py
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaCore import DataObject
from PyMca5.PyMcaGui.io.hdf5 import QNexusWidget
@@ -39,7 +40,8 @@ if hasattr(qt, 'QString'):
QString = qt.QString
else:
QString = str
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
class PyMcaNexusWidget(QNexusWidget.QNexusWidget):
def __init__(self, parent=None, mca=True):
@@ -100,23 +102,19 @@ class PyMcaNexusWidget(QNexusWidget.QNexusWidget):
return
def _stack1DSignal(self):
- if DEBUG:
- print("_stack1DSignal")
+ _logger.debug("_stack1DSignal")
self._stackSignal(index=-1, load=False)
def _loadStack1DSignal(self):
- if DEBUG:
- print("_stack1DSignal")
+ _logger.debug("_stack1DSignal")
self._stackSignal(index=-1, load=True)
def _loadStack2DSignal(self):
- if DEBUG:
- print("_loadStack2DSignal")
+ _logger.debug("_loadStack2DSignal")
self._stackSignal(index=0, load=True)
def _stack2DSignal(self, load=False):
- if DEBUG:
- print("_stack2DSignal")
+ _logger.debug("_stack2DSignal")
self._stackSignal(index=0, load=False)
def _stackSignal(self, index=-1, load=False):
@@ -171,7 +169,7 @@ class PyMcaNexusWidget(QNexusWidget.QNexusWidget):
try:
axes = axes.decode('utf-8')
except:
- print("WARNING: Cannot decode axes")
+ _logger.warning("Cannot decode axes")
axes = axes.split(":")
for axis in axes:
if axis in group.keys():
@@ -181,7 +179,7 @@ class PyMcaNexusWidget(QNexusWidget.QNexusWidget):
except:
# I cannot afford this Nexus specific things
# to break the generic HDF5 functionality
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
axesList = []
diff --git a/PyMca5/PyMcaGui/pymca/PyMcaPostBatch.py b/PyMca5/PyMcaGui/pymca/PyMcaPostBatch.py
index f460d72..2a34338 100644
--- a/PyMca5/PyMcaGui/pymca/PyMcaPostBatch.py
+++ b/PyMca5/PyMcaGui/pymca/PyMcaPostBatch.py
@@ -116,13 +116,16 @@ class PyMcaPostBatch(RGBCorrelator.RGBCorrelator):
return filelist
def test():
+ import logging
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
sys.excepthook = qt.exceptionHandler
app = qt.QApplication([])
app.lastWindowClosed.connect(app.quit)
import getopt
options=''
- longoptions=["nativefiledialogs=","transpose=", "fileindex="]
+ longoptions=["nativefiledialogs=", "transpose=", "fileindex=",
+ "logging=", "debug="]
opts, args = getopt.getopt(
sys.argv[1:],
options,
@@ -140,6 +143,9 @@ def test():
elif opt in '--fileindex':
if int(arg):
transpose=True
+
+ logging.basicConfig(level=getLoggingLevel(opts))
+
filelist=args
w = PyMcaPostBatch()
w.layout().setContentsMargins(11, 11, 11, 11)
diff --git a/PyMca5/PyMcaGui/pymca/QDispatcher.py b/PyMca5/PyMcaGui/pymca/QDispatcher.py
index f84651c..b584742 100644
--- a/PyMca5/PyMcaGui/pymca/QDispatcher.py
+++ b/PyMca5/PyMcaGui/pymca/QDispatcher.py
@@ -28,15 +28,16 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
import traceback
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
from PyMca5.PyMcaGui.io import QSourceSelector
from . import QDataSource
#import weakref
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class QDispatcher(qt.QWidget):
sigAddSelection = qt.pyqtSignal(object)
@@ -93,9 +94,8 @@ class QDispatcher(qt.QWidget):
self.tabWidget.currentChanged[int].connect(self._tabChanged)
def _addSelectionSlot(self, sel_list, event=None):
- if DEBUG:
- print("QDispatcher._addSelectionSlot")
- print("sel_list = ",sel_list)
+ _logger.debug("QDispatcher._addSelectionSlot")
+ _logger.debug("sel_list = %s", sel_list)
if event is None:
event = "addSelection"
@@ -144,31 +144,29 @@ class QDispatcher(qt.QWidget):
#I should create a weakref to it in order to be informed
#about its deletion.
if source.sourceType != "SPS":
- if DEBUG:
+ try:
dataObject = source.getDataObject(sel['Key'],
selection=sel['selection'])
- else:
- try:
- dataObject = source.getDataObject(sel['Key'],
- selection=sel['selection'])
- except:
- error = sys.exc_info()
- text = "Failed to read data source.\n"
- text += "Source: %s\n" % source.sourceName
- text += "Key: %s\n" % sel['Key']
- text += "Error: %s" % error[1]
- if QTVERSION < '4.0.0':
- qt.QMessageBox.critical(self,
- "%s" % error[0],
- text)
- else:
- msg = qt.QMessageBox(self)
- msg.setWindowTitle('Source Error')
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setInformativeText(text)
- msg.setDetailedText(\
- traceback.format_exc())
- continue
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ raise
+ error = sys.exc_info()
+ text = "Failed to read data source.\n"
+ text += "Source: %s\n" % source.sourceName
+ text += "Key: %s\n" % sel['Key']
+ text += "Error: %s" % error[1]
+ if QTVERSION < '4.0.0':
+ qt.QMessageBox.critical(self,
+ "%s" % error[0],
+ text)
+ else:
+ msg = qt.QMessageBox(self)
+ msg.setWindowTitle('Source Error')
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setInformativeText(text)
+ msg.setDetailedText(\
+ traceback.format_exc())
+ continue
else:
dataObject = source.getDataObject(sel['Key'],
selection=sel['selection'],
@@ -209,7 +207,7 @@ class QDispatcher(qt.QWidget):
self.sigRemoveSelection.emit(selectionList)
selectionList = []
else:
- print("Unhandled dispatcher event = ", event)
+ _logger.warning("Unhandled dispatcher event = %s", event)
del selectionList[-1]
if len(selectionList):
if event.lower() == "addselection":
@@ -221,9 +219,8 @@ class QDispatcher(qt.QWidget):
lastEvent = None
def _removeSelectionSlot(self, sel_list):
- if DEBUG:
- print("_removeSelectionSlot")
- print("sel_list = ",sel_list)
+ _logger.debug("_removeSelectionSlot")
+ _logger.debug("sel_list = %s", sel_list)
for sel in sel_list:
ddict = {}
ddict.update(sel)
@@ -231,23 +228,21 @@ class QDispatcher(qt.QWidget):
self.sigRemoveSelection.emit(ddict)
def _replaceSelectionSlot(self, sel_list):
- if DEBUG:
- print("_replaceSelectionSlot")
- print("sel_list = ",sel_list)
+ _logger.debug("_replaceSelectionSlot")
+ _logger.debug("sel_list = %s", sel_list)
if len(sel_list) == 1:
- self._addSelectionSlot([sel_list[0]], event = "replaceSelection")
+ self._addSelectionSlot([sel_list[0]], event="replaceSelection")
elif len(sel_list) > 1:
- self._addSelectionSlot([sel_list[0]], event = "replaceSelection")
- self._addSelectionSlot(sel_list[1:], event = "addSelection")
+ self._addSelectionSlot([sel_list[0]], event="replaceSelection")
+ self._addSelectionSlot(sel_list[1:], event="addSelection")
def _otherSignalsSlot(self, ddict):
self.sigOtherSignals.emit(ddict)
def _sourceSelectorSlot(self, ddict):
- if DEBUG:
- print("_sourceSelectorSlot(self, ddict)")
- print("ddict = ",ddict)
+ _logger.debug("_sourceSelectorSlot(self, ddict)")
+ _logger.debug("ddict = %s", ddict)
if ddict["event"] == "NewSourceSelected":
source = QDataSource.QDataSource(ddict["sourcelist"])
self.sourceList.append(source)
@@ -265,8 +260,7 @@ class QDispatcher(qt.QWidget):
found = 1
break
if not found:
- if DEBUG:
- print("WARNING: source not found")
+ _logger.debug("WARNING: source not found")
return
sourceType = source.sourceType
if ddict["event"] == "SourceReloaded":
@@ -280,8 +274,7 @@ class QDispatcher(qt.QWidget):
found = 1
break
if not found:
- if DEBUG:
- print("WARNING: source not found")
+ _logger.debug("WARNING: source not found")
return
sourceType = source.sourceType
del self.sourceList[self.sourceList.index(source)]
@@ -299,13 +292,10 @@ class QDispatcher(qt.QWidget):
self.selectorWidget[sourceType].setDataSource(None)
self.tabWidget.setCurrentWidget(self.selectorWidget[sourceType])
elif ddict["event"] == "SourceClosed":
- if DEBUG:
- print("not implemented yet")
-
+ _logger.debug("not implemented yet")
def _selectionUpdatedSlot(self, ddict):
- if DEBUG:
- print("_selectionUpdatedSlot(self, dict)",ddict)
+ _logger.debug("_selectionUpdatedSlot(self, dict=%s)")
if 'selectionlist' in ddict:
sel_list = ddict['selectionlist']
else:
@@ -332,8 +322,7 @@ class QDispatcher(qt.QWidget):
self._addSelectionSlot(sel_list)
def _tabChanged(self, value):
- if DEBUG:
- print("self._tabChanged(value), value = ",value)
+ _logger.debug("self._tabChanged(value), value = %s", value)
text = str(self.tabWidget.tabText(value))
ddict = {}
ddict['SourceType'] = text
@@ -355,16 +344,17 @@ class QDispatcher(qt.QWidget):
ddict['SourceName'] = self.selectorWidget[text].data.sourceName
else:
ddict['SourceName'] = None
- print(ddict)
- print("===========================")
+ _logger.info("%s", ddict)
+ _logger.info("===========================")
for source in self.sourceList:
- print(source)
- print(source.sourceType)
+ _logger.info(source)
+ _logger.info(source.sourceType)
sourceType = source.sourceType
- print(self.selectorWidget[sourceType].currentSelectionList())
+ _logger.info(self.selectorWidget[sourceType].currentSelectionList())
- if self.pluginsCallback is not None:
- self.pluginsCallback(info)
+ # this seems unused (info is not defined)
+ # if self.pluginsCallback is not None:
+ # self.pluginsCallback(info)
def test():
diff --git a/PyMca5/PyMcaGui/pymca/QHDF5Stack1D.py b/PyMca5/PyMcaGui/pymca/QHDF5Stack1D.py
index 04c7952..4097948 100644
--- a/PyMca5/PyMcaGui/pymca/QHDF5Stack1D.py
+++ b/PyMca5/PyMcaGui/pymca/QHDF5Stack1D.py
@@ -27,11 +27,10 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import HDF5Stack1D
from PyMca5.PyMcaGui.pymca import QHDF5StackWizard
-DEBUG = 0
class QHDF5Stack1D(HDF5Stack1D.HDF5Stack1D):
def __init__(self, filelist=None,
diff --git a/PyMca5/PyMcaGui/pymca/QHDF5StackWizard.py b/PyMca5/PyMcaGui/pymca/QHDF5StackWizard.py
index 103c115..908a4e5 100644
--- a/PyMca5/PyMcaGui/pymca/QHDF5StackWizard.py
+++ b/PyMca5/PyMcaGui/pymca/QHDF5StackWizard.py
@@ -36,6 +36,7 @@ from PyMca5.PyMcaGui.io.hdf5 import QNexusWidget
from PyMca5.PyMcaCore import NexusDataSource
from PyMca5 import PyMcaDirs
+
class IntroductionPage(qt.QWizardPage):
def __init__(self, parent):
qt.QWizardPage.__init__(self, parent)
@@ -44,6 +45,7 @@ class IntroductionPage(qt.QWizardPage):
text += "appropriate dataset(s) belonging to your stack"
self.setSubTitle(text)
+
class FileListPage(qt.QWizardPage):
def __init__(self, parent):
qt.QWizardPage.__init__(self, parent)
@@ -187,7 +189,7 @@ class DatasetSelectionPage(qt.QWizardPage):
attrs = list(entry.attrs)
if 'NX_class' in attrs:
attr = entry.attrs['NX_class']
- if sys.version > '2.9':
+ if hasattr(attr, "decode"):
try:
attr = attr.decode('utf-8')
except:
@@ -197,7 +199,7 @@ class DatasetSelectionPage(qt.QWizardPage):
attr = None
if attr is None:
return
- if attr != 'NXentry':
+ if attr not in ['NXentry', b'NXentry']:
return
#check if there is only one NXdata
@@ -206,62 +208,98 @@ class DatasetSelectionPage(qt.QWizardPage):
attr = entry[key].attrs.get('NX_class', None)
if attr is None:
continue
- if sys.version > '2.9':
+ if hasattr(attr, "decode"):
try:
attr = attr.decode('utf-8')
except:
print("WARNING: Cannot decode NX_class attribute")
continue
- if attr in ['NXdata']:
+ if attr in ['NXdata', b'NXdata']:
nxDataList.append(key)
if len(nxDataList) != 1:
return
nxData = entry[nxDataList[0]]
- #try to get the signals
+ ddict = {'counters': [],
+ 'aliases': []}
signalList = []
axesList = []
interpretation = ""
- for key in nxData.keys():
- if 'signal' in nxData[key].attrs.keys():
- if int(nxData[key].attrs['signal']) == 1:
- signalList.append(key)
- if len(signalList) == 1:
- if 'interpretation' in nxData[key].attrs.keys():
- interpretation = nxData[key].attrs['interpretation']
- if sys.version > '2.9':
- try:
- interpretation = interpretation.decode('utf-8')
- except:
- print("WARNING: Cannot decode interpretation")
- if interpretation == "image":
- self.stackIndexWidget.setIndex(0)
- if 'axes' in nxData[key].attrs.keys():
- axes = nxData[key].attrs['axes']
- if sys.version > '2.9':
- try:
- axes = axes.decode('utf-8')
- except:
- print("WARNING: Cannot decode axes")
- axes = axes.split(":")
- for axis in axes:
- if axis in nxData.keys():
- axesList.append(axis)
-
- if not len(signalList):
- return
- ddict = {}
- ddict['counters'] = []
- ddict['aliases'] = []
+ signal_key = nxData.attrs.get("signal")
+ if signal_key is not None:
+ # recent NXdata specification
+ if hasattr(signal_key, "decode"):
+ try:
+ signal_key = signal_key.decode('utf-8')
+ except AttributeError:
+ print("WARNING: Cannot decode NX_class attribute")
+
+ signal_dataset = nxData.get(signal_key)
+ if signal_dataset is None:
+ return
- for signal in signalList:
- path = posixpath.join("/",nxDataList[0], signal)
+ interpretation = signal_dataset.attrs.get("interpretation", "")
+ if hasattr(interpretation, "decode"):
+ try:
+ interpretation = interpretation.decode('utf-8')
+ except AttributeError:
+ print("WARNING: Cannot decode interpretation")
+
+ axesList = list(nxData.attrs.get("axes", []))
+ if not axesList:
+ # try the old method, still documented on nexusformat.org:
+ # colon-delimited "array" of dataset names as a signal attr
+ axes = signal_dataset.attrs.get('axes')
+ if axes is not None:
+ if hasattr(axes, "decode"):
+ try:
+ axes = axes.decode('utf-8')
+ except AttributeError:
+ print("WARNING: Cannot decode axes")
+ axes = axes.split(":")
+ axesList = [ax for ax in axes if ax in nxData]
+ signalList.append(signal_key)
+ else:
+ # old specification
+ for key in nxData.keys():
+ if 'signal' in nxData[key].attrs.keys():
+ if int(nxData[key].attrs['signal']) == 1:
+ signalList.append(key)
+ if len(signalList) == 1:
+ if 'interpretation' in nxData[key].attrs.keys():
+ interpretation = nxData[key].attrs['interpretation']
+ if sys.version > '2.9':
+ try:
+ interpretation = interpretation.decode('utf-8')
+ except:
+ print("WARNING: Cannot decode interpretation")
+
+ if 'axes' in nxData[key].attrs.keys():
+ axes = nxData[key].attrs['axes']
+ if sys.version > '2.9':
+ try:
+ axes = axes.decode('utf-8')
+ except:
+ print("WARNING: Cannot decode axes")
+ axes = axes.split(":")
+ for axis in axes:
+ if axis in nxData.keys():
+ axesList.append(axis)
+
+ if not len(signalList):
+ return
+
+ if interpretation in ["image", b"image"]:
+ self.stackIndexWidget.setIndex(0)
+
+ for signal_key in signalList:
+ path = posixpath.join("/", nxDataList[0], signal_key)
ddict['counters'].append(path)
- ddict['aliases'].append(posixpath.basename(signal))
+ ddict['aliases'].append(posixpath.basename(signal_key))
for axis in axesList:
- path = posixpath.join("/",nxDataList[0], axis)
+ path = posixpath.join("/", nxDataList[0], axis)
ddict['counters'].append(path)
ddict['aliases'].append(posixpath.basename(axis))
@@ -274,15 +312,13 @@ class DatasetSelectionPage(qt.QWizardPage):
return
self.nexusWidget.setWidgetConfiguration(ddict)
- if len(signalList):
- if len(axesList) == 0:
- self.nexusWidget.cntTable.setCounterSelection({'y':[0]})
- elif interpretation == "image":
- self.nexusWidget.cntTable.setCounterSelection({'y':[0], 'x':[1]})
- elif interpretation == "spectrum":
- self.nexusWidget.cntTable.setCounterSelection({'y':[0], 'x':[len(axesList)]})
- else:
- self.nexusWidget.cntTable.setCounterSelection({'y':[0]})
+
+ if axesList and (interpretation in ["image", b"image"]):
+ self.nexusWidget.cntTable.setCounterSelection({'y': [0], 'x': [1]})
+ elif axesList and (interpretation in ["spectrum", b"spectrum"]):
+ self.nexusWidget.cntTable.setCounterSelection({'y': [0], 'x': [len(axesList)]})
+ else:
+ self.nexusWidget.cntTable.setCounterSelection({'y': [0]})
def validatePage(self):
cntSelection = self.nexusWidget.cntTable.getCounterSelection()
@@ -313,6 +349,7 @@ class DatasetSelectionPage(qt.QWizardPage):
msg.setText(text)
msg.exec_()
+
class ShapePage(qt.QWizardPage):
def __init__(self, parent):
qt.QWizardPage.__init__(self, parent)
@@ -320,6 +357,7 @@ class ShapePage(qt.QWizardPage):
text = "Adjust the shape of your map if necessary"
self.setSubTitle(text)
+
class LocalQNexusWidget(QNexusWidget.QNexusWidget):
def __init__(self, parent=None, mca=False):
QNexusWidget.QNexusWidget.__init__(self, parent=parent,
@@ -332,6 +370,7 @@ class LocalQNexusWidget(QNexusWidget.QNexusWidget):
w.setWindowModality(qt.Qt.ApplicationModal)
w.show()
+
class QHDF5StackWizard(qt.QWizard):
def __init__(self, parent=None):
qt.QWizard.__init__(self, parent)
@@ -377,6 +416,7 @@ class QHDF5StackWizard(qt.QWizard):
self._datasetSelection.selection,\
[x[0] for x in self._datasetSelection.nexusWidget.getSelectedEntries()]
+
if __name__ == "__main__":
import sys
app = qt.QApplication(sys.argv)
diff --git a/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave.py b/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave.py
index cbfa1fb..540f547 100644
--- a/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave.py
+++ b/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#/*##########################################################################
-# Copyright (C) 2004-2016 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 V.A. Sole, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -24,6 +24,7 @@
# THE SOFTWARE.
#
#############################################################################*/
+from __future__ import absolute_import
__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
@@ -32,13 +33,16 @@ import sys
import os
import numpy
import traceback
+from io import StringIO
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaCore import PyMcaMatplotlibSave
from PyMca5.PyMcaGui import IconDict
-from PyMca5.PyMcaGui import PyMcaPrintPreview
from PyMca5 import PyMcaDirs
+from silx.gui.widgets.PrintPreview import SingletonPrintPreviewDialog
+
from matplotlib import cm
from matplotlib.font_manager import FontProperties
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
@@ -46,7 +50,7 @@ from matplotlib.figure import Figure
from matplotlib.colors import LinearSegmentedColormap, LogNorm, Normalize
from matplotlib.ticker import MaxNLocator, AutoLocator
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class TopWidget(qt.QWidget):
@@ -108,7 +112,7 @@ class SaveImageSetup(qt.QWidget):
self.setWindowTitle("PyMca - Matplotlib save image")
self.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict['gioconda16'])))
self.lastOutputDir = None
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
+ self.printPreview = SingletonPrintPreviewDialog(parent=self)
#top
self.top = TopWidget(self)
@@ -178,20 +182,34 @@ class SaveImageSetup(qt.QWidget):
msg.setWindowTitle('Matplotlib Save Image')
msg.exec_()
-
def printClicked(self):
try:
- pixmap = qt.QPixmap.grabWidget(self.imageWidget)
- self.printPreview.addPixmap(pixmap)
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
+ imgData = StringIO()
+ self.imageWidget.figure.savefig(imgData, format="svg") # dpi=...)
+ imgData.flush()
+ imgData.seek(0)
+ svgData = imgData.read()
+ svgRenderer = qt.QSvgRenderer()
+ svgRenderer.load(qt.QXmlStreamReader(svgData.encode(errors="replace")))
+ self.printPreview.addSvgItem(svgRenderer)
except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Error printing image: %s" % sys.exc_info()[1])
- msg.setWindowTitle('Matplotlib Save Image')
- msg.exec_()
+ try:
+ if hasattr(qt.QPixmap,"grabWidget"):
+ pixmap = qt.QPixmap.grabWidget(self.imageWidget)
+ else:
+ pixmap = self.imageWidget.grab()
+ self.printPreview.addPixmap(pixmap)
+ except:
+ msg = qt.QMessageBox(self)
+ msg.setIcon(qt.QMessageBox.Critical)
+ msg.setText("Error printing image: %s" % sys.exc_info()[1])
+ msg.setWindowTitle('Matplotlib Save Image')
+ msg.exec_()
+ return
+ if self.printPreview.isHidden():
+ self.printPreview.show()
+ self.printPreview.raise_()
+
def saveClicked(self):
outfile = qt.QFileDialog(self)
@@ -274,7 +292,7 @@ class SaveImageSetup(qt.QWidget):
format=finalFile[-3:],
dpi=self.imageWidget.config['outputdpi'])
except:
- print("WARNING: trying to save using obsolete method")
+ _logger.warning("trying to save using obsolete method")
config = self.imageWidget.getParameters()
try:
s=PyMcaMatplotlibSave.PyMcaMatplotlibSaveImage(self.imageWidget.imageData)
@@ -728,8 +746,7 @@ class QPyMcaMatplotlibImage(FigureCanvas):
elif self.config['colormap'] == 'ylgnbu_r':
cmap = cm.YlGnBu_r
else:
- print("Unsupported colormap %s" % self.config['colormap'])
-
+ _logger.warning("Unsupported colormap %s", self.config['colormap'])
if self.config['extent'] is None:
h, w = self.imageData.shape
@@ -802,7 +819,7 @@ class QPyMcaMatplotlibImage(FigureCanvas):
self._colorbar.locator = tick_locator
self._colorbar.update_ticks()
except:
- print("Colorbar error", sys.exc_info())
+ _logger.warning("Colorbar error %s", sys.exc_info())
pass
else:
self._colorbar = self.figure.colorbar(self._image,
diff --git a/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave1D.py b/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave1D.py
index 6b32e92..39cd550 100644
--- a/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave1D.py
+++ b/PyMca5/PyMcaGui/pymca/QPyMcaMatplotlibSave1D.py
@@ -31,14 +31,12 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import PyMca_Icons
IconDict = PyMca_Icons.IconDict
-from PyMca5.PyMcaGui import PyMcaPrintPreview
-from PyMca5.PyMcaCore import PyMcaDirs
-from matplotlib import cm
from matplotlib import __version__ as matplotlib_version
from matplotlib.font_manager import FontProperties
if "PyQt5" in sys.modules:
@@ -49,7 +47,7 @@ else:
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
-DEBUG = 0
+_logger = logging.getLogger(__name__)
colordict = {}
colordict['blue'] = '#0000ff'
@@ -494,8 +492,7 @@ class QPyMcaMatplotlibSave(FigureCanvas):
n = max(x.shape)
if n == 0:
#nothing to plot
- if DEBUG:
- print("nothing to plot")
+ _logger.debug("nothing to plot")
return
style = None
diff --git a/PyMca5/PyMcaGui/pymca/QSource.py b/PyMca5/PyMcaGui/pymca/QSource.py
index a05263f..1f2be17 100644
--- a/PyMca5/PyMcaGui/pymca/QSource.py
+++ b/PyMca5/PyMcaGui/pymca/QSource.py
@@ -27,10 +27,11 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
SOURCE_EVENT = qt.QEvent.User
class SourceEvent(qt.QEvent):
@@ -80,10 +81,9 @@ class QSource(qt.QObject):
reference = id(dataObject)
def dataObjectDestroyed(ref, dataObjectKey=key, dataObjectRef=reference):
- if DEBUG:
- print('data object destroyed, key was %s' % dataObjectKey)
- print('data object destroyed, ref was 0x%x' % dataObjectRef)
- print("self.surveyDict[key] = ",self.surveyDict[key])
+ _logger.debug('data object destroyed, key was %s', dataObjectKey)
+ _logger.debug('data object destroyed, ref was 0x%x', dataObjectRef)
+ _logger.debug("self.surveyDict[key] = %s", self.surveyDict[key])
n = len(self.surveyDict[dataObjectKey])
if n > 0:
@@ -96,8 +96,7 @@ class QSource(qt.QObject):
if len(self.surveyDict[dataObjectKey]) == 0:
del self.surveyDict[dataObjectKey]
- if DEBUG:
- print("SURVEY DICT AFTER DELETION = ", self.surveyDict)
+ _logger.debug("SURVEY DICT AFTER DELETION = %s", self.surveyDict)
return
# create a weak reference to the dataObject and we call it dataObjectRef
@@ -111,12 +110,10 @@ class QSource(qt.QObject):
self.surveyDict[key] = [dataObjectRef]
self.selections[key] = [(id(dataObjectRef), dataObjectRef.info)]
except ReferenceError:
- if DEBUG:
- print("NOT ADDED TO THE POLL dataObject = ", dataObject)
+ _logger.debug("NOT ADDED TO THE POLL dataObject = %s", dataObject)
return
- if DEBUG:
- print("SURVEY DICT AFTER ADDITION = ", self.surveyDict)
+ _logger.debug("SURVEY DICT AFTER ADDITION = %s", self.surveyDict)
if self.pollerThreadId is None:
# start a new polling thread
@@ -130,8 +127,7 @@ class QSource(qt.QObject):
#for key in self.surveyDict is dangerous
# runtime error: dictionnary changed during iteration
# a mutex is needed
- if DEBUG:
- print("In loop")
+ _logger.debug("In loop")
dummy = list(self.surveyDict.keys())
eventsToPost = {}
#for key in self.surveyDict:
@@ -139,8 +135,7 @@ class QSource(qt.QObject):
if key not in eventsToPost:
eventsToPost[key] = []
if self.isUpdated(self.sourceName, key):
- if DEBUG:
- print(self.sourceName,key,"is updated")
+ _logger.debug("%s %s is updated", self.sourceName, key)
try:
if len(self.surveyDict[key]):
#there are still instances of dataObjects
@@ -161,16 +156,14 @@ class QSource(qt.QObject):
del self.surveyDict[key]
del self.selections[key]
except KeyError:
- if DEBUG:
- print("key error in loop")
+ _logger.debug("key error in loop")
pass
for key in eventsToPost:
for event in eventsToPost[key]:
qt.QApplication.postEvent(self, event)
qt.QApplication.instance().processEvents()
time.sleep(self._pollTime)
- if DEBUG:
- print("woke up")
+ _logger.debug("woke up")
self.pollerThreadId = None
self.selections = {}
diff --git a/PyMca5/PyMcaGui/pymca/QStackWidget.py b/PyMca5/PyMcaGui/pymca/QStackWidget.py
index 36fe82a..ce20839 100644
--- a/PyMca5/PyMcaGui/pymca/QStackWidget.py
+++ b/PyMca5/PyMcaGui/pymca/QStackWidget.py
@@ -33,6 +33,7 @@ import os
import traceback
import numpy
import weakref
+import logging
if __name__ == "__main__":
# we have to get the Qt binding prior to import PyMcaQt
@@ -41,7 +42,7 @@ if __name__ == "__main__":
longoptions = ["fileindex=","old",
"filepattern=", "begin=", "end=", "increment=",
"nativefiledialogs=", "imagestack=", "image=",
- "backend=", "binding="]
+ "backend=", "binding=", "logging=", "debug="]
opts, args = getopt.getopt(
sys.argv[1:],
options,
@@ -56,8 +57,13 @@ if __name__ == "__main__":
if sys.version_info < (3,):
try:
import sip
- sip.setapi("QString", 2)
- sip.setapi("QVariant", 2)
+ sip.setapi('QString', 2)
+ sip.setapi('QVariant', 2)
+ sip.setapi('QDate', 2)
+ sip.setapi('QDateTime', 2)
+ sip.setapi('QTextStream', 2)
+ sip.setapi('QTime', 2)
+ sip.setapi('QUrl', 2)
except:
print("Cannot set sip API")
import PyQt4.QtCore
@@ -87,7 +93,6 @@ from PyMca5.PyMcaGui import CloseEventNotifyingWidget
from PyMca5.PyMcaGui import MaskImageWidget
convertToRowAndColumn = MaskImageWidget.convertToRowAndColumn
-from PyMca5.PyMcaGui.pymca import StackROIWindow
from PyMca5.PyMcaGui.pymca import RGBCorrelator
from PyMca5.PyMcaGui.pymca.RGBCorrelatorWidget import ImageShapeDialog
from PyMca5.PyMcaGui import IconDict
@@ -96,19 +101,20 @@ from PyMca5 import PyMcaDirs
from PyMca5.PyMcaIO import ArraySave
HDF5 = ArraySave.HDF5
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+# _logger.setLevel(logging.DEBUG)
QTVERSION = qt.qVersion()
-if DEBUG:
- StackBase.DEBUG = DEBUG
+if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackBase.logger.setLevel(logging.DEBUG)
class QStackWidget(StackBase.StackBase,
CloseEventNotifyingWidget.CloseEventNotifyingWidget):
- def __init__(self, parent = None,
- mcawidget = None,
- rgbwidget = None,
- vertical = False,
- master = True):
+ def __init__(self, parent=None,
+ mcawidget=None,
+ rgbwidget=None,
+ vertical=False,
+ master=True):
StackBase.StackBase.__init__(self)
CloseEventNotifyingWidget.CloseEventNotifyingWidget.__init__(self,
parent)
@@ -202,16 +208,16 @@ class QStackWidget(StackBase.StackBase,
standalonesave=standaloneSaving,
profileselection=True,
aspect=True)
- infotext = 'Toggle background subtraction from current image\n'
+ infotext = 'Toggle background subtraction from current image\n'
infotext += 'subtracting a straight line between the ROI limits.'
self.roiBackgroundIcon = qt.QIcon(qt.QPixmap(IconDict["subtract"]))
- self.roiBackgroundButton = self.roiWidget.graphWidget._addToolButton(\
+ self.roiBackgroundButton = self.roiWidget.graphWidget._addToolButton(
self.roiBackgroundIcon,
self._roiSubtractBackgroundClicked,
infotext,
- toggle = True,
- state = False,
- position = 6)
+ toggle=True,
+ state=False,
+ position=6)
self.roiGraphWidget = self.roiWidget.graphWidget
self.stackWindow.mainLayout.addWidget(self.stackWidget)
self.roiWindow.mainLayout.addWidget(self.roiWidget)
@@ -224,37 +230,37 @@ class QStackWidget(StackBase.StackBase,
#add some missing icons
offset = 6
- infotext = 'If checked, spectra will be added normalized to the number\n'
+ infotext = 'If checked, spectra will be added normalized to the number\n'
infotext += 'of pixels. Be carefull if you are preparing a batch and you\n'
infotext += 'fit the normalized spectra because the data in the batch will\n'
infotext += 'have a different weight because they are not normalized.'
self.normalizeIcon = qt.QIcon(qt.QPixmap(IconDict["normalize16"]))
- self.normalizeButton = self.stackGraphWidget._addToolButton(\
+ self.normalizeButton = self.stackGraphWidget._addToolButton( \
self.normalizeIcon,
self.normalizeIconChecked,
infotext,
- toggle = True,
- state = False,
- position = 6)
+ toggle=True,
+ state=False,
+ position=6)
offset += 1
if self.master:
self.loadIcon = qt.QIcon(qt.QPixmap(IconDict["fileopen"]))
- self.loadStackButton = self.stackGraphWidget._addToolButton(\
+ self.loadStackButton = self.stackGraphWidget._addToolButton( \
self.loadIcon,
self.loadSlaveStack,
'Load another stack of same shape',
- position = offset)
+ position=offset)
offset += 1
- self.pluginIcon = qt.QIcon(qt.QPixmap(IconDict["plugin"]))
+ self.pluginIcon = qt.QIcon(qt.QPixmap(IconDict["plugin"]))
infotext = "Call/Load Stack Plugins"
self.stackGraphWidget._addToolButton(self.pluginIcon,
self._pluginClicked,
infotext,
- toggle = False,
- state = False,
- position = offset)
+ toggle=False,
+ state=False,
+ position=offset)
def setStack(self, *var, **kw):
self.stackWidget.setImageData(None)
@@ -263,7 +269,7 @@ class QStackWidget(StackBase.StackBase,
if (1 in self._stack.data.shape) and\
isinstance(self._stack.data, numpy.ndarray):
oldshape = self._stack.data.shape
- dialog = ImageShapeDialog(self, shape = oldshape[0:2])
+ dialog = ImageShapeDialog(self, shape=oldshape[0:2])
dialog.setModal(True)
ret = dialog.exec_()
if ret:
@@ -304,14 +310,14 @@ class QStackWidget(StackBase.StackBase,
xScale = self._stack.info.get("xScale", None)
yScale = self._stack.info.get("yScale", None)
if self.roiBackgroundButton.isChecked():
- self.roiWidget.graphWidget.graph.setGraphTitle(\
- self._ROIImageNames[0]+" Net")
- self.roiWidget.setImageData(self._ROIImageList[0]-\
+ self.roiWidget.graphWidget.graph.setGraphTitle( \
+ self._ROIImageNames[0] + " Net")
+ self.roiWidget.setImageData(self._ROIImageList[0] - \
self._ROIImageList[-1],
xScale=xScale,
yScale=yScale)
else:
- self.roiWidget.graphWidget.graph.setGraphTitle(\
+ self.roiWidget.graphWidget.graph.setGraphTitle( \
self._ROIImageNames[0])
self.roiWidget.setImageData(self._ROIImageList[0],
xScale=xScale,
@@ -398,7 +404,7 @@ class QStackWidget(StackBase.StackBase,
ArraySave.save3DArrayAsMonochromaticTiff(dataView,
filename,
- labels = None,
+ labels=None,
dtype=dtype,
mcaindex=mcaIndex)
@@ -442,7 +448,7 @@ class QStackWidget(StackBase.StackBase,
row1 = int(min([row1+0.5, self._stack.data.shape[0]]))
col0 = int(max([col0+0.5, 0]))
col1 = int(min([col1+0.5, self._stack.data.shape[1]]))
- view = self._stack.data[row0:row1+1, col0:col1+1,:]
+ view = self._stack.data[row0:row1+1, col0:col1+1, :]
return view
def saveStackAsNeXus(self, dtype=None, interpretation=None, compression=False):
@@ -528,14 +534,14 @@ class QStackWidget(StackBase.StackBase,
if not len(filename):
return
ArraySave.save3DArrayAsHDF5(self._stack.data, filename,
- labels = None, dtype=None, mode='nexus+')
+ labels=None, dtype=None, mode='nexus+')
def saveStackAsSimpleHDF5(self):
filename = self._getOutputHDF5Filename()
if not len(filename):
return
ArraySave.save3DArrayAsHDF5(self._stack.data, filename,
- labels = None, dtype=None, mode='simple')
+ labels=None, dtype=None, mode='simple')
def saveStackAsSimplestHDF5(self):
filename = self._getOutputHDF5Filename()
@@ -543,15 +549,15 @@ class QStackWidget(StackBase.StackBase,
return
view = self._getCroppedView()
ArraySave.save3DArrayAsHDF5(view, filename,
- labels = None, dtype=None, mode='simplest')
+ labels=None, dtype=None, mode='simplest')
def loadStack(self):
if self._stackImageData is not None:
#clear with a small stack
stack = DataObject.DataObject()
- stack.data = numpy.zeros((100,100,100), numpy.float32)
+ stack.data = numpy.zeros((100, 100, 100), numpy.float32)
self.setStack(stack)
- if self.stackSelector is None:
+ if self.stackSelector is None:
self.stackSelector = StackSelector.StackSelector(self)
stack = self.stackSelector.getStack()
if (type(stack) == type([])) or isinstance(stack, list):
@@ -635,7 +641,7 @@ class QStackWidget(StackBase.StackBase,
else:
self._closeSlave()
return
- if self.stackSelector is None:
+ if self.stackSelector is None:
self.stackSelector = StackSelector.StackSelector(self)
try:
@@ -725,8 +731,8 @@ class QStackWidget(StackBase.StackBase,
text = QString("Set User Plugin Directory")
menu.addAction(text)
actionList.append(text)
- global DEBUG
- if DEBUG:
+ global _logger
+ if _logger.getEffectiveLevel() == logging.DEBUG:
text = QString("Toggle DEBUG mode OFF")
else:
text = QString("Toggle DEBUG mode ON")
@@ -785,11 +791,12 @@ class QStackWidget(StackBase.StackBase,
self.setPluginDirectoryList(pluginsDirList)
return
if idx == 2:
- if DEBUG:
- DEBUG = 0
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ _logger.setLevel(logging.DEBUG)
+ StackBase.logger.setLevel(logging.DEBUG)
else:
- DEBUG = 1
- StackBase.DEBUG = DEBUG
+ _logger.setLevel(logging.NOTSET)
+ StackBase.logger.setLevel(logging.NOTSET)
return
key = callableKeys[idx]
methods = self.pluginInstanceDict[key].getMethods()
@@ -832,7 +839,7 @@ class QStackWidget(StackBase.StackBase,
msg.setInformativeText(qt.safe_str(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
def _actionHovered(self, action):
@@ -858,7 +865,7 @@ class QStackWidget(StackBase.StackBase,
self.mainLayout.addWidget(self.rgbWidget)
elif n == 2:
self.tab = qt.QTabWidget(self)
- self.mcaWidget = McaWindow.McaWindow()#vertical=False)
+ self.mcaWidget = McaWindow.McaWindow() #vertical=False
#self.mcaWidget.graph.setMinimumWidth(0.5 * \
# qt.QWidget.sizeHint(self).width())
self.tab.setMaximumHeight(1.3 * qt.QWidget.sizeHint(self).height())
@@ -867,7 +874,11 @@ class QStackWidget(StackBase.StackBase,
self.rgbWidget = RGBCorrelator.RGBCorrelator()
self.tab.addTab(self.rgbWidget, "RGB Correlator")
self.mainLayout.addWidget(self.tab)
- self.mcaWidget.setMiddleROIMarkerFlag(True)
+
+ curvesRoiWidget = self.mcaWidget.getCurvesRoiDockWidget().roiWidget
+ if hasattr(curvesRoiWidget, "setMiddleROIMarkerFlag"):
+ # Not implemented prior to silx >= 0.7
+ curvesRoiWidget.setMiddleROIMarkerFlag(True)
def _buildAndConnectButtonBox(self):
#the MCA selection
@@ -909,10 +920,11 @@ class QStackWidget(StackBase.StackBase,
# self.stackGraphWidget.setInfoText(" X = ???? Y = ???? Z = ????")
# self.stackGraphWidget.showInfo()
- self.stackGraphWidget.graph.sigPlotSignal.connect(\
+ self.stackGraphWidget.graph.sigPlotSignal.connect( \
self._stackGraphSignal)
+
self.mcaWidget.sigROISignal.connect(self._mcaWidgetSignal)
- self.roiWidget.graphWidget.graph.sigPlotSignal.connect(\
+ self.roiWidget.graphWidget.graph.sigPlotSignal.connect( \
self._stackGraphSignal)
def showOriginalImage(self):
@@ -923,8 +935,8 @@ class QStackWidget(StackBase.StackBase,
xScale = self._stack.info.get("xScale", None)
yScale = self._stack.info.get("yScale", None)
self.stackWidget.setImageData(self._stackImageData,
- xScale=xScale,
- yScale=yScale)
+ xScale=xScale,
+ yScale=yScale)
def showOriginalMca(self):
goodData = numpy.isfinite(self._mcaData0.y[0].sum())
@@ -936,7 +948,7 @@ class QStackWidget(StackBase.StackBase,
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Information)
msg.setWindowTitle("Non finite data")
- text = "Your data contain infinite values or nans.\n"
+ text = "Your data contain infinite values or nans.\n"
text += "Pixels containing those values will be ignored."
msg.setText(text)
msg.exec_()
@@ -950,7 +962,7 @@ class QStackWidget(StackBase.StackBase,
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Information)
msg.setWindowTitle("No active curve selected")
- text = "Please select the MCA active curve."
+ text = "Please select the MCA active curve."
msg.setText(text)
msg.exec_()
return
@@ -965,8 +977,8 @@ class QStackWidget(StackBase.StackBase,
xScale = self._stack.info.get("xScale", None)
yScale = self._stack.info.get("yScale", None)
if self.roiBackgroundButton.isChecked():
- self.roiWidget.graphWidget.graph.setGraphTitle(image_names[0]+\
- " Net")
+ self.roiWidget.graphWidget.graph.setGraphTitle(image_names[0] + \
+ " Net")
self.roiWidget.setImageData(imageList[0]-imageList[-1],
xScale=xScale,
yScale=yScale)
@@ -1037,18 +1049,18 @@ class QStackWidget(StackBase.StackBase,
if self.normalizeButton.isChecked():
if self._selectionMask is None:
- npixels = self._stackImageData.shape[0] *\
+ npixels = self._stackImageData.shape[0] * \
self._stackImageData.shape[1]
else:
npixels = self._selectionMask.sum()
if npixels == 0:
- npixels = self._stackImageData.shape[0] *\
+ npixels = self._stackImageData.shape[0] * \
self._stackImageData.shape[1]
legend += "/%d" % npixels
return self.sendMcaSelection(dataObject,
- key = "Selection",
- legend =legend,
- action = action)
+ key="Selection",
+ legend=legend,
+ action=action)
def _removeMcaClicked(self):
#remove the mca
@@ -1063,7 +1075,7 @@ class QStackWidget(StackBase.StackBase,
if curve.startswith(legend):
legend = curve
break
- self.sendMcaSelection(dataObject, legend = legend, action = "REMOVE")
+ self.sendMcaSelection(dataObject, legend=legend, action="REMOVE")
def _replaceMcaClicked(self):
#replace the mca
@@ -1071,7 +1083,7 @@ class QStackWidget(StackBase.StackBase,
self._addMcaClicked(action="REPLACE")
self.__ROIConnected = True
- def sendMcaSelection(self, mcaObject, key = None, legend = None, action = None):
+ def sendMcaSelection(self, mcaObject, key=None, legend=None, action=None):
if action is None:
action = "ADD"
if key is None:
@@ -1084,9 +1096,9 @@ class QStackWidget(StackBase.StackBase,
legend += "/%d" % npixels
sel = {}
sel['SourceName'] = "EDF Stack"
- sel['Key'] = key
- sel['legend'] = legend
- sel['dataobject'] = mcaObject
+ sel['Key'] = key
+ sel['legend'] = legend
+ sel['dataobject'] = mcaObject
if action == "ADD":
self.mcaWidget._addSelection([sel])
elif action == "REMOVE":
@@ -1106,11 +1118,10 @@ class QStackWidget(StackBase.StackBase,
if instance_id == id(self):
return
- if DEBUG:
- if self._slaveList is not None:
- print("MASTER setSelectionMask CALLED")
- elif self._masterStack is not None:
- print("SLAVE setSelectionMask CALLED")
+ if self._slaveList is not None:
+ _logger.debug("MASTER setSelectionMask CALLED")
+ elif self._masterStack is not None:
+ _logger.debug("SLAVE setSelectionMask CALLED")
#inform built in widgets
for widget in [self.stackWidget, self.roiWidget]:
@@ -1131,8 +1142,7 @@ class QStackWidget(StackBase.StackBase,
instanceList.append(id(slave.pluginInstanceDict[key]))
if instance_id not in instanceList:
#Originated by the master
- if DEBUG:
- print("INFORMING SLAVE")
+ _logger.warning("INFORMING SLAVE")
slave.setSelectionMask(mask, instance_id=id(self))
if self._masterStack is not None:
@@ -1143,8 +1153,7 @@ class QStackWidget(StackBase.StackBase,
instanceList.append(id(self.pluginInstanceDict[key]))
if instance_id in instanceList:
#Originated by the slave
- if DEBUG:
- print("INFORMING MASTER")
+ _logger.debug("INFORMING MASTER")
self._masterStack.setSelectionMask(mask, instance_id=id(self))
#Inform plugins
@@ -1177,11 +1186,9 @@ class QStackWidget(StackBase.StackBase,
return
if ddict['event'] == "hFlipSignal":
if ddict['id'] != id(self.stackWidget):
- self.stackWidget.graph.invertYAxis(ddict['current'])
- self.stackWidget.graph.replot()
+ self.stackWidget.graph.getYAxis().setInverted(ddict['current'])
if ddict['id'] != id(self.roiWidget):
- self.roiWidget.graph.invertYAxis(ddict['current'])
- self.roiWidget.graph.replot()
+ self.roiWidget.graph.getYAxis().setInverted(ddict['current'])
return
def _stackGraphSignal(self, ddict):
@@ -1198,8 +1205,8 @@ class QStackWidget(StackBase.StackBase,
x = min(int(x), limits[0]-1)
y = min(int(y), limits[1]-1)
z = self._stackImageData[x, y]
- self.stackGraphWidget.setInfoText(" X = %d Y = %d Z = %.4g" %\
- (y, x, z))
+ self.stackGraphWidget.setInfoText( \
+ " X = %d Y = %d Z = %.4g" % (y, x, z))
def _mcaWidgetSignal(self, ddict):
if not self.__ROIConnected:
@@ -1248,7 +1255,7 @@ def test():
stackData = numpy.zeros((nrows, ncols, nchannels), numpy.float)
for i in range(nchannels):
stackData[:, :, i] = a * i
- stackData[0:10,:,:] = 0
+ stackData[0:10, :, :] = 0
w = QStackWidget()
w.setStack(stackData, mcaindex=2)
w.show()
@@ -1256,6 +1263,7 @@ def test():
if __name__ == "__main__":
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
sys.excepthook = qt.exceptionHandler
try:
opts, args = getopt.getopt(
@@ -1263,7 +1271,7 @@ if __name__ == "__main__":
options,
longoptions)
except:
- print(sys.exc_info()[1])
+ print("%s" % sys.exc_info()[1])
sys.exit(1)
fileindex = 0
filepattern=None
@@ -1273,6 +1281,7 @@ if __name__ == "__main__":
increment=None
backend=None
PyMcaDirs.nativeFileDialogs=True
+
for opt, arg in opts:
if opt in '--begin':
if "," in arg:
@@ -1290,22 +1299,25 @@ if __name__ == "__main__":
else:
increment = int(arg)
elif opt in '--filepattern':
- filepattern = arg.replace('"','')
- filepattern = filepattern.replace("'","")
+ filepattern = arg.replace('"', '')
+ filepattern = filepattern.replace("'", "")
elif opt in '--fileindex':
fileindex = int(arg)
elif opt in ['--imagestack', "--image"]:
imagestack = int(arg)
elif opt in '--nativefiledialogs':
if int(arg):
- PyMcaDirs.nativeFileDialogs=True
+ PyMcaDirs.nativeFileDialogs = True
else:
- PyMcaDirs.nativeFileDialogs=False
+ PyMcaDirs.nativeFileDialogs = False
elif opt in '--backend':
backend = arg
#elif opt in '--old':
# import QEDFStackWidget
# sys.exit(QEDFStackWidget.runAsMain())
+
+ logging.basicConfig(level=getLoggingLevel(opts))
+
if filepattern is not None:
if (begin is None) or (end is None):
raise ValueError("A file pattern needs at least a set of begin and end indices")
@@ -1316,10 +1328,10 @@ if __name__ == "__main__":
if backend is not None:
# set the default backend
try:
- from PyMca5.PyMcaGraph.Plot import Plot
- Plot.defaultBackend = backend
+ from silx.gui.plot import PlotWidget
+ PlotWidget.setDefaultBackend(backend)
except:
- print("WARNING: Cannot set backend to %s" % backend)
+ _logger.warning("WARNING: Cannot set backend to %s", backend)
widget = QStackWidget()
w = StackSelector.StackSelector(widget)
if filepattern is not None:
diff --git a/PyMca5/PyMcaGui/pymca/RGBCorrelator.py b/PyMca5/PyMcaGui/pymca/RGBCorrelator.py
index 06d876b..500bb6b 100644
--- a/PyMca5/PyMcaGui/pymca/RGBCorrelator.py
+++ b/PyMca5/PyMcaGui/pymca/RGBCorrelator.py
@@ -157,6 +157,7 @@ class RGBCorrelator(qt.QWidget):
qt.QWidget.show(self)
def test():
+ import logging
app = qt.QApplication([])
app.lastWindowClosed.connect(app.quit)
if 0:
@@ -167,14 +168,15 @@ def test():
w = RGBCorrelator()
w.resize(800, 600)
import getopt
- options=''
- longoptions=[]
+ from PyMca5.PyMcaCore.LoggingLevel import getLoggingLevel
+ options = ''
+ longoptions = ["logging=", "debug="]
opts, args = getopt.getopt(
sys.argv[1:],
options,
longoptions)
- for opt,arg in opts:
- pass
+
+ logging.basicConfig(level=getLoggingLevel(opts))
filelist=args
if len(filelist):
try:
diff --git a/PyMca5/PyMcaGui/pymca/RGBCorrelatorSlider.py b/PyMca5/PyMcaGui/pymca/RGBCorrelatorSlider.py
index d2995cf..59c85a0 100644
--- a/PyMca5/PyMcaGui/pymca/RGBCorrelatorSlider.py
+++ b/PyMca5/PyMcaGui/pymca/RGBCorrelatorSlider.py
@@ -27,11 +27,13 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import DoubleSlider
qt = DoubleSlider.qt
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class RGBCorrelatorSlider(qt.QWidget):
sigRGBCorrelatorSliderSignal = qt.pyqtSignal(object)
@@ -145,22 +147,19 @@ class RGBCorrelatorSlider(qt.QWidget):
self.sigRGBCorrelatorSliderSignal.emit(ddict)
def _redSliderChanged(self, ddict):
- if DEBUG:
- print("RGBCorrelatorSlider._redSliderChanged()")
+ _logger.debug("RGBCorrelatorSlider._redSliderChanged()")
if self.__emitSignals:
ddict['event'] = "redChanged"
self.sigRGBCorrelatorSliderSignal.emit(ddict)
def _greenSliderChanged(self, ddict):
- if DEBUG:
- print("RGBCorrelatorSlider._greenSliderChanged()")
+ _logger.debug("RGBCorrelatorSlider._greenSliderChanged()")
if self.__emitSignals:
ddict['event'] = "greenChanged"
self.sigRGBCorrelatorSliderSignal.emit(ddict)
def _blueSliderChanged(self, ddict):
- if DEBUG:
- print("RGBCorrelatorSlider._blueSliderChanged()")
+ _logger.debug("RGBCorrelatorSlider._blueSliderChanged()")
if self.__emitSignals:
ddict['event'] = "blueChanged"
self.sigRGBCorrelatorSliderSignal.emit(ddict)
diff --git a/PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py b/PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py
index 5057b12..596d494 100644
--- a/PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py
+++ b/PyMca5/PyMcaGui/pymca/RGBCorrelatorWidget.py
@@ -31,6 +31,7 @@ import sys
import os
import numpy
import traceback
+import logging
from . import RGBCorrelatorSlider
from . import RGBCorrelatorTable
from PyMca5.PyMcaGui.pymca import RGBImageCalculator
@@ -73,7 +74,7 @@ try:
except:
TOMOGUI_FLAG = False
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class RGBCorrelatorWidget(qt.QWidget):
@@ -306,8 +307,7 @@ class RGBCorrelatorWidget(qt.QWidget):
self.toggleSlidersButton.setIcon(self._slidersOnIcon)
def _sliderSlot(self, ddict):
- if DEBUG:
- print("RGBCorrelatorWidget._sliderSlot()")
+ _logger.debug("RGBCorrelatorWidget._sliderSlot()")
if self.__imageLength is None: return
tableDict = self.tableWidget.getElementSelection()
if ddict['event'] == 'redChanged':
@@ -339,8 +339,7 @@ class RGBCorrelatorWidget(qt.QWidget):
self.__recolor(['r', 'g', 'b'])
def _tableSlot(self, ddict):
- if DEBUG:
- print("RGBCorrelatorWidget._tableSlot()")
+ _logger.debug("RGBCorrelatorWidget._tableSlot()")
if self.__imageLength is None: return
if ddict['r'] == []:ddict['r'] = None
if ddict['g'] == []:ddict['g'] = None
@@ -881,8 +880,7 @@ class RGBCorrelatorWidget(qt.QWidget):
self.addImage(imgData, title)
continue
except:
- if DEBUG:
- print("Built-in tif support unsuccessful")
+ _logger.debug("Built-in tif support unsuccessful")
pass
#try a pure image format from PyQt
qimage = qt.QImage(fname)
@@ -939,7 +937,7 @@ class RGBCorrelatorWidget(qt.QWidget):
msg.setInformativeText(str(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
def addBatchDatFile(self, filename, ignoresigma=None, csv=False):
diff --git a/PyMca5/PyMcaGui/pymca/RGBImageCalculator.py b/PyMca5/PyMcaGui/pymca/RGBImageCalculator.py
index a9cace6..20c304e 100644
--- a/PyMca5/PyMcaGui/pymca/RGBImageCalculator.py
+++ b/PyMca5/PyMcaGui/pymca/RGBImageCalculator.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
+import logging
from PyMca5.PyMcaGui import MaskImageWidget
from PyMca5.PyMcaGui import ColormapDialog
from PyMca5 import spslut
@@ -43,7 +44,8 @@ COLORMAPLIST = [spslut.GREYSCALE, spslut.REVERSEGREY, spslut.TEMP,
spslut.RED, spslut.GREEN, spslut.BLUE, spslut.MANY]
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class RGBImageCalculator(qt.QWidget):
sigAddImageClicked = qt.pyqtSignal(object)
@@ -170,8 +172,7 @@ class RGBImageCalculator(qt.QWidget):
return self.graphWidget.plotImage(update=update)
def _calculateClicked(self):
- if DEBUG:
- print("Calculate clicked")
+ _logger.debug("Calculate clicked")
text = "%s" % self.mathExpression.text()
if not len(text):
qt.QMessageBox.critical(self, "Calculation Error",
@@ -217,8 +218,7 @@ class RGBImageCalculator(qt.QWidget):
self.graphWidget.graph.setGraphTitle("%s" % name)
def _addImageClicked(self):
- if DEBUG:
- print("Add image clicked")
+ _logger.debug("Add image clicked")
if self._imageData is None:
return
if self._imageData == []:
@@ -234,8 +234,7 @@ class RGBImageCalculator(qt.QWidget):
self.sigAddImageClicked.emit(ddict)
def _removeImageClicked(self):
- if DEBUG:
- print("remove image clicked")
+ _logger.debug("remove image clicked")
text = "%s" % self.name.text()
if not len(text):
qt.QMessageBox.critical(self, "Name Error",
@@ -244,8 +243,7 @@ class RGBImageCalculator(qt.QWidget):
self.sigRemoveImageClicked.emit(text)
def _replaceImageClicked(self):
- if DEBUG:
- print("replace image clicked")
+ _logger.debug("replace image clicked")
text = "%s" % self.name.text()
if not len(text):
qt.QMessageBox.critical(self, "Name Error",
diff --git a/PyMca5/PyMcaGui/pymca/ScanFitToolButton.py b/PyMca5/PyMcaGui/pymca/ScanFitToolButton.py
new file mode 100644
index 0000000..150a3ad
--- /dev/null
+++ b/PyMca5/PyMcaGui/pymca/ScanFitToolButton.py
@@ -0,0 +1,158 @@
+#/*##########################################################################
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+"""This module defines a QToolButton opening a fit menu when clicked:
+
+ - :class:`ScanFitToolButton`
+
+This button takes a plot object as constructor parameter.
+"""
+
+
+import silx.gui.icons
+
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from PyMca5.PyMcaGui.math.fitting import SimpleFitGui
+from PyMca5.PyMcaGui.pymca import ScanFit
+
+
+if hasattr(qt, 'QString'):
+ QString = qt.QString
+else:
+ QString = qt.safe_str
+
+
+class ScanFitToolButton(qt.QToolButton):
+ def __init__(self, plot, parent=None):
+ """QAction offering a menu with two fit options: simple fit
+ and custom fit.
+
+ :param plot: :class:`ScanWindow` instance on which to operate
+ :param parent: Parent QObject. If parent is an action group the action
+ will be automatically inserted into the group.
+ """
+ qt.QToolButton.__init__(self, parent)
+ self.setIcon(silx.gui.icons.getQIcon('math-fit'))
+ self.setToolTip("Fit of Active Curve")
+ self.clicked.connect(self._buttonClicked)
+
+ self.plot = plot
+
+ if not hasattr(self.plot, "scanFit"):
+ self.scanFit = ScanFit.ScanFit()
+ else:
+ # ScanWindow can define a customized scanFit with custom fit functions
+ self.scanFit = self.plot.scanFit
+ self.scanFit.sigScanFitSignal.connect(
+ self._scanFitSignalReceived)
+
+ self.customFit = SimpleFitGui.SimpleFitGui()
+ self.customFit.sigSimpleFitSignal.connect(
+ self._customFitSignalReceived)
+
+ self.fitButtonMenu = qt.QMenu()
+ self.fitButtonMenu.addAction(
+ QString("Simple Fit"),
+ self._scanFitSignal)
+ self.fitButtonMenu.addAction(
+ QString("Customized Fit"),
+ self._customFitSignal)
+
+ self._scanFitLegend = None
+ self._customFitLegend = None
+
+ def _buttonClicked(self):
+ """Display a menu to select simple fit or custom fit.
+
+ Selecting simple fit calls :meth:`_scanFitSignal`.
+ Selecting customized fit calls :meth:`_customFitSignal`.
+ """
+ self.fitButtonMenu.exec_(self.plot.cursor().pos())
+
+ def _getOneCurve(self):
+ """Return active curve if any. Else return first curve, if any.
+ Else return None
+ :return: [x, y, legend, info, params] or None"""
+ curve = self.plot.getActiveCurve()
+ if curve is None:
+ curves = self.plot.getAllCurves()
+ if len(curves):
+ curve = curves[0]
+ return curve
+
+ def _showFitWidget(self):
+ """Initialize fit dialog widget and raise it.
+
+ :attr:`_activeFitDialog` must be set to :attr:`scanFit` or
+ :attr:`customFit` before this method is called.
+ """
+ curve = self._getOneCurve()
+ if curve is None:
+ return
+ x, y, legend, info, params = curve
+
+ xmin, xmax = self.plot.getGraphXLimits()
+
+ fitLegend = legend + " Fit"
+ if fitLegend in self.plot.getAllCurves(just_legend=True):
+ self.plot.removeCurve(fitLegend)
+
+ if self._activeFitDialog is self.scanFit:
+ self._scanFitLegend = fitLegend
+ elif self._activeFitDialog is self.customFit:
+ self._customFitLegend = fitLegend
+
+ self._activeFitDialog.setData(x=x,
+ y=y,
+ xmin=xmin,
+ xmax=xmax,
+ legend=legend)
+ if self._activeFitDialog.isHidden():
+ self._activeFitDialog.show()
+ self._activeFitDialog.raise_()
+
+ def _scanFitSignal(self):
+ self._activeFitDialog = self.scanFit
+ self._showFitWidget()
+
+ def _customFitSignal(self):
+ self._activeFitDialog = self.customFit
+ self._showFitWidget()
+
+ def _scanFitSignalReceived(self, ddict):
+ if ddict['event'] == "FitFinished":
+ xplot = self.scanFit.specfit.xdata * 1.0
+ yplot = self.scanFit.specfit.gendata(parameters=ddict['data'])
+
+ self.plot.addCurve(x=xplot, y=yplot, legend=self._scanFitLegend,
+ resetzoom=False)
+
+ def _customFitSignalReceived(self, ddict):
+ if ddict['event'] == "FitFinished":
+ xplot = ddict['x']
+ yplot = ddict['yfit']
+
+ self.plot.addCurve(xplot, yplot, legend=self._customFitLegend,
+ resetzoom=False)
diff --git a/PyMca5/PyMcaGui/pymca/ScanWindow.py b/PyMca5/PyMcaGui/pymca/ScanWindow.py
index 4f025de..37ea258 100644
--- a/PyMca5/PyMcaGui/pymca/ScanWindow.py
+++ b/PyMca5/PyMcaGui/pymca/ScanWindow.py
@@ -23,219 +23,343 @@
# THE SOFTWARE.
#
#############################################################################*/
-__author__ = "V.A. Sole - ESRF Data Analysis"
-__contact__ = "sole@esrf.fr"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+"""This module defines a :class:`ScanWindow` inheriting a *silx*
+:class:`PlotWindow` with additional tools and actions.
+The main addition is a :class:`PluginsToolButton` button added to the toolbar,
+to open a menu with plugins."""
+
import os
+import copy
+import logging
import numpy
-#from numpy import argsort, nonzero, take
-import time
-import traceback
+import sys
+
+from silx.gui.plot import PlotWindow
+from silx.gui.plot.PrintPreviewToolButton import SingletonPrintPreviewToolButton
+
+import PyMca5
+from PyMca5.PyMcaGui.pymca import ScanWindowInfoWidget
from PyMca5.PyMcaGui import PyMcaQt as qt
+from PyMca5.PyMcaGui.PluginsToolButton import PluginsToolButton
+from PyMca5.PyMcaGui.math import SimpleActions
+from PyMca5.PyMcaGui.pymca import ScanFit
+from PyMca5.PyMcaGui.pymca.ScanFitToolButton import ScanFitToolButton
+from PyMca5.PyMcaCore import DataObject
+from PyMca5.PyMcaGui.pymca import QPyMcaMatplotlibSave1D
+from PyMca5.PyMcaGui.plotting.PyMca_Icons import change_icons
+
if hasattr(qt, 'QString'):
QString = qt.QString
else:
QString = qt.safe_str
-if __name__ == "__main__":
- app = qt.QApplication([])
-
-from PyMca5.PyMcaGui.io import PyMcaFileDialogs
-from PyMca5.PyMcaGui.plotting import PlotWindow
-from . import ScanFit
-from PyMca5.PyMcaMath import SimpleMath
-from PyMca5.PyMcaCore import DataObject
-import copy
-from PyMca5.PyMcaGui import PyMcaPrintPreview
-from PyMca5.PyMcaCore import PyMcaDirs
-from . import ScanWindowInfoWidget
-#implement the plugins interface
-from PyMca5.PyMcaGui import QPyMcaMatplotlibSave1D
-MATPLOTLIB = True
-#force understanding of utf-8 encoding
-#otherways it cannot generate svg output
-try:
- import encodings.utf_8
-except:
- #not a big problem
- pass
PLUGINS_DIR = None
-try:
- import PyMca5
- if os.path.exists(os.path.join(os.path.dirname(PyMca5.__file__), "PyMcaPlugins")):
- from PyMca5 import PyMcaPlugins
- PLUGINS_DIR = os.path.dirname(PyMcaPlugins.__file__)
+
+if os.path.exists(os.path.join(os.path.dirname(PyMca5.__file__), "PyMcaPlugins")):
+ from PyMca5 import PyMcaPlugins
+ PLUGINS_DIR = os.path.dirname(PyMcaPlugins.__file__)
+else:
+ directory = os.path.dirname(__file__)
+ while True:
+ if os.path.exists(os.path.join(directory, "PyMcaPlugins")):
+ PLUGINS_DIR = os.path.join(directory, "PyMcaPlugins")
+ break
+ directory = os.path.dirname(directory)
+ if len(directory) < 5:
+ break
+userPluginsDirectory = PyMca5.getDefaultUserPluginsDirectory()
+if userPluginsDirectory is not None:
+ if PLUGINS_DIR is None:
+ PLUGINS_DIR = userPluginsDirectory
else:
- directory = os.path.dirname(__file__)
- while True:
- if os.path.exists(os.path.join(directory, "PyMcaPlugins")):
- PLUGINS_DIR = os.path.join(directory, "PyMcaPlugins")
- break
- directory = os.path.dirname(directory)
- if len(directory) < 5:
- break
- userPluginsDirectory = PyMca5.getDefaultUserPluginsDirectory()
- if userPluginsDirectory is not None:
- if PLUGINS_DIR is None:
- PLUGINS_DIR = userPluginsDirectory
- else:
- PLUGINS_DIR = [PLUGINS_DIR, userPluginsDirectory]
-except:
- pass
-
-DEBUG = 0
-
-class ScanWindow(PlotWindow.PlotWindow):
- def __init__(self, parent=None, name="Scan Window", specfit=None, backend=None,
- plugins=True, newplot=True, roi=True, fit=True,
- control=True, position=True, info=False, **kw):
-
- super(ScanWindow, self).__init__(parent,
- newplot=newplot,
- plugins=plugins,
- backend=backend,
- roi=roi,
- fit=fit,
- control=control,
- position=position,
- **kw)
+ PLUGINS_DIR = [PLUGINS_DIR, userPluginsDirectory]
+
+
+_logger = logging.getLogger(__name__)
+# _logger.setLevel(logging.DEBUG)
+
+
+class BaseScanWindow(PlotWindow):
+ """:class:`PlotWindow` augmented with plugins, fitting actions,
+ a widget for displaying scan metadata and simple curve processing actions.
+ """
+ def __init__(self, parent=None, name="Scan Window", fit=True, backend=None,
+ plugins=True, control=True, position=True, roi=True,
+ specfit=None, info=False, save=True):
+ super(BaseScanWindow, self).__init__(parent,
+ backend=backend,
+ roi=roi,
+ control=control,
+ position=position,
+ save=save,
+ mask=False,
+ colormap=False,
+ aspectRatio=False,
+ yInverted=False,
+ copy=True,
+ print_=False)
self.setDataMargins(0, 0, 0.025, 0.025)
- #self._togglePointsSignal()
+
self.setPanWithArrowKeys(True)
- self.setWindowType("SCAN")
- # this two objects are the same
- self.dataObjectsList = self._curveList
- # but this is tricky
- self.dataObjectsDict = {}
+ self._plotType = "SCAN" # needed by legacy plugins
self.setWindowTitle(name)
- self.matplotlibDialog = None
- if PLUGINS_DIR is not None:
- if type(PLUGINS_DIR) == type([]):
- pluginDir = PLUGINS_DIR
- else:
- pluginDir = [PLUGINS_DIR]
- self.getPlugins(method="getPlugin1DInstance",
- directoryList=pluginDir)
+ # No context menu by default, execute zoomBack on right click
+ plotArea = self.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
+ # Toolbar:
+ # hide interactive toolbar (zoom and pan mode buttons)
+ self.getInteractiveModeToolBar().setVisible(False)
+ # additional buttons
+ self._mathToolBar = qt.QToolBar(self)
+
+ self.addToolBar(self._mathToolBar)
+
+ self.fitToolButton = None
+ self.scanFit = None
+ if fit:
+ self.scanFit = ScanFit.ScanFit(specfit=specfit)
+ self.fitToolButton = ScanFitToolButton(self)
+ self.toolBar().insertWidget(self.getMaskAction(), # before MaskAction (hidden)
+ self.fitToolButton)
+
+ self.avgAction = SimpleActions.AverageAction(plot=self)
+ self.derivativeAction = SimpleActions.DerivativeAction(plot=self)
+ self.smoothAction = SimpleActions.SmoothAction(plot=self)
+ self.swapSignAction = SimpleActions.SwapSignAction(plot=self)
+ self.yMinToZero = SimpleActions.YMinToZeroAction(plot=self)
+ self.subtractAction = SimpleActions.SubtractAction(plot=self)
+
+ self._mathToolBar.addAction(self.avgAction)
+ self._mathToolBar.addAction(self.derivativeAction)
+ self._mathToolBar.addAction(self.smoothAction)
+ self._mathToolBar.addAction(self.swapSignAction)
+ self._mathToolBar.addAction(self.yMinToZero)
+ self._mathToolBar.addAction(self.subtractAction)
+
+ self.pluginsToolButton = None
+ """Plugins tool button, used to load and call plugins.
+ It inherits the PluginLoader API:
+
+ - getPlugins
+ - getPluginDirectoryList
+ - setPluginDirectoryList
+
+ It can be None, if plugins are disabled when initializing
+ the ScanWindow.
+ """
+
+ if plugins:
+ self.pluginsToolButton = PluginsToolButton(plot=self)
+
+ if PLUGINS_DIR is not None:
+ if isinstance(PLUGINS_DIR, list):
+ pluginDir = PLUGINS_DIR
+ else:
+ pluginDir = [PLUGINS_DIR]
+ self.pluginsToolButton.getPlugins(
+ method="getPlugin1DInstance",
+ directoryList=pluginDir)
+ self.pluginsAction = self._mathToolBar.addWidget(self.pluginsToolButton)
+
+ self._printPreviewToolBar = qt.QToolBar(self)
+ self._printPreviewToolBar.setMovable(False)
+ self._printPreviewToolBar.setFloatable(False)
+ self.addToolBar(self._printPreviewToolBar)
+ self._printPreviewToolBar.addWidget(qt.HorizontalSpacer(self._printPreviewToolBar))
+ self.printPreview = SingletonPrintPreviewToolButton(parent=self._printPreviewToolBar,
+ plot=self)
+ self.printPreviewAction = self._printPreviewToolBar.addWidget(self.printPreview)
+
+ self.scanWindowInfoWidget = None
+ self.infoDockWidget = None
if info:
self.scanWindowInfoWidget = ScanWindowInfoWidget.\
ScanWindowInfoWidget()
self.infoDockWidget = qt.QDockWidget(self)
self.infoDockWidget.layout().setContentsMargins(0, 0, 0, 0)
self.infoDockWidget.setWidget(self.scanWindowInfoWidget)
- self.infoDockWidget.setWindowTitle(self.windowTitle()+(" Info"))
+ self.infoDockWidget.setWindowTitle("Scan Info")
self.addDockWidget(qt.Qt.BottomDockWidgetArea,
- self.infoDockWidget)
- controlMenu = qt.QMenu()
- controlMenu.addAction(QString("Show/Hide Legends"),
- self.toggleLegendWidget)
- controlMenu.addAction(QString("Show/Hide Info"),
- self._toggleInfoWidget)
- controlMenu.addAction(QString("Toggle Crosshair"),
- self.toggleCrosshairCursor)
- controlMenu.addAction(QString("Toggle Arrow Keys Panning"),
- self.toggleArrowKeysPanning)
- self.setControlMenu(controlMenu)
- else:
- self.scanWindowInfoWidget = None
- #self.fig = None
- if fit:
- self.scanFit = ScanFit.ScanFit(specfit=specfit)
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
- self.simpleMath = SimpleMath.SimpleMath()
- self.outputDir = None
- self.outputFilter = None
-
- #signals
- # this one was made in the base class
- #self.setCallback(self.graphCallback)
- if fit:
- from PyMca5.PyMcaGui.math.fitting import SimpleFitGui
- self.customFit = SimpleFitGui.SimpleFitGui()
- self.scanFit.sigScanFitSignal.connect(self._scanFitSignalReceived)
- self.customFit.sigSimpleFitSignal.connect( \
- self._customFitSignalReceived)
-
- self.fitButtonMenu = qt.QMenu()
- self.fitButtonMenu.addAction(QString("Simple Fit"),
- self._simpleFitSignal)
- self.fitButtonMenu.addAction(QString("Customized Fit") ,
- self._customFitSignal)
-
- def _toggleInfoWidget(self):
- if self.infoDockWidget.isHidden():
- self.infoDockWidget.show()
- legend = self.getActiveCurve(just_legend=True)
- if legend is not None:
- ddict ={}
- ddict['event'] = "curveClicked"
- ddict['label'] = legend
- ddict['legend'] = legend
- self.graphCallback(ddict)
- else:
- self.infoDockWidget.hide()
-
- def _buildLegendWidget(self):
- if self.legendWidget is None:
- super(ScanWindow, self)._buildLegendWidget()
- if hasattr(self, "infoDockWidget") and \
- hasattr(self, "roiDockWidget"):
- self.tabifyDockWidget(self.infoDockWidget,
- self.roiDockWidget,
- self.legendDockWidget)
- elif hasattr(self, "infoDockWidget"):
- self.tabifyDockWidget(self.infoDockWidget,
- self.legendDockWidget)
-
- def _toggleROI(self, position=None):
- super(ScanWindow, self)._toggleROI(position=position)
- if hasattr(self, "infoDockWidget"):
- self.tabifyDockWidget(self.infoDockWidget,
- self.roiDockWidget)
+ self.infoDockWidget)
+
+ self.sigActiveCurveChanged.connect(self.__updateInfoWidget)
+
+ self.sigActiveCurveChanged.connect(self.__updateGraphTitle)
+ self.matplotlibDialog = None
+
+ saveAction = self.getOutputToolBar().getSaveAction()
+ for ext in ["png", "eps", "svg"]:
+ name_filter = 'Customized graphics (*.%s)' % ext
+ # if silx-kit/silx#2013 is merged, the following line can be removed for silx 0.9
+ saveAction.setFileFilter(dataKind='curve', # single curve case
+ nameFilter=name_filter,
+ func=self._graphicsSave)
+ saveAction.setFileFilter(dataKind='curves',
+ nameFilter=name_filter,
+ func=self._graphicsSave)
+
+ change_icons(self)
+
+ def _customControlButtonMenu(self):
+ """Display Options button sub-menu. Overloaded to add
+ _toggleInfoAction"""
+ # overloaded from PlotWindow to add "Show/Hide Info"
+ controlMenu = self.controlButton.menu()
+ controlMenu.clear()
+ controlMenu.addAction(self.getLegendsDockWidget().toggleViewAction())
+
+ if self.infoDockWidget is not None:
+ controlMenu.addAction(self.infoDockWidget.toggleViewAction())
+ controlMenu.addAction(self.getRoiAction())
+ controlMenu.addAction(self.getMaskAction())
+ controlMenu.addAction(self.getConsoleAction())
+
+ controlMenu.addSeparator()
+ controlMenu.addAction(self.getCrosshairAction())
+ controlMenu.addAction(self.getPanWithArrowKeysAction())
+
+ def __updateInfoWidget(self, previous_legend, legend):
+ """Called on active curve changed, to update the info widget"""
+ x, y, legend, info, params = self.getCurve(legend)
+ self.scanWindowInfoWidget.updateFromXYInfo(x, y, info)
+
+ def __updateGraphTitle(self, previous_legend, legend):
+ """Called on active curve changed, to update the graph title"""
+ if legend is None and previous_legend is not None:
+ self.setGraphTitle()
+ elif legend is not None:
+ self.setGraphTitle(legend)
+
+ def setWindowType(self, wtype=None):
+ if wtype not in [None, "SCAN", "MCA"]:
+ raise AttributeError("Unsupported window type %s." % wtype)
+ self._plotType = wtype
+
+ def _zoomBack(self, pos):
+ self.getLimitsHistory().pop()
+
+ def _graphicsSave(self, plot, filename, nameFilter=""):
+ # note: the method's signature must conform to
+ # saveAction.setFileFilter requirements
+ x, y, legend, info = plot.getActiveCurve()[:4]
+ curveList = plot.getAllCurves()
+ size = (6, 3) # in inches
+ legends = len(curveList) > 1
+ if self.matplotlibDialog is None:
+ self.matplotlibDialog = QPyMcaMatplotlibSave1D.\
+ QPyMcaMatplotlibSaveDialog(size=size,
+ logx=plot.isXAxisLogarithmic(),
+ logy=plot.isYAxisLogarithmic(),
+ legends=legends,
+ bw=False)
+
+ mtplt = self.matplotlibDialog.plot
+
+ mtplt.setParameters({'logy': plot.isXAxisLogarithmic(),
+ 'logx': plot.isYAxisLogarithmic(),
+ 'legends': legends,
+ 'bw': False})
+ xmin, xmax = plot.getGraphXLimits()
+ ymin, ymax = plot.getGraphYLimits()
+ mtplt.setLimits(xmin, xmax, ymin, ymax)
+
+ legend0 = legend
+ dataCounter = 1
+ alias = "%c" % (96 + dataCounter)
+ mtplt.addDataToPlot(x, y, legend=legend0, alias=alias)
+ for curve in curveList:
+ x, y, legend, info = curve[0:4]
+ if legend == legend0:
+ continue
+ dataCounter += 1
+ alias = "%c" % (96 + dataCounter)
+ mtplt.addDataToPlot(x, y, legend=legend, alias=alias)
+
+ self.matplotlibDialog.setXLabel(plot.getGraphXLabel())
+ self.matplotlibDialog.setYLabel(plot.getGraphYLabel())
+
+ if legends:
+ mtplt.plotLegends()
+ ret = self.matplotlibDialog.exec_()
+ if ret == qt.QDialog.Accepted:
+ mtplt.saveFile(filename)
+ return
+
+
+class ScanWindow(BaseScanWindow):
+ """ScanWindow, adding dataObject management to BaseScanWindow
+ """
+
+ def __init__(self, parent=None, name="Scan Window", fit=True, backend=None,
+ plugins=True, control=True, position=True, roi=True,
+ specfit=None, info=False, save=True):
+ BaseScanWindow.__init__(self,
+ parent, name, fit, backend,
+ plugins, control, position, roi,
+ specfit, info, save)
+
+ self.dataObjectsDict = {}
+
+ self.sigContentChanged.connect(self._handleContentChanged)
+
+ @property
+ def dataObjectsList(self):
+ return self.getAllCurves(just_legend=True)
+
+ @property
+ def _curveList(self):
+ return self.getAllCurves(just_legend=True)
+
+ def _handleContentChanged(self, action, kind, legend):
+ if action == 'remove' and kind == "curve":
+ self.removeCurves([legend])
def setDispatcher(self, w):
w.sigAddSelection.connect(self._addSelection)
w.sigRemoveSelection.connect(self._removeSelection)
w.sigReplaceSelection.connect(self._replaceSelection)
- def _addSelection(self, selectionlist, replot=True):
- if DEBUG:
- print("_addSelection(self, selectionlist)",selectionlist)
- if type(selectionlist) == type([]):
- sellist = selectionlist
- else:
- sellist = [selectionlist]
+ def _addSelection(self, selectionlist, resetzoom=True, replot=None):
+ """Add curves to plot and data objects to :attr:`dataObjectsDict`
+ """
+ _logger.debug("_addSelection(self, selectionlist) " +
+ str(selectionlist))
+ if replot is not None:
+ _logger.warning(
+ 'deprecated replot argument, use resetzoom instead')
+ resetzoom = replot and resetzoom
+
+ sellist = selectionlist if isinstance(selectionlist, list) else \
+ [selectionlist]
- if len(self._curveList):
+ if len(self.getAllCurves(just_legend=True)):
activeCurve = self.getActiveCurve(just_legend=True)
else:
activeCurve = None
nSelection = len(sellist)
for selectionIndex in range(nSelection):
sel = sellist[selectionIndex]
- if selectionIndex == (nSelection - 1):
- actualReplot = replot
- else:
- actualReplot = False
- source = sel['SourceName']
- key = sel['Key']
- legend = sel['legend'] #expected form sourcename + scan key
- if not ("scanselection" in sel): continue
- if sel['scanselection'] == "MCA":
+ key = sel['Key']
+ legend = sel['legend'] # expected form sourcename + scan key
+ if "scanselection" not in sel or not sel["scanselection"] or \
+ sel['scanselection'] == "MCA":
+ continue
+ if len(key.split(".")) > 2:
continue
- if not sel["scanselection"]:continue
- if len(key.split(".")) > 2: continue
dataObject = sel['dataobject']
- #only one-dimensional selections considered
- if dataObject.info["selectiontype"] != "1D": continue
+ # only one-dimensional selections considered
+ if dataObject.info["selectiontype"] != "1D":
+ continue
- #there must be something to plot
+ # there must be something to plot
if not hasattr(dataObject, 'y'):
continue
+
if len(dataObject.y) == 0:
# nothing to be plot
continue
@@ -250,27 +374,21 @@ class ScanWindow(PlotWindow.PlotWindow):
else:
#nothing to be plot
continue
- if dataObject.x is None:
+ if getattr(dataObject, 'x', None) is None:
ylen = len(dataObject.y[0])
- if ylen:
- xdata = numpy.arange(ylen).astype(numpy.float)
- else:
- #nothing to be plot
+ if not ylen:
+ # nothing to be plot
continue
+ xdata = numpy.arange(ylen).astype(numpy.float)
elif len(dataObject.x) > 1:
- if DEBUG:
- print("Mesh plots")
+ # mesh plot
continue
else:
if numpy.isscalar(dataObject.x[0]):
dataObject.x[0] = numpy.array([dataObject.x[0]])
xdata = dataObject.x[0]
- sps_source = False
- if 'SourceType' in sel:
- if sel['SourceType'] == 'SPS':
- sps_source = True
- if sps_source:
+ if sel.get('SourceType') == "SPS":
ycounter = -1
if 'selection' not in dataObject.info:
dataObject.info['selection'] = copy.deepcopy(sel['selection'])
@@ -278,66 +396,60 @@ class ScanWindow(PlotWindow.PlotWindow):
xlabel = None
ylabel = None
ycounter += 1
- if dataObject.m is None:
- mdata = [numpy.ones(len(ydata)).astype(numpy.float)]
- elif len(dataObject.m[0]) > 0:
- if len(dataObject.m[0]) == len(ydata):
- index = numpy.nonzero(dataObject.m[0])[0]
- if not len(index):
- continue
- xdata = numpy.take(xdata, index)
- ydata = numpy.take(ydata, index)
- mdata = numpy.take(dataObject.m[0], index)
- #A priori the graph only knows about plots
- ydata = ydata/mdata
- else:
+ # normalize ydata with monitor
+ if dataObject.m is not None and len(dataObject.m[0]) > 0:
+ if len(dataObject.m[0]) != len(ydata):
raise ValueError("Monitor data length different than counter data")
- else:
- mdata = [numpy.ones(len(ydata)).astype(numpy.float)]
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ # A priori the graph only knows about plots
+ ydata = ydata / mdata
ylegend = 'y%d' % ycounter
- if dataObject.info['selection'] is not None:
- if type(dataObject.info['selection']) == type({}):
- if 'x' in dataObject.info['selection']:
- #proper scan selection
- ilabel = dataObject.info['selection']['y'][ycounter]
- ylegend = dataObject.info['LabelNames'][ilabel]
- ylabel = ylegend
- if sel['selection']['x'] is not None:
- if len(dataObject.info['selection']['x']):
- xlabel = dataObject.info['LabelNames'] \
- [dataObject.info['selection']['x'][0]]
+ if isinstance(dataObject.info['selection'], dict):
+ if 'x' in dataObject.info['selection']:
+ # proper scan selection
+ ilabel = dataObject.info['selection']['y'][ycounter]
+ ylegend = dataObject.info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if sel['selection']['x'] is not None:
+ if len(dataObject.info['selection']['x']):
+ xlabel = dataObject.info['LabelNames'] \
+ [dataObject.info['selection']['x'][0]]
dataObject.info["xlabel"] = xlabel
dataObject.info["ylabel"] = ylabel
newLegend = legend + " " + ylegend
self.dataObjectsDict[newLegend] = dataObject
self.addCurve(xdata, ydata, legend=newLegend, info=dataObject.info,
- xlabel=xlabel, ylabel=ylabel, replot=False)
- # replot=actualReplot)
+ xlabel=xlabel, ylabel=ylabel, resetzoom=False)
if self.scanWindowInfoWidget is not None:
if not self.infoDockWidget.isHidden():
activeLegend = self.getActiveCurve(just_legend=True)
- if activeLegend is not None:
- if activeLegend == newLegend:
- self.scanWindowInfoWidget.updateFromDataObject\
- (dataObject)
+ if activeLegend == newLegend:
+ self.scanWindowInfoWidget.updateFromDataObject \
+ (dataObject)
else:
+ # TODO: better to implement scanWindowInfoWidget.clear
dummyDataObject = DataObject.DataObject()
- dummyDataObject.y=[numpy.array([])]
- dummyDataObject.x=[numpy.array([])]
+ dummyDataObject.y = [numpy.array([])]
+ dummyDataObject.x = [numpy.array([])]
self.scanWindowInfoWidget.updateFromDataObject(dummyDataObject)
else:
- #we have to loop for all y values
+ # we have to loop for all y values
ycounter = -1
for ydata in dataObject.y:
ylen = len(ydata)
- if ylen == 1:
- if len(xdata) > 1:
- ydata = ydata[0] * numpy.ones(len(xdata)).astype(numpy.float)
+ if ylen == 1 and len(xdata) > 1:
+ ydata = ydata[0] * numpy.ones(len(xdata)).astype(numpy.float)
elif len(xdata) == 1:
xdata = xdata[0] * numpy.ones(ylen).astype(numpy.float)
ycounter += 1
- newDataObject = DataObject.DataObject()
+ newDataObject = DataObject.DataObject()
newDataObject.info = copy.deepcopy(dataObject.info)
+
if dataObject.m is not None:
for imon in range(len(dataObject.m)):
if numpy.isscalar(dataObject.m[imon]):
@@ -345,31 +457,29 @@ class ScanWindow(PlotWindow.PlotWindow):
numpy.array([dataObject.m[imon]])
if dataObject.m is None:
mdata = numpy.ones(len(ydata)).astype(numpy.float)
- elif len(dataObject.m[0]) > 0:
- if len(dataObject.m[0]) == len(ydata):
- index = numpy.nonzero(dataObject.m[0])[0]
- if not len(index):
- continue
- xdata = numpy.take(xdata, index)
- ydata = numpy.take(ydata, index)
- mdata = numpy.take(dataObject.m[0], index)
- #A priori the graph only knows about plots
- ydata = ydata/mdata
- elif len(dataObject.m[0]) == 1:
- mdata = numpy.ones(len(ydata)).astype(numpy.float)
- mdata *= dataObject.m[0][0]
- index = numpy.nonzero(dataObject.m[0])[0]
- if not len(index):
- continue
- xdata = numpy.take(xdata, index)
- ydata = numpy.take(ydata, index)
- mdata = numpy.take(dataObject.m[0], index)
- #A priori the graph only knows about plots
- ydata = ydata/mdata
- else:
- raise ValueError("Monitor data length different than counter data")
- else:
+ elif len(dataObject.m[0]) == len(ydata):
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ # A priori the graph only knows about plots
+ ydata = ydata / mdata
+ elif len(dataObject.m[0]) == 1:
mdata = numpy.ones(len(ydata)).astype(numpy.float)
+ mdata *= dataObject.m[0][0]
+ index = numpy.nonzero(dataObject.m[0])[0]
+ if not len(index):
+ continue
+ xdata = numpy.take(xdata, index)
+ ydata = numpy.take(ydata, index)
+ mdata = numpy.take(dataObject.m[0], index)
+ # A priori the graph only knows about plots
+ ydata = ydata / mdata
+ else:
+ raise ValueError("Monitor data length different than counter data")
+
newDataObject.x = [xdata]
newDataObject.y = [ydata]
newDataObject.m = [mdata]
@@ -377,26 +487,24 @@ class ScanWindow(PlotWindow.PlotWindow):
ylegend = 'y%d' % ycounter
xlabel = None
ylabel = None
- if sel['selection'] is not None:
- if type(sel['selection']) == type({}):
- if 'x' in sel['selection']:
- #proper scan selection
- newDataObject.info['selection']['x'] = sel['selection']['x']
- newDataObject.info['selection']['y'] = [sel['selection']['y'][ycounter]]
- newDataObject.info['selection']['m'] = sel['selection']['m']
- ilabel = newDataObject.info['selection']['y'][0]
- ylegend = newDataObject.info['LabelNames'][ilabel]
- ylabel = ylegend
- if len(newDataObject.info['selection']['x']):
- ilabel = newDataObject.info['selection']['x'][0]
- xlabel = newDataObject.info['LabelNames'][ilabel]
- else:
- xlabel = "Point number"
+ if isinstance(sel['selection'], dict) and 'x' in sel['selection']:
+ # proper scan selection
+ newDataObject.info['selection']['x'] = sel['selection']['x']
+ newDataObject.info['selection']['y'] = [sel['selection']['y'][ycounter]]
+ newDataObject.info['selection']['m'] = sel['selection']['m']
+ ilabel = newDataObject.info['selection']['y'][0]
+ ylegend = newDataObject.info['LabelNames'][ilabel]
+ ylabel = ylegend
+ if len(newDataObject.info['selection']['x']):
+ ilabel = newDataObject.info['selection']['x'][0]
+ xlabel = newDataObject.info['LabelNames'][ilabel]
+ else:
+ xlabel = "Point number"
if ('operations' in dataObject.info) and len(dataObject.y) == 1:
newDataObject.info['legend'] = legend
symbol = 'x'
else:
- symbol=None
+ symbol = None
newDataObject.info['legend'] = legend + " " + ylegend
newDataObject.info['selectionlegend'] = legend
yaxis = None
@@ -405,925 +513,153 @@ class ScanWindow(PlotWindow.PlotWindow):
elif 'operations' in dataObject.info:
if dataObject.info['operations'][-1] == 'derivate':
yaxis = 'right'
- #print("sending legend = ", newDataObject.info['legend'], "replot = ", False)
self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
self.addCurve(xdata, ydata, legend=newDataObject.info['legend'],
- info=newDataObject.info,
- symbol=symbol,
- yaxis=yaxis,
- xlabel=xlabel,
- ylabel=ylabel,
- replot=False)
- self.dataObjectsList = self._curveList
+ info=newDataObject.info,
+ symbol=symbol,
+ yaxis=yaxis,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ resetzoom=False)
try:
- if activeCurve is None:
- if len(self._curveList) > 0:
- activeCurve = self._curveList[0]
- ddict = {}
- ddict['event'] = "curveClicked"
- ddict['label'] = activeCurve
- self.graphCallback(ddict)
+ if activeCurve is None and self._curveList:
+ self.setActiveCurve(self._curveList[0])
finally:
- if replot:
- #self.replot()
+ if resetzoom:
self.resetZoom()
- self.updateLegends()
def _removeSelection(self, selectionlist):
- if DEBUG:
- print("_removeSelection(self, selectionlist)",selectionlist)
- if type(selectionlist) == type([]):
- sellist = selectionlist
- else:
- sellist = [selectionlist]
+ _logger.debug("_removeSelection(self, selectionlist) " +
+ str(selectionlist))
+
+ sellist = selectionlist if isinstance(selectionlist, list) else \
+ [selectionlist]
removelist = []
for sel in sellist:
- source = sel['SourceName']
- key = sel['Key']
- if not ("scanselection" in sel): continue
+ key = sel['Key']
+ if "scanselection" not in sel or not sel["scanselection"]:
+ continue
if sel['scanselection'] == "MCA":
continue
- if not sel["scanselection"]:continue
- if len(key.split(".")) > 2: continue
-
- legend = sel['legend'] #expected form sourcename + scan key
- if type(sel['selection']) == type({}):
- if 'y' in sel['selection']:
- for lName in ['cntlist', 'LabelNames']:
- if lName in sel['selection']:
- for index in sel['selection']['y']:
- removelist.append(legend +" "+\
- sel['selection'][lName][index])
+ if len(key.split(".")) > 2:
+ continue
+
+ legend = sel['legend'] # expected form sourcename + scan key
+ if isinstance(sel['selection'], dict) and 'y' in sel['selection']:
+ for lName in ['cntlist', 'LabelNames']:
+ if lName in sel['selection']:
+ for index in sel['selection']['y']:
+ removelist.append(legend + " " +
+ sel['selection'][lName][index])
if len(removelist):
self.removeCurves(removelist)
- def removeCurves(self, removeList, replot=True):
- for legend in removeList:
- if legend == removeList[-1]:
- self.removeCurve(legend, replot=replot)
- else:
- self.removeCurve(legend, replot=False)
- if legend in self.dataObjectsDict:
- del self.dataObjectsDict[legend]
- self.dataObjectsList = self._curveList
-
def _replaceSelection(self, selectionlist):
- if DEBUG:
- print("_replaceSelection(self, selectionlist)",selectionlist)
- if type(selectionlist) == type([]):
- sellist = selectionlist
- else:
- sellist = [selectionlist]
+ """Delete existing curves and data objects, then add new selection.
+ """
+ _logger.debug("_replaceSelection(self, selectionlist) " +
+ str(selectionlist))
+
+ sellist = selectionlist if isinstance(selectionlist, list) else \
+ [selectionlist]
- doit = 0
+ doit = False
for sel in sellist:
- if not ("scanselection" in sel): continue
+ if "scanselection" not in sel or not sel["scanselection"]:
+ continue
if sel['scanselection'] == "MCA":
continue
- if not sel["scanselection"]:continue
- if len(sel["Key"].split(".")) > 2: continue
+ if len(sel["Key"].split(".")) > 2:
+ continue
dataObject = sel['dataobject']
if dataObject.info["selectiontype"] == "1D":
if hasattr(dataObject, 'y'):
- doit = 1
+ doit = True
break
if not doit:
return
self.clearCurves()
- self.dataObjectsDict={}
- self.dataObjectsList=self._curveList
- self._addSelection(selectionlist, replot=True)
-
- def _handleMarkerEvent(self, ddict):
- if ddict['event'] == 'markerMoved':
- label = ddict['label']
- if label.startswith('ROI'):
- return self._handleROIMarkerEvent(ddict)
- else:
- if DEBUG:
- print("Unhandled marker %s" % label)
- return
-
- def graphCallback(self, ddict):
- if DEBUG:
- print("graphCallback", ddict)
- if ddict['event'] in ['markerMoved', 'markerSelected']:
- self._handleMarkerEvent(ddict)
- elif ddict['event'] in ["mouseMoved", "MouseAt"]:
- if self._toggleCounter > 0:
- activeCurve = self.getActiveCurve()
- if activeCurve in [None, []]:
- self._handleMouseMovedEvent(ddict)
- else:
- x, y, legend, info = activeCurve[0:4]
- # calculate the maximum distance
- xMin, xMax = self.getGraphXLimits()
- maxXDistance = abs(xMax - xMin)
- yMin, yMax = self.getGraphYLimits()
- maxYDistance = abs(yMax - yMin)
- if (maxXDistance > 0.0) and (maxYDistance > 0.0):
- closestIndex = (pow((x - ddict['x'])/maxXDistance, 2) + \
- pow((y - ddict['y'])/maxYDistance, 2))
- else:
- closestIndex = (pow(x - ddict['x'], 2) + \
- pow(y - ddict['y'], 2))
- xText = '----'
- yText = '----'
- if len(closestIndex):
- closestIndex = closestIndex.argmin()
- xCurve = x[closestIndex]
- if abs(xCurve - ddict['x']) < (0.05 * maxXDistance):
- yCurve = y[closestIndex]
- if abs(yCurve - ddict['y']) < (0.05 * maxYDistance):
- xText = '%.7g' % xCurve
- yText = '%.7g' % yCurve
- if xText == '----':
- if self.getGraphCursor():
- self._xPos.setStyleSheet("color: rgb(255, 0, 0);")
- self._yPos.setStyleSheet("color: rgb(255, 0, 0);")
- xText = '%.7g' % ddict['x']
- yText = '%.7g' % ddict['y']
- else:
- self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
- self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
- else:
- self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
- self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
- self._xPos.setText(xText)
- self._yPos.setText(yText)
- else:
- self._xPos.setStyleSheet("color: rgb(0, 0, 0);")
- self._yPos.setStyleSheet("color: rgb(0, 0, 0);")
- self._handleMouseMovedEvent(ddict)
- elif ddict['event'] in ["curveClicked", "legendClicked"]:
- legend = ddict["label"]
- if legend is None:
- if len(self.dataObjectsList):
- legend = self.dataObjectsList[0]
- else:
- return
- if legend not in self.dataObjectsList:
- if DEBUG:
- print("unknown legend %s" % legend)
- return
-
- #force the current x label to the appropriate value
- dataObject = self.dataObjectsDict[legend]
- if 'selection' in dataObject.info:
- ilabel = dataObject.info['selection']['y'][0]
- ylabel = dataObject.info['LabelNames'][ilabel]
- if len(dataObject.info['selection']['x']):
- ilabel = dataObject.info['selection']['x'][0]
- xlabel = dataObject.info['LabelNames'][ilabel]
- else:
- xlabel = "Point Number"
- if len(dataObject.info['selection']['m']):
- ilabel = dataObject.info['selection']['m'][0]
- ylabel += "/" + dataObject.info['LabelNames'][ilabel]
- else:
- xlabel = dataObject.info.get('xlabel', None)
- ylabel = dataObject.info.get('ylabel', None)
- if xlabel is not None:
- self.setGraphXLabel(xlabel)
- if ylabel is not None:
- self.setGraphYLabel(ylabel)
- self.setGraphTitle(legend)
- self.setActiveCurve(legend)
- #self.setGraphTitle(legend)
- if self.scanWindowInfoWidget is not None:
- if not self.infoDockWidget.isHidden():
- self.scanWindowInfoWidget.updateFromDataObject\
- (dataObject)
- elif ddict['event'] == "removeCurveEvent":
- legend = ddict['legend']
- self.removeCurves([legend])
- elif ddict['event'] == "renameCurveEvent":
- legend = ddict['legend']
- newlegend = ddict['newlegend']
- if legend in self.dataObjectsDict:
- self.dataObjectsDict[newlegend]= copy.deepcopy(self.dataObjectsDict[legend])
- self.dataObjectsDict[newlegend].info['legend'] = newlegend
- self.dataObjectsList.append(newlegend)
- self.removeCurves([legend], replot=False)
- self.newCurve(self.dataObjectsDict[newlegend].x[0],
- self.dataObjectsDict[newlegend].y[0],
- legend=self.dataObjectsDict[newlegend].info['legend'])
-
- #make sure the plot signal is forwarded because we have overwritten
- #its handling
- self.sigPlotSignal.emit(ddict)
-
-
- def _customFitSignalReceived(self, ddict):
- if ddict['event'] == "FitFinished":
- newDataObject = self.__customFitDataObject
-
- xplot = ddict['x']
- yplot = ddict['yfit']
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
-
- #here I should check the log or linear status
- self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
- self.addCurve(xplot,
- yplot,
- legend=newDataObject.info['legend'])
-
- def _scanFitSignalReceived(self, ddict):
- if DEBUG:
- print("_scanFitSignalReceived", ddict)
- if ddict['event'] == "EstimateFinished":
- return
- if ddict['event'] == "FitFinished":
- newDataObject = self.__fitDataObject
-
- xplot = self.scanFit.specfit.xdata * 1.0
- yplot = self.scanFit.specfit.gendata(parameters=ddict['data'])
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
-
- self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
- self.addCurve(x=xplot, y=yplot, legend=newDataObject.info['legend'])
-
- def _fitIconSignal(self):
- if DEBUG:
- print("_fitIconSignal")
- self.fitButtonMenu.exec_(self.cursor().pos())
-
- def _simpleFitSignal(self):
- if DEBUG:
- print("_simpleFitSignal")
- self._QSimpleOperation("fit")
-
- def _customFitSignal(self):
- if DEBUG:
- print("_customFitSignal")
- self._QSimpleOperation("custom_fit")
-
- def _saveIconSignal(self):
- if DEBUG:
- print("_saveIconSignal")
- self._QSimpleOperation("save")
-
- def _averageIconSignal(self):
- if DEBUG:
- print("_averageIconSignal")
- self._QSimpleOperation("average")
-
- def _smoothIconSignal(self):
- if DEBUG:
- print("_smoothIconSignal")
- self._QSimpleOperation("smooth")
-
- def _getOutputFileName(self):
- #get outputfile
- self.outputDir = PyMcaDirs.outputDir
- if self.outputDir is None:
- self.outputDir = os.getcwd()
- wdir = os.getcwd()
- elif os.path.exists(self.outputDir):
- wdir = self.outputDir
- else:
- self.outputDir = os.getcwd()
- wdir = self.outputDir
-
- filterlist = ['Specfile MCA *.mca',
- 'Specfile Scan *.dat',
- 'Specfile MultiScan *.dat',
- 'Raw ASCII *.txt',
- '","-separated CSV *.csv',
- '";"-separated CSV *.csv',
- '"tab"-separated CSV *.csv',
- 'OMNIC CSV *.csv',
- 'Widget PNG *.png',
- 'Widget JPG *.jpg',
- 'Graphics PNG *.png',
- 'Graphics EPS *.eps',
- 'Graphics SVG *.svg']
- fileList, fileFilter = PyMcaFileDialogs.getFileList(self,
- filetypelist=filterlist,
- message="Output File Selection",
- currentdir=wdir,
- single=True,
- mode="SAVE",
- getfilter=True,
- currentfilter=self.outputFilter)
- if not len(fileList):
- return
- filterused = fileFilter.split()
- filetype = filterused[1]
- extension = filterused[2]
- outdir = qt.safe_str(fileList[0])
- try:
- self.outputDir = os.path.dirname(outdir)
- PyMcaDirs.outputDir = os.path.dirname(outdir)
- except:
- print("setting output directory to default")
- self.outputDir = os.getcwd()
- try:
- outputFile = os.path.basename(outdir)
- except:
- outputFile = outdir
- if len(outputFile) < 5:
- outputFile = outputFile + extension[-4:]
- elif outputFile[-4:] != extension[-4:]:
- outputFile = outputFile + extension[-4:]
- return os.path.join(self.outputDir, outputFile), filetype, filterused
-
- def _QSimpleOperation(self, operation):
- try:
- self._simpleOperation(operation)
- except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setInformativeText(str(sys.exc_info()[1]))
- msg.setDetailedText(traceback.format_exc())
- msg.exec_()
-
- def _saveOperation(self, fileName, fileType, fileFilter):
- filterused = fileFilter
- filetype = fileType
- filename = fileName
- if os.path.exists(filename):
- os.remove(filename)
- if filterused[0].upper() == "WIDGET":
- fformat = filename[-3:].upper()
- pixmap = qt.QPixmap.grabWidget(self)
- if not pixmap.save(filename, fformat):
- qt.QMessageBox.critical(self,
- "Save Error",
- "%s" % sys.exc_info()[1])
- return
- try:
- if filename[-3:].upper() in ['EPS', 'PNG', 'SVG']:
- self.graphicsSave(filename)
- return
- except:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Graphics Saving Error: %s" % (sys.exc_info()[1]))
- msg.exec_()
- return
- systemline = os.linesep
- os.linesep = '\n'
- try:
- if sys.version < "3.0":
- ffile=open(filename, "wb")
- else:
- ffile=open(filename, "w", newline='')
- except IOError:
- msg = qt.QMessageBox(self)
- msg.setIcon(qt.QMessageBox.Critical)
- msg.setText("Input Output Error: %s" % (sys.exc_info()[1]))
- msg.exec_()
- return
- x, y, legend, info = self.getActiveCurve()
- xlabel = info.get("xlabel", "X")
- ylabel = info.get("ylabel", "Y")
- if 0:
- if "selection" in info:
- if type(info['selection']) == type({}):
- if 'x' in info['selection']:
- #proper scan selection
- ilabel = info['selection']['y'][0]
- ylegend = info['LabelNames'][ilabel]
- ylabel = ylegend
- if info['selection']['x'] is not None:
- if len(info['selection']['x']):
- xlabel = info['LabelNames'] [info['selection']['x'][0]]
- else:
- xlabel = "Point number"
- try:
- if filetype in ['Scan', 'MultiScan']:
- ffile.write("#F %s\n" % filename)
- savingDate = "#D %s\n"%(time.ctime(time.time()))
- ffile.write(savingDate)
- ffile.write("\n")
- ffile.write("#S 1 %s\n" % legend)
- ffile.write(savingDate)
- ffile.write("#N 2\n")
- ffile.write("#L %s %s\n" % (xlabel, ylabel) )
- for i in range(len(y)):
- ffile.write("%.7g %.7g\n" % (x[i], y[i]))
- ffile.write("\n")
- if filetype == 'MultiScan':
- scan_n = 1
- curveList = self.getAllCurves()
- for x, y, key, info in curveList:
- if key == legend:
- continue
- xlabel = info.get("xlabel", "X")
- ylabel = info.get("ylabel", "Y")
- if 0:
- if "selection" in info:
- if type(info['selection']) == type({}):
- if 'x' in info['selection']:
- #proper scan selection
- ilabel = info['selection']['y'][0]
- ylegend = info['LabelNames'][ilabel]
- ylabel = ylegend
- if info['selection']['x'] is not None:
- if len(info['selection']['x']):
- xlabel = info['LabelNames'] [info['selection']['x'][0]]
- else:
- xlabel = "Point number"
- scan_n += 1
- ffile.write("#S %d %s\n" % (scan_n, key))
- ffile.write(savingDate)
- ffile.write("#N 2\n")
- ffile.write("#L %s %s\n" % (xlabel, ylabel) )
- for i in range(len(y)):
- ffile.write("%.7g %.7g\n" % (x[i], y[i]))
- ffile.write("\n")
- elif filetype == 'ASCII':
- for i in range(len(y)):
- ffile.write("%.7g %.7g\n" % (x[i], y[i]))
- elif filetype == 'CSV':
- if "," in filterused[0]:
- csvseparator = ","
- elif ";" in filterused[0]:
- csvseparator = ";"
- elif "OMNIC" in filterused[0]:
- csvseparator = ","
- else:
- csvseparator = "\t"
- if "OMNIC" not in filterused[0]:
- ffile.write('"%s"%s"%s"\n' % (xlabel,csvseparator,ylabel))
- for i in range(len(y)):
- ffile.write("%.7E%s%.7E\n" % (x[i], csvseparator,y[i]))
- else:
- ffile.write("#F %s\n" % filename)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
- ffile.write("\n")
- ffile.write("#S 1 %s\n" % legend)
- ffile.write("#D %s\n"%(time.ctime(time.time())))
- ffile.write("#@MCA %16C\n")
- ffile.write("#@CHANN %d %d %d 1\n" % (len(y), x[0], x[-1]))
- ffile.write("#@CALIB %.7g %.7g %.7g\n" % (0, 1, 0))
- ffile.write(self.array2SpecMca(y))
- ffile.write("\n")
- ffile.close()
- os.linesep = systemline
- except:
- os.linesep = systemline
- raise
- return
-
-
- def _simpleOperation(self, operation):
- if operation == 'subtract':
- self._subtractOperation()
- return
- if operation == "save":
- #getOutputFileName
- filename = self._getOutputFileName()
- if filename is None:
- return
- self._saveOperation(filename[0], filename[1], filename[2])
- return
- if operation != "average":
- #get active curve
- legend = self.getActiveCurveLegend()
- if legend is None:return
-
- found = False
- for key in self.dataObjectsList:
- if key == legend:
- found = True
- break
-
- if found:
- dataObject = self.dataObjectsDict[legend]
- else:
- print("I should not be here")
- print("active curve =",legend)
- print("but legend list = ",self.dataObjectsList)
- return
- y = dataObject.y[0]
- if dataObject.x is not None:
- x = dataObject.x[0]
- else:
- x = numpy.arange(len(y)).astype(numpy.float)
- ilabel = dataObject.info['selection']['y'][0]
- ylabel = dataObject.info['LabelNames'][ilabel]
- if len(dataObject.info['selection']['x']):
- ilabel = dataObject.info['selection']['x'][0]
- xlabel = dataObject.info['LabelNames'][ilabel]
- else:
- xlabel = "Point Number"
- else:
- x = []
- y = []
- legend = ""
- i = 0
- ndata = 0
- for key in self._curveList:
- if DEBUG:
- print("key -> ", key)
- if key in self.dataObjectsDict:
- x.append(self.dataObjectsDict[key].x[0]) #only the first X
- if len(self.dataObjectsDict[key].y) == 1:
- y.append(self.dataObjectsDict[key].y[0])
- else:
- sel_legend = self.dataObjectsDict[key].info['legend']
- ilabel = 0
- #I have to get the proper y associated to the legend
- if sel_legend in key:
- if key.index(sel_legend) == 0:
- label = key[len(sel_legend):]
- while (label.startswith(' ')):
- label = label[1:]
- if not len(label):
- break
- if label in self.dataObjectsDict[key].info['LabelNames']:
- ilabel = self.dataObjectsDict[key].info['LabelNames'].index(label)
- if DEBUG:
- print("LABEL = ", label)
- print("ilabel = ", ilabel)
- y.append(self.dataObjectsDict[key].y[ilabel])
- if i == 0:
- legend = key
- firstcurve = key
- i += 1
- else:
- legend += " + " + key
- lastcurve = key
- ndata += 1
- if ndata == 0: return #nothing to average
- dataObject = self.dataObjectsDict[firstcurve]
-
- #create the output data object
- newDataObject = DataObject.DataObject()
- newDataObject.data = None
- newDataObject.info = copy.deepcopy(dataObject.info)
- if 'selectionlegend' in newDataObject.info:
- del newDataObject.info['selectionlegend']
- if not ('operations' in newDataObject.info):
- newDataObject.info['operations'] = []
- newDataObject.info['operations'].append(operation)
-
- sel = {}
- sel['SourceType'] = "Operation"
- #get new x and new y
- if operation == "derivate":
- #xmin and xmax
- xlimits=self.getGraphXLimits()
- xplot, yplot = self.simpleMath.derivate(x, y, xlimits=xlimits)
- ilabel = dataObject.info['selection']['y'][0]
- ylabel = dataObject.info['LabelNames'][ilabel]
- newDataObject.info['LabelNames'][ilabel] = ylabel+"'"
- newDataObject.info['plot_yaxis'] = "right"
- sel['SourceName'] = legend
- sel['Key'] = "'"
- sel['legend'] = legend + sel['Key']
- outputlegend = legend + sel['Key']
- elif operation == "average":
- xplot, yplot = self.simpleMath.average(x, y)
- if len(legend) < 80:
- sel['SourceName'] = legend
- sel['Key'] = ""
- sel['legend'] = "(%s)/%d" % (legend, ndata)
- outputlegend = "(%s)/%d" % (legend, ndata)
- else:
- sel['SourceName'] = legend
- legend = "Average of %d from %s to %s" % (ndata, firstcurve, lastcurve)
- sel['Key'] = ""
- sel['legend'] = legend
- outputlegend = legend
- elif operation == "swapsign":
- xplot = x * 1
- yplot = -y
- sel['SourceName'] = legend
- sel['Key'] = ""
- sel['legend'] = "-(%s)" % legend
- outputlegend = "-(%s)" % legend
- elif operation == "smooth":
- xplot = x * 1
- yplot = self.simpleMath.smooth(y)
- sel['SourceName'] = legend
- sel['Key'] = ""
- sel['legend'] = "%s Smooth" % legend
- outputlegend = "%s Smooth" % legend
- if 'operations' in dataObject.info:
- if len(dataObject.info['operations']):
- if dataObject.info['operations'][-1] == "smooth":
- sel['legend'] = legend
- outputlegend = legend
- elif operation == "forceymintozero":
- xplot = x * 1
- yplot = y - min(y)
- sel['SourceName'] = legend
- sel['Key'] = ""
- sel['legend'] = "(%s) - ymin" % legend
- outputlegend = "(%s) - ymin" % legend
- elif operation == "fit":
- #remove a existing fit if present
- xmin,xmax=self.getGraphXLimits()
- outputlegend = legend + " Fit"
- for key in self._curveList:
- if key == outputlegend:
- self.removeCurves([outputlegend], replot=False)
- break
- self.scanFit.setData(x = x,
- y = y,
- xmin = xmin,
- xmax = xmax,
- legend = legend)
- if self.scanFit.isHidden():
- self.scanFit.show()
- self.scanFit.raise_()
- elif operation == "custom_fit":
- #remove a existing fit if present
- xmin, xmax=self.getGraphXLimits()
- outputlegend = legend + "Custom Fit"
- keyList = list(self._curveList)
- for key in keyList:
- if key == outputlegend:
- self.removeCurves([outputlegend], replot=False)
- break
- self.customFit.setData(x = x,
- y = y,
- xmin = xmin,
- xmax = xmax,
- legend = legend)
- if self.customFit.isHidden():
- self.customFit.show()
- self.customFit.raise_()
- else:
- raise ValueError("Unknown operation %s" % operation)
- if operation not in ["fit", "custom_fit"]:
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = [numpy.ones(len(yplot)).astype(numpy.float)]
-
- #and add it to the plot
- if True and (operation not in ['fit', 'custom_fit']):
- sel['dataobject'] = newDataObject
- sel['scanselection'] = True
- sel['selection'] = copy.deepcopy(dataObject.info['selection'])
- sel['selectiontype'] = "1D"
- if operation == 'average':
- self._replaceSelection([sel])
- elif operation != 'fit':
- self._addSelection([sel])
- else:
- self.__fitDataObject = newDataObject
- return
- else:
- newDataObject.info['legend'] = outputlegend
- if operation == 'fit':
- self.__fitDataObject = newDataObject
- return
- if operation == 'custom_fit':
- self.__customFitDataObject = newDataObject
- return
-
- self.dataObjectsDict[newDataObject.info['legend']] = newDataObject
- #here I should check the log or linear status
- self.addCurve(x=xplot, y=yplot, legend=newDataObject.info['legend'], replot=False)
- self.replot()
-
- def graphicsSave(self, filename):
- #use the plugin interface
- x, y, legend, info = self.getActiveCurve()[:4]
- curveList = self.getAllCurves()
- size = (6, 3) #in inches
- bw = False
- if len(curveList) > 1:
- legends = True
- else:
- legends = False
- if self.matplotlibDialog is None:
- self.matplotlibDialog = QPyMcaMatplotlibSave1D.\
- QPyMcaMatplotlibSaveDialog(size=size,
- logx=self._logX,
- logy=self._logY,
- legends=legends,
- bw = bw)
- mtplt = self.matplotlibDialog.plot
- mtplt.setParameters({'logy':self._logY,
- 'logx':self._logX,
- 'legends':legends,
- 'bw':bw})
- xmin, xmax = self.getGraphXLimits()
- ymin, ymax = self.getGraphYLimits()
- mtplt.setLimits(xmin, xmax, ymin, ymax)
-
- legend0 = legend
- xdata = x
- ydata = y
- dataCounter = 1
- alias = "%c" % (96+dataCounter)
- mtplt.addDataToPlot( xdata, ydata, legend=legend0, alias=alias )
- for curve in curveList:
- xdata, ydata, legend, info = curve[0:4]
- if legend == legend0:
- continue
- dataCounter += 1
- alias = "%c" % (96+dataCounter)
- mtplt.addDataToPlot( xdata, ydata, legend=legend, alias=alias )
-
- if sys.version < '3.0':
- self.matplotlibDialog.setXLabel(qt.safe_str(self.getGraphXLabel()))
- self.matplotlibDialog.setYLabel(qt.safe_str(self.getGraphYLabel()))
- else:
- self.matplotlibDialog.setXLabel(self.getGraphXLabel())
- self.matplotlibDialog.setYLabel(self.getGraphYLabel())
-
- if legends:
- mtplt.plotLegends()
- ret = self.matplotlibDialog.exec_()
- if ret == qt.QDialog.Accepted:
- mtplt.saveFile(filename)
- return
-
- def getActiveCurveLegend(self):
- return super(ScanWindow,self).getActiveCurve(just_legend=True)
-
- def _deriveIconSignal(self):
- if DEBUG:
- print("_deriveIconSignal")
- self._QSimpleOperation('derivate')
-
- def _swapSignIconSignal(self):
- if DEBUG:
- print("_swapSignIconSignal")
- self._QSimpleOperation('swapsign')
-
- def _yMinToZeroIconSignal(self):
- if DEBUG:
- print("_yMinToZeroIconSignal")
- self._QSimpleOperation('forceymintozero')
-
- def _subtractIconSignal(self):
- if DEBUG:
- print("_subtractIconSignal")
- self._QSimpleOperation('subtract')
-
- def _subtractOperation(self):
- #identical to twice the average with the negative active curve
- #get active curve
- legend = self.getActiveCurveLegend()
- if legend is None:
- return
+ self.dataObjectsDict = {}
+ self._addSelection(selectionlist, resetzoom=True)
- found = False
- for key in self.dataObjectsList:
- if key == legend:
- found = True
- break
+ def removeCurves(self, removeList):
+ for legend in removeList:
+ self.removeCurve(legend)
+ if legend in self.dataObjectsDict:
+ del self.dataObjectsDict[legend]
- if found:
- dataObject = self.dataObjectsDict[legend]
- else:
- print("I should not be here")
- print("active curve =",legend)
- print("but legend list = ",self.dataObjectsList)
- return
- x = dataObject.x[0]
- y = dataObject.y[0]
- ilabel = dataObject.info['selection']['y'][0]
- ylabel = dataObject.info['LabelNames'][ilabel]
- if len(dataObject.info['selection']['x']):
- ilabel = dataObject.info['selection']['x'][0]
- xlabel = dataObject.info['LabelNames'][ilabel]
- else:
- xlabel = "Point Number"
-
- xActive = x
- yActive = y
- yActiveLegend = legend
- yActiveLabel = ylabel
- xActiveLabel = xlabel
-
- operation = "subtract"
- sel_list = []
- i = 0
- ndata = 0
- keyList = list(self._curveList)
- for key in keyList:
- legend = ""
- x = [xActive]
- y = [-yActive]
- if DEBUG:
- print("key -> ", key)
- if key in self.dataObjectsDict:
- x.append(self.dataObjectsDict[key].x[0]) #only the first X
- if len(self.dataObjectsDict[key].y) == 1:
- y.append(self.dataObjectsDict[key].y[0])
- ilabel = self.dataObjectsDict[key].info['selection']['y'][0]
- else:
- sel_legend = self.dataObjectsDict[key].info['legend']
- ilabel = self.dataObjectsDict[key].info['selection']['y'][0]
- #I have to get the proper y associated to the legend
- if sel_legend in key:
- if key.index(sel_legend) == 0:
- label = key[len(sel_legend):]
- while (label.startswith(' ')):
- label = label[1:]
- if not len(label):
- break
- if label in self.dataObjectsDict[key].info['LabelNames']:
- ilabel = self.dataObjectsDict[key].info['LabelNames'].index(label)
- if DEBUG:
- print("LABEL = ", label)
- print("ilabel = ", ilabel)
- y.append(self.dataObjectsDict[key].y[ilabel])
- outputlegend = "(%s - %s)" % (key, yActiveLegend)
- ndata += 1
- xplot, yplot = self.simpleMath.average(x, y)
- yplot *= 2
- #create the output data object
- newDataObject = DataObject.DataObject()
- newDataObject.data = None
- newDataObject.info.update(self.dataObjectsDict[key].info)
- if not ('operations' in newDataObject.info):
- newDataObject.info['operations'] = []
- newDataObject.info['operations'].append(operation)
- newDataObject.info['LabelNames'][ilabel] = "(%s - %s)" % \
- (newDataObject.info['LabelNames'][ilabel], yActiveLabel)
- newDataObject.x = [xplot]
- newDataObject.y = [yplot]
- newDataObject.m = None
- sel = {}
- sel['SourceType'] = "Operation"
- sel['SourceName'] = key
- sel['Key'] = ""
- sel['legend'] = outputlegend
- sel['dataobject'] = newDataObject
- sel['scanselection'] = True
- sel['selection'] = copy.deepcopy(dataObject.info['selection'])
- #sel['selection']['y'] = [ilabel]
- sel['selectiontype'] = "1D"
- sel_list.append(sel)
- if True:
- #The legend menu was not working with the next line
- #but if works if I add the list
- self._replaceSelection(sel_list)
- else:
- oldlist = list(self.dataObjectsDict)
- self._addSelection(sel_list)
- self.removeCurves(oldlist)
-
- #The plugins interface
- def getGraphYLimits(self):
- #if the active curve is mapped to second axis
- #I should give the second axis limits
- return super(ScanWindow, self).getGraphYLimits()
-
- #end of plugins interface
- def addCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
- color=None, symbol=None, linestyle=None,
- xlabel=None, ylabel=None, yaxis=None,
+ def addCurve(self, x, y, legend=None, info=None, replace=False,
+ resetzoom=True, color=None, symbol=None,
+ linestyle=None, xlabel=None, ylabel=None, yaxis=None,
xerror=None, yerror=None, **kw):
+ """Add a curve. If a curve with the same legend already exists,
+ the unspecified parameters (color, symbol, linestyle, yaxis) are
+ assumed to be identical to the parameters of the existing curve."""
+ if "replot" in kw:
+ _logger.warning("addCurve deprecated replot argument, "
+ "use resetzoom instead")
+ resetzoom = kw["replot"] and resetzoom
if legend in self._curveList:
if info is None:
info = {}
oldStuff = self.getCurve(legend)
- if len(oldStuff):
- oldX, oldY, oldLegend, oldInfo = oldStuff
+ if oldStuff is not None:
+ oldX, oldY, oldLegend, oldInfo, oldParams = oldStuff
else:
oldInfo = {}
if color is None:
- color = info.get("plot_color", oldInfo.get("plot_color", None))
+ color = info.get("plot_color",
+ oldInfo.get("plot_color", None))
if symbol is None:
- symbol = info.get("plot_symbol",oldInfo.get("plot_symbol", None))
+ symbol = info.get("plot_symbol",
+ oldInfo.get("plot_symbol", None))
if linestyle is None:
- linestyle = info.get("plot_linestyle",oldInfo.get("plot_linestyle", None))
+ linestyle = info.get("plot_linestyle",
+ oldInfo.get("plot_linestyle", None))
if yaxis is None:
- yaxis = info.get("plot_yaxis",oldInfo.get("plot_yaxis", None))
+ yaxis = info.get("plot_yaxis",
+ oldInfo.get("plot_yaxis", None))
else:
if info is None:
info = {}
if color is None:
color = info.get("plot_color", None)
if symbol is None:
- symbol = info.get("plot_symbol", None)
+ symbol = info.get("plot_symbol", None)
if linestyle is None:
- linestyle = info.get("plot_linestyle", None)
+ linestyle = info.get("plot_linestyle", None)
if yaxis is None:
- yaxis = info.get("plot_yaxis", None)
+ yaxis = info.get("plot_yaxis", None)
if legend in self.dataObjectsDict:
# the info is changing
- super(ScanWindow, self).addCurve(x, y, legend=legend, info=info,
- replace=replace, replot=replot, color=color, symbol=symbol,
- linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
- xerror=xerror, yerror=yerror, **kw)
+ super(ScanWindow, self).addCurve(
+ x, y, legend=legend, info=info,
+ replace=replace, color=color, symbol=symbol,
+ linestyle=linestyle, xlabel=xlabel, ylabel=ylabel,
+ yaxis=yaxis, xerror=xerror, yerror=yerror,
+ resetzoom=resetzoom, **kw)
else:
# create the data object
- self.newCurve(x, y, legend=legend, info=info,
- replace=replace, replot=replot, color=color, symbol=symbol,
- linestyle=linestyle, xlabel=xlabel, ylabel=ylabel, yaxis=yaxis,
- xerror=xerror, yerror=yerror, **kw)
-
- def newCurve(self, x, y, legend=None, info=None, replace=False, replot=True,
- color=None, symbol=None, linestyle=None,
- xlabel=None, ylabel=None, yaxis=None,
+ self.newCurve(
+ x, y, legend=legend, info=info,
+ replace=replace, color=color, symbol=symbol,
+ linestyle=linestyle, xlabel=xlabel, ylabel=ylabel,
+ yaxis=yaxis, xerror=xerror, yerror=yerror,
+ resetzoom=resetzoom, **kw)
+
+ def newCurve(self, x, y, legend=None, info=None, replace=False,
+ resetzoom=True, color=None, symbol=None,
+ linestyle=None, xlabel=None, ylabel=None, yaxis=None,
xerror=None, yerror=None, **kw):
+ """
+ Create and add a data object to :attr:`dataObjectsDict`
+ """
+ if "replot" in kw:
+ _logger.warning("addCurve deprecated replot argument, "
+ "use resetzoom instead")
+ resetzoom = kw["replot"] and resetzoom
if legend is None:
legend = "Unnamed curve 1.1"
if xlabel is None:
@@ -1332,7 +668,6 @@ class ScanWindow(PlotWindow.PlotWindow):
ylabel = "Y"
if info is None:
info = {}
- # this is awfull but I have no other way to pass the plot information ...
if color is not None:
info["plot_color"] = color
if symbol is not None:
@@ -1352,243 +687,44 @@ class ScanWindow(PlotWindow.PlotWindow):
newDataObject.info['Key'] = ""
newDataObject.info['selectiontype'] = "1D"
newDataObject.info['LabelNames'] = [xlabel, ylabel]
- newDataObject.info['selection'] = {'x':[0], 'y':[1]}
- sel_list = []
- sel = {}
- sel['SourceType'] = "Operation"
- sel['SourceName'] = legend
- sel['Key'] = ""
- sel['legend'] = legend
- sel['dataobject'] = newDataObject
- sel['scanselection'] = True
- sel['selection'] = {'x':[0], 'y':[1], 'm':[], 'cntlist':[xlabel, ylabel]}
- #sel['selection']['y'] = [ilabel]
- sel['selectiontype'] = "1D"
- sel_list.append(sel)
+ newDataObject.info['selection'] = {'x': [0], 'y': [1]}
+
+ sel = {'SourceType': "Operation",
+ 'SourceName': legend,
+ 'Key': "",
+ 'legend': legend,
+ 'dataobject': newDataObject,
+ 'scanselection': True,
+ 'selection': {'x': [0], 'y': [1], 'm': [],
+ 'cntlist': [xlabel, ylabel]},
+ 'selectiontype': "1D"}
+ sel_list = [sel]
if replace:
self._replaceSelection(sel_list)
else:
- self._addSelection(sel_list, replot=replot)
-
- def printGraph(self):
- if self.printPreview.printer is None:
- # setup needed
- self.printPreview.setup()
- self._printer = self.printPreview.printer
- if self._printer is None:
- # printer was not selected
- return
- #self._printer = None
- if PlotWindow.PlotWidget.SVG:
- svg = True
- self._svgRenderer = self.getSvgRenderer()
- else:
- svg = False
- if hasattr(self, "getWidgetHandle"):
- widget = self.getWidgetHandle()
- else:
- widget = self.centralWidget()
- if hasattr(widget, "grab"):
- pixmap = widget.grab()
- else:
- pixmap = qt.QPixmap.grabWidget(widget)
-
- title = None
- comment = None
- if self.scanWindowInfoWidget is not None:
- if not self.infoDockWidget.isHidden():
- info = self.scanWindowInfoWidget.getInfo()
- title = info['scan'].get('source', None)
- comment = info['scan'].get('scan', None)+"\n"
- h, k, l = info['scan'].get('hkl')
- if h != "----":
- comment += "H = %s K = %s L = %s\n" % (h, k, l)
- peak = info['graph']['peak']
- peakAt = info['graph']['peakat']
- fwhm = info['graph']['fwhm']
- fwhmAt = info['graph']['fwhmat']
- com = info['graph']['com']
- mean = info['graph']['mean']
- std = info['graph']['std']
- minimum = info['graph']['min']
- maximum = info['graph']['max']
- delta = info['graph']['delta']
- xLabel = self.getGraphXLabel()
- comment += "Peak %s at %s = %s\n" % (peak, xLabel, peakAt)
- comment += "FWHM %s at %s = %s\n" % (fwhm, xLabel, fwhmAt)
- comment += "COM = %s Mean = %s STD = %s\n" % (com, mean, std)
- comment += "Min = %s Max = %s Delta = %s\n" % (minimum,
- maximum,
- delta)
-
- if hasattr(self, "scanFit"):
- if not self.scanFit.isHidden():
- if comment is None:
- comment = ""
- comment += "\n"
- comment += self.scanFit.getText()
-
- if svg:
- self.printPreview.addSvgItem(self._svgRenderer,
- title=None,
- comment=comment,
- commentPosition="LEFT")
- else:
- self.printPreview.addPixmap(pixmap,
- title=None,
- comment=comment,
- commentPosition="LEFT")
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
-
- def getSvgRenderer(self, printer=None):
- if printer is None:
- if self.printPreview.printer is None:
- # setup needed
- self.printPreview.setup()
- self._printer = self.printPreview.printer
- printer = self._printer
- if printer is None:
- # printer was not selected
- # return a renderer without adjusting the viewbox
- if sys.version < '3.0':
- import cStringIO as StringIO
- imgData = StringIO.StringIO()
- else:
- from io import StringIO
- imgData = StringIO()
- self.saveGraph(imgData, fileFormat='svg')
- imgData.flush()
- imgData.seek(0)
- svgData = imgData.read()
- imgData = None
- svgRenderer = qt.QSvgRenderer()
- svgRenderer._svgRawData = svgData
- svgRenderer._svgRendererData = qt.QXmlStreamReader(svgData)
- if not svgRenderer.load(svgRenderer._svgRendererData):
- raise RuntimeError("Cannot interpret svg data")
- return svgRenderer
-
- # we have what is to be printed
- if sys.version < '3.0':
- import cStringIO as StringIO
- imgData = StringIO.StringIO()
- else:
- from io import StringIO
- imgData = StringIO()
- self.saveGraph(imgData, fileFormat='svg')
- imgData.flush()
- imgData.seek(0)
- svgData = imgData.read()
- imgData = None
- svgRenderer = qt.QSvgRenderer()
-
- #svgRenderer = PlotWindow.PlotWindow.getSvgRenderer(self)
-
- # we have to specify the bounding box
- config = self.getPrintConfiguration()
- width = config['width']
- height = config['height']
- xOffset = config['xOffset']
- yOffset = config['yOffset']
- units = config['units']
- keepAspectRatio = config['keepAspectRatio']
-
-
- dpix = printer.logicalDpiX()
- dpiy = printer.logicalDpiY()
-
- # get the available space
- availableWidth = printer.width()
- availableHeight = printer.height()
-
- # convert the offsets to dpi
- if units.lower() in ['inch', 'inches']:
- xOffset = xOffset * dpix
- yOffset = yOffset * dpiy
- if width is not None:
- width = width * dpix
- if height is not None:
- height = height * dpiy
- elif units.lower() in ['cm', 'centimeters']:
- xOffset = (xOffset/2.54) * dpix
- yOffset = (yOffset/2.54) * dpiy
- if width is not None:
- width = (width/2.54) * dpix
- if height is not None:
- height = (height/2.54) * dpiy
- else:
- # page units
- xOffset = availableWidth * xOffset
- yOffset = availableHeight * yOffset
- if width is not None:
- width = availableWidth * width
- if height is not None:
- height = availableHeight * height
-
- availableWidth -= xOffset
- availableHeight -= yOffset
-
- if width is not None:
- if (availableWidth + 0.1) < width:
- txt = "Available width %f is less than requested width %f" % \
- (availableWidth, width)
- raise ValueError(txt)
- availableWidth = width
- if height is not None:
- if (availableHeight + 0.1) < height:
- txt = "Available height %f is less than requested height %f" % \
- (availableHeight, height)
- raise ValueError(txt)
- availableHeight = height
-
- if keepAspectRatio:
- #get the aspect ratio
- widget = self.getWidgetHandle()
- if widget is None:
- # does this make sense?
- graphWidth = availableWidth
- graphHeight = availableHeight
- else:
- graphWidth = float(widget.width())
- graphHeight = float(widget.height())
-
- graphRatio = graphHeight / graphWidth
- # that ratio has to be respected
+ self._addSelection(sel_list, resetzoom=resetzoom)
- bodyWidth = availableWidth
- bodyHeight = availableWidth * graphRatio
-
- if bodyHeight > availableHeight:
- bodyHeight = availableHeight
- bodyWidth = bodyHeight / graphRatio
- else:
- bodyWidth = availableWidth
- bodyHeight = availableHeight
-
- body = qt.QRectF(xOffset,
- yOffset,
- bodyWidth,
- bodyHeight)
- # this does not work if I set the svgData before
- svgRenderer.setViewBox(body)
- svgRenderer._viewBox = body
- if not sys.version.startswith("2"):
- svgData = svgData.encode(encoding="utf-8",
- errors="replace")
- svgRenderer._svgRawData = svgData
- svgRenderer._svgRendererData = qt.QXmlStreamReader(svgData)
-
- if not svgRenderer.load(svgRenderer._svgRendererData):
- raise RuntimeError("Cannot interpret svg data")
- return svgRenderer
def test():
- w = ScanWindow()
+ import numpy
+ app = qt.QApplication([])
+ w = ScanWindow(info=True)
x = numpy.arange(1000.)
- y = 10 * x + 10000. * numpy.exp(-0.5*(x-500)*(x-500)/400)
- w.addCurve(x, y, legend="dummy", replot=True, replace=True)
+ y1 = 10 * x + 10000. * numpy.exp(-0.5*(x-500)*(x-500)/400)
+ y2 = y1 + 5000. * numpy.exp(-0.5*(x-700)*(x-700)/200)
+ y3 = y1 + 7000. * numpy.exp(-0.5*(x-200)*(x-200)/1000)
+ w.addCurve(x, y1, legend="dummy1",
+ info={"SourceName": "Synthetic data 1 (linear+gaussian)",
+ "hkl": [1.1, 1.2, 1.3],
+ "Header": ["#S 1 toto"]})
+ w.addCurve(x, y2, legend="dummy2",
+ info={"SourceName": "Synthetic data 2",
+ "hkl": [2.1, 2.2, 2.3],
+ "Header": ["#S 2"]})
+ w.addCurve(x, y3, legend="dummy3",
+ info={"SourceName": "Synthetic data 3",
+ "hkl": ["3.1", 3.2, 3.3],
+ "Header": ["#S 3"]})
w.resetZoom()
app.lastWindowClosed.connect(app.quit)
w.show()
diff --git a/PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py b/PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py
index cff8ec9..d0e5133 100644
--- a/PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py
+++ b/PyMca5/PyMcaGui/pymca/ScanWindowInfoWidget.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#/*##########################################################################
-# Copyright (C) 2004-2014 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -28,7 +28,7 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import sys
+
import numpy
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
@@ -43,44 +43,46 @@ This module implements an info widget containing :
"""
-DEBUG=0
-STATISTICS=1
+DEBUG = 0
+STATISTICS = 1
+
+
class SpecArithmetic(object):
"""
This class tries to mimic SPEC operations.
Correct peak positions and fwhm information
have to be made via a fit.
"""
+
def search_peak(self, xdata, ydata):
- """
- Search a peak and its position in arrays xdata ad ydata.
- Return three integer:
- - peak position
- - peak value
- - index of peak position in array xdata
- This result may accelerate the fwhm search.
- """
- ydata = numpy.array(ydata, copy=False)
- ymax = ydata[numpy.isfinite(ydata)].max()
- idx = self.__give_index(ymax, ydata)
- return xdata[idx], ymax, idx
-
-
- def search_com(self, xdata,ydata):
+ """
+ Search a peak and its position in arrays xdata ad ydata.
+ Return three integer:
+ - peak position
+ - peak value
+ - index of peak position in array xdata
+ This result may accelerate the fwhm search.
+ """
+ ydata = numpy.array(ydata, copy=False)
+ ymax = ydata[numpy.isfinite(ydata)].max()
+ idx = self.__give_index(ymax, ydata)
+ return xdata[idx], ymax, idx
+
+ @staticmethod
+ def search_com(xdata, ydata):
"""
Return the center of mass in arrays xdata and ydata
"""
- num = numpy.sum(xdata*ydata)
- denom = numpy.sum(ydata)
+ num = numpy.sum(xdata * ydata)
+ denom = numpy.sum(ydata)
if abs(denom) > 0:
- result = num/denom
+ result = num / denom
else:
- result = 0
+ result = 0
return result
-
- def search_fwhm(self, xdata,ydata,peak=None,index=None):
+ def search_fwhm(self, xdata, ydata, peak=None, index=None):
"""
Search a fwhm and its center in arrays xdata and ydatas.
If no fwhm is found, (0,0) is returned.
@@ -88,23 +90,23 @@ class SpecArithmetic(object):
accelerate calculation
"""
if peak is None or index is None:
- x,mypeak,index_peak = self.search_peak(xdata,ydata)
+ x, mypeak, index_peak = self.search_peak(xdata, ydata)
else:
- mypeak = peak
+ mypeak = peak
index_peak = index
- hm = mypeak/2
+ hm = mypeak / 2
idx = index_peak
try:
while ydata[idx] >= hm:
- idx = idx-1
+ idx -= 1
x0 = float(xdata[idx])
- x1 = float(xdata[idx+1])
+ x1 = float(xdata[idx + 1])
y0 = float(ydata[idx])
- y1 = float(ydata[idx+1])
+ y1 = float(ydata[idx + 1])
- lhmx = (hm*(x1-x0) - (y0*x1)+(y1*x0)) / (y1-y0)
+ lhmx = (hm * (x1 - x0) - (y0 * x1) + (y1 * x0)) / (y1 - y0)
except ZeroDivisionError:
lhmx = 0
except IndexError:
@@ -113,39 +115,40 @@ class SpecArithmetic(object):
idx = index_peak
try:
while ydata[idx] >= hm:
- idx = idx+1
+ idx += 1
- x0 = float(xdata[idx-1])
+ x0 = float(xdata[idx - 1])
x1 = float(xdata[idx])
- y0 = float(ydata[idx-1])
+ y0 = float(ydata[idx - 1])
y1 = float(ydata[idx])
- uhmx = (hm*(x1-x0) - (y0*x1)+(y1*x0)) / (y1-y0)
+ uhmx = (hm * (x1 - x0) - (y0 * x1) + (y1 * x0)) / (y1 - y0)
except ZeroDivisionError:
uhmx = 0
except IndexError:
uhmx = xdata[-1]
- FWHM = uhmx - lhmx
- CFWHM = (uhmx+lhmx)/2
- return FWHM,CFWHM
+ fwhm = uhmx - lhmx
+ cfwhm = (uhmx + lhmx) / 2
+ return fwhm, cfwhm
+ @staticmethod
+ def __give_index(elem, array):
+ """
+ Return the index of elem in array
+ """
+ mylist = array.tolist()
+ return mylist.index(elem)
- def __give_index(self, elem,array):
- """
- Return the index of elem in array
- """
- mylist = array.tolist()
- return mylist.index(elem)
class HKL(qt.QWidget):
- def __init__(self, parent = None, h= "", k= "", l=""):
+
+ def __init__(self, parent=None, h="", k="", l=""):
qt.QWidget.__init__(self, parent)
layout = qt.QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(2)
-
hlabel = qt.QLabel(self)
hlabel.setText('H:')
self.h = qt.QLineEdit(self)
@@ -176,91 +179,98 @@ class HKL(qt.QWidget):
def setHKL(self, h="", k="", l=""):
dformat = "%.4f"
- if type(h) == type (""):
+ if isinstance(h, str):
self.h.setText(h)
else:
self.h.setText(dformat % h)
- if type(k) == type (""):
+ if isinstance(k, str):
self.k.setText(k)
else:
self.k.setText(dformat % k)
- if type(l) == type (""):
+ if isinstance(l, str):
self.l.setText(l)
else:
self.l.setText(dformat % l)
+
class GraphInfoWidget(qt.QWidget):
+ """Widget displaying statistics about curve data:
+ peak info (x position, y value, fwhm, center of fwhm), max y value,
+ min y value, delta y, mean y, center of mass of y values, standard
+ deviation of y.
+
+ This information is extracted directly from the curve data."""
def __init__(self, parent):
qt.QWidget.__init__(self, parent)
layout = qt.QGridLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(2)
- #peak
- peak = qt.QLabel(self)
+ # peak
+ peak = qt.QLabel(self)
peak.setText("Peak: ")
self.peak = qt.QLineEdit(self)
self.peak.setReadOnly(True)
- hboxPeak = qt.QWidget(self)
+ hboxPeak = qt.QWidget(self)
hboxPeak.l = qt.QHBoxLayout(hboxPeak)
hboxPeak.l.setContentsMargins(0, 0, 0, 0)
hboxPeak.l.setSpacing(0)
- peakAt = qt.QLabel(hboxPeak)
+ peakAt = qt.QLabel(hboxPeak)
peakAt.setText(" at:")
self.peakAt = qt.QLineEdit(hboxPeak)
self.peak.setReadOnly(True)
hboxPeak.l.addWidget(peakAt)
hboxPeak.l.addWidget(self.peakAt)
- #fwhm
- fwhm = qt.QLabel(self)
+ # fwhm
+ fwhm = qt.QLabel(self)
fwhm.setText("Fwhm: ")
self.fwhm = qt.QLineEdit(self)
self.fwhm.setReadOnly(True)
- hboxFwhm = qt.QWidget(self)
+ hboxFwhm = qt.QWidget(self)
hboxFwhm.l = qt.QHBoxLayout(hboxFwhm)
hboxFwhm.l.setContentsMargins(0, 0, 0, 0)
hboxFwhm.l.setSpacing(0)
- fwhmAt = qt.QLabel(hboxFwhm)
+ fwhmAt = qt.QLabel(hboxFwhm)
fwhmAt.setText(" at:")
self.fwhmAt = qt.QLineEdit(hboxFwhm)
self.fwhm.setReadOnly(True)
hboxFwhm.l.addWidget(fwhmAt)
hboxFwhm.l.addWidget(self.fwhmAt)
- #statistics
- #COM
- com = qt.QLabel(self)
+ # statistics
+ # COM
+ com = qt.QLabel(self)
com.setText("COM:")
self.com = qt.QLineEdit(self)
self.com.setReadOnly(True)
- #mean
- mean = qt.QLabel(self)
+ # mean
+ mean = qt.QLabel(self)
mean.setText("Mean:")
self.mean = qt.QLineEdit(self)
self.mean.setReadOnly(True)
- #STD
- std = qt.QLabel(self)
+ # STD
+ std = qt.QLabel(self)
std.setText("STD:")
self.std = qt.QLineEdit(self)
self.std.setReadOnly(True)
- #Max
- maximum = qt.QLabel(self)
+ # Max
+ maximum = qt.QLabel(self)
maximum.setText("Max:")
- self.maximum= qt.QLineEdit(self)
+ self.maximum = qt.QLineEdit(self)
self.maximum.setReadOnly(True)
- #mean
- minimum = qt.QLabel(self)
+ # mean
+ minimum = qt.QLabel(self)
minimum.setText("Min:")
- self.minimum= qt.QLineEdit(self)
+ self.minimum = qt.QLineEdit(self)
self.minimum.setReadOnly(True)
- #STD
- delta = qt.QLabel(self)
+ # STD
+ delta = qt.QLabel(self)
delta.setText("Delta:")
self.delta = qt.QLineEdit(self)
self.delta.setReadOnly(True)
@@ -286,59 +296,46 @@ class GraphInfoWidget(qt.QWidget):
layout.addWidget(self.delta, 1, 8)
self.specArithmetic = SpecArithmetic()
- def updateFromDataObject(self, dataObject):
- ydata = numpy.ravel(dataObject.y[0])
- ylen = len(ydata)
- if ylen:
- if dataObject.x is None:
- xdata = numpy.arange(ylen).astype(numpy.float)
- elif not len(dataObject.x):
- xdata = numpy.arange(ylen).astype(numpy.float)
- else:
- xdata = numpy.ravel(dataObject.x[0])
- else:
- xdata = None
- self.updateFromXY(xdata, ydata)
-
-
def updateFromXY(self, xdata, ydata):
if len(ydata):
- peakpos,peak,myidx = self.specArithmetic.search_peak(xdata,ydata)
- com = self.specArithmetic.search_com(xdata,ydata)
- fwhm,cfwhm = self.specArithmetic.search_fwhm(xdata,ydata,
- peak=peak,index=myidx)
- ymax = max(ydata)
- ymin = min(ydata)
+ peakpos, peak, myidx = self.specArithmetic.search_peak(
+ xdata, ydata)
+ com = self.specArithmetic.search_com(xdata, ydata)
+ fwhm, cfwhm = self.specArithmetic.search_fwhm(xdata, ydata,
+ peak=peak, index=myidx)
+ ymax = max(ydata)
+ ymin = min(ydata)
ymean = sum(ydata) / len(ydata)
if len(ydata) > 1:
- ystd = numpy.sqrt(sum((ydata-ymean)*(ydata-ymean))/len(ydata))
+ ystd = numpy.sqrt(
+ sum((ydata - ymean) * (ydata - ymean)) / len(ydata))
else:
ystd = 0
- delta = ymax - ymin
+ delta = ymax - ymin
fformat = "%.7g"
peakpos = fformat % peakpos
- peak = fformat % peak
- myidx = "%d" % myidx
- com = fformat % com
- fwhm = fformat % fwhm
- cfwhm = fformat % cfwhm
- ymean = fformat % ymean
- ystd = fformat % ystd
- ymax = fformat % ymax
- ymin = fformat % ymin
- delta = fformat % delta
+ peak = fformat % peak
+ # myidx = "%d" % myidx
+ com = fformat % com
+ fwhm = fformat % fwhm
+ cfwhm = fformat % cfwhm
+ ymean = fformat % ymean
+ ystd = fformat % ystd
+ ymax = fformat % ymax
+ ymin = fformat % ymin
+ delta = fformat % delta
else:
peakpos = "----"
- peak = "----"
- myidx = "----"
- com = "----"
- fwhm = "----"
- cfwhm = "----"
- ymean = "----"
- ystd = "----"
- ymax = "----"
- ymin = "----"
- delta = "----"
+ peak = "----"
+ # myidx = "----"
+ com = "----"
+ fwhm = "----"
+ cfwhm = "----"
+ ymean = "----"
+ ystd = "----"
+ ymax = "----"
+ ymin = "----"
+ delta = "----"
self.peak.setText(peak)
self.peakAt.setText(peakpos)
self.fwhm.setText(fwhm)
@@ -351,29 +348,32 @@ class GraphInfoWidget(qt.QWidget):
self.delta.setText(delta)
def getInfo(self):
- ddict={}
- ddict['peak'] = self.peak.text()
- ddict['peakat'] = self.peakAt.text()
- ddict['fwhm'] = self.fwhm.text()
- ddict['fwhmat'] = self.fwhmAt.text()
- ddict['com'] = self.com.text()
- ddict['mean'] = self.mean.text()
- ddict['std'] = self.std.text()
- ddict['min'] = self.minimum.text()
- ddict['max'] = self.maximum.text()
- ddict['delta'] = self.delta.text()
- return ddict
-
+ return {
+ 'peak': self.peak.text(),
+ 'peakat': self.peakAt.text(),
+ 'fwhm': self.fwhm.text(),
+ 'fwhmat': self.fwhmAt.text(),
+ 'com': self.com.text(),
+ 'mean': self.mean.text(),
+ 'std': self.std.text(),
+ 'min': self.minimum.text(),
+ 'max': self.maximum.text(),
+ 'delta': self.delta.text(),
+ }
class ScanInfoWidget(qt.QWidget):
- def __init__(self, parent = None):
+ """Widget displaying curve metadata:
+ data source, first scan header line, H, K, L
+
+ This information is extracted from the curve info dict."""
+ def __init__(self, parent=None):
qt.QWidget.__init__(self, parent)
layout = qt.QGridLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(2)
- #scan info
+ # scan info
hBox = qt.QWidget(self)
hBoxLayout = qt.QHBoxLayout(hBox)
hBoxLayout.setContentsMargins(0, 0, 0, 0)
@@ -392,22 +392,21 @@ class ScanInfoWidget(qt.QWidget):
self.hkl = HKL(self)
layout.addWidget(hBox, 0, 0, 1, 7)
- #layout.addWidget(self.sourceLabel, 0, 1)#, 1, 9)
+ # layout.addWidget(self.sourceLabel, 0, 1)#, 1, 9)
layout.addWidget(scanLabel, 1, 0)
layout.addWidget(self.scanLabel, 1, 1)
layout.addWidget(self.hkl, 1, 4, 1, 3)
- def updateFromDataObject(self, dataObject):
- info = dataObject.info
+ def updateFromInfoDict(self, info):
source = info.get('SourceName', None)
if source is None:
self.sourceLabel.setText("")
else:
- if type(source) == type(""):
+ if isinstance(source, str):
self.sourceLabel.setText(source)
else:
self.sourceLabel.setText(source[0])
- scan = info.get('Header', None)
+ scan = info.get('Header', None)
if scan is None:
scan = ""
if "envdict" in info:
@@ -415,63 +414,55 @@ class ScanInfoWidget(qt.QWidget):
self.scanLabel.setText(scan)
else:
self.scanLabel.setText(scan[0])
- hkl = info.get('hkl', None)
+ hkl = info.get('hkl', None)
if hkl is None:
self.hkl.setHKL("----", "----", "----")
else:
self.hkl.setHKL(*hkl)
def getInfo(self):
- ddict = {}
- ddict['source'] = self.sourceLabel.text()
- ddict['scan'] = self.scanLabel.text()
- ddict['hkl'] = ["%s" % self.hkl.h.text(),
- "%s" % self.hkl.k.text(),
- "%s" % self.hkl.l.text()]
- return ddict
+ return {
+ 'source': self.sourceLabel.text(),
+ 'scan': self.scanLabel.text(),
+ 'hkl': ["%s" % self.hkl.h.text(),
+ "%s" % self.hkl.k.text(),
+ "%s" % self.hkl.l.text()]
+ }
+
class ScanWindowInfoWidget(qt.QWidget):
- def __init__(self, parent = None):
+
+ def __init__(self, parent=None):
qt.QWidget.__init__(self, parent)
layout = qt.QVBoxLayout(self)
layout.setContentsMargins(2, 2, 2, 2)
layout.setSpacing(2)
- self.scanInfo = ScanInfoWidget(self)
+ self.scanInfo = ScanInfoWidget(self)
self.graphInfo = GraphInfoWidget(self)
layout.addWidget(self.scanInfo)
layout.addWidget(self.graphInfo)
- #print "hiding graph info"
- #self.graphInfo.hide()
- def updateFromDataObject(self, dataObject):
- self.scanInfo.updateFromDataObject(dataObject)
- self.graphInfo.updateFromDataObject(dataObject)
+ def updateFromXYInfo(self, xdata, ydata, info):
+ self.scanInfo.updateFromInfoDict(info)
+ self.graphInfo.updateFromXY(xdata, ydata)
def getInfo(self):
- ddict = {}
- ddict['scan'] = self.scanInfo.getInfo()
- ddict['graph'] = self.graphInfo.getInfo()
- return ddict
+ return {
+ 'scan': self.scanInfo.getInfo(),
+ 'graph': self.graphInfo.getInfo()
+ }
+
def test():
- app = qt.QApplication([])
- w = ScanWindowInfoWidget()
- app.lastWindowClosed.connect(app.quit)
- """
- winfo.grid(sticky='wesn')
- if STATISTICS:
- winfo.configure(h=65,k=45621,l=32132,peak=6666876,
- fwhm=0.2154,com=544,
- ymax=10.,ymin=4,ystd=1,ymean=5)
- else:
- winfo.configure(h=65,k=45621,l=32132,peak=6666876,
- fwhm=0.2154,com=544)
- """
- w.show()
- app.exec_()
+ app = qt.QApplication([])
+ w = ScanWindowInfoWidget()
+ app.lastWindowClosed.connect(app.quit)
+ w.show()
+ app.exec_()
if __name__ == '__main__':
- test()
+ test()
+
diff --git a/PyMca5/PyMcaGui/pymca/StackBrowser.py b/PyMca5/PyMcaGui/pymca/StackBrowser.py
index 1fe9885..d903014 100644
--- a/PyMca5/PyMcaGui/pymca/StackBrowser.py
+++ b/PyMca5/PyMcaGui/pymca/StackBrowser.py
@@ -29,13 +29,15 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import numpy
+import logging
from PyMca5.PyMcaGui import MaskImageWidget
from PyMca5.PyMcaGui import FrameBrowser
from PyMca5.PyMcaCore import DataObject
qt = MaskImageWidget.qt
IconDict = MaskImageWidget.IconDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackBrowser(MaskImageWidget.MaskImageWidget):
def __init__(self, *var, **kw):
@@ -184,8 +186,7 @@ class StackBrowser(MaskImageWidget.MaskImageWidget):
if background is None:
background = self._backgroundSubtraction
if not len(self.dataObjectsList):
- if DEBUG:
- print("nothing to show")
+ _logger.debug("nothing to show")
return
legend = self.dataObjectsList[0]
if type(legend) == type([]):
diff --git a/PyMca5/PyMcaGui/pymca/StackSelector.py b/PyMca5/PyMcaGui/pymca/StackSelector.py
index 8cddcb1..c3e6432 100644
--- a/PyMca5/PyMcaGui/pymca/StackSelector.py
+++ b/PyMca5/PyMcaGui/pymca/StackSelector.py
@@ -32,6 +32,7 @@ import sys
import os
import copy
import traceback
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5 import PyMcaDirs
from PyMca5 import DataObject
@@ -59,7 +60,7 @@ except ImportError:
pass
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class StackSelector(object):
@@ -206,7 +207,7 @@ class StackSelector(object):
msg.setInformativeText("%s" % sys.exc_info()[1])
msg.setDetailedText(traceback.format_exc())
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
elif len(filelist):
if not omnicfile:
@@ -220,7 +221,7 @@ class StackSelector(object):
msg.exec_loop()
else:
msg.exec_()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
if aifirafile:
masterStack = DataObject.DataObject()
@@ -425,7 +426,7 @@ if __name__ == "__main__":
options,
longoptions)
except:
- print(sys.exc_info()[1])
+ _logger.error(sys.exc_info()[1])
sys.exit(1)
fileindex = 0
filepattern = None
diff --git a/PyMca5/PyMcaGui/pymca/SumRulesTool.py b/PyMca5/PyMcaGui/pymca/SumRulesTool.py
index e0414dd..fd0b859 100644
--- a/PyMca5/PyMcaGui/pymca/SumRulesTool.py
+++ b/PyMca5/PyMcaGui/pymca/SumRulesTool.py
@@ -28,6 +28,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
import os
from os.path import isdir as osPathIsDir
from os.path import basename as osPathBasename
@@ -37,14 +38,16 @@ import numpy
from PyMca5.PyMcaMath.fitting.SpecfitFuns import upstep, downstep
from PyMca5.PyMca import PyMcaQt as qt
-from PyMca5.PyMca import PlotWindow as DataDisplay
+
from PyMca5.PyMca import Elements
from PyMca5.PyMca import ConfigDict
from PyMca5.PyMca import PyMcaDataDir, PyMcaDirs
from PyMca5.PyMca import QSpecFileWidget
from PyMca5.PyMca import SpecFileDataSource
-from PyMca5.PyMcaGui import IconDict
+
+from silx.gui.plot import PlotWindow as DataDisplay
+from silx.gui.plot.LegendSelector import LegendsDockWidget
if hasattr(qt, "QString"):
QString = qt.QString
@@ -58,7 +61,7 @@ else:
QStringList = list
-DEBUG = 0
+_logger = logging.getLogger(__name__)
NEWLINE = '\n'
class Calculations(object):
@@ -115,9 +118,9 @@ class Calculations(object):
# Determine number of states in outer shell
if econf == '3d':
- if DEBUG >= 1:
- print('Calculations.magneticMoment -- considering 3d material:')
- print('\tp: %s, q: %s, r:%s'%(str(p),str(q),str(r)))
+ _logger.debug(
+ 'Calculations.magneticMoment -- considering 3d material:'
+ '\n\tp: %s, q: %s, r:%s', str(p), str(q), str(r))
nMax = 10.
# Calculate Integrals
if q is not None:
@@ -128,9 +131,8 @@ class Calculations(object):
mSpin = abs((3.*p - 2.*q) * (nMax - n) / r)
mRatio = abs(2.*q/(9.*p-6.*q))
elif econf == '4f':
- if DEBUG >= 1:
- print('Calculations.magneticMoment -- considering 4f material:')
- print('\tp: %s, q: %s, r:%s'%(str(p),str(q),str(r)))
+ _logger.debug('Calculations.magneticMoment -- considering 4f material:'
+ '\n\tp: %s, q: %s, r:%s', str(p), str(q), str(r))
nMax = 14.
if q is not None:
mOrbt = abs(q * (nMax - n) / r)
@@ -154,9 +156,9 @@ class MarkerSpinBox(qt.QDoubleSpinBox):
self.window = window
self.plotWindow = plotWindow
#self.graph = graph
- self.markerID = self.plotWindow.insertXMarker(0.,
- legend=label,
- text=label)
+ self.markerID = self.plotWindow.addXMarker(0.,
+ legend=label,
+ text=label)
# Initialize
self.setMinimum(0.)
@@ -198,7 +200,7 @@ class MarkerSpinBox(qt.QDoubleSpinBox):
def showMarker(self):
self.plotWindow.removeMarker(self.label)
- self.markerID = self.plotWindow.insertXMarker(
+ self.markerID = self.plotWindow.addXMarker(
self.value(),
legend=self.label,
text=self.label,
@@ -218,7 +220,7 @@ class MarkerSpinBox(qt.QDoubleSpinBox):
draggable = False
# Make shure that the marker is deleted
# If marker is not present, removeMarker just passes..
- self.markerID = self.plotWindow.insertXMarker(
+ self.markerID = self.plotWindow.addXMarker(
self.value(),
legend=self.label,
text=self.label,
@@ -241,11 +243,10 @@ class MarkerSpinBox(qt.QDoubleSpinBox):
try:
val = float(val)
except ValueError:
- if DEBUG == 1:
- print('_valueChanged -- Sorry, it ain\'t gonna float: %s'%str(val))
+ _logger.debug('_valueChanged -- Sorry, it ain\'t gonna float: %s', str(val))
return
# Marker of same label as self.label gets replaced..
- self.markerID = self.plotWindow.insertXMarker(
+ self.markerID = self.plotWindow.addXMarker(
val,
legend=self.label,
text=self.label,
@@ -289,8 +290,7 @@ class LineEditDisplay(qt.QLineEdit):
elif isinstance(self.controller, qt.QDoubleSpinBox):
tmp = self.controller.value()
else:
- if DEBUG == 1:
- print('LineEditDisplay.checkController -- Reached untreated case, setting empty string')
+ _logger.debug('LineEditDisplay.checkController -- Reached untreated case, setting empty string')
tmp = ''
self.setText(tmp)
@@ -311,8 +311,7 @@ class LineEditDisplay(qt.QLineEdit):
elif isinstance(self.controller, qt.QDoubleSpinBox):
text = inp + ' ' + self.unit
else:
- if DEBUG == 1:
- print('LineEditDisplay.setText -- Reached untreated case, setting empty string')
+ _logger.debug('LineEditDisplay.setText -- Reached untreated case, setting empty string')
text = ''
qt.QLineEdit.setText(self, text)
@@ -370,45 +369,22 @@ class SumRulesWindow(qt.QMainWindow):
def __init__(self, parent=None):
qt.QMainWindow.__init__(self, parent)
self.setWindowTitle('Sum Rules Tool')
- if hasattr(DataDisplay,'PlotWindow'):
- self.plotWindow = DataDisplay.PlotWindow(
- parent=self,
- backend=None,
- plugins=False, # Hide plugin tool button
- newplot=False, # Hide mirror active curve, ... functionality
- roi=False, # No ROI widget
- control=False, # Hide option button
- position=True, # Show x,y position display
- kw={'logx': False, # Hide logarithmic x-scale tool button
- 'logy': False, # Hide logarithmic y-scale tool button
- 'flip': False, # Hide whatever this does
- 'fit': False}) # Hide simple fit tool button
- self.plotWindow._buildLegendWidget()
- else:
- self.plotWindow = DataDisplay.ScanWindow(self)
-
- # Hide Buttons in the toolbar
- if hasattr(self.plotWindow,'scanWindowInfoWidget'):
- # Get rid of scanInfoWidget
- self.plotWindow.scanWindowInfoWidget.hide()
- self.plotWindow.graph.enablemarkermode()
- # Hide unnecessary buttons in the toolbar
- toolbarChildren = self.plotWindow.toolBar
- # QWidget.findChildren(<qt-type>) matches
- # all child widgets with the specified type
- toolbarButtons = toolbarChildren.findChildren(qt.QToolButton)
- toolbarButtons[3].hide() # LogX
- toolbarButtons[4].hide() # LogY
- toolbarButtons[6].hide() # Simple Fit
- toolbarButtons[7].hide() # Average Plotted Curves
- toolbarButtons[8].hide() # Derivative
- toolbarButtons[9].hide() # Smooth
- toolbarButtons[11].hide() # Set active to zero
- toolbarButtons[12].hide() # Subtract active curve
- toolbarButtons[13].hide() # Save active curve
- toolbarButtons[14].hide() # Plugins
- else:
- self.plotWindow
+ self.plotWindow = DataDisplay(
+ parent=self,
+ roi=False, # No ROI widget
+ control=False, # hide option button, legend widget added later
+ position=True, # Show x,y position display
+ fit=False, # Hide simple fit tool button
+ colormap=False,
+ aspectRatio=False,
+ yInverted=False,
+ copy=True,
+ print_=False,
+ mask=False)
+
+ self._legendsDockWidget = LegendsDockWidget(plot=self.plotWindow)
+ self.plotWindow.addDockWidget(qt.Qt.RightDockWidgetArea,
+ self._legendsDockWidget)
self.__savedConf = False
self.__savedData = False
@@ -822,8 +798,8 @@ class SumRulesWindow(qt.QMainWindow):
self.buttonEstimate.setShortcut(qt.Qt.CTRL+qt.Qt.Key_E)
self.buttonEstimate.clicked.connect(self.estimate)
self.buttonEstimate.setEnabled(False)
- self.plotWindow.toolBar.addSeparator()
- self.plotWindow.toolBar.addWidget(self.buttonEstimate)
+ self.plotWindow.toolBar().addSeparator()
+ self.plotWindow.toolBar().addWidget(self.buttonEstimate)
self.plotWindow.sigPlotSignal.connect(self._handlePlotSignal)
@@ -1000,16 +976,14 @@ class SumRulesWindow(qt.QMainWindow):
try:
n = float(electronOccupation.text())
except ValueError:
- if DEBUG == 1:
- print('calcMM -- Could not convert electron occupation')
+ _logger.debug('calcMM -- Could not convert electron occupation')
return
electronConfiguration = ddict[self.__tabElem]['electron configuration']
econf = str(electronConfiguration.currentText())
try:
mmO, mmS, mmR = mathObj.magneticMoment(p,q,r,n,econf)
except ValueError as e:
- if DEBUG == 1:
- print(e)
+ _logger.debug(e)
mmO, mmS, mmR = 3*['---']
self.mmOrbt.setText(str(mmO))
self.mmSpin.setText(str(mmS))
@@ -1220,14 +1194,13 @@ class SumRulesWindow(qt.QMainWindow):
#keysLoaded = confDict.keys()
#keysValues = self.valuesDict.keys()
except KeyError as e:
- if DEBUG:
- print('loadConfiguration -- Key Error in \'%s\''%filename)
- print('\tMessage:', e)
- else:
- msg = qt.QMessageBox()
- msg.setWindowTitle('Sum Rules Analysis Error')
- msg.setIcon(qt.QMessageBox.Warning)
- msg.setText('Malformed configuration file \'%s\''%filename)
+ _logger.debug('loadConfiguration -- Key Error in \'%s\'', filename)
+ _logger.debug('\tMessage: %s', e)
+
+ msg = qt.QMessageBox()
+ msg.setWindowTitle('Sum Rules Analysis Error')
+ msg.setIcon(qt.QMessageBox.Warning)
+ msg.setText('Malformed configuration file \'%s\''%filename)
return
self.__savedConf = True
@@ -1265,7 +1238,7 @@ class SumRulesWindow(qt.QMainWindow):
except KeyError:
msg = ('setElement -- \'%s\' not found in '%symbol)
msg += 'Elements.Element dictionary'
- print(msg)
+ _logger.error(msg)
# Update valuesDict
self.valuesDict[self.__tabElem]['info'] = ddict
# Update the EdgeCBs
@@ -1349,15 +1322,12 @@ class SumRulesWindow(qt.QMainWindow):
tmp = float(value)
obj.setValue(tmp)
except ValueError:
- if hasattr(self.plotWindow,'graph'):
- xmin, xmax = self.plotWindow.graph.getX1AxisLimits()
- else:
- xmin, xmax = self.plotWindow.getGraphXLimits()
+ xmin, xmax = self.plotWindow.getGraphXLimits()
tmp = xmin + (xmax-xmin)/10.
- if DEBUG:
- msg = 'setValuesDict -- Float conversion failed'
- msg += ' while setting marker positions. Value:', value
- print(msg)
+ _logger.debug(
+ 'setValuesDict -- Float conversion failed'
+ ' while setting marker positions. Value: %s',
+ value)
elif isinstance(obj, qt.QCheckBox):
if value == 'True':
state = qt.Qt.Checked
@@ -1369,10 +1339,10 @@ class SumRulesWindow(qt.QMainWindow):
tmp = float(value)
obj.setValue(tmp)
except ValueError:
- if DEBUG:
- msg = 'setValuesDict -- Float conversion failed'
- msg += ' while setting QDoubleSpinBox value. Value:', value
- print(msg)
+ _logger.debug(
+ 'setValuesDict -- Float conversion failed'
+ ' while setting QDoubleSpinBox value. Value: %s',
+ value)
elif isinstance(obj, qt.QComboBox):
idx = obj.findText(QString(value))
obj.setCurrentIndex(idx)
@@ -1416,7 +1386,6 @@ class SumRulesWindow(qt.QMainWindow):
# Add spectrum to plotWindow using the
if identifier == 'xmcd':
self.xmcdData = (xSorted, ySorted)
- #self.plotWindow.graph.mapToY2(intLegend)
elif identifier == 'xas':
self.xasData = (xSorted, ySorted)
# Trigger replot when data is added
@@ -1553,8 +1522,7 @@ class SumRulesWindow(qt.QMainWindow):
idxPost = numpy.nonzero((postMin <= x) & (x <= postMax))[0]
if (len(idxPre) == 0) or (len(idxPost) == 0):
- if DEBUG:
- print('estimateBG -- Somethings wrong with pre/post edge markers')
+ _logger.debug('estimateBG -- Somethings wrong with pre/post edge markers')
return
xPreMin = x[idxPre.min()]
@@ -1578,16 +1546,15 @@ class SumRulesWindow(qt.QMainWindow):
if x02 < x01:
par1 = (ratio, x02, width)
par2 = ((1.-ratio), x01, width)
- if DEBUG:
- print('estimateBG -- x02 < x01, using par1: %s and par2: %s'\
- %(str(par1),str(par2)))
+ _logger.debug('estimateBG -- x02 < x01, using par1: %s and par2: %s',
+ par1, par2)
model = bottom + sign * diff * (erf(par1, x) + erf(par2, x))
else:
par1 = (ratio, x01, width)
par2 = ((1.-ratio), x02, width)
- if DEBUG:
- print('estimateBG -- x01 < x02, using par1: %s and par2: %s'\
- %(str(par1),str(par2)))
+
+ _logger.debug('estimateBG -- x01 < x02, using par1: %s and par2: %s',
+ par1, par2)
model = bottom + sign * diff * (erf(par1, x) + erf(par2, x))
preModel = numpy.asarray(len(x)*[avgPre])
@@ -1599,46 +1566,33 @@ class SumRulesWindow(qt.QMainWindow):
model,
self.__xasBGmodel,
{},
- replot=False)
+ resetzoom=False)
self.plotWindow.addCurve(x,
preModel,
'Pre BG model',
{},
- replot=False)
+ resetzoom=False)
self.plotWindow.addCurve(x,
postModel,
'Post BG model',
{},
- replot=False)
- if hasattr(self.plotWindow, 'graph'):
- self.plotWindow.graph.replot()
- else:
- self.plotWindow.replot()
- self.plotWindow.updateLegends()
+ resetzoom=False)
def plotOnDemand(self, window):
# Remove all curves
- if hasattr(self.plotWindow,'graph'):
- legends = self.plotWindow.getAllCurves(just_legend=True)
- for legend in legends:
- self.plotWindow.removeCurve(legend, replot=False)
- else:
- self.plotWindow.clearCurves()
+ self.plotWindow.clearCurves()
if (self.xmcdData is None) or (self.xasData is None):
# Nothing to do
return
xyList = []
- mapToY2 = False
window = window.lower()
if window == self.__tabElem:
if self.xmcdCorrData is not None:
- if DEBUG == 1:
- print('plotOnDemand -- __tabElem: Using self.xmcdCorrData')
+ _logger.debug('plotOnDemand -- __tabElem: Using self.xmcdCorrData')
xmcdX, xmcdY = self.xmcdCorrData
xmcdLabel = 'xmcd corr'
else:
- if DEBUG == 1:
- print('plotOnDemand -- __tabElem: Using self.xmcdData')
+ _logger.debug('plotOnDemand -- __tabElem: Using self.xmcdData')
xmcdX, xmcdY = self.xmcdData
xmcdLabel = 'xmcd'
xasX, xasY = self.xasData
@@ -1663,13 +1617,11 @@ class SumRulesWindow(qt.QMainWindow):
x, y = self.xasData
self.xasDataCorr = x, y-yBG
if self.xmcdCorrData is not None:
- if DEBUG:
- print('plotOnDemand -- __tabInt: Using self.xmcdCorrData')
+ _logger.debug('plotOnDemand -- __tabInt: Using self.xmcdCorrData')
xmcdX, xmcdY = self.xmcdCorrData
xmcdIntLabel = 'xmcd corr Int'
else:
- if DEBUG:
- print('plotOnDemand -- __tabInt: Using self.xmcdData')
+ _logger.debug('plotOnDemand -- __tabInt: Using self.xmcdData')
xmcdX, xmcdY = self.xmcdData
xmcdIntLabel = 'xmcd Int'
mathObj = Calculations()
@@ -1690,8 +1642,7 @@ class SumRulesWindow(qt.QMainWindow):
xmax = max(xmax, x.max())
ymin = min(ymin, y.min())
ymax = max(ymax, y.max())
- if DEBUG == 1:
- print('plotOnDemand -- adding Curve..')
+ _logger.debug('plotOnDemand -- adding Curve..')
"""
if mapToY2:
if hasattr(self.plotWindow, 'graph'):
@@ -1706,27 +1657,21 @@ class SumRulesWindow(qt.QMainWindow):
legend=legend,
info=info,
replace=False,
- replot=True)
- # Assure margins in plot when using matplotlibbacken
- if not hasattr(self.plotWindow, 'graph'):
- if DEBUG == 1:
- print('plotOnDemand -- Setting margins..')
- print('\txmin:',xmin,'xmax:',xmax)
- print('\tymin:',ymin,'ymax:',ymax)
- # Pass if no curves present
- curves = self.plotWindow.getAllCurves(just_legend=True)
- if len(curves) == 0:
- # At this point xymin, xymax should be infinite..
- pass
- xmargin = 0.1 * (xmax - xmin)
- ymargin = 0.1 * (ymax - ymin)
- self.plotWindow.setGraphXLimits(xmin-xmargin,
- xmax+xmargin)
- self.plotWindow.setGraphYLimits(ymin-ymargin,
- ymax+ymargin)
- # Need to force replot here for correct display
- self.plotWindow.replot()
- self.plotWindow.updateLegends()
+ resetzoom=True)
+ # Assure margins in plot when using matplotlibbackend
+ _logger.debug('plotOnDemand -- Setting margins..\n'
+ '\txmin: %s xmax: %s\n\tymin: %s ymax: %s',
+ xmin, xmax , ymin, ymax)
+ # Pass if no curves present
+ if not len(self.plotWindow.getAllCurves(just_legend=True)):
+ # At this point xymin, xymax should be infinite..
+ pass
+ xmargin = 0.1 * (xmax - xmin)
+ ymargin = 0.1 * (ymax - ymin)
+ self.plotWindow.setGraphXLimits(xmin-xmargin,
+ xmax+xmargin)
+ self.plotWindow.setGraphYLimits(ymin-ymargin,
+ ymax+ymargin)
def addMarker(self, window, label='X MARKER', xpos=None, unit=''):
# Add spinbox controlling the marker
@@ -1758,7 +1703,7 @@ class SumRulesWindow(qt.QMainWindow):
def _handleTabChangedSignal(self, idx):
if idx >= len(self.tabList):
- print('Tab changed -- Index out of range')
+ _logger.info('Tab changed -- Index out of range')
return
tab = self.tabList[idx]
self.plotOnDemand(window=tab)
@@ -1909,8 +1854,7 @@ class LoadDichorismDataDialog(qt.QFileDialog):
# contents in the top right widget
filename = str(filename)
if osPathIsDir(filename):
- if DEBUG == 1:
- print('LoadDichorismDataDialog.setDataSource -- Invalid path or filename..')
+ _logger.debug('LoadDichorismDataDialog.setDataSource -- Invalid path or filename..')
return
try:
src = SpecFileDataSource.SpecFileDataSource(filename)
diff --git a/PyMca5/PyMcaGui/pymca/XMCDWindow.py b/PyMca5/PyMcaGui/pymca/XMCDWindow.py
index 293d848..8d109a1 100644
--- a/PyMca5/PyMcaGui/pymca/XMCDWindow.py
+++ b/PyMca5/PyMcaGui/pymca/XMCDWindow.py
@@ -28,6 +28,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy, copy
+import logging
import sys
from os.path import splitext, basename, dirname, exists, join as pathjoin
from PyMca5.PyMcaGui import IconDict
@@ -37,7 +38,7 @@ from PyMca5.PyMcaIO import ConfigDict
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import specfilewrapper as specfile
from PyMca5 import PyMcaDataDir
-from PyMca5.PyMcaGui import ScanWindow as sw
+from PyMca5.PyMcaGui.pymca import ScanWindow
if hasattr(qt, "QString"):
QString = qt.QString
@@ -46,8 +47,9 @@ else:
QString = str
QStringList = list
-DEBUG = 0
-if DEBUG:
+_logger = logging.getLogger(__name__)
+
+if _logger.getEffectiveLevel() == logging.DEBUG:
numpy.set_printoptions(threshold=50)
NEWLINE = '\n'
@@ -257,8 +259,7 @@ class XMCDOptions(qt.QDialog):
except IndexError:
# Returned list is empty
return
- if DEBUG:
- print('saveOptions -- Filename: "%s"' % filename)
+ _logger.debug('saveOptions -- Filename: "%s"', filename)
if len(filename) == 0:
self.saved = False
return False
@@ -304,25 +305,22 @@ class XMCDOptions(qt.QDialog):
try:
self.setOptions(confDict['XMCDOptions'])
except ValueError as e:
- if DEBUG:
- print('loadOptions -- int conversion failed:',)
- print('Invalid value for option \'%s\'' % e)
- else:
- msg = qt.QMessageBox()
- msg.setWindowTitle('XMCD Options Error')
- msg.setText('Configuration file \'%s\' corruted' % filename)
- msg.exec_()
- return
+ _logger.debug('loadOptions -- int conversion failed:\n'
+ 'Invalid value for option \'%s\'', e)
+ msg = qt.QMessageBox()
+ msg.setWindowTitle('XMCD Options Error')
+ msg.setText('Configuration file \'%s\' corruted' % filename)
+ msg.exec_()
+ return
except KeyError as e:
- if DEBUG:
- print('loadOptions -- invalid identifier:',)
- print('option \'%s\' not found' % e)
- else:
- msg = qt.QMessageBox()
- msg.setWindowTitle('XMCD Options Error')
- msg.setText('Configuration file \'%s\' corruted' % filename)
- msg.exec_()
- return
+ _logger.debug('loadOptions -- invalid identifier:\n'
+ 'option \'%s\' not found', e)
+
+ msg = qt.QMessageBox()
+ msg.setWindowTitle('XMCD Options Error')
+ msg.setText('Configuration file \'%s\' corruted' % filename)
+ msg.exec_()
+ return
self.saved = True
def getOptions(self):
@@ -367,15 +365,8 @@ class XMCDOptions(qt.QDialog):
if type(button) == type(qt.QRadioButton()):
button.setChecked(True)
-class XMCDScanWindow(sw.ScanWindow):
- xmcdToolbarOptions = {
- 'logx': False,
- 'logy': False,
- 'flip': False,
- 'fit': False,
- 'roi': False,
- }
+class XMCDScanWindow(ScanWindow.ScanWindow):
plotModifiedSignal = qt.pyqtSignal()
saveOptionsSignal = qt.pyqtSignal('QString')
@@ -389,22 +380,22 @@ class XMCDScanWindow(sw.ScanWindow):
:param parent: Parent Widget, None per default
:type parent: QWidget
"""
- sw.ScanWindow.__init__(self,
- parent,
- name='XLD/XMCD Analysis',
- specfit=None,
- plugins=False,
- newplot=False,
- **self.xmcdToolbarOptions)
- if hasattr(self, 'pluginsIconFlag'):
- self.pluginsIconFlag = False
+ ScanWindow.ScanWindow.__init__(self,
+ parent,
+ name='XLD/XMCD Analysis',
+ specfit=None,
+ plugins=False,
+ roi=False, fit=False)
self.plotWindow = origin
- if hasattr(self, 'scanWindowInfoWidget'):
- if self.scanWindowInfoWidget:
- self.scanWindowInfoWidget.hide()
+
+ # hide the first 2 actions
+ self.xAxisLogarithmicAction.setVisible(False)
+ self.yAxisLogarithmicAction.setVisible(False)
+
+ # hide additional toolbar with simple math actions
+ self._mathToolBar.setVisible(False)
# Buttons to push spectra to main Window
- buttonWidget = qt.QWidget()
buttonAdd = qt.QPushButton('Add', self)
buttonAdd.setToolTip('Add active curve to main window')
buttonReplace = qt.QPushButton('Replace', self)
@@ -419,11 +410,16 @@ class XMCDScanWindow(sw.ScanWindow):
buttonReplaceAll.setToolTip(
'Replace all curves in main window '
+'with all curves from analysis window')
- self.graphBottomLayout.addWidget(qt.HorizontalSpacer())
- self.graphBottomLayout.addWidget(buttonAdd)
- self.graphBottomLayout.addWidget(buttonAddAll)
- self.graphBottomLayout.addWidget(buttonReplace)
- self.graphBottomLayout.addWidget(buttonReplaceAll)
+
+ # this is a hack: silx does not provide an attribute for the
+ # bottom bar, but it has a handle for the last widget in the bar
+ # which uses a HBoxLayout.
+ bottomBarHLayout = self.positionWidget.layout()
+ bottomBarHLayout.addWidget(qt.HorizontalSpacer())
+ bottomBarHLayout.addWidget(buttonAdd)
+ bottomBarHLayout.addWidget(buttonAddAll)
+ bottomBarHLayout.addWidget(buttonReplace)
+ bottomBarHLayout.addWidget(buttonReplaceAll)
buttonAdd.clicked.connect(self.add)
buttonReplace.clicked.connect(self.replace)
@@ -448,8 +444,9 @@ class XMCDScanWindow(sw.ScanWindow):
self.xmcd = None
self.xas = None
- if hasattr(self, '_buildLegendWidget'):
- self._buildLegendWidget()
+ self.getLegendsDockWidget().show()
+ self.addDockWidget(qt.Qt.RightDockWidgetArea,
+ self.getLegendsDockWidget())
def sizeHint(self):
if self.parent():
@@ -551,8 +548,7 @@ class XMCDScanWindow(sw.ScanWindow):
keys = sorted(self.curvesDict.keys())
xRangeList = [self.curvesDict[k].x[0] for k in keys]
if not len(xRangeList):
- if DEBUG:
- print('interpXRange -- Nothing to do')
+ _logger.debug('interpXRange -- Nothing to do')
return None
num = 0
@@ -586,11 +582,10 @@ class XMCDScanWindow(sw.ScanWindow):
mask = numpy.nonzero((x > xmin) &
(x < xmax))[0]
out = numpy.sort(numpy.take(x, mask))
- if DEBUG:
- print('interpXRange -- Resulting xrange:')
- print('\tmin = %f' % out.min())
- print('\tmax = %f' % out.max())
- print('\tnum = %f' % len(out))
+ _logger.debug('interpXRange -- Resulting xrange:')
+ _logger.debug('\tmin = %f', out.min())
+ _logger.debug('\tmax = %f', out.max())
+ _logger.debug('\tnum = %f', len(out))
return out
def processSelection(self, groupA, groupB):
@@ -612,8 +607,8 @@ class XMCDScanWindow(sw.ScanWindow):
self.curvesDict = self.copyCurves(groupA + groupB)
if (len(self.curvesDict) == 0) or\
- ((len(self.selectionDict['A']) == 0) and\
- (len(self.selectionDict['B']) == 0)):
+ ((len(self.selectionDict['A']) == 0) and
+ (len(self.selectionDict['B']) == 0)):
# Nothing to do
return
@@ -622,19 +617,16 @@ class XMCDScanWindow(sw.ScanWindow):
# Get active curve
active = self.plotWindow.getActiveCurve()
if active:
- if DEBUG:
- print('processSelection -- xrange: use active')
- x, y, leg, info = active[0:4]
+ _logger.debug('processSelection -- xrange: use active')
+ x = active.getXData()
xRange = self.interpXRange(xRange=x)
else:
return
elif self.optsDict['equidistant']:
- if DEBUG:
- print('processSelection -- xrange: use equidistant')
+ _logger.debug('processSelection -- xrange: use equidistant')
xRange = self.interpXRange(equidistant=True)
else:
- if DEBUG:
- print('processSelection -- xrange: use first')
+ _logger.debug('processSelection -- xrange: use first')
xRange = self.interpXRange()
if hasattr(self.plotWindow, 'graph'):
activeLegend = self.plotWindow.graph.getActiveCurve(justlegend=True)
@@ -687,9 +679,9 @@ class XMCDScanWindow(sw.ScanWindow):
ylabel=ylabel,
color=color)
if idx == 'A':
- self.avgA = self.dataObjectsList[-1]
+ self.avgA = self.getAllCurves(just_legend=True)[-1]
if idx == 'B':
- self.avgB = self.dataObjectsList[-1]
+ self.avgB = self.getAllCurves(just_legend=True)[-1]
if (self.avgA and self.avgB):
self.performXMCD()
@@ -740,8 +732,7 @@ class XMCDScanWindow(sw.ScanWindow):
out[legend] = tmp
else:
# TODO: Errorhandling, curve not found
- if DEBUG:
- print("copyCurves -- Retrieved none type curve")
+ _logger.debug("copyCurves -- Retrieved none type curve")
continue
return out
@@ -769,9 +760,8 @@ class XMCDScanWindow(sw.ScanWindow):
"""
if (len(xarr) != len(yarr)) or\
(len(xarr) == 0) or (len(yarr) == 0):
- if DEBUG:
- print('specAverage -- invalid input!')
- print('Array lengths do not match or are 0')
+ _logger.debug('specAverage -- invalid input!')
+ _logger.debug('Array lengths do not match or are 0')
return None, None
same = True
@@ -819,9 +809,8 @@ class XMCDScanWindow(sw.ScanWindow):
if xmax < xmax0:
xmax0 = xmax
if xmax <= xmin:
- if DEBUG:
- print('specAverage -- ')
- print('No overlap between spectra!')
+ _logger.debug('specAverage --\n'
+ 'No overlap between spectra!')
return numpy.array([]), numpy.array([])
# Clip xRange to maximal overlap in spectra
@@ -869,17 +858,15 @@ class XMCDScanWindow(sw.ScanWindow):
a = self.dataObjectsDict[self.avgA]
b = self.dataObjectsDict[self.avgB]
else:
- if DEBUG:
- print('performXAS -- Data not found: ')
- print('\tavg_m = %f' % self.avgA)
- print('\tavg_p = %f' % self.avgB)
+ _logger.debug('performXAS -- Data not found: ')
+ _logger.debug('\tavg_m = %f', self.avgA)
+ _logger.debug('\tavg_p = %f', self.avgB)
return
if numpy.all( a.x[0] == b.x[0] ):
avg = .5*(b.y[0] + a.y[0])
else:
- if DEBUG:
- print('performXAS -- x ranges are not the same! ')
- print('Force interpolation')
+ _logger.debug('performXAS -- x ranges are not the same! ')
+ _logger.debug('Force interpolation')
avg = self.performAverage([a.x[0], b.x[0]],
[a.y[0], b.y[0]],
b.x[0])
@@ -893,7 +880,7 @@ class XMCDScanWindow(sw.ScanWindow):
xlabel=xlabel,
ylabel=ylabel,
color="pink")
- self.xas = self.dataObjectsList[-1]
+ self.xas = self.getAllCurves(just_legend=True)[-1]
def performXMCD(self):
keys = self.dataObjectsDict.keys()
@@ -901,15 +888,13 @@ class XMCDScanWindow(sw.ScanWindow):
a = self.dataObjectsDict[self.avgA]
b = self.dataObjectsDict[self.avgB]
else:
- if DEBUG:
- print('performXMCD -- Data not found:')
+ _logger.debug('performXMCD -- Data not found:')
return
if numpy.all( a.x[0] == b.x[0] ):
diff = b.y[0] - a.y[0]
else:
- if DEBUG:
- print('performXMCD -- x ranges are not the same! ')
- print('Force interpolation using p Average xrange')
+ _logger.debug('performXMCD -- x ranges are not the same! ')
+ _logger.debug('Force interpolation using p Average xrange')
# Use performAverage d = 2 * avg(y1, -y2)
# and force interpolation on p-xrange
diff = 2. * self.performAverage([a.x[0], b.x[0]],
@@ -927,8 +912,8 @@ class XMCDScanWindow(sw.ScanWindow):
ylabel=ylabel,
yaxis="right")
# DELETE ME self.graph.mapToY2(' '.join([xmcdLegend, ylabel]))
- self._zoomReset()
- self.xmcd = self.dataObjectsList[-1]
+ self.resetZoom()
+ self.xmcd = self.getAllCurves(just_legend=True)[-1]
def selectionInfo(self, idx, key):
"""
@@ -1012,7 +997,7 @@ class XMCDScanWindow(sw.ScanWindow):
return
title = ''
- legends = self.dataObjectsList
+ legends = self.getAllCurves(just_legend=True)
tmpLegs = sorted(self.curvesDict.keys())
if len(tmpLegs) > 0:
title += self.curvesDict[tmpLegs[0]].info.get('selectionlegend','')
@@ -1080,12 +1065,12 @@ class XMCDScanWindow(sw.ScanWindow):
self.saveOptionsSignal.emit(splitext(sepFileName)[0])
def add(self):
- if len(self.dataObjectsList) == 0:
+ if len(self.getAllCurves(just_legend=True)) == 0:
return
activeCurve = self.getActiveCurve()
if activeCurve is None:
return
- (xVal, yVal, legend, info) = activeCurve
+ (xVal, yVal, legend, info) = activeCurve[0:4]
#if 'selectionlegend' in info:
# newLegend = info['selectionlegend']
#elif 'operation' in info:
@@ -1100,7 +1085,8 @@ class XMCDScanWindow(sw.ScanWindow):
self.plotModifiedSignal.emit()
def addAll(self):
- for (xVal, yVal, legend, info) in self.getAllCurves():
+ for curve in self.getAllCurves():
+ (xVal, yVal, legend, info) = curve[0:4]
#if 'selectionlegend' in info:
# newLegend = info['selectionlegend']
#elif 'operation' in info:
@@ -1115,12 +1101,12 @@ class XMCDScanWindow(sw.ScanWindow):
self.plotModifiedSignal.emit()
def replace(self):
- if len(self.dataObjectsList) == 0:
+ if len(self.getAllCurves(just_legend=True)) == 0:
return
activeCurve = self.getActiveCurve()
if activeCurve is None:
return
- (xVal, yVal, legend, info) = activeCurve
+ (xVal, yVal, legend, info) = activeCurve[0:4]
if 'selectionlegend' in info:
newLegend = info['selectionlegend']
elif 'operation' in info:
@@ -1136,7 +1122,8 @@ class XMCDScanWindow(sw.ScanWindow):
def replaceAll(self):
allCurves = self.getAllCurves()
- for (idx, (xVal, yVal, legend, info)) in enumerate(allCurves):
+ for (idx, curve) in enumerate(allCurves):
+ (xVal, yVal, legend, info) = curve[0:4]
if 'selectionlegend' in info:
newLegend = info['selectionlegend']
elif 'operation' in info:
@@ -1258,10 +1245,8 @@ class XMCDTreeWidget(qt.QTreeWidget):
out = []
convert = (convertType != str)
if ncol > (self.columnCount()-1):
- if DEBUG:
- print('getColum -- Selected column out of bounds')
+ _logger.debug('getColum -- Selected column out of bounds')
raise IndexError("Selected column '%d' out of bounds" % ncol)
- return out
if selectedOnly:
sel = self.selectedItems()
else:
@@ -1276,8 +1261,7 @@ class XMCDTreeWidget(qt.QTreeWidget):
if convertType == float:
tmp = float('NaN')
else:
- if DEBUG:
- print('getColum -- Conversion failed!')
+ _logger.debug('getColum -- Conversion failed!')
raise TypeError
out += [tmp]
return out
@@ -1477,8 +1461,7 @@ class XMCDWidget(qt.QWidget):
helpFileHandle.close()
self.helpFileBrowser.setHtml(helpFileHTML)
except IOError:
- if DEBUG:
- print('XMCDWindow -- init: Unable to read help file')
+ _logger.debug('XMCDWindow -- init: Unable to read help file')
self.helpFileBrowser = None
self.selectionDict = {'D': [],
@@ -2004,7 +1987,7 @@ class XMCDWidget(qt.QWidget):
if len(namesList) == len(valuesList):
ret.append(dict(zip(namesList, valuesList)))
else:
- print("Number of motors and values does not match!")
+ _logger.warning("Number of motors and values does not match!")
return ret
def _setLists(self):
@@ -2024,12 +2007,11 @@ class XMCDWidget(qt.QWidget):
if self.plotWindow is not None:
curves = self.plotWindow.getAllCurves()
else:
- if DEBUG:
- print('_setLists -- Set self.plotWindow before calling self._setLists')
+ _logger.debug('_setLists -- Set self.plotWindow before calling self._setLists')
return
# nCurves = len(curves)
- self.legendList = [leg for (xvals, yvals, leg, info) in curves]
- self.infoList = [info for (xvals, yvals, leg, info) in curves]
+ self.legendList = [curve.getLegend() for curve in curves]
+ self.infoList = [curve.getInfo() for curve in curves]
# Try to recover the scan number from the legend, if not set
# Requires additional import:
#from re import search as regexpSearch
@@ -2086,7 +2068,7 @@ def main():
app = qt.QApplication([])
# Create dummy ScanWindow
- swin = sw.ScanWindow()
+ swin = ScanWindow.ScanWindow()
info0 = {'xlabel': 'foo',
'ylabel': 'arb',
'MotorNames': 'oxPS PhaseA Phase BRUKER CRYO OXFORD',
@@ -2096,13 +2078,13 @@ def main():
info2 = {'MotorNames': 'PhaseD oxPS PhaseA Phase BRUKER CRYO OXFORD',
'MotorValues': '-9.45353059 -25.37448851 24.37665651 18.88048044 -0.26018745 2 0.901968648111 '}
x = numpy.arange(100.,1100.)
- y0 = 10*x + 10000.*numpy.exp(-0.5*(x-500)**2/400) + 1500*numpy.random.random(1000.)
- y1 = 10*x + 10000.*numpy.exp(-0.5*(x-600)**2/400) + 1500*numpy.random.random(1000.)
- y2 = 10*x + 10000.*numpy.exp(-0.5*(x-400)**2/400) + 1500*numpy.random.random(1000.)
+ y0 = 10*x + 10000.*numpy.exp(-0.5*(x-500)**2/400) + 1500*numpy.random.random(1000)
+ y1 = 10*x + 10000.*numpy.exp(-0.5*(x-600)**2/400) + 1500*numpy.random.random(1000)
+ y2 = 10*x + 10000.*numpy.exp(-0.5*(x-400)**2/400) + 1500*numpy.random.random(1000)
- swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='Ihor', info=info2, replot=False, replace=False)
- swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='Iver', info=info0, replot=False, replace=False)
- swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='Ihor', info=info1, replot=False, replace=False)
+ swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='Ihor', info=info2, replace=False)
+ swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='Iver', info=info0, replace=False)
+ swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='Ihor', info=info1, replace=False)
# info['Key'] is overwritten when using newCurve
swin.dataObjectsDict['Curve2 Ihor'].info['Key'] = '1.1'
diff --git a/PyMca5/PyMcaIO/ArraySave.py b/PyMca5/PyMcaIO/ArraySave.py
index 9989db6..8c4a7e1 100644
--- a/PyMca5/PyMcaIO/ArraySave.py
+++ b/PyMca5/PyMcaIO/ArraySave.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -33,29 +33,50 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import numpy
import time
+import logging
+_logger = logging.getLogger(__name__)
+import sys
try:
from PyMca5.PyMcaIO import EdfFile
from PyMca5.PyMcaIO import TiffIO
except ImportError:
- print("ArraySave.py is importing EdfFile and TiffIO from local directory")
+ _logger.info("ArraySave.py is importing EdfFile and TiffIO from local directory")
import EdfFile
import TiffIO
HDF5 = True
try:
import h5py
+ if sys.version_info < (3, ):
+ text_dtype = h5py.special_dtype(vlen=unicode)
+ else:
+ text_dtype = h5py.special_dtype(vlen=str)
except ImportError:
HDF5 = False
-DEBUG = 0
+def to_unicode(s):
+ """Return string as unicode.
+
+ :param s: A string (bytestring or unicode string).
+ If s is a bytestring, it is assumed that it is utf-8 encoded text"""
+ if hasattr(s, "decode"):
+ return s.decode("utf-8")
+ return s
+
+
+def to_h5py_utf8(str_list):
+ """Convert a string or a list of strings to a variable length utf-8 string
+ compatible with h5py.
+ """
+ return numpy.array(str_list, dtype=text_dtype)
def getDate():
localtime = time.localtime()
gtime = time.gmtime()
- #year, month, day, hour, minute, second,\
+ # year, month, day, hour, minute, second,\
# week_day, year_day, delta = time.localtime()
year = localtime[0]
month = localtime[1]
@@ -63,10 +84,10 @@ def getDate():
hour = localtime[3]
minute = localtime[4]
second = localtime[5]
- #get the difference against Greenwich
+ # get the difference against Greenwich
delta = hour - gtime[3]
- return "%4d-%02d-%02dT%02d:%02d:%02d%+02d:00" % (year, month, day, hour,
- minute, second, delta)
+ return u"%4d-%02d-%02dT%02d:%02d:%02d%+02d:00" % (year, month, day, hour,
+ minute, second, delta)
def save2DArrayListAsASCII(datalist, filename,
@@ -140,11 +161,11 @@ def save2DArrayListAsEDF(datalist, filename, labels=None, dtype=None):
for i in range(ndata):
if dtype is None:
edfout.WriteImage({'Title': labels[i]},
- datalist[i], Append=1)
+ datalist[i], Append=1)
else:
edfout.WriteImage({'Title': labels[i]},
- datalist[i].astype(dtype),
- Append=1)
+ datalist[i].astype(dtype),
+ Append=1)
del edfout # force file close
@@ -192,7 +213,7 @@ def save2DArrayListAsMonochromaticTiff(datalist, filename,
try:
os.remove(fname)
except OSError:
- print("Cannot remove file %s" % fname)
+ _logger.warning("Cannot remove file %s", fname)
pass
if (savedData == 0) or multifile:
outfileInstance = TiffIO.TiffIO(fname, mode="wb+")
@@ -217,6 +238,7 @@ def save2DArrayListAsMonochromaticTiff(datalist, filename,
savedData += 1
outfileInstance.close() # force file close
+
def openHDF5File(name, mode='a', **kwargs):
"""
Open an HDF5 file.
@@ -235,37 +257,22 @@ def openHDF5File(name, mode='a', **kwargs):
h5file = h5py.File(name, mode, **kwargs)
if h5file.mode != 'r' and len(h5file) == 0:
if 'file_name' not in h5file.attrs:
- attr = 'file_name'
- txt = "%s" % name
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
+ h5file.attrs.create('file_name', to_h5py_utf8(name))
if 'file_time' not in h5file.attrs:
- attr = 'file_time'
- txt = "%s" % getDate()
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
+ h5file.attrs.create('file_time', to_h5py_utf8(getDate()))
if 'HDF5_version' not in h5file.attrs:
- attr = 'HDF5_version'
txt = "%s" % h5py.version.hdf5_version
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
+ h5file.attrs.create('HDF5_version', to_h5py_utf8(txt))
if 'HDF5_API_version' not in h5file.attrs:
- attr = 'HDF5_API_version'
txt = "%s" % h5py.version.api_version
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
+ h5file.attrs.create('HDF5_API_version', to_h5py_utf8(txt))
if 'h5py_version' not in h5file.attrs:
- attr = 'h5py_version'
txt = "%s" % h5py.version.version
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
+ h5file.attrs.create('h5py_version', to_h5py_utf8(txt))
if 'creator' not in h5file.attrs:
- attr = 'creator'
- txt = "%s" % 'PyMca'
- dtype = '<S%d' % len(txt)
- h5file.attrs.create(attr, txt, dtype=dtype)
- #if 'format_version' not in self.attrs and len(h5file) == 0:
- # h5file.attrs['format_version'] = __format_version__
+ h5file.attrs.create('creator', to_h5py_utf8('PyMca'))
+ # if 'format_version' not in self.attrs and len(h5file) == 0:
+ # h5file.attrs['format_version'] = __format_version__
return h5file
@@ -286,24 +293,23 @@ def getHDF5FileInstanceAndBuffer(filename, shape,
hdf = openHDF5File(filename, 'a')
entryName = "data"
- #entry
+ # entry
nxEntry = hdf.require_group(entryName)
if 'NX_class' not in nxEntry.attrs:
- nxEntry.attrs['NX_class'] = 'NXentry'.encode('utf-8')
- elif nxEntry.attrs['NX_class'] != 'NXentry'.encode('utf-8'):
- #should I raise an error?
+ nxEntry.attrs['NX_class'] = u'NXentry'
+ elif nxEntry.attrs['NX_class'] not in [b'NXentry', u"NXentry"]:
+ # should I raise an error?
pass
- nxEntry['title'] = "PyMca saved 3D Array".encode('utf-8')
- nxEntry['start_time'] = getDate().encode('utf-8')
+ nxEntry['title'] = u"PyMca saved 3D Array"
+ nxEntry['start_time'] = getDate()
nxData = nxEntry.require_group('NXdata')
if 'NX_class' not in nxData.attrs:
- nxData.attrs['NX_class'] = 'NXdata'.encode('utf-8')
- elif nxData.attrs['NX_class'] == 'NXdata'.encode('utf-8'):
- #should I raise an error?
+ nxData.attrs['NX_class'] = u'NXdata'
+ elif nxData.attrs['NX_class'] in [b'NXdata', u'NXdata']:
+ # should I raise an error?
pass
if compression:
- if DEBUG:
- print("Saving compressed and chunked dataset")
+ _logger.debug("Saving compressed and chunked dataset")
chunk1 = int(shape[1] / 10)
if chunk1 == 0:
chunk1 = shape[1]
@@ -319,30 +325,33 @@ def getHDF5FileInstanceAndBuffer(filename, shape,
chunk2 = int(shape[2] / i)
break
data = nxData.require_dataset(buffername,
- shape=shape,
- dtype=dtype,
- chunks=(1, chunk1, chunk2),
- compression=compression)
+ shape=shape,
+ dtype=dtype,
+ chunks=(1, chunk1, chunk2),
+ compression=compression)
else:
#no chunking
- if DEBUG:
- print("Saving not compressed and not chunked dataset")
+ _logger.debug("Saving not compressed and not chunked dataset")
data = nxData.require_dataset(buffername,
- shape=shape,
- dtype=dtype,
- compression=None)
- data.attrs['signal'] = numpy.int32(1)
+ shape=shape,
+ dtype=dtype,
+ compression=None)
+ nxData.attrs['signal'] = to_unicode(buffername)
if interpretation is not None:
- data.attrs['interpretation'] = interpretation.encode('utf-8')
+ data.attrs['interpretation'] = to_unicode(interpretation)
+
for i in range(len(shape)):
dim = numpy.arange(shape[i]).astype(numpy.float32)
dset = nxData.require_dataset('dim_%d' % i,
- dim.shape,
- dim.dtype,
- dim,
- chunks=dim.shape)
- dset.attrs['axis'] = numpy.int32(i + 1)
- nxEntry['end_time'] = getDate().encode('utf-8')
+ dim.shape,
+ dim.dtype,
+ dim,
+ chunks=dim.shape)
+
+ nxData.attrs["axes"] = to_h5py_utf8(['dim_%d' % i
+ for i in range(len(shape))])
+
+ nxEntry['end_time'] = getDate()
return hdf, data
@@ -374,6 +383,7 @@ def save3DArrayAsMonochromaticTiff(data, filename,
outfileInstance.writeImage(tmpData, info={'Title': labels[i]})
if (ndata > 10):
print("Saved image %d of %d" % (i + 1, ndata))
+ _logger.info("Saved image %d of %d", i + 1, ndata)
elif mcaindex == 1:
for i in range(ndata):
if i == 1:
@@ -384,6 +394,7 @@ def save3DArrayAsMonochromaticTiff(data, filename,
tmpData = data[:, i, :].astype(dtype)
outfileInstance.writeImage(tmpData, info={'Title': labels[i]})
if (ndata > 10):
+ _logger.info("Saved image %d of %d", i + 1, ndata)
print("Saved image %d of %d" % (i + 1, ndata))
else:
for i in range(ndata):
@@ -395,20 +406,23 @@ def save3DArrayAsMonochromaticTiff(data, filename,
tmpData = data[i].astype(dtype)
outfileInstance.writeImage(tmpData, info={'Title': labels[i]})
if (ndata > 10):
+ _logger.info("Saved image %d of %d",
+ i + 1, ndata)
print("Saved image %d of %d" % (i + 1, ndata))
outfileInstance.close() # force file close
+
# it should be used to name the data that for the time being is named 'data'.
def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='nexus',
mcaindex=-1, interpretation=None, compression=None):
if not HDF5:
raise IOError('h5py does not seem to be installed in your system')
if (mcaindex == 0) and (interpretation in ["spectrum", None]):
- #stack of images to be saved as stack of spectra
+ # stack of images to be saved as stack of spectra
modify = True
shape = [data.shape[1], data.shape[2], data.shape[0]]
elif (mcaindex != 0) and (interpretation in ["image"]):
- #stack of spectra to be saved as stack of images
+ # stack of spectra to be saved as stack of images
modify = True
shape = [data.shape[2], data.shape[0], data.shape[1]]
else:
@@ -417,7 +431,7 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
if dtype is None:
dtype = data.dtype
if mode.lower() in ['nexus', 'nexus+']:
- #raise IOError, 'NeXus data saving not implemented yet'
+ # raise IOError, 'NeXus data saving not implemented yet'
if os.path.exists(filename):
try:
os.remove(filename)
@@ -425,27 +439,26 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
raise IOError("Cannot overwrite existing file!")
hdf = openHDF5File(filename, 'a')
entryName = "data"
- #entry
+ # entry
nxEntry = hdf.require_group(entryName)
if 'NX_class' not in nxEntry.attrs:
- nxEntry.attrs['NX_class'] = 'NXentry'.encode('utf-8')
- elif nxEntry.attrs['NX_class'] != 'NXentry'.encode('utf-8'):
- #should I raise an error?
+ nxEntry.attrs['NX_class'] = u'NXentry'
+ elif nxEntry.attrs['NX_class'] not in [b'NXentry', u'NXentry']:
+ # should I raise an error?
pass
- nxEntry['title'] = numpy.string_("PyMca saved 3D Array".encode('utf-8'))
- nxEntry['start_time'] = numpy.string_(getDate().encode('utf-8'))
+ nxEntry['title'] = u"PyMca saved 3D Array"
+ nxEntry['start_time'] = getDate()
nxData = nxEntry.require_group('NXdata')
- if ('NX_class' not in nxData.attrs):
- nxData.attrs['NX_class'] = 'NXdata'.encode('utf-8')
- elif nxData.attrs['NX_class'] != 'NXdata'.encode('utf-8'):
- #should I raise an error?
+ if 'NX_class' not in nxData.attrs:
+ nxData.attrs['NX_class'] = u'NXdata'
+ elif nxData.attrs['NX_class'] not in [u'NXdata', b'NXdata']:
+ # should I raise an error?
pass
if modify:
- if interpretation in ["image", "image".encode('utf-8')]:
+ if interpretation in [b"image", u"image"]:
if compression:
- if DEBUG:
- print("Saving compressed and chunked dataset")
+ _logger.debug("Saving compressed and chunked dataset")
#risk of taking a 10 % more space in disk
chunk1 = int(shape[1] / 10)
if chunk1 == 0:
@@ -460,31 +473,31 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
chunk2 = int(shape[2] / i)
break
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- chunks=(1, chunk1, chunk2),
- compression=compression)
+ shape=shape,
+ dtype=dtype,
+ chunks=(1, chunk1, chunk2),
+ compression=compression)
else:
- if DEBUG:
- print("Saving not compressed and not chunked dataset")
+ _logger.debug("Saving not compressed and not chunked dataset")
#print not compressed -> Not chunked
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- compression=None)
+ shape=shape,
+ dtype=dtype,
+ compression=None)
for i in range(data.shape[-1]):
tmp = data[:, :, i:i + 1]
tmp.shape = 1, shape[1], shape[2]
dset[i, 0:shape[1], :] = tmp
- print("Saved item %d of %d" % (i + 1, data.shape[-1]))
+ _logger.info("Saved item %d of %d",
+ i + 1, data.shape[-1])
elif 0:
- #if I do not match the input and output shapes it takes ages
- #to save the images as spectra. However, it is much faster
- #when performing spectra operations.
+ # if I do not match the input and output shapes it takes ages
+ # to save the images as spectra. However, it is much faster
+ # when performing spectra operations.
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- chunks=(1, shape[1], shape[2]))
+ shape=shape,
+ dtype=dtype,
+ chunks=(1, shape[1], shape[2]))
for i in range(data.shape[1]): # shape[0]
chunk = numpy.zeros((1, data.shape[2], data.shape[0]),
dtype)
@@ -498,35 +511,33 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
tmpData = data[k:k + 1, i, :]
tmpData.shape = -1
chunk[0, :, k] = tmpData
- print("Saving item %d of %d" % (i, data.shape[1]))
+ _logger.info("Saving item %d of %d",
+ i, data.shape[1])
dset[i, :, :] = chunk
else:
- #if I do not match the input and output shapes it takes ages
- #to save the images as spectra. This is a very fast saving, but
- #the performance is awful when reading.
+ # if I do not match the input and output shapes it takes ages
+ # to save the images as spectra. This is a very fast saving, but
+ # the performance is awful when reading.
if compression:
- if DEBUG:
- print("Saving compressed and chunked dataset")
+ _logger.debug("Saving compressed and chunked dataset")
dset = nxData.require_dataset('data',
shape=shape,
dtype=dtype,
chunks=(shape[0], shape[1], 1),
compression=compression)
else:
- if DEBUG:
- print("Saving not compressed and not chunked dataset")
+ _logger.debug("Saving not compressed and not chunked dataset")
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- compression=None)
+ shape=shape,
+ dtype=dtype,
+ compression=None)
for i in range(data.shape[0]):
tmp = data[i:i + 1, :, :]
tmp.shape = shape[0], shape[1], 1
dset[:, :, i:i + 1] = tmp
else:
if compression:
- if DEBUG:
- print("Saving compressed and chunked dataset")
+ _logger.debug("Saving compressed and chunked dataset")
chunk1 = int(shape[1] / 10)
if chunk1 == 0:
chunk1 = shape[1]
@@ -541,30 +552,31 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
if (shape[2] % i) == 0:
chunk2 = int(shape[2] / i)
break
- if DEBUG:
- print("Used chunk size = (1, %d, %d)" % (chunk1, chunk2))
+ _logger.debug("Used chunk size = (1, %d, %d)",
+ chunk1, chunk2)
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- chunks=(1, chunk1, chunk2),
- compression=compression)
+ shape=shape,
+ dtype=dtype,
+ chunks=(1, chunk1, chunk2),
+ compression=compression)
else:
- if DEBUG:
- print("Saving not compressed and notchunked dataset")
+ _logger.debug("Saving not compressed and notchunked dataset")
dset = nxData.require_dataset('data',
- shape=shape,
- dtype=dtype,
- compression=None)
+ shape=shape,
+ dtype=dtype,
+ compression=None)
tmpData = numpy.zeros((1, data.shape[1], data.shape[2]),
data.dtype)
for i in range(data.shape[0]):
tmpData[0:1] = data[i:i + 1]
dset[i:i + 1] = tmpData[0:1]
- print("Saved item %d of %d" % (i + 1, data.shape[0]))
+ _logger.info("Saved item %d of %d", i + 1, data.shape[0])
+
+ nxData.attrs["signal"] = u'data'
- dset.attrs['signal'] = "1".encode('utf-8')
if interpretation is not None:
- dset.attrs['interpretation'] = interpretation.encode('utf-8')
+ dset.attrs['interpretation'] = to_unicode(interpretation)
+
axesAttribute = []
for i in range(len(shape)):
if axes is None:
@@ -584,18 +596,20 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
dimlabel = 'dim_%d' % i
axesAttribute.append(dimlabel)
adset = nxData.require_dataset(dimlabel,
- dim.shape,
- dim.dtype,
- compression=None)
+ dim.shape,
+ dim.dtype,
+ compression=None)
adset[:] = dim[:]
adset.attrs['axis'] = i + 1
- dset.attrs['axes'] = (":".join(axesAttribute)).encode('utf-8')
- nxEntry['end_time'] = numpy.string_(getDate().encode('utf-8'))
+
+ nxData.attrs["axes"] = to_h5py_utf8([axAttr for axAttr in axesAttribute])
+
+ nxEntry['end_time'] = getDate()
if mode.lower() == 'nexus+':
- #create link
- g = h5py.h5g.open(hdf.fid, '/'.encode('utf-8'))
- g.link('/data/NXdata/data'.encode('utf-8'),
- '/data/data'.encode('utf-8'),
+ # create link
+ g = h5py.h5g.open(hdf.fid, '/')
+ g.link('/data/NXdata/data',
+ '/data/data',
h5py.h5g.LINK_HARD)
elif mode.lower() == 'simplest':
@@ -607,17 +621,17 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
hdf = h5py.File(filename, 'a')
if compression:
hdf.require_dataset('data',
- shape=shape,
- dtype=dtype,
- data=data,
- chunks=(1, shape[1], shape[2]),
- compression=compression)
+ shape=shape,
+ dtype=dtype,
+ data=data,
+ chunks=(1, shape[1], shape[2]),
+ compression=compression)
else:
hdf.require_dataset('data',
- shape=shape,
- data=data,
- dtype=dtype,
- compression=None)
+ shape=shape,
+ data=data,
+ dtype=dtype,
+ compression=None)
else:
if os.path.exists(filename):
try:
@@ -629,13 +643,14 @@ def save3DArrayAsHDF5(data, filename, axes=None, labels=None, dtype=None, mode='
hdf = h5py.File(filename, 'a')
dataGroup = hdf.require_group('data')
dataGroup.require_dataset('data',
- shape=shape,
- dtype=dtype,
- data=data,
- chunks=(1, shape[1], shape[2]))
+ shape=shape,
+ dtype=dtype,
+ data=data,
+ chunks=(1, shape[1], shape[2]))
hdf.flush()
hdf.close()
+
def main():
a = numpy.arange(1000000.)
a.shape = 20, 50, 1000
@@ -643,6 +658,7 @@ def main():
getHDF5FileInstanceAndBuffer('/test2.h5', (100, 100, 100))
print("Date String = ", getDate())
+
if __name__ == "__main__":
main()
diff --git a/PyMca5/PyMcaIO/BAXSCSVFileParser.py b/PyMca5/PyMcaIO/BAXSCSVFileParser.py
index b7ab9ca..0369d18 100644
--- a/PyMca5/PyMcaIO/BAXSCSVFileParser.py
+++ b/PyMca5/PyMcaIO/BAXSCSVFileParser.py
@@ -33,9 +33,11 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaIO import SpecFileAbstractClass
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class BufferedFile(object):
def __init__(self, filename):
@@ -127,8 +129,7 @@ class BAXSCSVFileParser(object):
return self.__getitem__(int(n[0])-1)
def allmotors(self):
- if DEBUG:
- print("BAXCSVFileParser allmotors called")
+ _logger.debug("BAXCSVFileParser allmotors called")
return []
class BAXSCSVScan(SpecFileAbstractClass.SpecFileAbstractScan):
diff --git a/PyMca5/PyMcaIO/EDFStack.py b/PyMca5/PyMcaIO/EDFStack.py
index c033572..2b734e7 100644
--- a/PyMca5/PyMcaIO/EDFStack.py
+++ b/PyMca5/PyMcaIO/EDFStack.py
@@ -37,6 +37,7 @@ from PyMca5.PyMcaMisc import PhysicalMemory
import numpy
import sys
import os
+import logging
# Offer automatic conversion to HDF5 in case of lacking
# memory to hold the Stack.
@@ -49,7 +50,8 @@ except:
SOURCE_TYPE = "EdfFileStack"
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
X_AXIS=0
Y_AXIS=1
@@ -232,9 +234,9 @@ class EDFStack(DataObject.DataObject):
samplingStep = None
i = 2
while samplingStep is None:
- print("**************************************************")
- print(" Memory error!, attempting %dx%d sampling reduction ") % (i,i)
- print("**************************************************")
+ _logger.warning("**************************************************")
+ _logger.warning(" Memory error!, attempting %dx%d sampling reduction ", i,i)
+ _logger.warning("**************************************************")
s1, s2 = arrRet[::i, ::i].shape
try:
self.data = numpy.zeros((s1, s2,
@@ -451,14 +453,14 @@ class EDFStack(DataObject.DataObject):
self.data[self.incrProgressBar, :,:] = pieceOfStack[:,:]
except:
if pieceOfStack.shape[1] != arrRet.shape[1]:
- print(" ERROR on file %s" % tempEdfFileName)
- print(" DIM 1 error Assuming missing data were at the end!!!")
+ _logger.warning(" ERROR on file %s", tempEdfFileName)
+ _logger.warning(" DIM 1 error Assuming missing data were at the end!!!")
if pieceOfStack.shape[0] != arrRet.shape[0]:
- print(" ERROR on file %s" % tempEdfFileName)
- print(" DIM 0 error Assuming missing data were at the end!!!")
- self.data[self.incrProgressBar,\
- :pieceOfStack.shape[0],\
- :pieceOfStack.shape[1]] = pieceOfStack[:,:]
+ _logger.warning(" ERROR on file %s", tempEdfFileName)
+ _logger.warning(" DIM 0 error Assuming missing data were at the end!!!")
+ self.data[self.incrProgressBar,
+ :pieceOfStack.shape[0],
+ :pieceOfStack.shape[1]] = pieceOfStack[:, :]
self.incrProgressBar += 1
self.onProgress(self.incrProgressBar)
self.onEnd()
@@ -571,8 +573,9 @@ class EDFStack(DataObject.DataObject):
prefix = name[0:n-i+1]
prefix = os.path.join(os.path.dirname(filename),prefix)
if not os.path.exists(prefix + number + suffix):
- print("Internal error in EDFStack")
- print("file should exist: %s " % (prefix + number + suffix))
+ _logger.error("Internal error in EDFStack "
+ "file should exist: %s ",
+ prefix + number + suffix)
return
i = 0
if begin is None:
@@ -609,7 +612,7 @@ class EDFStack(DataObject.DataObject):
sourceInfo["KeyList"]= self.__keyList
def getKeyInfo(self, key):
- print("Not implemented")
+ _logger.info("Not implemented")
return {}
def isIndexedStack(self):
diff --git a/PyMca5/PyMcaIO/EdfFile.py b/PyMca5/PyMcaIO/EdfFile.py
index 481ca6e..901655b 100644
--- a/PyMca5/PyMcaIO/EdfFile.py
+++ b/PyMca5/PyMcaIO/EdfFile.py
@@ -92,10 +92,10 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
section is going to be translated into an 1D, 2D or 3D Numpy Array, and accessed
through GetData method call.
"""
-DEBUG = 0
################################################################################
import sys
import numpy
+import logging
import os.path #, tempfile, shutil
try:
import gzip
@@ -130,6 +130,9 @@ try:
except:
CAN_USE_FASTEDF = 0
+_logger = logging.getLogger(__name__)
+
+
################################################################################
# constants
HEADER_BLOCK_SIZE = 1024
@@ -630,7 +633,7 @@ class EdfFile(object):
try:
datasize = self.__GetSizeNumpyType__(datatype)
except TypeError:
- print("What is the meaning of this error?")
+ _logger.debug("What is the meaning of this error?")
datasize = 8
if self.Images[Index].NumDim == 3:
sizeToRead = self.Images[Index].Dim1 * \
@@ -702,7 +705,7 @@ class EdfFile(object):
else:
if fastedf:
- print("I could not use fast routines")
+ _logger.info("I could not use fast routines")
type_ = self.__GetDefaultNumpyType__(self.Images[Index].DataType, index=Index)
size_pixel = self.__GetSizeNumpyType__(type_)
Data = numpy.array([], type_)
@@ -953,20 +956,16 @@ class EdfFile(object):
#Internal Methods
def __makeSureFileIsOpen(self):
- if DEBUG:
- print("Making sure file is open")
+ _logger.debug("Making sure file is open")
if not self.__ownedOpen:
return
if self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- if DEBUG:
- print("Special case. Image is buffered")
+ _logger.debug("Special case. Image is buffered")
return
if self.File in [0, None]:
- if DEBUG:
- print("File is None")
+ _logger.debug("File is None")
elif self.File.closed:
- if DEBUG:
- print("Reopening closed file")
+ _logger.debug("Reopening closed file")
accessMode = self.File.mode
fileName = self.File.name
newFile = open(fileName, accessMode)
@@ -974,20 +973,16 @@ class EdfFile(object):
return
def __makeSureFileIsClosed(self):
- if DEBUG:
- print("Making sure file is closed")
+ _logger.debug("Making sure file is closed")
if not self.__ownedOpen:
return
if self.ADSC or self.MARCCD or self.PILATUS_CBF or self.SPE:
- if DEBUG:
- print("Special case. Image is buffered")
+ _logger.debug("Special case. Image is buffered")
return
if self.File in [0, None]:
- if DEBUG:
- print("File is None")
+ _logger.debug("File is None")
elif not self.File.closed:
- if DEBUG:
- print("Closing file")
+ _logger.debug("Closing file")
self.File.close()
return
diff --git a/PyMca5/PyMcaIO/HDF5Stack1D.py b/PyMca5/PyMcaIO/HDF5Stack1D.py
index 041bf1e..b6cef57 100644
--- a/PyMca5/PyMcaIO/HDF5Stack1D.py
+++ b/PyMca5/PyMcaIO/HDF5Stack1D.py
@@ -33,22 +33,23 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import posixpath
import numpy
import h5py
+import logging
+_logger = logging.getLogger(__name__)
try:
from PyMca5.PyMcaCore import DataObject
from PyMca5.PyMcaMisc import PhysicalMemory
except ImportError:
- print("HDF5Stack1D importing DataObject from local directory!")
+ _logger.info("HDF5Stack1D importing DataObject from local directory!")
import DataObject
import PhysicalMemory
try:
from PyMca5.PyMcaCore import NexusDataSource
from PyMca5.PyMcaCore import NexusTools
except ImportError:
- print("HDF5Stack1D importing NexusDataSource from local directory!")
+ _logger.info("HDF5Stack1D importing NexusDataSource from local directory!")
import NexusDataSource
import NexusDataSource
-DEBUG = 0
SOURCE_TYPE = "HDF5Stack1D"
class HDF5Stack1D(DataObject.DataObject):
@@ -82,10 +83,9 @@ class HDF5Stack1D(DataObject.DataObject):
That means scanlist = ["/whatever1"]
and selection['y'] = "/whatever2/counts"
"""
- if DEBUG:
- print("filelist = ", filelist)
- print("selection = ", selection)
- print("scanlist = ", scanlist)
+ _logger.debug("filelist = %s", filelist)
+ _logger.debug("selection = %s", selection)
+ _logger.debug("scanlist = %s", scanlist)
# all the files in the same source
hdfStack = NexusDataSource.NexusDataSource(filelist)
@@ -186,7 +186,7 @@ class HDF5Stack1D(DataObject.DataObject):
# this is the case of a selection inside a group
scanlist.append("1.%d" % i)
except KeyError:
- print("%s not in file, ignoring." % dirname)
+ _logger.warning("%s not in file, ignoring.", dirname)
if not len(scanlist):
if not ySelection.startswith("/"):
path = "/" + ySelection
@@ -231,9 +231,8 @@ class HDF5Stack1D(DataObject.DataObject):
if not nScans:
raise IOError("No entry contains the required data")
- if DEBUG:
- print("Retained number of files = %d" % nFiles)
- print("Retained number of scans = %d" % nScans)
+ _logger.debug("Retained number of files = %d", nFiles)
+ _logger.debug("Retained number of scans = %d", nScans)
# Now is to decide the number of mca ...
# I assume all the scans contain the same number of mca
@@ -264,8 +263,7 @@ class HDF5Stack1D(DataObject.DataObject):
numpy.float64]:
# Some datasets form CLS (origin APS?) arrive as data format
# equal to ">u2" and are not triggered as integer types
- if DEBUG:
- print("Not basic dataset type %s" % self.__dtype)
+ _logger.debug("Not basic dataset type %s", self.__dtype)
if ("%s" % self.__dtype).endswith("2"):
self.__dtype = numpy.float32
else:
@@ -279,8 +277,7 @@ class HDF5Stack1D(DataObject.DataObject):
mcaIndex = selection.get('index', len(shape)-1)
if mcaIndex == -1:
mcaIndex = len(shape) - 1
- if DEBUG:
- print("mcaIndex = %d" % mcaIndex)
+ _logger.debug("mcaIndex = %d", mcaIndex)
considerAsImages = False
dim0, dim1, mcaDim = self.getDimensions(nFiles, nScans, shape,
index=mcaIndex)
@@ -328,9 +325,9 @@ class HDF5Stack1D(DataObject.DataObject):
except (MemoryError, ValueError):
# some versions report ValueError instead of MemoryError
if (nFiles == 1) and (len(shape) == 3):
- print("Attempting dynamic loading")
+ _logger.warning("Attempting dynamic loading")
if mSelection is not None:
- print("Ignoring monitor")
+ _logger.warning("Ignoring monitor")
self.data = yDataset
if mSelection is not None:
mdtype = tmpHdf[mpath].dtype
@@ -442,7 +439,7 @@ class HDF5Stack1D(DataObject.DataObject):
n = nStart
if IN_MEMORY == False:
# We can only deal with one dynamic dataset
- print("Selection %s ignored" % ySelection)
+ _logger.warning("Selection %s ignored", ySelection)
continue
if JUST_KEYS:
entryName = goodEntryNames[int(scan.split(".")[-1])-1]
@@ -528,8 +525,8 @@ class HDF5Stack1D(DataObject.DataObject):
case = 0
_time[nStart: nStart + nMcaInYDataset] += timeData
if case == -1:
- print("I do not know how to handle this time data")
- print("Ignoring time information")
+ _logger.warning("I do not know how to handle this time data")
+ _logger.warning("Ignoring time information")
_time= None
if (len(yDataset.shape) == 3) and\
(dim1 == yDataset.shape[1]):
@@ -705,8 +702,8 @@ class HDF5Stack1D(DataObject.DataObject):
if i != mcaIndex:
nRequiredValues *= self.data.shape[i]
if _time.size != nRequiredValues:
- print("I do not know how to interpret the time information")
- print("Ignoring time information")
+ _logger.warning("I do not know how to interpret the time information")
+ _logger.warning("Ignoring time information")
_time = None
else:
_time.shape = -1
@@ -732,7 +729,7 @@ class HDF5Stack1D(DataObject.DataObject):
if xDataset.size == shape[self.info['McaIndex']]:
self.x = [xDataset.reshape(-1)]
else:
- print("Ignoring xSelection")
+ _logger.warning("Ignoring xSelection")
elif _channels is not None:
_channels.shape = -1
self.x = [_channels]
@@ -748,8 +745,7 @@ class HDF5Stack1D(DataObject.DataObject):
index = -1
if index == -1:
index = len(shape) - 1
- if DEBUG:
- print("INDEX = %d" % index)
+ _logger.debug("INDEX = %d", index)
#figure out the shape of the stack
if len(shape) == 0:
#a scalar?
@@ -780,9 +776,8 @@ class HDF5Stack1D(DataObject.DataObject):
nMca *= shape[i]
mcaDim = shape[index]
- if DEBUG:
- print("nMca = %d" % nMca)
- print("mcaDim = ", mcaDim)
+ _logger.debug("nMca = %d", nMca)
+ _logger.debug("mcaDim = %s", mcaDim)
# HDF allows to work directly from the files without loading
# them into memory.
diff --git a/PyMca5/PyMcaIO/JcampFileParser.py b/PyMca5/PyMcaIO/JcampFileParser.py
index 95b0e1b..fd8d910 100644
--- a/PyMca5/PyMcaIO/JcampFileParser.py
+++ b/PyMca5/PyMcaIO/JcampFileParser.py
@@ -31,32 +31,31 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
+import logging
import sys
import numpy
import mmap
import re
+import time
from PyMca5.PyMcaIO import JcampReader
from PyMca5.PyMcaIO import SpecFileAbstractClass
if sys.version < "3":
from StringIO import StringIO
else:
from io import StringIO
-DEBUG = 0
-if DEBUG:
- import time
+_logger = logging.getLogger(__name__)
+
class JcampFileParser(SpecFileAbstractClass.SpecFileAbstractClass):
def __init__(self, filename, single=False):
# get the number of entries in the file
self.__lastEntryData = -1
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if sys.maxsize > 2**32:
self._useMMap = True
else:
self._useMMap = False
- if DEBUG:
- print("USING MMPA = ", self._useMMap)
+ _logger.debug("USING MMPA = %s", self._useMMap)
if self._useMMap:
# 64-bit supported
f = open(filename, "rb")
@@ -95,18 +94,16 @@ class JcampFileParser(SpecFileAbstractClass.SpecFileAbstractClass):
current = f.tell()
line = f.readline()
f.close()
- if DEBUG:
- print("Elapsed CURRENT = ", time.time() - t0)
+ _logger.debug("Elapsed CURRENT = %s",
+ time.time() - t0)
self._filename = os.path.abspath(filename)
- if DEBUG:
- print("PARSING FIRST ")
- t0 = time.time()
+ _logger.debug("PARSING FIRST ")
+ t0 = time.time()
self._parseEntryData(0)
- if DEBUG:
- elapsed = time.time() - t0
- print("ELAPSED PER SCAN = ", elapsed)
- print("N SCANS = ", self.scanno())
- print("EXPECTED = ", elapsed * self.scanno())
+ elapsed = time.time() - t0
+ _logger.debug("ELAPSED PER SCAN = %s", elapsed)
+ _logger.debug("N SCANS = %s", self.scanno())
+ _logger.debug("EXPECTED = %s", elapsed * self.scanno())
def _parseEntryData(self, idx):
if idx == self.__lastEntryData:
@@ -141,7 +138,7 @@ class JcampFileParser(SpecFileAbstractClass.SpecFileAbstractClass):
try:
fileheader = instance._header
except:
- print("JCampFileParser cannot access '_header' attribute")
+ _logger.warning("JCampFileParser cannot access '_header' attribute")
fileheader=None
data = numpy.zeros((x.size, 2), numpy.float32)
data[:, 0] = x
diff --git a/PyMca5/PyMcaIO/JcampReader.py b/PyMca5/PyMcaIO/JcampReader.py
index c732101..654bf3d 100644
--- a/PyMca5/PyMcaIO/JcampReader.py
+++ b/PyMca5/PyMcaIO/JcampReader.py
@@ -61,16 +61,19 @@ import os
import sys
import re
import numpy
+import logging
+
patternKey=re.compile(r'^[#][#]\s*(?P<name>[^=]+)=(?P<value>.*)$')
#patternNumber = re.compile(r'([+-]?\d+\.?\d*)')
patternNumber = re.compile(r'[+-]?[0-9]+\.?[0-9]*(?:[eE][+-]?[0-9]+)?')
-DEBUG = 0
-if DEBUG:
- text = '1.23 +2 456-7.98+5 10+3.4E+01 98-7.6E-2+3'
- print("RESULT:")
- print(re.findall(patternNumber, text))
- print("EXPECTED:")
- print(['1.23', '+2', '456', '-7.98', '+5', '10', '+3.4E+01', '98', '-7.6E-2', '+3'])
+_logger = logging.getLogger(__name__)
+
+
+text = '1.23 +2 456-7.98+5 10+3.4E+01 98-7.6E-2+3'
+_logger.debug("RESULT:")
+_logger.debug("\t%s", re.findall(patternNumber, text))
+_logger.debug("EXPECTED:")
+_logger.debug("\t%s", ['1.23', '+2', '456', '-7.98', '+5', '10', '+3.4E+01', '98', '-7.6E-2', '+3'])
class BufferedFile(object):
def __init__(self, filenameOrBuffer, block=False):
@@ -193,7 +196,7 @@ class JcampReader(object):
deltaX = float(self.info["DELTAX"])
nPoints = int(self.info.get("NPOINTS", 0))
if nPoints != len(yValues):
- print("Number of points does not match number of values")
+ _logger.warning("Number of points does not match number of values")
nPoints = len(yValues)
# this formula is given in the article
x = firstX + numpy.arange(nPoints) * \
@@ -251,7 +254,7 @@ class JcampReader(object):
deltaX = float(self.info["DELTAX"])
nPoints = int(self.info.get("NPOINTS", 0))
if nPoints != len(yValues):
- print("Number of points does not match number of values")
+ _logger.warning("Number of points does not match number of values")
nPoints = len(yValues)
# this formula is given in the article
x = firstX + numpy.arange(nPoints) * \
diff --git a/PyMca5/PyMcaIO/LispixMap.py b/PyMca5/PyMcaIO/LispixMap.py
index 28732f0..79e0b94 100644
--- a/PyMca5/PyMcaIO/LispixMap.py
+++ b/PyMca5/PyMcaIO/LispixMap.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2015 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -34,9 +34,11 @@ import os
import sys
import struct
import numpy
+import logging
from PyMca5 import DataObject
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
SOURCE_TYPE = "EdfFileStack"
class LispixMap(DataObject.DataObject):
@@ -187,7 +189,7 @@ class LispixMap(DataObject.DataObject):
self.data.shape = rows, columns, channels
mcaIndex = 2
else:
- print("Assuming spectra")
+ _logger.info("Assuming spectra")
self.data.shape = rows, columns, channels
mcaIndex = 2
@@ -211,16 +213,17 @@ def _getDataAndDescriptionFileName(filename):
If the associated file is not existing, it returns None.
"""
- if filename.lower().endswith("raw"):
+ tmpFileName = filename.lower()
+ if tmpFileName.endswith("raw"):
dataDile = filename
headerFile = filename[:-3] + "rpl"
else:
headerFile = filename
- if not os.path.exists(headerFile):
- headerFile = None
+ if os.path.exists(headerFile):
+ dataFile = headerFile[:-3] + "raw"
else:
- headerFile = filename
- dataFile = filename[:-3] + "raw"
+ headerFile = ".rpl file not found"
+ dataFile = ".raw file not found"
return dataFile, headerFile
def _parseHeaderFile(headerFile):
@@ -239,15 +242,17 @@ def _parseHeaderFile(headerFile):
record-by vector # image, vector, or dont-care
"""
- data = open(headerFile, "r").readlines()
- numericKeyList = ["width", "Width",
- "height", "Height",
- "depth", "Depth",
- "offset", "Offset",
- "data-length", "Data-length"]
- asciiKeyList = ["data-type", "Data-type",
- "byte-order", "Byte-order",
- "record-by", "Record-by"]
+ f = open(headerFile, "r")
+ data = f.readlines()
+ f.close()
+ numericKeyList = ["width",
+ "height",
+ "depth",
+ "offset",
+ "data-length"]
+ asciiKeyList = ["data-type",
+ "byte-order",
+ "record-by"]
otherKeys = []
description = {}
description["depth"] = 1
@@ -255,8 +260,9 @@ def _parseHeaderFile(headerFile):
description["data-length"] = 1
description["data-type"] = "unsigned"
description["byte-order"] = "little-endian"
- for line in data:
+ for tmpLine in data:
treated = False
+ line = tmpLine.lower()
for key in numericKeyList:
if line.startswith(key):
cleanLine = line.replace("\t", " ")
@@ -281,9 +287,7 @@ def _parseHeaderFile(headerFile):
if not treated:
content = line.replace("\t", " ")
if len(content.strip(" ")):
- if DEBUG:
- print("Ignored line:")
- print(line)
+ _logger.debug("Ignored line: %s", line)
return description
diff --git a/PyMca5/PyMcaIO/MRCMap.py b/PyMca5/PyMcaIO/MRCMap.py
index 4d0da68..9502256 100644
--- a/PyMca5/PyMcaIO/MRCMap.py
+++ b/PyMca5/PyMcaIO/MRCMap.py
@@ -30,19 +30,18 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-import os
import sys
-import re
import struct
import numpy
-import copy
+import logging
from PyMca5 import DataObject
if sys.version < '2.6':
def bytes(x):
return str(x)
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
SOURCE_TYPE = "EdfFileStack"
class MRCMap(DataObject.DataObject):
diff --git a/PyMca5/PyMcaIO/NumpyStack.py b/PyMca5/PyMcaIO/NumpyStack.py
index 87cf575..a0b517e 100644
--- a/PyMca5/PyMcaIO/NumpyStack.py
+++ b/PyMca5/PyMcaIO/NumpyStack.py
@@ -35,10 +35,8 @@ The purpose of using this class instead of using StackBase is to simplify the
use of McaAdvancedFitBatch with in-memory arrays.
"""
-import numpy
from PyMca5.PyMcaCore import DataObject
-DEBUG = 0
SOURCE_TYPE = "EdfFileStack"
class NumpyStack(DataObject.DataObject):
diff --git a/PyMca5/PyMcaIO/OlympusCSVFileParser.py b/PyMca5/PyMcaIO/OlympusCSVFileParser.py
index e90fb9e..56fd18e 100644
--- a/PyMca5/PyMcaIO/OlympusCSVFileParser.py
+++ b/PyMca5/PyMcaIO/OlympusCSVFileParser.py
@@ -33,8 +33,10 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class BufferedFile(object):
def __init__(self, filename):
@@ -184,9 +186,8 @@ class OlympusCSVScan(object):
a = "#S %d %s" % (self._number + 1, self.command())
return [a]
- def header(self,key):
- if DEBUG:
- print("Requested key = ", key)
+ def header(self, key):
+ _logger.debug("Requested key = %s", key)
if key in ['S', '#S']:
return self.fileheader()[0]
elif key == 'N':
diff --git a/PyMca5/PyMcaIO/OmnicMap.py b/PyMca5/PyMcaIO/OmnicMap.py
index 045d454..3eacc07 100644
--- a/PyMca5/PyMcaIO/OmnicMap.py
+++ b/PyMca5/PyMcaIO/OmnicMap.py
@@ -36,9 +36,12 @@ import re
import struct
import numpy
import copy
+import logging
from PyMca5 import DataObject
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
SOURCE_TYPE = "EdfFileStack"
@@ -79,9 +82,8 @@ class OmnicMap(DataObject.DataObject):
s = data[firstByte:(firstByte + 100 - 16)]
if sys.version >= '3.0':
s = str(s)
- if DEBUG:
- print("firstByte = %d" % firstByte)
- print("s1 = %s " % s)
+ _logger.debug("firstByte = %d", firstByte)
+ _logger.debug("s1 = %s ", s)
exp = re.compile('(-?[0-9]+\.?[0-9]*)')
tmpValues = exp.findall(s)
spectrumIndex = int(tmpValues[0])
@@ -92,20 +94,17 @@ class OmnicMap(DataObject.DataObject):
else:
# I have to calculate them from the scan
xPosition, yPosition = self.getPositionFromIndexAndInfo(0, omnicInfo)
- if DEBUG:
- print("spectrumIndex, nSpectra, xPosition, yPosition = %d %d %f %f" %\
- (spectrumIndex, self.nSpectra, xPosition, yPosition))
+ _logger.debug("spectrumIndex, nSpectra, xPosition, yPosition = %d %d %f %f",
+ spectrumIndex, self.nSpectra, xPosition, yPosition)
if sys.version < '3.0':
chain = "Spectrum"
else:
chain = bytes("Spectrum", 'utf-8')
secondByte = data[(firstByte + 1):].index(chain)
secondByte += firstByte + 1
- if DEBUG:
- print("secondByte = ", secondByte)
+ _logger.debug("secondByte = %s", secondByte)
self.nChannels = int((secondByte - firstByte - 100) / 4)
- if DEBUG:
- print("nChannels = %d" % self.nChannels)
+ _logger.debug("nChannels = %d", self.nChannels)
self.firstSpectrumOffset = firstByte - 16
#fill the header
@@ -130,10 +129,9 @@ class OmnicMap(DataObject.DataObject):
if (abs(yPosition - oldYPosition) > 1.0e-6) and\
(abs(xPosition - oldXPosition) < 1.0e-6):
break
- self.nRows = self.nRows + 1
- if DEBUG:
- print("DIMENSIONS X = %f Y=%d" %\
- ((self.nSpectra * 1.0) / self.nRows, self.nRows))
+ self.nRows += 1
+ _logger.debug("DIMENSIONS X = %f Y=%d",
+ self.nSpectra * 1.0 / self.nRows, self.nRows)
#arrange as an EDF Stack
self.info = {}
@@ -214,9 +212,8 @@ class OmnicMap(DataObject.DataObject):
ddict['Laser frequency'] = vFloats[16]
ddict['Data spacing'] = (lastX - firstX) / (ddict['Number of points'] - 1.0)
ddict['Background gain'] = vFloats[10]
- if DEBUG:
- for key in ddict.keys():
- print(key, ddict[key])
+ for key in ddict.keys():
+ _logger.debug("%s: %s", key, ddict[key])
ddict.update(self.getMapInformation(data))
return ddict
@@ -257,9 +254,8 @@ class OmnicMap(DataObject.DataObject):
ddict['Mapping stage X step size'] = deltaX
ddict['Mapping stage Y step size'] = deltaY
ddict['Number of spectra'] = abs((1 + ((y1 - y0) / deltaY)) * (1 + ((x1 - x0) / deltaX)))
- if DEBUG:
- for key in ddict.keys():
- print(key, ddict[key])
+ for key in ddict.keys():
+ _logger.debug("%s: %s", key, ddict[key])
return ddict
def getOmnicInfo(self):
@@ -302,7 +298,7 @@ class OmnicMap(DataObject.DataObject):
if __name__ == "__main__":
filename = None
if len(sys.argv) > 2:
- DEBUG = int(sys.argv[2])
+ _logger.setLevel(logging.DEBUG)
if len(sys.argv) > 1:
filename = sys.argv[1]
elif os.path.exists("SambaPhg_IR.map"):
diff --git a/PyMca5/PyMcaIO/PilatusCBF.py b/PyMca5/PyMcaIO/PilatusCBF.py
index 9c6f260..12f7b03 100644
--- a/PyMca5/PyMcaIO/PilatusCBF.py
+++ b/PyMca5/PyMcaIO/PilatusCBF.py
@@ -49,7 +49,8 @@ else:
import io
_fileClass = io.IOBase
-DEBUG = False
+_logger = logging.getLogger(__name__)
+
DATA_TYPES = { "signed 8-bit integer" : np.int8,
"signed 16-bit integer" : np.int16,
@@ -135,8 +136,7 @@ class PilatusCBF(object):
if item not in self.__header.keys():
missing.append(item)
if len(missing) > 0:
- if DEBUG:
- print("CBF file misses the keys " + " ".join(missing))
+ _logger.debug("CBF file misses the keys %s", " ".join(missing))
def _readbinary_byte_offset(self, inStream):
"""
@@ -241,7 +241,7 @@ class PilatusCBF(object):
except KeyError:
bytecode = np.int32
self.bpp = 32
- logging.warning("Defaulting type to int32")
+ _logger.warning("Defaulting type to int32")
if self.__header["conversions"] == "x-CBF_BYTE_OFFSET":
self.__data = self._readbinary_byte_offset(self.cif["_array_data.data"]).astype(bytecode).reshape((self.dim2, self.dim1))
@@ -298,7 +298,7 @@ class CIF(dict):
@return the
"""
if not os.path.isfile(_strFilename):
- print("I cannot find the file %s" % _strFilename)
+ _logger.error("I cannot find the file %s", _strFilename)
raise IOError("I cannot find the file %s" % _strFilename)
if _bKeepComment:
self._parseCIF(open(_strFilename, "rb").read())
@@ -335,7 +335,7 @@ class CIF(dict):
@rtype: string
"""
if not os.path.isfile(_strFilename):
- print("I cannot find the file %s" % _strFilename)
+ _logger.error("I cannot find the file %s", _strFilename)
raise IOError("I cannot find the file %s" % _strFilename)
lLinesRead = open(_strFilename, "r").readlines()
sText = ""
@@ -345,12 +345,14 @@ class CIF(dict):
if CIF.isAscii(sLine):
sText += sLine[:iPos] + "\n"
- if iPos > 80 :
- print("Warning, this line is too long and could cause problems in PreQuest\n", sLine)
+ if iPos > 80:
+ _logger.warning("Warning, this line is too long and could cause problems in PreQuest\n"
+ "%s", sLine)
else :
sText += sLine
if len(sLine.strip()) > 80 :
- print("Warning, this line is too long and could cause problems in PreQuest\n", sLine)
+ _logger.warning("Warning, this line is too long and could cause problems in PreQuest\n"
+ "%s", sLine)
return sText
@@ -564,13 +566,13 @@ class CIF(dict):
try:
fFile = open(_strFilename, "w")
except IOError:
- print("Error during the opening of file for write : %s" % _strFilename)
+ _logger.error("Error during the opening of file for write : %s", _strFilename)
return
fFile.write(self._cif2str(_strFilename))
try:
fFile.close()
except IOError:
- print("Error during the closing of file for write : %s" % _strFilename)
+ _logger.error("Error during the closing of file for write : %s", _strFilename)
raise
@@ -683,7 +685,7 @@ class CIF(dict):
@rtype: dictionnary
"""
if not os.path.isfile(_strFilename):
- print("I cannot find the file %s" % _strFilename)
+ _logger.error("I cannot find the file %s", _strFilename)
raise IOError("I cannot find the file %s" % _strFilename)
lInFile = open(_strFilename, "r").readlines()
self["_audit_creation_method"] = 'From 2-D detector using FIT2D and CIFfile'
@@ -744,8 +746,6 @@ class CIF(dict):
return False
if __name__ == "__main__":
- import os
- import sys
from PyMca5 import EdfFile
#fd = open('Cu_ZnO_20289.mccd', 'rb')
filename = sys.argv[1]
diff --git a/PyMca5/PyMcaIO/SRSFileParser.py b/PyMca5/PyMcaIO/SRSFileParser.py
index c809d25..dbda936 100644
--- a/PyMca5/PyMcaIO/SRSFileParser.py
+++ b/PyMca5/PyMcaIO/SRSFileParser.py
@@ -33,9 +33,11 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaIO import SpecFileAbstractClass
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class BufferedFile(object):
def __init__(self, filename):
@@ -105,8 +107,7 @@ class SRSFileParser(object):
labels = line[:-1].replace("\t", " ").split(" ")
readingData = True
else:
- if DEBUG:
- print("Unhandled line %s" % line[:-1])
+ _logger.debug("Unhandled line %s", line[:-1])
line = _fileObject.readline()
header.append("#N %d" % len(labels))
txt = "#L "
diff --git a/PyMca5/PyMcaIO/SpecFileAbstractClass.py b/PyMca5/PyMcaIO/SpecFileAbstractClass.py
index 868e7e5..37f07fa 100644
--- a/PyMca5/PyMcaIO/SpecFileAbstractClass.py
+++ b/PyMca5/PyMcaIO/SpecFileAbstractClass.py
@@ -38,7 +38,12 @@ It can be used to wrap other formats as specile
"""
import os
import numpy
-DEBUG = 0
+import logging
+
+
+_logger = logging.getLogger(__name__)
+
+
class SpecFileAbstractClass(object):
def __init__(self, filename):
if not os.path.exists(filename):
@@ -50,16 +55,14 @@ class SpecFileAbstractClass(object):
If there is only one scan returns 1:1
with two scans returns 1:2
"""
- if DEBUG:
- print("list method called")
+ _logger.debug("list method called")
return "1:1"
def __getitem__(self, item):
"""
Returns the scan data
"""
- if DEBUG:
- print("__getitem__ called")
+ _logger.debug("__getitem__ called")
return self.scandata[item]
def select(self, key):
@@ -139,8 +142,7 @@ class SpecFileAbstractScan(object):
return self.__cols
def command(self):
- if DEBUG:
- print("command called")
+ _logger.debug("command called")
text = ""
if self.scanheader is not None:
if len(self.scanheader):
@@ -162,8 +164,7 @@ class SpecFileAbstractScan(object):
return text
def fileheader(self):
- if DEBUG:
- print("file header called")
+ _logger.debug("file header called")
labels = '#L '
for label in self.labels:
labels += ' '+label
@@ -173,8 +174,7 @@ class SpecFileAbstractScan(object):
else:
return ['#S 1 Unknown command']
else:
- if DEBUG:
- print("returning ",self.scanheader)
+ _logger.debug("returning %s", self.scanheader)
return self.scanheader
def header(self,key):
diff --git a/PyMca5/PyMcaIO/SpecFileStack.py b/PyMca5/PyMcaIO/SpecFileStack.py
index 1b51b11..24ca907 100644
--- a/PyMca5/PyMcaIO/SpecFileStack.py
+++ b/PyMca5/PyMcaIO/SpecFileStack.py
@@ -33,6 +33,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaCore import DataObject
from PyMca5.PyMcaIO import specfilewrapper as specfile
from PyMca5.PyMcaCore import SpecFileDataSource
@@ -44,12 +45,14 @@ try:
except:
pass
SOURCE_TYPE = "SpecFileStack"
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
X_AXIS = 0
Y_AXIS = 1
Z_AXIS = 2
+
class SpecFileStack(DataObject.DataObject):
def __init__(self, filelist=None):
DataObject.DataObject.__init__(self)
@@ -299,10 +302,10 @@ class SpecFileStack(DataObject.DataObject):
for i in range(5):
print("\7")
sampling_order += 1
- print("**************************************************")
- print(" Memory error!, attempting %dx%d sub-sampling " % \
- (sampling_order, sampling_order))
- print("**************************************************")
+ _logger.warning("**************************************************")
+ _logger.warning(" Memory error!, attempting %dx%d sub-sampling ",
+ sampling_order, sampling_order)
+ _logger.warning("**************************************************")
s0 = int(shape[0] / sampling_order)
s1 = int(shape[1] / sampling_order)
#if shape[0] % sampling_order:
@@ -323,8 +326,8 @@ class SpecFileStack(DataObject.DataObject):
tempInstance = specfile.Specfile(tempFileName)
if tempInstance is None:
if not os.path.exists(tempFileName):
- print("File %s does not exists" % tempFileName)
- raise IOError( \
+ _logger.error("File %s does not exists", tempFileName)
+ raise IOError(
"File %s does not exists" % tempFileName)
scan = tempInstance.select(keylist[-1])
for i in iterlist:
@@ -460,8 +463,8 @@ class SpecFileStack(DataObject.DataObject):
prefix = name[0:n - i + 1]
prefix = os.path.join(os.path.dirname(filename), prefix)
if not os.path.exists(prefix + number + suffix):
- print("Internal error in EDFStack")
- print("file should exist: %s" % (prefix + number + suffix))
+ _logger.warning("Internal error in EDFStack")
+ _logger.warning("file should exist: %s", prefix + number + suffix)
return
i = 0
if begin is None:
@@ -499,7 +502,7 @@ class SpecFileStack(DataObject.DataObject):
sourceInfo["KeyList"] = self.__keyList
def getKeyInfo(self, key):
- print("Not implemented")
+ _logger.info("Not implemented")
return {}
def isIndexedStack(self):
diff --git a/PyMca5/PyMcaIO/SupaVisioMap.py b/PyMca5/PyMcaIO/SupaVisioMap.py
index 8fb028c..0d92944 100644
--- a/PyMca5/PyMcaIO/SupaVisioMap.py
+++ b/PyMca5/PyMcaIO/SupaVisioMap.py
@@ -35,11 +35,14 @@ import os
import numpy
import struct
import time
+import logging
from PyMca5 import DataObject
from PyMca5.PyMcaIO import PyMcaIOHelper
-DEBUG = 0
-SOURCE_TYPE="EdfFileStack"
+
+_logger = logging.getLogger(__name__)
+
+SOURCE_TYPE = "EdfFileStack"
class SupaVisioMap(DataObject.DataObject):
def __init__(self, filename):
@@ -95,7 +98,7 @@ if __name__ == "__main__":
elif os.path.exists(".\PIGE\010826.pige"):
filename = ".\PIGE\010826.pige"
if filename is not None:
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
w = SupaVisioMap(filename)
else:
print("Please supply input filename")
diff --git a/PyMca5/PyMcaIO/TextImageStack.py b/PyMca5/PyMcaIO/TextImageStack.py
index b42c254..0a66dc4 100644
--- a/PyMca5/PyMcaIO/TextImageStack.py
+++ b/PyMca5/PyMcaIO/TextImageStack.py
@@ -33,10 +33,12 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
import sys
import os
+import logging
from PyMca5 import DataObject
SOURCE_TYPE = "EdfFileStack"
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class TextImageStack(DataObject.DataObject):
def __init__(self, filelist = None, imagestack=None, dtype=None):
@@ -82,9 +84,9 @@ class TextImageStack(DataObject.DataObject):
samplingStep = None
i = 2
while samplingStep is None:
- print("**************************************************")
- print(" Memory error!, attempting %dx%d sampling reduction ") % (i,i)
- print("**************************************************")
+ _logger.warning("**************************************************")
+ _logger.warning(" Memory error!, attempting %dx%d sampling reduction ", i, i)
+ _logger.warning("**************************************************")
s1, s2 = arrRet[::i, ::i].shape
try:
self.data = numpy.zeros((self.__nFiles, s1, s2),
@@ -178,8 +180,8 @@ class TextImageStack(DataObject.DataObject):
prefix = name[0:n-i+1]
prefix = os.path.join(os.path.dirname(filename),prefix)
if not os.path.exists(prefix + number + suffix):
- print("Internal error in EDFStack")
- print("file should exist: %s " % (prefix + number + suffix))
+ _logger.warning("Internal error in EDFStack")
+ _logger.warning("file should exist: %s ", prefix + number + suffix)
return
i = 0
if begin is None:
@@ -216,7 +218,7 @@ class TextImageStack(DataObject.DataObject):
sourceInfo["KeyList"]= self.__keyList
def getKeyInfo(self, key):
- print("Not implemented")
+ _logger.info("Not implemented")
return {}
def isIndexedStack(self):
diff --git a/PyMca5/PyMcaIO/ThermoEMSFileParser.py b/PyMca5/PyMcaIO/ThermoEMSFileParser.py
index c2a76ec..5a76012 100644
--- a/PyMca5/PyMcaIO/ThermoEMSFileParser.py
+++ b/PyMca5/PyMcaIO/ThermoEMSFileParser.py
@@ -33,8 +33,10 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class BufferedFile(object):
def __init__(self, filename):
@@ -211,9 +213,8 @@ class ThermoEMSScan(object):
#a = "#S %d %s" % (self._number + 1, self.command())
#return [a]
- def header(self,key):
- if DEBUG:
- print("Requested key = ", key)
+ def header(self, key):
+ _logger.debug("Requested key = %s", key)
if key in ['S', '#S']:
return self.fileheader()[0]
elif key == 'N':
diff --git a/PyMca5/PyMcaIO/TiffIO.py b/PyMca5/PyMcaIO/TiffIO.py
index c564135..3fc93b8 100644
--- a/PyMca5/PyMcaIO/TiffIO.py
+++ b/PyMca5/PyMcaIO/TiffIO.py
@@ -36,8 +36,10 @@ import sys
import os
import struct
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
ALLOW_MULTIPLE_STRIPS = False
TAG_ID = { 256:"NumberOfColumns", # S or L ImageWidth
@@ -158,8 +160,7 @@ class TiffIO(object):
if fortyTwo != 42:
raise IOError("Invalid TIFF version %d" % fortyTwo)
else:
- if DEBUG:
- print("VALID TIFF VERSION")
+ _logger.debug("VALID TIFF VERSION")
if sys.byteorder != fileOrder:
swap = True
else:
@@ -181,8 +182,7 @@ class TiffIO(object):
def __makeSureFileIsOpen(self):
if not self.fd.closed:
return
- if DEBUG:
- print("Reopening closed file")
+ _logger.debug("Reopening closed file")
fileName = self.fd.name
if self._access is None:
# we do not own the file
@@ -195,8 +195,7 @@ class TiffIO(object):
def __makeSureFileIsClosed(self):
if self._access is None:
# we do not own the file
- if DEBUG:
- print("Not closing not owned file")
+ _logger.debug("Not closing not owned file")
return
if not self.fd.closed:
@@ -230,25 +229,21 @@ class TiffIO(object):
offsetToIFD = 0
else:
offsetToIFD = struct.unpack(fmt, inStr)[0]
- if DEBUG:
- print("Offset to first IFD = %d" % offsetToIFD)
+ _logger.debug("Offset to first IFD = %d", offsetToIFD)
while offsetToIFD != 0:
self._IFD.append(offsetToIFD)
nImages += 1
fd.seek(offsetToIFD)
fmt = st + 'H'
numberOfDirectoryEntries = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Number of directory entries = %d" % numberOfDirectoryEntries)
+ _logger.debug("Number of directory entries = %d", numberOfDirectoryEntries)
fmt = st + 'I'
fd.seek(offsetToIFD + 2 + 12 * numberOfDirectoryEntries)
offsetToIFD = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Next Offset to IFD = %d" % offsetToIFD)
+ _logger.debug("Next Offset to IFD = %d", offsetToIFD)
# offsetToIFD = 0
- if DEBUG:
- print("Number of images found = %d" % nImages)
+ _logger.debug("Number of images found = %d", nImages)
return nImages
def _parseImageFileDirectory(self, nImage):
@@ -258,8 +253,7 @@ class TiffIO(object):
fd.seek(offsetToIFD)
fmt = st + 'H'
numberOfDirectoryEntries = struct.unpack(fmt,fd.read(struct.calcsize(fmt)))[0]
- if DEBUG:
- print("Number of directory entries = %d" % numberOfDirectoryEntries)
+ _logger.debug("Number of directory entries = %d", numberOfDirectoryEntries)
fmt = st + 'HHI4s'
tagIDList = []
@@ -292,15 +286,15 @@ class TiffIO(object):
valueOffsetList.append(actualValue)
else:
valueOffsetList.append(valueOffset)
- if DEBUG:
- if tagID in TAG_ID:
- print("tagID = %s" % TAG_ID[tagID])
- else:
- print("tagID = %d" % tagID)
- print("fieldType = %s" % FIELD_TYPE[fieldType][0])
- print("nValues = %d" % nValues)
- # if nValues == 1:
- # print("valueOffset = %s" % valueOffset)
+
+ if tagID in TAG_ID:
+ _logger.debug("tagID = %s", TAG_ID[tagID])
+ else:
+ _logger.debug("tagID = %d", tagID)
+ _logger.debug("fieldType = %s", FIELD_TYPE[fieldType][0])
+ _logger.debug("nValues = %d", nValues)
+ # if nValues == 1:
+ # print("valueOffset = %s" % valueOffset)
return tagIDList, fieldTypeList, nValuesList, valueOffsetList
def _readIFDEntry(self, tag, tagIDList, fieldTypeList, nValuesList, valueOffsetList):
@@ -332,8 +326,7 @@ class TiffIO(object):
try:
text = raw.decode("utf-8")
except UnicodeDecodeError:
- if DEBUG:
- print("TIFF file tag %d contains non ASCII/UTF-8 characters. " % tag)
+ _logger.debug("TIFF file tag %d contains non ASCII/UTF-8 characters. ", tag)
text = raw.decode("utf-8", errors='replace')
# Use a valid ASCII character to limit ferther encoding error
text = text.replace(u"\ufffd", "?")
@@ -363,8 +356,7 @@ class TiffIO(object):
def _readInfo(self, nImage, close=True):
if nImage in self._imageInfoCacheIndex:
- if DEBUG:
- print("Reading info from cache")
+ _logger.debug("Reading info from cache")
return self._imageInfoCache[self._imageInfoCacheIndex.index(nImage)]
# read the header
@@ -424,7 +416,7 @@ class TiffIO(object):
if TAG_PHOTOMETRIC_INTERPRETATION in tagIDList:
interpretation = valueOffsetList[tagIDList.index(TAG_PHOTOMETRIC_INTERPRETATION)]
else:
- print("WARNING: Non standard TIFF. Photometric interpretation TAG missing")
+ _logger.warning("WARNING: Non standard TIFF. Photometric interpretation TAG missing")
helpString = ""
@@ -483,13 +475,13 @@ class TiffIO(object):
tagIDList, fieldTypeList, nValuesList, valueOffsetList)[0]
else:
rowsPerStrip = nRows
- print("WARNING: Non standard TIFF. Rows per strip TAG missing")
+ _logger.warning("WARNING: Non standard TIFF. Rows per strip TAG missing")
if TAG_STRIP_BYTE_COUNTS in tagIDList:
stripByteCounts = self._readIFDEntry(TAG_STRIP_BYTE_COUNTS,
tagIDList, fieldTypeList, nValuesList, valueOffsetList)
else:
- print("WARNING: Non standard TIFF. Strip byte counts TAG missing")
+ _logger.warning("WARNING: Non standard TIFF. Strip byte counts TAG missing")
if hasattr(nBits, 'index'):
expectedSum = 0
for n in nBits:
@@ -509,8 +501,7 @@ class TiffIO(object):
interpretation = 1
# we cannot rely on any cache in this case
useInfoCache = False
- if DEBUG:
- print("FORCED MONO")
+ _logger.debug("FORCED MONO")
else:
useInfoCache = True
@@ -560,8 +551,7 @@ class TiffIO(object):
return info
def _readImage(self, nImage, **kw):
- if DEBUG:
- print("Reading image %d" % nImage)
+ _logger.debug("Reading image %d", nImage)
if 'close' in kw:
close = kw['close']
else:
@@ -569,8 +559,7 @@ class TiffIO(object):
rowMin = kw.get('rowMin', None)
rowMax = kw.get('rowMax', None)
if nImage in self._imageDataCacheIndex:
- if DEBUG:
- print("Reading image data from cache")
+ _logger.debug("Reading image data from cache")
return self._imageDataCache[self._imageDataCacheIndex.index(nImage)]
self.__makeSureFileIsOpen()
@@ -592,8 +581,7 @@ class TiffIO(object):
raise IOError("Compressed TIFF images not supported except packbits")
else:
# PackBits compression
- if DEBUG:
- print("Using PackBits compression")
+ _logger.debug("Using PackBits compression")
interpretation = info["photometricInterpretation"]
if interpretation == 2:
@@ -688,7 +676,7 @@ class TiffIO(object):
if nRows == rowsPerStrip:
actualBytesPerRow = int(image.nbytes / nRows)
if actualBytesPerRow != bytesPerRow:
- print("Warning: Bogus StripByteCounts information")
+ _logger.warning("Warning: Bogus StripByteCounts information")
bytesPerRow = actualBytesPerRow
nBytes = (rowMax-rowMin+1) * bytesPerRow
fd.seek(stripOffsets[0] + rowMin * bytesPerRow)
@@ -855,8 +843,7 @@ class TiffIO(object):
# get the image file directories
nImages = self.getImageFileDirectories()
- if DEBUG:
- print("File contains %d images" % nImages)
+ _logger.debug("File contains %d images", nImages)
if nImages == 0:
fd.seek(4)
fmt = st + 'I'
@@ -1093,8 +1080,7 @@ class TiffIO(object):
stripOffsetsString += struct.pack(fmt, value)
stripByteCountsString += struct.pack(fmt, stripByteCounts)
- if DEBUG:
- print("IMAGE WILL START AT %d" % stripOffsets[0])
+ _logger.debug("IMAGE WILL START AT %d", stripOffsets[0])
# sample format
if dtype in [numpy.float32, numpy.float64] or\
diff --git a/PyMca5/PyMcaIO/specfile/src/sfinit.c b/PyMca5/PyMcaIO/specfile/src/sfinit.c
index 7291427..3c3c517 100644
--- a/PyMca5/PyMcaIO/specfile/src/sfinit.c
+++ b/PyMca5/PyMcaIO/specfile/src/sfinit.c
@@ -1,5 +1,5 @@
# /*##########################################################################
-# Copyright (C) 1995-2017 European Synchrotron Radiation Facility
+# Copyright (C) 1995-2018 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
@@ -521,11 +521,12 @@ sfReadFile(SpecFile *sf,SfCursor *cursor,int *error) {
free(buffer);
sf->no_scans = cursor->scanno;
- /*
- * Save last
- */
- sfSaveScan(sf,cursor,error);
-
+ if (sf->no_scans > 0) {
+ /*
+ * Save last
+ */
+ sfSaveScan(sf,cursor,error);
+ }
return;
}
@@ -790,24 +791,21 @@ sfSaveScan(SpecFile *sf, SfCursor *cursor,int *error) {
static void
sfAssignScanNumbers(SpecFile *sf) {
- int size,i;
- char *buffer,*ptr;
-
- char buffer2[50];
+ int i;
+ char *ptr;
+ char buffer[50];
+ char buffer2[50];
register ObjectList *object,
*object2;
SpecScan *scan,
*scan2;
- size = 50;
- buffer = (char *) malloc(size);
-
for ( object = (sf->list).first; object; object=object->next) {
scan = (SpecScan *) object->contents;
lseek(sf->fd,scan->offset,SEEK_SET);
- read(sf->fd,buffer,size);
+ read(sf->fd,buffer,sizeof(buffer));
buffer[49] = '\0';
for ( ptr = buffer+3,i=0; *ptr != ' ';ptr++,i++) buffer2[i] = *ptr;
diff --git a/PyMca5/PyMcaIO/specfilewrapper.py b/PyMca5/PyMcaIO/specfilewrapper.py
index 44e82f9..7ba7653 100644
--- a/PyMca5/PyMcaIO/specfilewrapper.py
+++ b/PyMca5/PyMcaIO/specfilewrapper.py
@@ -34,6 +34,7 @@ import os
import sys
import numpy
import re
+import logging
from PyMca5.PyMcaIO import specfile
from PyMca5.PyMcaIO import Fit2DChiFileParser
from PyMca5.PyMcaIO import APSMEDFileParser
@@ -42,14 +43,16 @@ from PyMca5.PyMcaIO import BAXSCSVFileParser
from PyMca5.PyMcaIO import OlympusCSVFileParser
from PyMca5.PyMcaIO import ThermoEMSFileParser
from PyMca5.PyMcaIO import JcampFileParser
+
+_logger = logging.getLogger(__name__)
+
try:
from PyMca5.PyMcaIO import SPXFileParser
SPX = True
except:
- print("specfilewrapper cannot import SPXFileParser")
+ _logger.info("specfilewrapper cannot import SPXFileParser")
SPX = False
-DEBUG = 0
if sys.version >= '2.6':
def safe_str(bytesObject):
@@ -106,16 +109,13 @@ def Specfile(filename):
qxas = False
if len(line):
#it is a Specfile
- if DEBUG:
- print("This looks as a specfile")
+ _logger.debug("This looks as a specfile")
output=specfile.Specfile(filename)
elif SPX and filename.upper().endswith("SPX"):
- if DEBUG:
- print("This looks as an SPX file")
+ _logger.debug("This looks as an SPX file")
output = SPXFileParser.SPXFileParser(filename)
else:
- if DEBUG:
- print("this does not look as a specfile")
+ _logger.debug("this does not look as a specfile")
if len(line0) > 7:
if line0.startswith('$SPEC_ID') or\
line0.startswith('$DATE_MEA') or\
@@ -130,27 +130,22 @@ def Specfile(filename):
if (not qxas) and (not amptek) and APSMEDFileParser.isAPSMEDFile(filename):
return APSMEDFileParser.APSMEDFileParser(filename)
if (not qxas) and (not amptek) and SRSFileParser.isSRSFile(filename):
- if DEBUG:
- print("SRSFileParser")
+ _logger.debug("SRSFileParser")
return SRSFileParser.SRSFileParser(filename)
if (not qxas) and (not amptek) and BAXSCSVFileParser.isBAXSCSVFile(filename):
- if DEBUG:
- print("BAXSCSVFileParser")
+ _logger.debug("BAXSCSVFileParser")
return BAXSCSVFileParser.BAXSCSVFileParser(filename)
if (not qxas) and (not amptek) and \
OlympusCSVFileParser.isOlympusCSVFile(filename):
- if DEBUG:
- print("OlympusCSVFileParser")
+ _logger.debug("OlympusCSVFileParser")
return OlympusCSVFileParser.OlympusCSVFileParser(filename)
if (not qxas) and (not amptek) and \
ThermoEMSFileParser.isThermoEMSFile(filename):
- if DEBUG:
- print("ThermoEMSFileParser")
+ _logger.debug("ThermoEMSFileParser")
return ThermoEMSFileParser.ThermoEMSFileParser(filename)
if (not qxas) and (not amptek) and \
JcampFileParser.isJcampFile(filename):
- if DEBUG:
- print("JcampFileParser")
+ _logger.debug("JcampFileParser")
return JcampFileParser.JcampFileParser(filename)
output = specfilewrapper(filename, amptek=amptek, qxas=qxas)
return output
@@ -427,8 +422,7 @@ class myscandata(object):
return self.__cols
def command(self):
- if DEBUG:
- print("command called")
+ _logger.debug("command called")
if self.qxas is not None:
if 'S' in self.qxas:
text = self.qxas['S']
@@ -467,8 +461,7 @@ class myscandata(object):
def fileheader(self, key=''):
# key is there for compatibility
- if DEBUG:
- print("file header called")
+ _logger.debug("file header called")
return self._fileheader
def header(self, key):
diff --git a/PyMca5/PyMcaMath/SimpleMath.py b/PyMca5/PyMcaMath/SimpleMath.py
index 880c56b..e2dde53 100644
--- a/PyMca5/PyMcaMath/SimpleMath.py
+++ b/PyMca5/PyMcaMath/SimpleMath.py
@@ -31,8 +31,13 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from . import SGModule
+
+_logger = logging.getLogger(__name__)
+
+
class SimpleMath(object):
def derivate(self,xdata,ydata, xlimits=None):
x=numpy.array(xdata, copy=False, dtype=numpy.float)
@@ -87,9 +92,8 @@ class SimpleMath(object):
"""
if (len(xarr) != len(yarr)) or\
(len(xarr) == 0) or (len(yarr) == 0):
- if DEBUG:
- print('specAverage -- invalid input!')
- print('Array lengths do not match or are 0')
+ _logger.debug('specAverage -- invalid input!\n'
+ 'Array lengths do not match or are 0')
return None, None
same = True
@@ -139,9 +143,8 @@ class SimpleMath(object):
if xmax < xmax0:
xmax0 = xmax
if xmax <= xmin:
- if DEBUG:
- print('specAverage -- ')
- print('No overlap between spectra!')
+ _logger.debug('specAverage -- \n'
+ 'No overlap between spectra!')
return numpy.array([]), numpy.array([])
# make sure x0 is sorted
diff --git a/PyMca5/PyMcaMath/fitting/SimpleFitAll.py b/PyMca5/PyMcaMath/fitting/SimpleFitAll.py
index b340e17..d469c04 100644
--- a/PyMca5/PyMcaMath/fitting/SimpleFitAll.py
+++ b/PyMca5/PyMcaMath/fitting/SimpleFitAll.py
@@ -36,7 +36,6 @@ import logging
from PyMca5.PyMcaIO import ConfigDict
import PyMca5
-DEBUG = False
if sys.version_info < (3, ):
text_dtype = h5py.special_dtype(vlen=unicode)
@@ -177,7 +176,7 @@ class SimpleFitAll(object):
except:
_logger.error(
"Error %s processing index = %d", sys.exc_info()[1], i)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
self.onProcessSpectraFinished()
self._status = "Ready"
diff --git a/PyMca5/PyMcaMath/fitting/SimpleFitModule.py b/PyMca5/PyMcaMath/fitting/SimpleFitModule.py
index 6cfde86..2a4e705 100644
--- a/PyMca5/PyMcaMath/fitting/SimpleFitModule.py
+++ b/PyMca5/PyMcaMath/fitting/SimpleFitModule.py
@@ -37,13 +37,16 @@ import copy
import logging
import glob
import types
+import logging
from . import Gefit
from . import SpecfitFuns
from PyMca5 import getDefaultUserFitFunctionsDirectory
_logger = logging.getLogger(__name__)
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
class SimpleFit(object):
@@ -121,7 +124,7 @@ class SimpleFit(object):
if ffile is not None:
self.importFunctions(ffile)
else:
- print("WARNING:Function %s not among defined functions" % fName)
+ _logger.warning("WARNING:Function %s not among defined functions", fName)
continue
self._fitConfiguration['functions'][fName]['configuration']=\
ddict['functions'][fName]['configuration']
@@ -135,8 +138,7 @@ class SimpleFit(object):
return
if (oldConfig['fit']['xmin'] != self._fitConfiguration['fit']['xmin']) or\
(oldConfig['fit']['xmax'] != self._fitConfiguration['fit']['xmax']):
- if DEBUG:
- print("SETTING DATA AGAIN")
+ _logger.debug("SETTING DATA AGAIN")
self.setData(self._x0, self._y0,
xmin=self._fitConfiguration['fit']['xmin'],
xmax=self._fitConfiguration['fit']['xmax'])
@@ -145,15 +147,13 @@ class SimpleFit(object):
for key in ['strip_flag', 'stripanchorsflag', 'stripalgorithm',
'stripwidth', 'stripiterations', 'stripconstant']:
if oldConfig['fit'][key] != self._fitConfiguration['fit'][key]:
- if DEBUG:
- print("RECALCULATING STRIP")
+ _logger.debug("RECALCULATING STRIP")
self._getStripBackground()
break
if key == 'stripanchorsflag':
if len(oldConfig['fit']['stripanchorslist']) !=\
len(self._fitConfiguration['fit']['stripanchorslist']):
- if DEBUG:
- print("ANCHORS CHANGE, RECALCULATING STRIP")
+ _logger.debug("ANCHORS CHANGE, RECALCULATING STRIP")
self._getStripBackground()
break
@@ -204,8 +204,7 @@ class SimpleFit(object):
self._fitConfiguration['fit']['xmax'] = xmax * 1.0
if sigma is not None:
self._sigma = self._sigma0[idx]
- if DEBUG:
- print("TODO: Make sure we have something to fit")
+ _logger.debug("TODO: Make sure we have something to fit")
#get strip/SNIP background
self._z = self._getStripBackground()
@@ -427,8 +426,7 @@ class SimpleFit(object):
#SNIP algorithm
if self._fitConfiguration['fit']['stripalgorithm'] in ["SNIP", 1]:
- if DEBUG:
- print("CALCULATING SNIP")
+ _logger.debug("CALCULATING SNIP")
if len(anchorslist) == 0:
anchorslist = [0, len(ysmooth)-1]
anchorslist.sort()
@@ -448,15 +446,14 @@ class SimpleFit(object):
#strip background
niter = self._fitConfiguration['fit']['stripiterations']
if niter > 0:
- if DEBUG:
- print("CALCULATING STRIP")
- print("iterations = ", niter)
- print("constant = ",
- self._fitConfiguration['fit']['stripconstant'])
- print("width = ",
- self._fitConfiguration['fit']['stripwidth'])
- print("anchors = ", anchorslist)
- result=SpecfitFuns.subac(ysmooth,
+ _logger.debug("CALCULATING STRIP")
+ _logger.debug("iterations = ", niter)
+ _logger.debug("constant = %s",
+ self._fitConfiguration['fit']['stripconstant'])
+ _logger.debug("width = %s",
+ self._fitConfiguration['fit']['stripwidth'])
+ _logger.debug("anchors = %s", anchorslist)
+ result = SpecfitFuns.subac(ysmooth,
self._fitConfiguration['fit']['stripconstant'],
niter,
self._fitConfiguration['fit']['stripwidth'],
@@ -476,8 +473,7 @@ class SimpleFit(object):
1,
anchorslist)
else:
- if DEBUG:
- print("NO STRIP, NO SNIP")
+ _logger.debug("NO STRIP, NO SNIP")
result = numpy.zeros(ysmooth.shape, numpy.float) + min(ysmooth)
return result
@@ -538,9 +534,8 @@ class SimpleFit(object):
self.estimateFunction()
fitFunctionDict = self._fitConfiguration['functions']\
[fitFunction]
- if DEBUG:
- print("ESTIMATION parameters = ",functionParameters)
- print("ESTIMATION constraints = ",functionConstraints)
+ _logger.debug("ESTIMATION parameters = %s", functionParameters)
+ _logger.debug("ESTIMATION constraints = %s", functionConstraints)
self._setStatus("Fit function estimation finished")
#estimations are made
@@ -717,8 +712,7 @@ class SimpleFit(object):
weightflag = 0
else:
weightflag = 1
- if DEBUG:
- print("STILL TO HANDLE DERIVATIVES")
+ _logger.debug("STILL TO HANDLE DERIVATIVES")
model_deriv = self.modelFunctionDerivative
if self._fitConfiguration['fit']['strip_flag']:
y = self._y - self._z
@@ -727,7 +721,7 @@ class SimpleFit(object):
self._fitResult = None
if not flagconstrained:
param_constrains = []
- if DEBUG:
+ try:
result = Gefit.LeastSquaresFit(self.modelFunction,param_val,
xdata=self._x,
ydata=y,
@@ -736,26 +730,18 @@ class SimpleFit(object):
weightflag=weightflag,
model_deriv=model_deriv,
fulloutput=True)
- else:
- try:
- result = Gefit.LeastSquaresFit(self.modelFunction,param_val,
- xdata=self._x,
- ydata=y,
- sigmadata=self._sigma,
- constrains=param_constrains,
- weightflag=weightflag,
- model_deriv=model_deriv,
- fulloutput=True)
- except:
- text = sys.exc_info()[1]
- if type(text) is not type(" "):
- text = text.args
- if len(text):
- text = text[0]
- else:
- text = ''
- self._setStatus('Fit error : %s' %text)
+ except:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
+ text = sys.exc_info()[1]
+ if type(text) is not type(" "):
+ text = text.args
+ if len(text):
+ text = text[0]
+ else:
+ text = ''
+ self._setStatus('Fit error : %s' %text)
+ raise
self._fitResult = {}
self._fitResult['fit_function'] = self.getFitFunction()
@@ -766,16 +752,15 @@ class SimpleFit(object):
self._fitResult['niter'] = result[3]
self._fitResult['lastdeltachi'] = result[4]
self._fitResult['n_background_parameters'] = self.__nBackgroundParameters
- if DEBUG:
- print("Found parameters = ", self._fitResult['fittedvalues'])
- i=0
+ _logger.debug("Found parameters = %s", self._fitResult['fittedvalues'])
+ i = 0
self._fitResult['parameters'] = []
for param in self.paramlist:
- if param['code'] != 'IGNORE':
- self._fitResult['parameters'].append(param['name'])
- param['fitresult'] = result[0][i]
- param['sigma']= result[2][i]
- i = i + 1
+ if param['code'] != 'IGNORE':
+ self._fitResult['parameters'].append(param['name'])
+ param['fitresult'] = result[0][i]
+ param['sigma'] = result[2][i]
+ i += 1
self._setStatus("Fit finished")
return result
@@ -836,7 +821,7 @@ class SimpleFit(object):
try:
y += self._z
except:
- print("Cannot add strip background")
+ _logger.warning("Cannot add strip background")
return y
def _evaluateFunction(self, x=None):
@@ -917,5 +902,5 @@ def test():
a.exec_()
if __name__=="__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
test()
diff --git a/PyMca5/PyMcaMath/fitting/Specfit.py b/PyMca5/PyMcaMath/fitting/Specfit.py
index d238afe..abad09b 100644
--- a/PyMca5/PyMcaMath/fitting/Specfit.py
+++ b/PyMca5/PyMcaMath/fitting/Specfit.py
@@ -33,10 +33,15 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from . import SpecfitFuns
from .Gefit import LeastSquaresFit
from PyMca5.PyMcaCore import EventHandler
-DEBUG = 0
+
+
+_logger = logging.getLogger(__name__)
+
+
class Specfit(object):
#def __init__(self,x=None,y=None,sigmay=None):
def __init__(self, *vars, **kw):
@@ -576,9 +581,8 @@ class Specfit(object):
try:
theory=newfun.THEORY
except:
- if DEBUG:
- print("No theory name")
- theory="%s" % file
+ _logger.debug("No theory name")
+ theory = "%s" % file
try:
parameters=newfun.PARAMETERS
except:
@@ -631,7 +635,7 @@ class Specfit(object):
#tkMessageBox.showerror('Error',"Problem implementing user theory")
badluck=1
if badluck:
- print("ERROR IMPORTING")
+ _logger.warning("ERROR IMPORTING")
return badluck
def startfit(self,mcafit=0):
@@ -800,7 +804,7 @@ class Specfit(object):
try:
idx = numpy.nonzero((self.xdata>=x[0]) & (self.xdata<=x[-1]))[0]
except:
- print("ERROR ",x)
+ _logger.warning("ERROR %s", x)
yy=numpy.take(self.ydata,idx)
nrx=numpy.shape(x)[0]
nry=numpy.shape(yy)[0]
@@ -912,7 +916,7 @@ class Specfit(object):
if self.fitconfig['fittheory'] is not None:
error = self.settheory(self.fitconfig[key])
if error:
- print("ERROR on background and/or theory configuration")
+ _logger.warning("ERROR on background and/or theory configuration")
result.update(self.fitconfig)
return result
@@ -951,9 +955,8 @@ class Specfit(object):
y = self.ydata0
if 'debug' in kw:
- mcadebug = 1
- else:
- mcadebug = 0
+ _logger.setLevel(logging.DEBUG)
+
if 'Yscaling' in kw:
if kw['Yscaling'] is not None:
yscaling=kw['Yscaling']
@@ -1004,14 +1007,12 @@ class Specfit(object):
sensitivity)
for idx in peaksidx:
peaks.append(self.xdata[int(idx)])
- if mcadebug:
- print("MCA Found peaks = ",peaks)
+ _logger.debug("MCA Found peaks = %s", peaks)
if len(peaks):
regions=self.mcaregions(peaks,self.xdata[fwhm]-self.xdata[0])
else:
regions=[]
- if mcadebug:
- print(" regions = ",regions)
+ _logger.debug(" regions = %s", regions)
#if the function needs a scaling just give it
#removed estimate should deal with it
#self.configure(Yscaling=yscaling,yscaling=yscaling)
diff --git a/PyMca5/PyMcaMath/fitting/SpecfitFunctions.py b/PyMca5/PyMcaMath/fitting/SpecfitFunctions.py
index ad443af..f2ed4bd 100644
--- a/PyMca5/PyMcaMath/fitting/SpecfitFunctions.py
+++ b/PyMca5/PyMcaMath/fitting/SpecfitFunctions.py
@@ -32,11 +32,13 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import numpy
+import logging
arctan = numpy.arctan
from PyMca5.PyMcaMath.fitting import SpecfitFuns
from PyMca5.PyMcaMath.fitting.Gefit import LeastSquaresFit
-DEBUG=0
+_logger = logging.getLogger(__name__)
+
try:
HOME=os.getenv('HOME')
@@ -276,7 +278,7 @@ class SpecfitFunctions(object):
ngauss=1
newpar=[]
for i in range(ngauss):
- print("Defining Gaussian numer %d " % (i+1))
+ _logger.info("Defining Gaussian numer %d ", i+1)
newpar.append(input('Height = '))
newpar.append(input('Position = '))
newpar.append(input('FWHM = '))
diff --git a/PyMca5/PyMcaMath/fitting/StackSimpleFit.py b/PyMca5/PyMcaMath/fitting/StackSimpleFit.py
index 41af8b8..866069e 100644
--- a/PyMca5/PyMcaMath/fitting/StackSimpleFit.py
+++ b/PyMca5/PyMcaMath/fitting/StackSimpleFit.py
@@ -33,12 +33,14 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaIO import ConfigDict
from . import SimpleFitModule
from PyMca5.PyMcaIO import ArraySave
from PyMca5 import PyMcaDirs
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackSimpleFit(object):
def __init__(self, fit=None):
@@ -181,9 +183,9 @@ class StackSimpleFit(object):
if self.mask[self._row, self._column]:
self.processStackData(i)
except:
- print("Error %s processing index = %d, row = %d column = %d" %\
- (sys.exc_info()[1], i, self._row, self._column))
- if DEBUG:
+ _logger.warning("Error %s processing index = %d, row = %d column = %d",
+ sys.exc_info()[1], i, self._row, self._column)
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
self.onProcessStackFinished()
self._status = "Ready"
@@ -195,12 +197,10 @@ class StackSimpleFit(object):
x, y, sigma, xmin, xmax = self.getFitInputValues(i)
self.fit.setData(x, y, sigma=sigma, xmin=xmin, xmax=xmax)
if self._parameters is None:
- if DEBUG:
- print("First estimation")
+ _logger.debug("First estimation")
self.fit.estimate()
elif self.__ALWAYS_ESTIMATE:
- if DEBUG:
- print("Estimation due to settings")
+ _logger.debug("Estimation due to settings")
self.fit.estimate()
self.estimateFinished()
values, chisq, sigma, niter, lastdeltachi = self.fit.startFit()
@@ -296,12 +296,10 @@ class StackSimpleFit(object):
return x, y, sigma, self.xMin, self.xMax
def estimateFinished(self):
- if DEBUG:
- print("Estimate finished")
+ _logger.debug("Estimate finished")
def aboutToGetStackData(self, idx):
- if DEBUG:
- print("New spectrum %d" % idx)
+ _logger.debug("New spectrum %d", idx)
self._currentFitIndex = idx
if self.progressCallback is not None:
self.progressCallback(idx, self._nRows * self._nColumns)
@@ -313,8 +311,7 @@ class StackSimpleFit(object):
os.remove(self.outputFile)
def fitFinished(self):
- if DEBUG:
- print("fit finished")
+ _logger.debug("fit finished")
#get parameter results
fitOutput = self.fit.getResult(configuration=False)
@@ -322,7 +319,7 @@ class StackSimpleFit(object):
row= self._row
column = self._column
if result is None:
- print("result not valid for row %d, column %d" % (row, column))
+ _logger.warning("result not valid for row %d, column %d", row, column)
return
if self.fixedLenghtOutput and (self._parameters is None):
@@ -402,8 +399,7 @@ class StackSimpleFit(object):
return ddict
def onProcessStackFinished(self):
- if DEBUG:
- print("Stack proccessed")
+ _logger.debug("Stack proccessed")
self._status = "Stack Fitting finished"
if self.fixedLenghtOutput:
self._status = "Writing output files"
@@ -457,5 +453,4 @@ def test():
instance.processStack()
if __name__=="__main__":
- DEBUG = 0
test()
diff --git a/PyMca5/PyMcaMath/mva/NNMAModule.py b/PyMca5/PyMcaMath/mva/NNMAModule.py
index 950ee9f..4e0a07e 100644
--- a/PyMca5/PyMcaMath/mva/NNMAModule.py
+++ b/PyMca5/PyMcaMath/mva/NNMAModule.py
@@ -184,6 +184,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import numpy
+import logging
try:
import os
os.environ["MDP_DISABLE_SKLEARN"] = "yes"
@@ -196,7 +197,10 @@ except:
MDP = False
from . import py_nnma
-DEBUG = 0
+
+
+_logger = logging.getLogger(__name__)
+
function_list = ['FNMAI', 'ALS', 'FastHALS', 'GDCLS']
function_dict = {"NNSC": py_nnma.NNSC,
@@ -211,8 +215,13 @@ function_dict = {"NNSC": py_nnma.NNSC,
"FastHALS": py_nnma.FastHALS,
"SNMF": py_nnma.SNMF,
}
+
+VERBOSE = _logger.getEffectiveLevel() == logging.DEBUG
+
+
def nnma(stack, ncomponents, binning=None,
- function=None, eps=5e-5, verbose=DEBUG, maxcount=1000, kmeans=False):
+ function=None, eps=5e-5, verbose=VERBOSE,
+ maxcount=1000, kmeans=False):
if kmeans and (not MDP):
raise ValueError("K Means not supported")
#I take the defaults for the other parameters
diff --git a/PyMca5/PyMcaMath/mva/PCAModule.py b/PyMca5/PyMcaMath/mva/PCAModule.py
index c159bb8..af02372 100644
--- a/PyMca5/PyMcaMath/mva/PCAModule.py
+++ b/PyMca5/PyMcaMath/mva/PCAModule.py
@@ -32,6 +32,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
import time
+import logging
import numpy
import numpy.linalg
try:
@@ -50,13 +51,15 @@ except:
from . import Lanczos
from . import PCATools
-DEBUG = 0
+
+
+_logger = logging.getLogger(__name__)
+
# Make these functions accept arguments not relevant to
# them in order to simplify having a common graphical interface
def lanczosPCA(stack, ncomponents=10, binning=None, legacy=True, **kw):
- if DEBUG:
- print("lanczosPCA")
+ _logger.debug("lanczosPCA")
if binning is None:
binning = 1
@@ -322,7 +325,7 @@ def multipleArrayPCA(stackList0, ncomponents=10, binning=None, legacy=True, **kw
totalVariance = numpy.diag(covMatrix).sum()
evalues, evectors = numpy.linalg.eigh(covMatrix)
covMatrix = None
- print("Total Variance = ", totalVariance.sum())
+ _logger.info("Total Variance = %s", totalVariance.sum())
images = numpy.zeros((ncomponents, npixels), numpy.float32)
eigenvectors = numpy.zeros((ncomponents, eigenvectorLength), numpy.float32)
@@ -377,8 +380,7 @@ def expectationMaximizationPCA(stack, ncomponents=10, binning=None, legacy=True,
"""
This is a fast method when the number of components is small
"""
- if DEBUG:
- print("expectationMaximizationPCA")
+ _logger.debug("expectationMaximizationPCA")
#This part is common to all ...
if binning is None:
binning = 1
@@ -466,8 +468,7 @@ def numpyPCA(stack, ncomponents=10, binning=None, legacy=True, **kw):
"""
This is a covariance method using numpy
"""
- if DEBUG:
- print("PCAModule.numpyPCA called")
+ _logger.debug("PCAModule.numpyPCA called")
if hasattr(stack, "info"):
index = stack.info.get('McaIndex', -1)
elif "index" in kw:
@@ -508,13 +509,12 @@ def mdpICAFloat64(stack, ncomponents=10, binning=None,
def mdpPCA(stack, ncomponents=10, binning=None, dtype='float64', svd='True',
mask=None, spectral_mask=None, legacy=True, **kw):
- if DEBUG:
- print("MDP Method")
- print("binning =", binning)
- print("dtype = ", dtype)
- print("svd = ", svd)
+ _logger.debug("MDP Method")
+ _logger.debug("binning = %s", binning)
+ _logger.debug("dtype = %s", dtype)
+ _logger.debug("svd = %s", svd)
for key in kw:
- print("mdpPCA Key ignored: %s" % key)
+ _logger.info("mdpPCA Key ignored: %s", key)
#This part is common to all ...
if binning is None:
binning = 1
@@ -620,14 +620,12 @@ def mdpPCA(stack, ncomponents=10, binning=None, dtype='float64', svd='True',
pca.train(data[:i, :])
else:
pca.train(data[:i, spectral_mask > 0])
- if DEBUG:
- print("Half training")
+ _logger.debug("Half training")
if spectral_mask is None:
pca.train(data[i:, :])
else:
pca.train(data[i:, spectral_mask > 0])
- if DEBUG:
- print("Full training")
+ _logger.debug("Full training")
else:
if spectral_mask is None:
pca.train(data)
@@ -729,14 +727,12 @@ def mdpICA(stack, ncomponents=10, binning=None, dtype='float64',
if 1:
if (mdp.__version__ >= "2.5"):
- if DEBUG:
- print("TDSEPNone")
+ _logger.debug("TDSEPNone")
ica = mdp.nodes.TDSEPNode(white_comp=ncomponents,
verbose=False,
dtype="float64",
white_parm={'svd': svd})
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
shape = data.shape
if len(data.shape) == 3:
if r > 10:
@@ -802,22 +798,19 @@ def mdpICA(stack, ncomponents=10, binning=None, dtype='float64',
ica.train(data[:i, :])
else:
ica.train(data[:i, spectral_mask > 0])
- if DEBUG:
- print("Half training")
+ _logger.debug("Half training")
if spectral_mask is None:
ica.train(data[i:, :])
else:
ica.train(data[i:, spectral_mask > 0])
- if DEBUG:
- print("Full training")
+ _logger.debug("Full training")
else:
if spectral_mask is None:
ica.train(data)
else:
ica.train(data[:, spectral_mask > 0])
ica.stop_training()
- if DEBUG:
- print("training elapsed = %f" % (time.time() - t0))
+ _logger.debug("training elapsed = %f", time.time() - t0)
else:
if 0:
print("ISFANode (alike)")
@@ -826,14 +819,12 @@ def mdpICA(stack, ncomponents=10, binning=None, dtype='float64',
dtype='float64',
white_parm={'svd':svd})
elif 1:
- if DEBUG:
- print("FastICANode")
+ _logger.debug("FastICANode")
ica = mdp.nodes.FastICANode(white_comp=ncomponents,
verbose=False,
dtype=dtype)
else:
- if DEBUG:
- print("CuBICANode")
+ _logger.debug("CuBICANode")
ica = mdp.nodes.CuBICANode(white_comp=ncomponents,
verbose=False,
dtype=dtype)
@@ -858,8 +849,8 @@ def mdpICA(stack, ncomponents=10, binning=None, dtype='float64',
if (len(data.shape) == 3):
images = numpy.zeros((2 * ncomponents, r, c), data.dtype)
for i in range(r):
- print("Building images. Projecting data %d out of %d" %\
- (i + 1, r))
+ _logger.info("Building images. Projecting data %d out of %d",
+ i + 1, r)
if binning > 1:
if spectral_mask is None:
tmpData = data[i, :, :]
diff --git a/PyMca5/PyMcaMath/mva/PCATools.py b/PyMca5/PyMcaMath/mva/PCATools.py
index 6882f67..85261ef 100644
--- a/PyMca5/PyMcaMath/mva/PCATools.py
+++ b/PyMca5/PyMcaMath/mva/PCATools.py
@@ -31,6 +31,8 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
+import time
import numpy
import numpy.linalg
try:
@@ -41,7 +43,8 @@ except ImportError:
#print("WARNING: Not using BLAS/ATLAS, PCA calculation will be slower")
dotblas = numpy
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
def getCovarianceMatrix(stack,
index=None,
@@ -157,8 +160,7 @@ def getCovarianceMatrix(stack,
eigenvectorLength = nChannels
if (not force)and isinstance(data, numpy.ndarray):
- if DEBUG:
- print("Memory consuming calculation")
+ _logger.debug("Memory consuming calculation")
#make a direct calculation (memory cosuming)
#take a view to the data
dataView = data[:]
@@ -197,8 +199,7 @@ def getCovarianceMatrix(stack,
return covMatrix, sumSpectrum / usedPixels, usedPixels
#we are dealing with dynamically loaded data
- if DEBUG:
- print("DYNAMICALLY LOADED DATA")
+ _logger.debug("DYNAMICALLY LOADED DATA")
#create the needed storage space for the covariance matrix
try:
covMatrix = numpy.zeros((eigenvectorLength, eigenvectorLength),
@@ -224,7 +225,7 @@ def getCovarianceMatrix(stack,
except AttributeError:
txt = "%s" % type(data)
if 'h5py' in txt:
- print("Implementing h5py workaround")
+ _logger.warning("Implementing h5py workaround")
import h5py
data = h5py.Dataset(data.id)
else:
@@ -246,8 +247,7 @@ def getCovarianceMatrix(stack,
if divider <= 0:
step = oldShape[index]
break
- if DEBUG:
- print("Reading chunks of %d images" % step)
+ _logger.debug("Reading chunks of %d images", step)
nImagesRead = 0
if (binning == 1) and oldShape[index] >= step:
chunk1 = numpy.zeros((step, nPixels), numpy.float64)
@@ -321,8 +321,7 @@ def getCovarianceMatrix(stack,
i += iToRead
chunk1 = None
chunk2 = None
- if DEBUG:
- print("totalImages Read = ", nImagesRead)
+ _logger.debug("totalImages Read = %s", nImagesRead)
elif (binning > 1) and (oldShape[index] >= step):
chunk1 = numpy.zeros((step, nPixels), numpy.float64)
chunk2 = numpy.zeros((nPixels, step), numpy.float64)
@@ -411,8 +410,7 @@ def getCovarianceMatrix(stack,
step = nPixels
break
step = nPixels
- if DEBUG:
- print("Reading chunks of %d spectra" % step)
+ _logger.debug("Reading chunks of %d spectra", step)
cleanWeights.shape = 1, -1
if len(data.shape) == 2:
@@ -537,11 +535,10 @@ def getCovarianceMatrix(stack,
def numpyPCA(stack, index=-1, ncomponents=10, binning=None,
center=True, scale=True, mask=None, spectral_mask=None, legacy=True, **kw):
- if DEBUG:
- print("PCATools.numpyPCA")
- print("index = %d" % index)
- print("center = %s" % center)
- print("scale = %s" % scale)
+ _logger.debug("PCATools.numpyPCA")
+ _logger.debug("index = %d", index)
+ _logger.debug("center = %s", center)
+ _logger.debug("scale = %s", scale)
#recover the actual data to work with
if hasattr(stack, "info") and hasattr(stack, "data"):
#we are dealing with a PyMca data object
@@ -573,7 +570,7 @@ def numpyPCA(stack, index=-1, ncomponents=10, binning=None,
except AttributeError:
txt = "%s" % type(data)
if 'h5py' in txt:
- print("Implementing h5py workaround")
+ _logger.warning("Implementing h5py workaround")
import h5py
data = h5py.Dataset(data.id)
else:
@@ -609,7 +606,7 @@ def numpyPCA(stack, index=-1, ncomponents=10, binning=None,
totalVariance = numpy.diag(cov)
standardDeviation = numpy.sqrt(totalVariance)
standardDeviation = standardDeviation + (standardDeviation == 0)
- print("Total Variance = ", totalVariance.sum())
+ _logger.info("Total Variance = %s", totalVariance.sum())
normalizeToUnitStandardDeviation = scale
if 0:
@@ -620,18 +617,18 @@ def numpyPCA(stack, index=-1, ncomponents=10, binning=None,
cov[i, :] /= numpy.sqrt(totalVariance[i])
cov[:, i] /= numpy.sqrt(totalVariance[i])
- if DEBUG:
- import time
- t0 = time.time()
+ t0 = time.time()
+
evalues, evectors = numpy.linalg.eigh(cov)
# The total variance should also be the sum of all the eigenvalues
calculatedTotalVariance = evalues.sum()
if abs(totalVariance.sum() - evalues.sum()) > 0.0001:
- print("WARNING: Discrepancy on total variance")
- print("Variance from covariance matrix = ", totalVariance.sum())
- print("Variance from sum of eigenvalues = ", calculatedTotalVariance)
- if DEBUG:
- print("Eig elapsed = ", time.time() - t0)
+ _logger.info("WARNING: Discrepancy on total variance")
+ _logger.info("Variance from covariance matrix = %s",
+ totalVariance.sum())
+ _logger.info("Variance from sum of eigenvalues = %s",
+ calculatedTotalVariance)
+ _logger.debug("Eig elapsed = %s", time.time() - t0)
cov = None
dtype = numpy.float32
@@ -649,12 +646,13 @@ def numpyPCA(stack, index=-1, ncomponents=10, binning=None,
eigenvalues[i0] = evalues[i]
partialExplainedVariance = 100. * evalues[i] / \
calculatedTotalVariance
- print("PC%02d Explained variance %.5f %% " %\
- (i0 + 1, partialExplainedVariance))
+ _logger.info("PC%02d Explained variance %.5f %% ",
+ i0 + 1, partialExplainedVariance)
totalExplainedVariance += partialExplainedVariance
eigenvectors[i0, :] = evectors[:, i]
#print("NORMA = ", numpy.dot(evectors[:, i].T, evectors[:, i]))
- print("Total explained variance = %.2f %% " % totalExplainedVariance)
+ _logger.info("Total explained variance = %.2f %% ",
+ totalExplainedVariance)
else:
idx = numpy.argsort(evalues)
eigenvalues[:] = evalues[idx]
diff --git a/PyMca5/PyMcaMisc/PhysicalMemory.py b/PyMca5/PyMcaMisc/PhysicalMemory.py
index 32ba9dd..39a21a0 100644
--- a/PyMca5/PyMcaMisc/PhysicalMemory.py
+++ b/PyMca5/PyMcaMisc/PhysicalMemory.py
@@ -34,6 +34,11 @@ import sys
import os
import ctypes
import traceback
+import logging
+
+
+_logger = logging.getLogger(__name__)
+
def loadCLibrary(name="libc.so"):
try:
@@ -134,8 +139,8 @@ def getPhysicalMemoryOrNone():
if value <= 0:
# Value makes no sense.
# return None as requested in case of failure
- print("WARNING: Returned physical memory does not make sense %d" % \
- value)
+ _logger.warning("WARNING: Returned physical memory does not make sense %d",
+ value)
return None
else:
return value
diff --git a/PyMca5/PyMcaPhysics/xas/XASClass.py b/PyMca5/PyMcaPhysics/xas/XASClass.py
index ac12ce1..049c2d2 100644
--- a/PyMca5/PyMcaPhysics/xas/XASClass.py
+++ b/PyMca5/PyMcaPhysics/xas/XASClass.py
@@ -35,8 +35,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import copy
-import os
-import sys
+import logging
import numpy
import time
from PyMca5.PyMca import XASNormalization
@@ -46,7 +45,8 @@ try:
_XAS = True
except ImportError:
_XAS = False
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
def polynom(x, parameters):
if hasattr(x, 'shape'):
@@ -134,7 +134,7 @@ def polspl_evaluate(set2,xl,xh,c,nc,nr):
#;
#; now the rest of the points
#;
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
fit2 = fit *1
for i in range(len(set2[0,:])): # loop over all the points
for j in range(1,int(nr+1)): # loop over the # of intervals
@@ -156,8 +156,9 @@ def polspl_evaluate(set2,xl,xh,c,nc,nr):
yval += c[cstart+k] * numpy.power(xval,(k-1))
fit[0, idx] = xval
fit[1, idx] = yval
- if DEBUG:
- print("GOOD? = ", numpy.allclose(fit, fit2))
+
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ _logger.debug("GOOD? = %s", numpy.allclose(fit, fit2))
return fit
def polspl(x,y,w,npts,xl,xh,nr,nc):
@@ -428,8 +429,8 @@ def postEdge(set2,kmin=None,kmax=None,polDegree=[3,3,3],knots=None, full=False):
c = numpy.zeros(36)
nc = numpy.zeros(10, numpy.int32)
if len(polDegree) > 10:
- print("Error: Maximum number of intervals is 10")
- print(" Number of intervals forced to 10")
+ _logger.warning("Error: Maximum number of intervals is 10")
+ _logger.warning(" Number of intervals forced to 10")
polDegree = polDegree[0:9]
x1 = 0.0 # set2[:,0].min()
@@ -441,8 +442,7 @@ def postEdge(set2,kmin=None,kmax=None,polDegree=[3,3,3],knots=None, full=False):
x2 = kmax
xrange1 = [x1,x2]
- if DEBUG:
- print("++++++++++++++++++",xrange1)
+ _logger.debug("++++++++++++++++++%s", xrange1)
if knots not in [None, []]:
if len(knots) == len(polDegree):
if knots[0] > kmin:
@@ -456,8 +456,8 @@ def postEdge(set2,kmin=None,kmax=None,polDegree=[3,3,3],knots=None, full=False):
if knots[-1] < kmax:
knots = list(knots) + [kmax]
if ( (len(polDegree)+1) != len(knots) ):
- print("Error: dimension of knots must be dimension of polDegree+1")
- print(" Forced automatic (equidistant) knot definition.")
+ _logger.warning("Error: dimension of knots must be dimension of polDegree+1")
+ _logger.warning(" Forced automatic (equidistant) knot definition.")
knots = None
else:
xrange1 = knots[0],knots[-1]
@@ -486,12 +486,12 @@ def postEdge(set2,kmin=None,kmax=None,polDegree=[3,3,3],knots=None, full=False):
goodi = (set2[:,0] >= xrange1[0]) & (set2[:,0] <= xrange1[1])
set22 = set2[goodi,:]
- if DEBUG:
- print(' Number of fitting points: %d'%(len(set22[:,0])))
- print(' polynomials used for fitting: %d'%(nr))
- print('# degree min max')
- for i in range(1,nr+1):
- print("%d %9d %9.2f %9.2f "%(i,nc[i]-1,xl[i],xh[i]))
+ _logger.debug(' Number of fitting points: %d', len(set22[:,0]))
+ _logger.debug(' polynomials used for fitting: %d', nr)
+ _logger.debug('# degree min max')
+ for i in range(1,nr+1):
+ _logger.debug("%d %9d %9.2f %9.2f ",
+ i, nc[i]-1, xl[i], xh[i])
# ;
# ; call spline
@@ -506,11 +506,11 @@ def postEdge(set2,kmin=None,kmax=None,polDegree=[3,3,3],knots=None, full=False):
#t0 = time.time()
if _XAS:
c = _xas.polspl(xx,yy,w,npts,xl,xh,nr,nc)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
t0 = time.time()
c2 = polspl(xx,yy,w,npts,xl,xh,nr,nc)
- print("polspl elapsed = ", time.time() - t0)
- print("OK?", numpy.allclose(c, c2))
+ _logger.debug("polspl elapsed = %s", time.time() - t0)
+ _logger.debug("OK? %s", numpy.allclose(c, c2))
else:
c = polspl(xx,yy,w,npts,xl,xh,nr,nc)
@@ -589,8 +589,7 @@ def getFTWindowWeights(tk, window="Gaussian", windpar=0.2, wrange=None):
window = window[0].upper() + window[1:].lower()
else:
window = names[window]
- if DEBUG:
- print("Using window ", window)
+ _logger.debug("Using window %s", window)
if wrange == None:
xmax = tk.max()
@@ -791,16 +790,14 @@ def getBackFT(fourier,npoint=4096,krange=[2.0,12.0],rstep=None,rmin=None,rmax=No
rstep = fourier[nn+1,0] - fourier[nn,0]
rstep2 = fourier[nn+2,0] - fourier[nn+1,0]
rdiff = numpy.abs (rstep - rstep2)
- if DEBUG:
- print(' back rstep = %f'%(rstep))
- print(' rdiff = %f'%rdiff)
+ _logger.debug(' back rstep = %f', rstep)
+ _logger.debug(' rdiff = %f', rdiff)
if (rdiff >= 1e-6):
raise ValueError("r griding is not regular; Use rstep keyword -> Abort")
#return fou
ptstart = int(rmin/rstep)
- if DEBUG:
- print(' ptstart = %d'%ptstart)
- print(' ptstart+npt = %d'%(ptstart+npt))
+ _logger.debug(' ptstart = %d', ptstart)
+ _logger.debug(' ptstart+npt = %d', ptstart+npt)
fou[ptstart:ptstart+npt,:]=fourier
else: #;--- interpolation
fou[:,0] = numpy.linspace(0,0,npoint-1,npoint)*rstep
@@ -1243,8 +1240,7 @@ class XASClass(object):
raise ValueError("Edge energy not set")
if (id(energy) == id(self._energy)) and self._equidistant:
# data do not need to be interpolated
- if DEBUG:
- print("NO INTERPOLATION")
+ _logger.debug("NO INTERPOLATION")
eWork = energy
muWork = mu
else:
@@ -1412,7 +1408,7 @@ class XASClass(object):
normalizedSpectrum[i:] *= (jump / \
(data["PostEdge"] - data["PreEdge"])[i:])
else:
- print("WARNING: Undefined jump normalization method. Assume Flattened")
+ _logger.warning("WARNING: Undefined jump normalization method. Assume Flattened")
jumpMethod = "Flattened"
i = numpy.argmin(energy < e0)
normalizedSpectrum[i:] *= (jump / \
@@ -1487,25 +1483,25 @@ if __name__ == "__main__":
#sys.exit()
from PyMca5.PyMca import PyMcaQt as qt
app = qt.QApplication([])
- from PyMca5.PyMca import PlotWindow
- w = PlotWindow.PlotWindow()
- w.addCurve(energy, mu, legend="original", replot=False)
+ from silx.gui.plot import Plot1D
+ w = Plot1D()
+ w.addCurve(energy, mu, legend="original")
w.addCurve(ddict["NormalizedEnergy"],
- ddict["NormalizedMu"], legend="Mu", yaxis="right", replot=False)
+ ddict["NormalizedMu"], legend="Mu", yaxis="right")
w.addCurve(ddict["NormalizedEnergy"],
- ddict["NormalizedSignal"], legend="Post", replot=False)
+ ddict["NormalizedSignal"], legend="Post")
w.addCurve(ddict["NormalizedEnergy"],
- ddict["NormalizedBackground"], legend="Pre",replot=False)
+ ddict["NormalizedBackground"], legend="Pre")
w.resetZoom()
w.show()
- exafs = PlotWindow.PlotWindow()
+ exafs = Plot1D()
idx = (ddict["EXAFSKValues"] >= ddict["KMin"]) & \
(ddict["EXAFSKValues"] <= ddict["KMax"])
exafs.addCurve(ddict["EXAFSKValues"][idx], ddict["EXAFSNormalized"][idx],
legend="Normalized EXAFS")
exafs.show()
#"""
- ft = PlotWindow.PlotWindow()
+ ft = Plot1D()
ft.addCurve(ddict["FT"]["FTRadius"], ddict["FT"]["FTIntensity"])
ft.resetZoom()
ft.show()
diff --git a/PyMca5/PyMcaPhysics/xas/XASNormalization.py b/PyMca5/PyMcaPhysics/xas/XASNormalization.py
index 03be8d3..2b97bb0 100644
--- a/PyMca5/PyMcaPhysics/xas/XASNormalization.py
+++ b/PyMca5/PyMcaPhysics/xas/XASNormalization.py
@@ -36,11 +36,13 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5.PyMcaMath.fitting import SpecfitFuns
from PyMca5.PyMcaMath import SGModule
from PyMca5.PyMcaMath.fitting.Gefit import LeastSquaresFit
-DEBUG = 0
-if DEBUG:
+_logger = logging.getLogger(__name__)
+
+if _logger.getEffectiveLevel() == logging.DEBUG:
from pylab import *
@@ -388,7 +390,7 @@ def XASPolynomialNormalization(spectrum,
normalizedSpectrum = (spectrum - pre_edge_function(prePol, energy))\
/post_edge_function(postPol, energy)
jump = post_edge_function(postPol, edge)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
plot(energy, spectrum, 'o')
plot(xPre, pre_edge_function(prePol, xPre), 'r')
plot(xPost, post_edge_function(postPol, xPost)+pre_edge_function(prePol, xPost), 'y')
@@ -433,8 +435,8 @@ def XASVictoreenNormalization(spectrum,
weightflag=0, linear=1)[0]
normalizedSpectrum = (spectrum - pre_edge_function(prePol, energy))\
/post_edge_function(postPol, energy)
- if DEBUG:
- print("VICTOREEN")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ _logger.info("VICTOREEN")
plot(energy, spectrum, 'o')
plot(xPre, pre_edge_function(prePol, xPre), 'r')
plot(xPost,
@@ -460,7 +462,7 @@ if __name__ == "__main__":
edge = estimateXANESEdge(spectrum+i, energy=energy)
print("EDGE ELAPSED = ", (time.time() - t0)/float(n))
print("EDGE = %f" % edge)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
n = 1
else:
n = 100
@@ -490,7 +492,7 @@ if __name__ == "__main__":
algorithm_parameters={'pre_edge_order':'Victoreen',
'post_edge_order':'Victoreen'})[0:2]
print("ELAPSED Victoreen = ", (time.time() - t0)/float(n))
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
#plot(energy, spectrum, 'b')
plot(nEne0, nSpe0, 'k', label='Polynomial')
plot(nEneP, nSpeP, 'b', label='Polynomial')
diff --git a/PyMca5/PyMcaPhysics/xas/XASStackBatch.py b/PyMca5/PyMcaPhysics/xas/XASStackBatch.py
index 0b363af..da80eaa 100644
--- a/PyMca5/PyMcaPhysics/xas/XASStackBatch.py
+++ b/PyMca5/PyMcaPhysics/xas/XASStackBatch.py
@@ -37,12 +37,14 @@ import os
import numpy
import h5py
import posixpath
+import logging
from PyMca5.PyMca import XASClass
from PyMca5.PyMcaIO import ConfigDict
import time
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class XASStackBatch(object):
def __init__(self, analyzer=None):
@@ -82,8 +84,7 @@ class XASStackBatch(object):
:return: A dictionnary with the results as keys.
"""
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if configuration is not None:
self._analyzer.setConfiguration(configuration)
@@ -95,7 +96,7 @@ class XASStackBatch(object):
# dictated by the current configuration
pass
else:
- print("WARNING: weight not handled yet")
+ _logger.warning("WARNING: weight not handled yet")
weightPolicy = 0 # no weight
#weightPolicy = 1 # use average weight from the sum spectrum
#weightPolicy = 2 # individual pixel weights (slow)
@@ -311,15 +312,15 @@ class XASStackBatch(object):
outputDict["images"] = output
out.flush()
out.close()
- if DEBUG:
- t = time.time() - t0
- print("First fit elapsed = %f" % t)
- print("Spectra per second = %f" % (data.shape[0]*data.shape[1]/float(t)))
- t0 = time.time()
+
+ t = time.time() - t0
+ _logger.debug("First fit elapsed = %f", t)
+ _logger.debug("Spectra per second = %f", data.shape[0]*data.shape[1]/float(t))
+ t0 = time.time()
return outputDict
if __name__ == "__main__":
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
analyzer = XASClass.XASClass()
instance = XASStackBatch(analyzer=analyzer)
configurationFile = "test.ini"
diff --git a/PyMca5/PyMcaPhysics/xrf/ClassMcaTheory.py b/PyMca5/PyMcaPhysics/xrf/ClassMcaTheory.py
index 9fc309e..b1aaf8e 100644
--- a/PyMca5/PyMcaPhysics/xrf/ClassMcaTheory.py
+++ b/PyMca5/PyMcaPhysics/xrf/ClassMcaTheory.py
@@ -34,6 +34,7 @@ import os
import sys
import numpy
import copy
+import logging
from .Strategies import STRATEGIES
from . import ConcentrationsTool
FISX = ConcentrationsTool.FISX
@@ -44,7 +45,7 @@ from PyMca5.PyMcaMath.fitting import SpecfitFuns
from PyMca5.PyMcaIO import ConfigDict
from PyMca5.PyMcaMath.fitting import Gefit
from PyMca5 import PyMcaDataDir
-DEBUG = 0
+_logger = logging.getLogger(__name__)
#"python ClassMcaTheory.py -s1.1 --file=03novs060sum.mca --pkm=McaTheory.dat --continuum=0 --strip=1 --sumflag=1 --maxiter=4"
CONTINUUM_LIST = [None,'Constant','Linear','Parabolic','Linear Polynomial','Exp. Polynomial']
OLDESCAPE = 0
@@ -154,10 +155,8 @@ class McaTheory(object):
def configure(self, newdict=None):
if newdict in [None, {}]:
if self.__toBeConfigured:
- if DEBUG:
- txt = "WARNING: This configuration is the one of last fit.\n"
- txt += "It does not correspond to the one of next fit."
- print(txt)
+ _logger.debug("WARNING: This configuration is the one of last fit.\n"
+ "It does not correspond to the one of next fit.")
return copy.deepcopy(self.config)
self.config.update(newdict)
self.__toBeConfigured = False
@@ -451,8 +450,7 @@ class McaTheory(object):
_nescape_ = 0
if self.config['fit']['escapeflag']:
if self.__USE_FISX_ESCAPE:
- if DEBUG:
- print("Using fisx escape")
+ _logger.debug("Using fisx escape")
xcom = FisxHelper.xcom
detector_composition = Elements.getMaterialMassFractions([detele],
[1.0])
@@ -764,8 +762,7 @@ class McaTheory(object):
_nescape_ = 0
if self.config['fit']['escapeflag']:
if self.__USE_FISX_ESCAPE:
- if DEBUG:
- print("Using fisx escape")
+ _logger.debug("Using fisx escape")
xcom = FisxHelper.xcom
detector_composition = Elements.getMaterialMassFractions([detele],
[1.0])
@@ -865,8 +862,7 @@ class McaTheory(object):
_nescape_ = 0
if self.config['fit']['escapeflag']:
if self.__USE_FISX_ESCAPE:
- if DEBUG:
- print("Using fisx escape")
+ _logger.debug("Using fisx escape")
xcom = FisxHelper.xcom
detector_composition = Elements.getMaterialMassFractions([detele],
[1.0])
@@ -995,8 +991,7 @@ class McaTheory(object):
if (self.lastxmin != self.config['fit']['xmin']) or\
(self.lastxmax != self.config['fit']['xmax']):
if self.ydata0 is not None:
- if DEBUG:
- print("Limits changed")
+ _logger.debug("Limits changed")
self.setData(x=self.xdata0,
y=self.ydata0,
sigmay=self.sigmay0,
@@ -1008,18 +1003,15 @@ class McaTheory(object):
if hasattr(self, "xdata"):
if self.STRIP:
if calculateStrip:
- if DEBUG:
- print("Calling to calculate non analytical background in config")
+ _logger.debug("Calling to calculate non analytical background in config")
self.__getselfzz()
else:
- if DEBUG:
- print("Using previous non analytical background in config")
+ _logger.debug("Using previous non analytical background in config")
self.datatofit = numpy.concatenate((self.xdata,
self.ydata-self.zz, self.sigmay),1)
self.laststrip = 1
else:
- if DEBUG:
- print("Using previous data")
+ _logger.debug("Using previous data")
self.datatofit = numpy.concatenate((self.xdata,
self.ydata, self.sigmay),1)
self.laststrip = 0
@@ -1049,8 +1041,7 @@ class McaTheory(object):
a strategy based on concentrations
"""
if self.__toBeConfigured:
- if DEBUG:
- print("setData RESTORE ORIGINAL CONFIGURATION")
+ _logger.debug("setData RESTORE ORIGINAL CONFIGURATION")
self.configure(self.__originalConfiguration)
if 'x' in kw:
x=kw['x']
@@ -1216,8 +1207,7 @@ class McaTheory(object):
#SNIP algorithm
if self.config['fit']['stripalgorithm'] == 1:
- if DEBUG:
- print("CALCULATING SNIP")
+ _logger.debug("CALCULATING SNIP")
if len(anchorslist) == 0:
anchorslist = [0, len(ysmooth)-1]
anchorslist.sort()
@@ -1243,8 +1233,7 @@ class McaTheory(object):
#strip background
niter = self.config['fit']['stripiterations']
if niter > 0:
- if DEBUG:
- print("CALCULATING STRIP")
+ _logger.debug("CALCULATING STRIP")
if (niter > 1000) and (self.config['fit']['stripwidth'] == 1):
self.zz=SpecfitFuns.subac(ysmooth,
self.config['fit']['stripconstant'],
@@ -1805,8 +1794,7 @@ class McaTheory(object):
def estimate(self):
if self.__toBeConfigured:
- if DEBUG:
- print("CONFIGURING FROM ESTIMATION")
+ _logger.debug("CONFIGURING FROM ESTIMATION")
self.configure(self.__originalConfiguration)
self.parameters, self.codes = self.specfitestimate(self.xdata, self.ydata,self.zz)
#self.estimatelinpoly(self.xdata, self.ydata,self.zz)
diff --git a/PyMca5/PyMcaPhysics/xrf/Elements.py b/PyMca5/PyMcaPhysics/xrf/Elements.py
index 51f4aaf..0683074 100644
--- a/PyMca5/PyMcaPhysics/xrf/Elements.py
+++ b/PyMca5/PyMcaPhysics/xrf/Elements.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -2410,7 +2410,7 @@ def getMaterialMassAttenuationCoefficients(compoundList0, fractionList0, energy0
elif type(energy0) == numpy.ndarray:
energy = energy0.tolist()
- for compound in compoundList:
+ for compound, compoundFraction in zip(compoundList, compoundFractionList):
elts=[]
#get energy list
if compound in Element.keys():
@@ -2431,7 +2431,7 @@ def getMaterialMassAttenuationCoefficients(compoundList0, fractionList0, energy0
#the proportion of the element in that compound times the compound fraction
fraction = [Element[elt]['mass'] *nb for (elt, nb) in zip(elts, nbs) ]
- div = compoundFractionList[compoundList.index(compound)]/sum(fraction)
+ div = compoundFraction/sum(fraction)
fraction = [x * div for x in fraction]
if energy is None:
#get energy list
diff --git a/PyMca5/PyMcaPhysics/xrf/FastXRFLinearFit.py b/PyMca5/PyMcaPhysics/xrf/FastXRFLinearFit.py
index f91f083..0b88c9e 100644
--- a/PyMca5/PyMcaPhysics/xrf/FastXRFLinearFit.py
+++ b/PyMca5/PyMcaPhysics/xrf/FastXRFLinearFit.py
@@ -35,6 +35,7 @@ Module to perform a fast linear fit on a stack of fluorescence spectra.
"""
import os
import numpy
+import logging
from PyMca5.PyMcaMath.linalg import lstsq
from . import ClassMcaTheory
from PyMca5.PyMcaMath.fitting import Gefit
@@ -43,7 +44,8 @@ from PyMca5.PyMcaMath.fitting import SpecfitFuns
from PyMca5.PyMcaIO import ConfigDict
import time
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class FastXRFLinearFit(object):
def __init__(self, mcafit=None):
@@ -101,15 +103,13 @@ class FastXRFLinearFit(object):
if hasattr(y, "info"):
if "McaLiveTime" in y.info:
livetime = y.info["McaLiveTime"]
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
if configuration is not None:
self._mcaTheory.setConfiguration(configuration)
elif self._config is None:
raise ValueError("Fit configuration missing")
else:
- if DEBUG:
- print("Setting default configuration")
+ _logger.debug("Setting default configuration")
self._mcaTheory.setConfiguration(self._config)
# read the current configuration
# it is a copy, we can modify it at will
@@ -164,8 +164,7 @@ class FastXRFLinearFit(object):
# background
if config['fit']['stripflag']:
if config['fit']['stripalgorithm'] == 1:
- if DEBUG:
- print("SNIP")
+ _logger.debug("SNIP")
else:
raise RuntimeError("Please use the faster SNIP background")
@@ -335,9 +334,8 @@ class FastXRFLinearFit(object):
uncertainties = numpy.zeros((nFree, nRows, nColumns), numpy.float32)
#perform the initial fit
- if DEBUG:
- print("Configuration elapsed = %f" % (time.time() - t0))
- t0 = time.time()
+ _logger.debug("Configuration elapsed = %f", time.time() - t0)
+ t0 = time.time()
totalSpectra = data.shape[0] * data.shape[1]
jStep = min(100, data.shape[1])
if weightPolicy == 2:
@@ -397,11 +395,12 @@ class FastXRFLinearFit(object):
results[:, i, jStart:jEnd] = parameters
uncertainties[:, i, jStart:jEnd] = ddict['uncertainties']
jStart = jEnd
- if DEBUG:
- t = time.time() - t0
- print("First fit elapsed = %f" % t)
- print("Spectra per second = %f" % (data.shape[0]*data.shape[1]/float(t)))
- t0 = time.time()
+ t = time.time() - t0
+ _logger.debug("First fit elapsed = %f", t)
+ if t > 0.:
+ _logger.debug("Spectra per second = %f",
+ data.shape[0]*data.shape[1]/float(t))
+ t0 = time.time()
# cleanup zeros
# start with the parameter with the largest amount of negative values
@@ -434,7 +433,8 @@ class FastXRFLinearFit(object):
i = item[1]
badMask = item[2]
results[i][badMask] = 0.0
- print("WARNING: %d pixels of parameter %s forced to zero" % (item[0], freeNames[i]))
+ _logger.warning("WARNING: %d pixels of parameter %s forced to zero",
+ item[0], freeNames[i])
continue
zeroList.sort()
zeroList.reverse()
@@ -458,12 +458,10 @@ class FastXRFLinearFit(object):
for i in badParameters:
results[i][badMask] = 0.0
uncertainties[i][badMask] = 0.0
- if DEBUG:
- print("WARNING: %d pixels of parameter %s set to zero" % (badMask.sum(),
- freeNames[i]))
+ _logger.debug("WARNING: %d pixels of parameter %s set to zero",
+ badMask.sum(), freeNames[i])
else:
- if DEBUG:
- print("Number of secondary fits = %d" % (nFits + 1))
+ _logger.debug("Number of secondary fits = %d", nFits + 1)
nFits += 1
A = derivatives[:, [i for i in range(nFree) if i not in badParameters]]
#assume we'll not have too many spectra
@@ -533,9 +531,9 @@ class FastXRFLinearFit(object):
uncertainties[i][badMask] = ddict['uncertainties'][idx]
idx += 1
- if DEBUG and refit:
+ if refit:
t = time.time() - t0
- print("Fit of negative peaks elapsed = %f" % t)
+ _logger.debug("Fit of negative peaks elapsed = %f", t)
t0 = time.time()
outputDict = {'parameters':results, 'uncertainties':uncertainties, 'names':freeNames}
@@ -550,8 +548,7 @@ class FastXRFLinearFit(object):
fitFirstSpectrum = False
if config['concentrations']['usematrix']:
- if DEBUG:
- print("USING MATRIX")
+ _logger.debug("USING MATRIX")
if config['concentrations']['reference'].upper() == "AUTO":
fitFirstSpectrum = True
elif autotime:
@@ -611,16 +608,14 @@ class FastXRFLinearFit(object):
referenceElement = addInfo['ReferenceElement']
referenceTransitions = addInfo['ReferenceTransitions']
- if DEBUG:
- print("Reference <%s> transition <%s>" % (referenceElement, referenceTransitions))
+ _logger.debug("Reference <%s> transition <%s>",
+ referenceElement, referenceTransitions)
if referenceElement in ["", None, "None"]:
- if DEBUG:
- print("No reference")
+ _logger.debug("No reference")
counter = 0
for i, group in enumerate(fitresult['result']['groups']):
if group.lower().startswith("scatter"):
- if DEBUG:
- print("skept %s" % group)
+ _logger.debug("skept %s", group)
continue
outputDict['names'].append("C(%s)" % group)
if counter == 0:
@@ -640,8 +635,7 @@ class FastXRFLinearFit(object):
fitresult['result'][group]['fitarea'])
counter += 1
else:
- if DEBUG:
- print("With reference")
+ _logger.debug("With reference")
idx = None
testGroup = referenceElement+ " " + referenceTransitions.split()[0]
for i, group in enumerate(fitresult['result']['groups']):
@@ -659,8 +653,7 @@ class FastXRFLinearFit(object):
counter = 0
for i, group in enumerate(fitresult['result']['groups']):
if group.lower().startswith("scatter"):
- if DEBUG:
- print("skept %s" % group)
+ _logger.debug("skept %s", group)
continue
outputDict['names'].append("C(%s)" % group)
goodI = results[nFreeBackgroundParameters+i] > 0
@@ -677,10 +670,8 @@ class FastXRFLinearFit(object):
(concentrationsResult[layer]['mass fraction'][group]))
counter += 1
outputDict['concentrations'] = massFractions
- if DEBUG:
- t = time.time() - t0
- print("Calculation of concentrations elapsed = %f" % t)
- t0 = time.time()
+ t = time.time() - t0
+ _logger.debug("Calculation of concentrations elapsed = %f", t)
####################################################
return outputDict
@@ -718,7 +709,8 @@ def getFileListFromPattern(pattern, begin, end, increment=None):
return fileList
if __name__ == "__main__":
- DEBUG = True
+ logging.basicConfig(level=logging.INFO)
+ _logger.setLevel(logging.DEBUG)
import glob
import sys
from PyMca5.PyMca import EDFStack
diff --git a/PyMca5/PyMcaPhysics/xrf/FisxHelper.py b/PyMca5/PyMcaPhysics/xrf/FisxHelper.py
index e2b1af3..7f986aa 100644
--- a/PyMca5/PyMcaPhysics/xrf/FisxHelper.py
+++ b/PyMca5/PyMcaPhysics/xrf/FisxHelper.py
@@ -31,15 +31,18 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
-import sys
-import time
+import logging
from fisx import DataDir
from fisx import Elements as FisxElements
from fisx import Material
from fisx import Detector
from fisx import XRF
+import time
+import sys
xcom = None
-DEBUG = 0
+
+_logger = logging.getLogger(__name__)
+
def getElementsInstance(dataDir=None, bindingEnergies=None, xcomFile=None):
if dataDir is None:
@@ -48,7 +51,7 @@ def getElementsInstance(dataDir=None, bindingEnergies=None, xcomFile=None):
from PyMca5.PyMcaDataDir import PYMCA_DATA_DIR as pymcaDataDir
from PyMca5 import getDataFile
except:
- print("Using fisx shell constants and ratios")
+ _logger.info("Using fisx shell constants and ratios")
pymcaDataDir = None
if bindingEnergies is None:
if pymcaDataDir is None:
@@ -60,11 +63,9 @@ def getElementsInstance(dataDir=None, bindingEnergies=None, xcomFile=None):
xcomFile = os.path.join(dataDir, "XCOM_CrossSections.dat")
else:
xcomFile = getDataFile("XCOM_CrossSections.dat")
- if DEBUG:
- t0 = time.time()
+ t0 = time.time()
instance = FisxElements(dataDir, bindingEnergies, xcomFile)
- if DEBUG:
- print("Shell constants")
+ _logger.debug("Shell constants")
# the files should be taken from PyMca to make sure the same data are used
for key in ["K", "L", "M"]:
@@ -73,18 +74,15 @@ def getElementsInstance(dataDir=None, bindingEnergies=None, xcomFile=None):
# we have to make sure we have got a string
if hasattr(fname, "decode"):
fname = fname.decode("latin-1")
- if DEBUG:
- print("Before %s" % fname)
+ _logger.debug("Before %s", fname)
if pymcaDataDir is not None:
fname = getDataFile(key + "ShellConstants.dat")
else:
fname = os.path.join(os.path.dirname(fname),
key + "ShellConstants.dat")
instance.setShellConstantsFile(key, fname)
- if DEBUG:
- print("After %s" % instance.getShellConstantsFile(key))
- if DEBUG:
- print("Radiative transitions")
+ _logger.debug("After %s", instance.getShellConstantsFile(key))
+ _logger.debug("Radiative transitions")
for key in ["K", "L", "M"]:
fname = instance.getShellRadiativeTransitionsFile(key)
@@ -92,18 +90,15 @@ def getElementsInstance(dataDir=None, bindingEnergies=None, xcomFile=None):
# we have to make sure we have got a string ...
if hasattr(fname, "decode"):
fname = fname.decode("latin-1")
- if DEBUG:
- print("Before %s" % fname)
+ _logger.debug("Before %s", fname)
if pymcaDataDir is not None:
fname = getDataFile(key + "ShellRates.dat")
else:
fname = os.path.join(os.path.dirname(fname), key + "ShellRates.dat")
instance.setShellRadiativeTransitionsFile(key, fname)
- if DEBUG:
- print("After %s " % instance.getShellRadiativeTransitionsFile(key))
+ _logger.debug("After %s ", instance.getShellRadiativeTransitionsFile(key))
- if DEBUG:
- print("Reading Elapsed = ", time.time() - t0)
+ _logger.debug("Reading Elapsed = %s", time.time() - t0)
return instance
def getMultilayerFluorescence(multilayerSample,
@@ -122,42 +117,42 @@ def getMultilayerFluorescence(multilayerSample,
elementsFromMatrix=False,
secondary=None,
materials=None,
- secondaryCalculationLimit=None):
+ secondaryCalculationLimit=None,
+ cache=1):
if secondary is None:
secondary=0
if secondaryCalculationLimit is None:
secondaryCalculationLimit=0.0
+ if cache:
+ cache = 1
+ else:
+ cache = 0
- if DEBUG:
- print("Library actually using secondary = ", secondary)
- print("Library using secondary limit = ", secondaryCalculationLimit)
+ _logger.info("Library requested to use secondary = %s", secondary)
+ _logger.info("Library requested to use secondary limit = %s", secondaryCalculationLimit)
+ _logger.info("Library requested to use cache = %d", cache)
global xcom
if xcom is None:
- if DEBUG:
- print("Getting fisx elements instance")
+ _logger.debug("Getting fisx elements instance")
xcom = getElementsInstance()
if materials is not None:
- if DEBUG:
- print("Deleting materials")
+ _logger.debug("Deleting materials")
xcom.removeMaterials()
for material in materials:
- if DEBUG:
- print("Adding material making sure no duplicates")
+ _logger.debug("Adding material making sure no duplicates")
xcom.addMaterial(material, errorOnReplace=1)
# the instance
- if DEBUG:
- print("creating XRF instance")
+ _logger.debug("creating XRF instance")
xrf = XRF()
# the beam energies
if not len(energyList):
raise ValueError("Empty list of beam energies!!!")
- if DEBUG:
- print("setting beam")
+ _logger.debug("setting beam")
xrf.setBeam(energyList, weights=weightList,
characteristic=flagList)
# the beam filters (if any)
@@ -172,8 +167,7 @@ def getMultilayerFluorescence(multilayerSample,
Unless you know what you are doing, the funny factors must be 1.0
"""
- if DEBUG:
- print("setting beamFilters")
+ _logger.debug("setting beamFilters")
xrf.setBeamFilters(beamFilters)
# the sample description
@@ -186,20 +180,17 @@ def getMultilayerFluorescence(multilayerSample,
Unless you know what you are doing, the funny factors must be 1.0
"""
- if DEBUG:
- print("setting sample")
+ _logger.debug("setting sample")
xrf.setSample(multilayerSample)
# the attenuators
if attenuatorList is not None:
if len(attenuatorList) > 0:
- if DEBUG:
- print("setting attenuators")
+ _logger.debug("setting attenuators")
xrf.setAttenuators(attenuatorList)
# the geometry
- if DEBUG:
- print("setting Geometry")
+ _logger.debug("setting Geometry")
if alphaIn is None:
alphaIn = 45
if alphaOut is None:
@@ -207,8 +198,7 @@ def getMultilayerFluorescence(multilayerSample,
xrf.setGeometry(alphaIn, alphaOut)
# the detector
- if DEBUG:
- print("setting Detector")
+ _logger.debug("setting Detector")
if detector is not None:
# Detector can be a list as [material, density, thickness]
# or a Detector instance
@@ -259,38 +249,61 @@ def getMultilayerFluorescence(multilayerSample,
if elementsFromMatrix:
elementsList = matrixElementsList
- # enabling the cascade cache gets a (miserable) 15 % speed up
- if DEBUG:
- print("Using cascade cache")
- t0 = time.time()
+ t0 = time.time()
+ if cache:
+ # enabling the cascade cache gets a (miserable) 15 % speed up
+ _logger.debug("FisxHelper Using cache")
+ else:
+ _logger.debug("FisxHelper Not using cache")
treatedElements = []
emittedLines = []
+ for actualElement in actualElementsList:
+ element = actualElement.split()[0]
+ if element not in treatedElements:
+ if cache:
+ lines = xcom.getEmittedXRayLines(element)
+ sampleEnergies = [lines[key] for key in lines]
+ for e in sampleEnergies:
+ if e not in emittedLines:
+ emittedLines.append(e)
+ treatedElements.append(element)
+
for layer in multilayerSample:
composition = xcom.getComposition(layer[0])
for element in composition.keys():
- xcom.setElementCascadeCacheEnabled(element, 1)
- if hasattr(xcom, "updateCache"):
- if element not in treatedElements:
+ if element not in treatedElements:
+ if cache:
lines = xcom.getEmittedXRayLines(element)
sampleEnergies = [lines[key] for key in lines]
for e in sampleEnergies:
if e not in emittedLines:
emittedLines.append(e)
+ treatedElements.append(element)
+
+ if attenuatorList is not None:
+ for layer in attenuatorList:
+ composition = xcom.getComposition(layer[0])
+ for element in composition.keys():
+ if element not in treatedElements:
+ if cache:
+ lines = xcom.getEmittedXRayLines(element)
+ sampleEnergies = [lines[key] for key in lines]
+ for e in sampleEnergies:
+ if e not in emittedLines:
+ emittedLines.append(e)
treatedElements.append(element)
if hasattr(xcom, "updateCache"):
- if DEBUG:
- print("Filling atenuation cache")
composition = detectorInstance.getComposition(xcom)
for element in composition.keys():
- xcom.setElementCascadeCacheEnabled(element, 1)
if element not in treatedElements:
- lines = xcom.getEmittedXRayLines(element)
- sampleEnergies = [lines[key] for key in lines]
- for e in sampleEnergies:
- if e not in emittedLines:
- emittedLines.append(e)
+ if cache:
+ lines = xcom.getEmittedXRayLines(element)
+ sampleEnergies = [lines[key] for key in lines]
+ for e in sampleEnergies:
+ if e not in emittedLines:
+ emittedLines.append(e)
treatedElements.append(element)
for element in actualElementsList:
@@ -300,28 +313,40 @@ def getMultilayerFluorescence(multilayerSample,
for element in treatedElements:
# this limit seems overestimated but still reasonable
if xcom.getCacheSize(element) > 5000:
- print("Clearing cache")
+ _logger.info("Clearing cache for %s" % element)
xcom.clearCache(element)
- xcom.updateCache(element, energyList)
- xcom.updateCache(element, emittedLines)
- xcom.setCacheEnabled(element, 1)
- if DEBUG:
- print("Element %s cache size = %d" % (element, xcom.getCacheSize(element)))
-
+ if cache:
+ _logger.info("Updating cache for %s" % element)
+ xcom.updateCache(element, energyList)
+ xcom.updateCache(element, emittedLines)
+ else:
+ # should I clear the cache to be sure?
+ # for the time being, yes.
+ _logger.info("No cache. Clearing cache for %s" % element)
+ xcom.clearCache(element)
+ xcom.setCacheEnabled(element, cache)
+ _logger.info("Element %s cache size = %d",
+ element, xcom.getCacheSize(element))
for element in actualElementsList:
- xcom.setElementCascadeCacheEnabled(element.split()[0], 1)
+ xcom.setElementCascadeCacheEnabled(element.split()[0], cache)
if hasattr(xcom, "updateEscapeCache") and \
hasattr(xcom, "setEscapeCacheEnabled"):
if detector is not None:
for element in actualElementsList:
- lines = xcom.getEmittedXRayLines(element.split()[0])
- lines_energy = [lines[key] for key in lines]
- for e in lines_energy:
- if e not in emittedLines:
- emittedLines.append(e)
- xcom.setEscapeCacheEnabled(1)
- xcom.updateEscapeCache(detectorInstance.getComposition(xcom),
+ if cache:
+ lines = xcom.getEmittedXRayLines(element.split()[0])
+ lines_energy = [lines[key] for key in lines]
+ for e in lines_energy:
+ if e not in emittedLines:
+ emittedLines.append(e)
+ if not cache:
+ if hasattr(xcom, "clearEscapeCache"):
+ # the method is there but nor wrapped yet
+ xcom.clearEscapeCache()
+ xcom.setEscapeCacheEnabled(cache)
+ if cache:
+ xcom.updateEscapeCache(detectorInstance.getComposition(xcom),
emittedLines,
energyThreshold=detectorInstance.getEscapePeakEnergyThreshold(), \
intensityThreshold=detectorInstance.getEscapePeakIntensityThreshold(), \
@@ -329,23 +354,19 @@ def getMultilayerFluorescence(multilayerSample,
alphaIn=detectorInstance.getEscapePeakAlphaIn(),
thickness=0) # No escape by the back considered yet
else:
- if DEBUG:
- print("NOT CALLING UPDATE CACHE")
- if DEBUG:
- print("C++ elapsed filling cache = ", time.time() - t0)
+ _logger.debug("NOT CALLING UPDATE CACHE")
+ _logger.info("C++ elapsed filling cache = %s",
+ time.time() - t0)
- if DEBUG:
- print("Calling getMultilayerFluorescence")
- t0 = time.time()
+ _logger.debug("Calling getMultilayerFluorescence")
+ t0 = time.time()
expectedFluorescence = xrf.getMultilayerFluorescence(actualElementsList,
xcom,
secondary=secondary,
useGeometricEfficiency=useGeometricEfficiency,
useMassFractions=elementsFromMatrix,
secondaryCalculationLimit=secondaryCalculationLimit)
- if DEBUG:
- print("C++ elapsed TWO = ", time.time() - t0)
-
+ _logger.info("C++ elapsed TWO = %s", time.time() - t0)
if not elementsFromMatrix:
# If one element was present in one layer and not on others, PyMca only
# calculated contributions from the layers in which the element was
@@ -417,7 +438,8 @@ def _getFisxMaterials(fitConfiguration):
if fractionList[n] > 0.0:
composition[compoundList[n]] = fractionList[n]
else:
- print("ignoring ", compoundList[n], "fraction = ", fractionList[n])
+ _logger.info("ignoring %s, fraction = %s",
+ compoundList[n], fractionList[n])
# check the composition is expressed in terms of elements
# and not in terms of other undefined materials
totallyDefined = True
@@ -457,7 +479,7 @@ def _getFisxMaterials(fitConfiguration):
txt += "contains <%s> (defined as <%s>), " % (compound, compound + " ")
else:
txt += "contains <%s> (undefined)," % compound
- print(txt)
+ _logger.info(txt)
raise KeyError(txt)
return fisxMaterials
@@ -570,7 +592,8 @@ def _getFisxDetector(fitConfiguration, attenuatorsDetector=None):
else:
# make sure information is consistent
if attenuatorsDetector[0] not in [detectorMaterial, detectorMaterial+"1"]:
- print("%s not equal to %s" % (attenuatorsDetector[0], detectorMaterial))
+ _logger.warning("%s not equal to %s",
+ attenuatorsDetector[0], detectorMaterial)
msg = "Inconsistent detector material between DETECTOR and ATTENUATORS tab"
msg += "\n%s not equal to %s" % (attenuatorsDetector[0], detectorMaterial)
raise ValueError(msg)
@@ -595,8 +618,7 @@ def _getSecondaryCalculationLimitFromFitConfiguration(fitConfiguration):
limit = float(\
fitConfiguration["concentrations"]["secondarycalculationlimit"])
except:
- if DEBUG:
- print("Exception. Forcing no limit")
+ _logger.debug("Exception. Forcing no limit")
limit = 0.0
return limit
@@ -651,7 +673,7 @@ def _fisxFromFitConfigurationAction(fitConfiguration,
try:
secondary = fitConfiguration["concentrations"]["usemultilayersecondary"]
except:
- print("Exception. Forcing tertiary")
+ _logger.warning("Exception. Forcing tertiary")
secondary = 2
if action.upper() == "FLUORESCENCE":
@@ -761,7 +783,7 @@ def getFisxCorrectionFactors(*var, **kw):
secondOrder = ddict[element][family][layerKey]["counts"][1]
if firstOrder <= 0:
if secondOrder > 0.0:
- print("Inconsistency? secondary with no primary?")
+ _logger.warning("Inconsistency? secondary with no primary?")
ddict[element][family][layerKey]["correction_factor"][1] = 1
if nItems == 3:
ddict[element][family][layerKey]["correction_factor"][2] = 1
@@ -787,9 +809,7 @@ def getFisxCorrectionFactorsFromFitConfigurationFile(fileName,
secondaryCalculationLimit)
if __name__ == "__main__":
- DEBUG = 1
- import time
- import sys
+ _logger.setLevel(logging.DEBUG)
if len(sys.argv) < 2:
print("Usage: python FisxHelper FitConfigurationFile [element] [matrix_flag]")
sys.exit(0)
diff --git a/PyMca5/PyMcaPhysics/xrf/SingleLayerStrategy.py b/PyMca5/PyMcaPhysics/xrf/SingleLayerStrategy.py
index b55a74b..c077c13 100644
--- a/PyMca5/PyMcaPhysics/xrf/SingleLayerStrategy.py
+++ b/PyMca5/PyMcaPhysics/xrf/SingleLayerStrategy.py
@@ -31,10 +31,12 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import copy
+import logging
from . import Elements
from . import ConcentrationsTool
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class SingleLayerStrategy(object):
def __init__(self):
@@ -48,8 +50,7 @@ class SingleLayerStrategy(object):
Returning an empty fit configuration, or a number of iterations equal 0
will indicate the process is over.
"""
- if DEBUG:
- print("SingleLayerStrategy called with iteration ", currentIteration)
+ _logger.debug("SingleLayerStrategy called with iteration %s", currentIteration)
newConfiguration = copy.deepcopy(fitResult['config'])
strategyConfiguration = newConfiguration['SingleLayerStrategy']
if currentIteration is None:
@@ -122,8 +123,7 @@ class SingleLayerStrategy(object):
if "-" in group:
continue
if strategyConfiguration["flags"][materialCounter] in ["0", 0]:
- if DEBUG:
- print("ignoring ", group)
+ _logger.debug("ignoring %s", group)
continue
ele = group.split()[0]
material = strategyConfiguration["materials"][materialCounter]
@@ -157,7 +157,6 @@ class SingleLayerStrategy(object):
"Comment":"Last Single Layer Strategy iteration"}
# and update it
newConfiguration[parentKey][daughterKey][1] = materialName
- if DEBUG:
- print("Updated sample material: ", \
- newConfiguration["materials"][materialName])
+ _logger.debug("Updated sample material: %s",
+ newConfiguration["materials"][materialName])
return newConfiguration, currentIteration - 1
diff --git a/PyMca5/PyMcaPhysics/xrf/XRFMC/XMSOParser.py b/PyMca5/PyMcaPhysics/xrf/XRFMC/XMSOParser.py
index 5255231..1925b6a 100644
--- a/PyMca5/PyMcaPhysics/xrf/XRFMC/XMSOParser.py
+++ b/PyMca5/PyMcaPhysics/xrf/XRFMC/XMSOParser.py
@@ -32,9 +32,11 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
import xml.etree.ElementTree as ElementTree
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
def getXMSOFileFluorescenceInformation(xmsoFile):
f = ElementTree.parse(xmsoFile)
@@ -42,10 +44,9 @@ def getXMSOFileFluorescenceInformation(xmsoFile):
root = f.getroot()
transitions = ['K', 'Ka', 'Kb', 'L', 'L1', 'L2', 'L3', 'M']
for i in root.iter('fluorescence_line_counts'):
- if DEBUG:
- print(i.attrib)
- for key in ['symbol', 'total_counts']:
- print(key, '= ', i.get(key))
+ _logger.debug("%s", i.attrib)
+ for key in ['symbol', 'total_counts']:
+ _logger.debug('%s = %s', key, i.get(key))
element = i.get('symbol')
ddict[element] = {}
#ddict[element]['z'] = i.get('atomic_number')
@@ -54,10 +55,9 @@ def getXMSOFileFluorescenceInformation(xmsoFile):
'counts': [],
'correction_factor':[]}
for a in i.iter('fluorescence_line'):
- if DEBUG:
- print(a.attrib)
- for key in ['type', 'total_counts']:
- print(key, '= ', a.get(key))
+ _logger.debug("%s", a.attrib)
+ for key in ['type', 'total_counts']:
+ _logger.debug('%s = %s', key, a.get(key))
line = a.get('type')
ddict[element][line] = {}
#ddict[element][line]['total'] = float(a.get('total_counts'))
@@ -74,8 +74,7 @@ def getXMSOFileFluorescenceInformation(xmsoFile):
transitionsAffected.append(key)
cumulator = 0
for b in a.iter('counts'):
- if DEBUG:
- print(b.attrib)
+ _logger.debug("%s", b.attrib)
value = float(b.text)
ddict[element][line]['counts'].append(value)
cumulator += value
@@ -117,7 +116,7 @@ def test(xmsoFile='t.xmso'):
if line == "z":
#atomic number
continue
- if 1 or DEBUG or line in ['K', 'Ka', 'Kb', 'L', 'L1', 'L2', 'L3', 'M']:
+ if 1 or line in ['K', 'Ka', 'Kb', 'L', 'L1', 'L2', 'L3', 'M']:
correction1 = ddict[element][line]['correction_factor'][1]
correctionn = ddict[element][line]['correction_factor'][-1]
print("Element %s Line %s Correction 2 = %f Correction n = %f" %\
diff --git a/PyMca5/PyMcaPlugins/AdvancedAlignmentScanPlugin.py b/PyMca5/PyMcaPlugins/AdvancedAlignmentScanPlugin.py
index 441b635..3a310c3 100644
--- a/PyMca5/PyMcaPlugins/AdvancedAlignmentScanPlugin.py
+++ b/PyMca5/PyMcaPlugins/AdvancedAlignmentScanPlugin.py
@@ -27,7 +27,111 @@ __author__ = "Tonn Rueter & V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+__doc__ = """
+Due to uncertainties in the experimental set-up, recorded data might be shifted unrelated
+to physical effects probed in the experiment. The present plug-in calculates this shift and
+corrects the data using a variety of different methods.
+
+Usage and Description
+---------------------
+
+Data that is subject to a shift must be loaded into the plot window of the main application.
+The plug-in offers two ways to treat the data:
+
+ - A shortcut options, called *Perform FFT Shift*, calculates the shift and directly corrects
+ the data.
+ - The *Show Alignment Window* option, showing a window that allows for specification of the
+ shift and alignment methods, as well as offering the possibility to save calculated shifts
+ and load previously calculated shifts from a file.
+ It is also possible to enter shift values by hand.
+
+
+Once the *Alignment Window* is opened, the alignment method and the shift method must be specified.
+The alignment method specifies how the shift is calculated, while the shift method determines
+how the shift is applied to the data.
+
+The table shows three columns:
+
+ - The first one shows the plot legend of the data that will be
+ corrected by the shift method.
+ - The second column shows the plot legend from which the shift
+ is calculated.
+ - The third column shows the shift values calculated by the alignment method in
+ units of the plot windows x-axis.
+
+While columns one and two can not be edited, shift values
+can be entered by hand. Another way of setting the shift values is to load them from a existing
+\*.shift file using the Load button.
+
+Once the shift values are set, they can either be directly applied to the data present in the
+plot window, using the *Apply* button, or the data can be stored in memory. The latter options allow
+to use a reference signal recorded during the experiment, to determine the shift and then apply
+the shift values to a different set of data.
+
+.. note::
+
+ In order to match different sets of data to another, as necessary in the case of a
+ reference signal, the order in which the data is added to the plot window is crucial. If one
+ switches between two sets of data, where one set aligns the other one, it is highly encouraged
+ to consult the table in the *Alignment window* to check if every element in the two different
+ sets of data is assigned to its correct counterpart before applying the shift.
+
+
+If the data in the plot window is zoomed-in to a distinct feature, only this range of the data
+is used to calculate the shift.
+
+Methods used by the plug-in
+---------------------------
+
+Alignment methods are used to calculate the shift. Present methods include FFT, MAX, FIT and
+FIT DRV.
+
+*FFT*:
+
+ Uses the Fourier Transform of the curves to calculate their cross-correlation. The maximum
+ of the correlation is determined, and yields the shift value. This method is the default option.
+ Since it is not affected by the peak shape, it is fast and numerically robust.
+
+ .. note:: The shifts are given in real space values.
+
+*MAX*:
+
+ Determines the maximum of each curve. The shift is given by the differences in the x-position
+ of the maxima. Note that this method is highly vulnerable to noise in the data and spikes.
+
+*FIT*:
+
+ This method subtracts a background from the data using the SNIP algorithm and searches for peaks
+ in the data. For every curve, the single most pronounced feature is selected.
+ The peak is fitted by a Gaussian model. The shifts are then given by differences in the x-offsets
+ of the fitted Gaussians.
+
+*FIT DRV*:
+
+ Uses the same procedure as the FIT method. However the fit is applied to the first derivative of
+ the data. This method is only recommended for X-ray absorption data.
+
+Shift methods are used to apply the calculated shift to the data. Present methods include *Shift x-range*
+and *Inverse FFT shift*.
+
+*Shift x-range*:
+
+ This method adds the calculated shift value to every point.
+
+*Inverse FFT shift*:
+
+ Takes the Fourier Transform of a curve and multiplies the shift as a phase factor. The multiplication
+ of a phase factor in Fourier space translates to a shift in the x-range in real space. The shifted data
+ is given by the inverse Fourier transform.
+
+ .. note::
+
+ For this process, the data needs to have a equidistant x-range. If this is not the case, the data
+ will be interpolated on a equidistant x-range. Due to the cyclic nature of the Fourier transform, this
+ method is recommended for data that has linear background.
+"""
import numpy
+import logging
import sys
import traceback
from PyMca5.PyMcaGui import PyMcaQt as qt
@@ -41,13 +145,15 @@ from PyMca5.PyMcaMath.fitting.SpecfitFuns import gauss
from PyMca5.PyMcaMath.fitting import SpecfitFuns
from os.path import join as pathjoin
+_logger = logging.getLogger(__name__)
+
try:
from PyMca5 import Plugin1DBase
except ImportError:
- print("WARNING:AlignmentScanPlugin import from somewhere else")
+ _logger.warning("WARNING:AlignmentScanPlugin import from somewhere else")
from . import Plugin1DBase
-DEBUG = 0
+
class AlignmentWidget(qt.QDialog):
_storeCode = 2
@@ -257,8 +363,7 @@ class AlignmentWidget(qt.QDialog):
return False
if not str(filename).endswith('.shift'):
filename += '.shift'
- if DEBUG == 1:
- print('saveOptions -- Filename: "%s"' % filename)
+ _logger.debug('saveOptions -- Filename: "%s"', filename)
currentOrder = self.plugin.getOrder()
outDict = ConfigDict.ConfigDict()
llist, ddict = self.getDict()
@@ -482,8 +587,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
xmin = xmin0
if xmax0 < xmax:
xmax = xmax0
- if DEBUG == 1:
- print('calculateShiftsFit -- xmin = %.3f, xmax = %.3f'%(xmin, xmax))
+ _logger.debug('calculateShiftsFit -- xmin = %.3f, xmax = %.3f', xmin, xmax)
# Get active curve
activeCurve = self.getActiveCurve()
@@ -515,11 +619,11 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
numpy.asarray([yp0, xp0, fwhm0]),
xdata=x0[fitrange0],
ydata=y0[fitrange0])
- if DEBUG == 1:
- if derivative:
- print('calculateShiftsFit -- Results (Leg, PeakPos, Shift):')
- else:
- print('calculateShiftsFitDerivative -- Results (Leg, PeakPos, Shift):')
+
+ if derivative:
+ _logger.debug('calculateShiftsFit -- Results (Leg, PeakPos, Shift):')
+ else:
+ _logger.debug('calculateShiftsFitDerivative -- Results (Leg, PeakPos, Shift):')
for x,y,legend,info in curves:
idx = numpy.nonzero((xmin <= x) & (x <= xmax))[0]
x = numpy.take(x, idx)
@@ -553,8 +657,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
key = legend
retList.append(key)
retDict[key] = shift
- if DEBUG == 1:
- print( '\t%s\t%.3f\t%.3f'%(legend, fitp[1], shift))
+ _logger.debug('\t%s\t%.3f\t%.3f', legend, fitp[1], shift)
return retList, retDict
def calculateShiftsMax(self):
@@ -595,10 +698,9 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
# Determine the index of maximum in active curve
shift0 = numpy.argmax(y0)
- if DEBUG == 1:
- print('calculateShiftsMax -- Results:')
- print('\targmax(y) shift')
- for x,y,legend,info in curves:
+ _logger.debug('calculateShiftsMax -- Results:')
+ _logger.debug('\targmax(y) shift')
+ for x, y, legend, info in curves:
idx = numpy.nonzero((xmin <= x) & (x <= xmax))[0]
x = numpy.take(x, idx)
y = numpy.take(y, idx)
@@ -608,8 +710,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
key = legend
retList.append(key)
retDict[key] = shift
- if DEBUG == 1:
- print('\t%d %.3f'%(x[shifty],shift))
+ _logger.debug('\t%d %.3f', x[shifty], shift)
return retList, retDict
def calculateShiftsFFT(self, portion=.95):
@@ -629,8 +730,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
xmin = xmin0
if xmax0 < xmax:
xmax = xmax0
- if DEBUG == 1:
- print('calculateShiftsFFT -- xmin = %.3f, xmax = %.3f'%(xmin, xmax))
+ _logger.debug('calculateShiftsFFT -- xmin = %.3f, xmax = %.3f', xmin, xmax)
# Get active curve
activeCurve = self.getActiveCurve()
@@ -650,8 +750,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
y0 = numpy.take(y0, idx)
fft0 = numpy.fft.fft(y0)
- if DEBUG == 1:
- print('calculateShiftsFFT -- results (Legend len(idx) shift):')
+ _logger.debug('calculateShiftsFFT -- results (Legend len(idx) shift):')
for x,y,legend,info in curves:
idx = numpy.nonzero((x >= xmin) & (x <= xmax))[0]
x = numpy.take(x, idx)
@@ -681,8 +780,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
key = legend
retList.append(key)
retDict[key] = shift
- if DEBUG == 1:
- print('\t%s\t%d\t%f'%(legend,len(idx),shift))
+ _logger.debug('\t%s\t%d\t%f', legend, len(idx), shift)
return retList, retDict
# END Alignment Methods
@@ -723,19 +821,16 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
if msg.exec_() != qt.QMessageBox.Ok:
return False
- if DEBUG == 1:
- print('applyShifts -- Shifting ...')
+ _logger.debug('applyShifts -- Shifting ...')
for idx, (x, y, legend, info) in enumerate(curves):
shift = self.shiftDict[legend]
if shift is None:
- if DEBUG == 1:
- print('\tCurve \'%s\' not found in shiftDict\n%s'\
- %(legend,str(self.shiftDict)))
+ _logger.debug('\tCurve \'%s\' not found in shiftDict\n%s',
+ legend, str(self.shiftDict))
continue
if shift == float('NaN'):
- if DEBUG == 1:
- print('\tCurve \'%s\' has NaN shift'%legend)
+ _logger.debug('\tCurve \'%s\' has NaN shift', legend)
continue
# Limit shift to zoomed in area
@@ -752,8 +847,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
else:
replot = False
# Check if scan number is adopted by new curve
- if DEBUG == 1:
- print('\'%s\' -- shifts -> \'%s\' by %f'%(self.shiftList[idx], legend, shift))
+ _logger.debug('\'%s\' -- shifts -> \'%s\' by %f', self.shiftList[idx], legend, shift)
#selectionlegend = info.get('selectionlegend', legend)
selectionlegend = legend
self.addCurve(xShifted, yShifted,
@@ -813,8 +907,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
Method receives methodName from AlignmentWidget
instance and assigns the according shift method.
"""
- if DEBUG == 1:
- print('setShiftMethod -- %s'%methodName)
+ _logger.debug('setShiftMethod -- %s', methodName)
methodName = str(methodName)
if methodName == 'Inverse FFT shift':
self.shiftMethod = self.fftShift
@@ -829,8 +922,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
Method receives methodName from AlignmentWidget
instance and assigns the according alignment method.
"""
- if DEBUG == 1:
- print('setAlignmentMethod -- %s'%methodName)
+ _logger.debug('setAlignmentMethod -- %s', methodName)
methodName = str(methodName)
if methodName == 'FFT':
self.alignmentMethod = self.calculateShiftsFFT
@@ -894,8 +986,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
"""
curves = self.getAllCurves()
if len(curves) < 1:
- if DEBUG == 1:
- print('interpolate -- no curves present')
+ _logger.debug('interpolate -- no curves present')
raise ValueError("At least 1 curve needed")
return
@@ -960,9 +1051,8 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
xmin0 = xmin
if xmax > xmax0:
xmax0 = xmax
- if DEBUG == 1:
- print('getXLimits -- overlap = %s, xmin = %.3f, xmax =%.3f'\
- %(overlap,xmin0,xmax0))
+ _logger.debug('getXLimits -- overlap = %s, xmin = %.3f, xmax =%.3f',
+ overlap, xmin0, xmax0)
return xmin0, xmax0
def normalize(self, y):
@@ -1019,12 +1109,10 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
# Extract highest peak
sortIdx = y[peakIdx].argsort()[-1]
except IndexError:
- if DEBUG == 1:
- print('No peaks found..')
+ _logger.debug('No peaks found..')
return None
except SystemError:
- if DEBUG == 1:
- print('Peak search failed. Continue with y maximum')
+ _logger.debug('Peak search failed. Continue with y maximum')
peakIdx = [ybg.argmax()]
sortIdx = 0
xpeak = float(x[peakIdx][sortIdx])
@@ -1064,8 +1152,7 @@ class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase):
msg.setWindowTitle('Alignment Scan Error')
msg.setText('No help file found.')
msg.exec_()
- if DEBUG == 1:
- print('XMCDWindow -- init: Unable to read help file')
+ _logger.debug('XMCDWindow -- init: Unable to read help file')
self.helpFileBrowser = None
if self.helpFileBrowser is not None:
self.helpFileBrowser.show()
@@ -1083,7 +1170,7 @@ if __name__ == "__main__":
a.show()
x = numpy.arange(250, 750, 2, dtype=float)
- y1 = 1.0 + 50.0 * numpy.exp(-0.001*(x-500)**2) + 2.*numpy.random.random(250.)
- y2 = 1.0 + 20.5 * numpy.exp(-0.005*(x-600)**2) + 2.*numpy.random.random(250.)
+ y1 = 1.0 + 50.0 * numpy.exp(-0.001*(x-500)**2) + 2.*numpy.random.random(250)
+ y2 = 1.0 + 20.5 * numpy.exp(-0.005*(x-600)**2) + 2.*numpy.random.random(250)
app.exec_()
diff --git a/PyMca5/PyMcaPlugins/AlignmentScanPlugin.py b/PyMca5/PyMcaPlugins/AlignmentScanPlugin.py
index ee33c2e..e12aa47 100644
--- a/PyMca5/PyMcaPlugins/AlignmentScanPlugin.py
+++ b/PyMca5/PyMcaPlugins/AlignmentScanPlugin.py
@@ -207,18 +207,18 @@ if __name__ == "__main__":
import os
try:
from PyMca5.PyMcaGui import PyMcaQt as qt
- from PyMca5.PyMcaGui.plotting import PlotWindow
+ from PyMca5.PyMcaGui.pymca import ScanWindow
app = qt.QApplication([])
QT = True
- plot = PlotWindow.PlotWindow()
+ plot = ScanWindow.ScanWindow()
except:
# test without graphical interface
QT = False
from PyMca5.PyMcaGraph import Plot
plot = Plot.Plot()
pluginDir = [os.path.dirname(__file__)]
- plot.getPlugins(method="getPlugin1DInstance",
- directoryList=pluginDir)
+ plot.pluginsToolButton.getPlugins(method="getPlugin1DInstance",
+ directoryList=pluginDir)
i = numpy.arange(1000.)
y1 = 10.0 + 5000.0 * numpy.exp(-0.01*(i-50)**2)
y2 = 10.0 + 5000.0 * numpy.exp(-((i-55)/5.)**2)
diff --git a/PyMca5/PyMcaPlugins/BackgroundStackPlugin.py b/PyMca5/PyMcaPlugins/BackgroundStackPlugin.py
index 1357d39..5362658 100644
--- a/PyMca5/PyMcaPlugins/BackgroundStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/BackgroundStackPlugin.py
@@ -38,6 +38,7 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import SGWindow
from PyMca5.PyMcaGui import SNIPWindow
@@ -45,12 +46,13 @@ from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
import numpy
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class BackgroundStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
SGtext = "Replace current stack by a\n"
SGtext += "Savitsky-Golay treated one."
diff --git a/PyMca5/PyMcaPlugins/ExternalImagesStackPlugin.py b/PyMca5/PyMcaPlugins/ExternalImagesStackPlugin.py
index b78da58..34e8e50 100644
--- a/PyMca5/PyMcaPlugins/ExternalImagesStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/ExternalImagesStackPlugin.py
@@ -43,6 +43,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import os
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import EDFStack
@@ -51,10 +52,13 @@ from PyMca5.PyMcaGui import StackPluginResultsWindow
from PyMca5.PyMcaGui import ExternalImagesWindow
from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
class ExternalImagesStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Load':[self._loadImageFiles,
"Load Images",
@@ -77,8 +81,7 @@ class ExternalImagesStackPlugin(StackPluginBase.StackPluginBase):
self.widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
diff --git a/PyMca5/PyMcaPlugins/FastXRFLinearFitStackPlugin.py b/PyMca5/PyMcaPlugins/FastXRFLinearFitStackPlugin.py
index 90ad304..fb974a3 100644
--- a/PyMca5/PyMcaPlugins/FastXRFLinearFitStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/FastXRFLinearFitStackPlugin.py
@@ -60,7 +60,7 @@ These plugins will be compatible with any stack window that provides the functio
import sys
import os
import numpy
-import time
+import logging
import traceback
from PyMca5 import StackPluginBase
from PyMca5.PyMcaPhysics import FastXRFLinearFit
@@ -71,11 +71,13 @@ from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import ArraySave
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
function = self.calculate
@@ -97,8 +99,7 @@ class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase):
self.thread = None
def stackUpdated(self):
- if DEBUG:
- print("FastXRFLinearFitStackPlugin.stackUpdated() called")
+ _logger.debug("FastXRFLinearFitStackPlugin.stackUpdated() called")
self._widget = None
def selectionMaskUpdated(self):
@@ -110,8 +111,7 @@ class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase):
self._widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot ", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
@@ -158,7 +158,7 @@ class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase):
self.fitInstance = FastXRFLinearFit.FastXRFLinearFit()
#self._fitConfigurationFile="E:\DATA\COTTE\CH1777\G4-4720eV-NOWEIGHT-Constant-batch.cfg"
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.result = self.actualCalculation()
@@ -248,8 +248,8 @@ class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase):
parameters = self.configurationWidget.getParameters()
outputDir = parameters["output_dir"]
if outputDir in [None, ""]:
- if DEBUG:
- print("Nothing to be saved")
+ _logger.debug("Nothing to be saved")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
return
if parameters["file_root"] is None:
fileRoot = ""
diff --git a/PyMca5/PyMcaPlugins/FitStackPlugin.py b/PyMca5/PyMcaPlugins/FitStackPlugin.py
index e11205b..10c627c 100644
--- a/PyMca5/PyMcaPlugins/FitStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/FitStackPlugin.py
@@ -38,19 +38,21 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-
+import logging
+_logger = logging.getLogger(__name__)
try:
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import StackSimpleFitWindow
from PyMca5.PyMcaGui import PyMca_Icons
except ImportError:
- print("FitStackPlugin importing from somewhere else")
+ _logger.warning("FitStackPlugin importing from somewhere else")
-DEBUG = 0
class FitStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
+
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
function = self.fitStack
diff --git a/PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py b/PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py
index 7ede608..fa005be 100644
--- a/PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/ImageAlignmentStackPlugin.py
@@ -40,6 +40,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import FFTAlignmentWindow
@@ -51,12 +52,15 @@ from PyMca5.PyMcaGui import PyMcaFileDialogs
from PyMca5.PyMcaIO import specfilewrapper
from PyMca5.PyMcaGui import HDF5Widget
+_logger = logging.getLogger(__name__)
+
try:
from PyMca5.PyMcaGui import SIFTAlignmentWindow
sift = SIFTAlignmentWindow.sift
+ ocl = SIFTAlignmentWindow.silx.opencl.ocl
SIFT = True
except:
- print("SIFTAlignmentWindow not successful")
+ _logger.warning("SIFTAlignmentWindow not successful")
SIFT = False
try:
@@ -65,10 +69,11 @@ try:
except:
HDF5 = False
-DEBUG = 0
+
class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'FFT Alignment':[self._fftAlignment,
"Align using FFT",
@@ -132,7 +137,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
if filename is not None:
self.__hdf5 = self.initializeHDF5File(filename)
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
shifts = self.calculateShiftsFFT(stack,
reference,
offsets=offsets,
@@ -198,7 +203,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
@@ -267,14 +272,14 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
import pyopencl
except:
raise ImportError("PyOpenCL does not seem to be installed on your system")
- if sift.opencl.ocl is None:
+ if ocl is None:
raise ImportError("PyOpenCL does not seem to be installed on your system")
stack = self.getStackDataObject()
if stack is None:
return
mcaIndex = stack.info.get('McaIndex')
if not (mcaIndex in [0, 2, -1]):
- raise IndexError("Unsupported 1D index %d" % mcaIndex)
+ raise IndexError("Unsupported 1D index %d" % mcaIndex)
widget = SIFTAlignmentWindow.SIFTAlignmentDialog()
widget.setStack(stack)
mask = self.getStackSelectionMask()
@@ -293,7 +298,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
self.__hdf5 = self.initializeHDF5File(filename)
crop = False
device = ddict['opencl_device']
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
result = self.calculateShiftsSIFT(stack, reference, mask=mask, device=device,
crop=crop, filename=filename)
else:
@@ -315,28 +320,13 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
if mask.sum() == 0:
mask = None
if device is None:
- if sys.platform == 'darwin':
- max_workgroup_size = 1
- siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
- max_workgroup_size=max_workgroup_size,
- devicetype="cpu",
- init_sigma=sigma)
- else:
- siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
- devicetype="cpu",
- init_sigma=sigma)
+ siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
+ devicetype="cpu",
+ init_sigma=sigma)
else:
- deviceType = sift.opencl.ocl.platforms[device[0]].devices[device[1]].type
- if deviceType.lower() == "cpu" and sys.platform == 'darwin':
- max_workgroup_size = 1
- siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
- max_workgroup_size=max_workgroup_size,
- device=device,
- init_sigma=sigma)
- else:
- siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
- device=device,
- init_sigma=sigma)
+ siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
+ deviceid=device,
+ init_sigma=sigma)
data = stack.data
mcaIndex = stack.info['McaIndex']
if not (mcaIndex in [0, 2, -1]):
@@ -358,11 +348,10 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
shifts = numpy.zeros((data.shape[mcaIndex], 2), dtype=numpy.float32)
if mcaIndex == 0:
for i in range(data.shape[mcaIndex]):
- if DEBUG:
- print("SIFT Shifting image %d" % i)
+ _logger.debug("SIFT Shifting image %d", i)
result = siftInstance.align(data[i].astype(numpy.float32), shift_only=True, return_all=True)
- if DEBUG:
- print("Index = %d shift = %.4f, %.4f" % (i, result['offset'][0], result['offset'][1]))
+ _logger.debug("Index = %d shift = %.4f, %.4f",
+ i, result['offset'][0], result['offset'][1])
if filename is None:
stack.data[i] = result['result']
else:
@@ -373,12 +362,11 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
else:
image2 = numpy.zeros(reference.shape, dtype=numpy.float32)
for i in range(data.shape[mcaIndex]):
- if DEBUG:
- print("SIFT Shifting image %d" % i)
+ _logger.debug("SIFT Shifting image %d", i)
image2[:, :] = data[:, :, i]
result = siftInstance.align(image2, shift_only=True, return_all=True)
- if DEBUG:
- print("Index = %d shift = %.4f, %.4f" % (i, result['offset'][0], result['offset'][1]))
+ _logger.debug("Index = %d shift = %.4f, %.4f",
+ i, result['offset'][0], result['offset'][1])
if filename is None:
stack.data[:, :, i] = result['result']
else:
@@ -423,7 +411,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
@@ -437,9 +425,8 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
self.finishHDF5File(hdf)
def calculateShiftsFFT(self, stack, reference, offsets=None, widths=None, crop=False):
- if DEBUG:
- print("Offsets = ", offsets)
- print("Widths = ", widths)
+ _logger.debug("Offsets = %s", offsets)
+ _logger.debug("Widths = %s", widths)
data = stack.data
if offsets is None:
offsets = [0.0, 0.0]
@@ -479,8 +466,8 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
image1fft2 = fft2Function(image1)
shifts[i] = ImageRegistration.measure_offset_from_ffts(image2fft2,
image1fft2)
- if DEBUG:
- print("Index = %d shift = %.4f, %.4f" % (i, shifts[i][0], shifts[i][1]))
+ _logger.debug("Index = %d shift = %.4f, %.4f",
+ i, shifts[i][0], shifts[i][1])
self._progress = (100 * i) / total
elif mcaIndex in [2, -1]:
for i in range(data.shape[mcaIndex]):
@@ -490,8 +477,8 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
image1fft2 = fft2Function(image1)
shifts[i] = ImageRegistration.measure_offset_from_ffts(image2fft2,
image1fft2)
- if DEBUG:
- print("Index = %d shift = %.4f, %.4f" % (i, shifts[i][0], shifts[i][1]))
+ _logger.debug("Index = %d shift = %.4f, %.4f",
+ i, shifts[i][0], shifts[i][1])
self._progress = (100 * i) / total
else:
raise IndexError("Only stacks of images or spectra supported. 1D index should be 0 or 2")
@@ -515,11 +502,9 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
getfilter=True,
currentfilter=filefilter[0])
if len(filename):
- if DEBUG:
- print("file name = %s file filter = %s" % (filename, ffilter))
+ _logger.debug("file name = %s file filter = %s", filename, ffilter)
else:
- if DEBUG:
- print("nothing selected")
+ _logger.debug("nothing selected")
return
filename = filename[0]
if ffilter.startswith('HDF5'):
@@ -575,14 +560,13 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
currentfilter=filefilter[0])
if len(filename):
filename = filename[0]
- if DEBUG:
- print("file name = %s" % filename)
+ _logger.debug("file name = %s", filename)
else:
raise IOError("No output file selected")
if filename is not None:
self.__hdf5 = self.initializeHDF5File(filename)
crop = False
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
result = self.shiftStack(stack,
shifts,
crop=crop,
@@ -620,7 +604,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
except:
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
raise
dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
@@ -688,8 +672,7 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
stack.data[:, :, i] = tmpImage * window
else:
outputStack[i] = tmpImage * window
- if DEBUG:
- print("Index %d bilinear shifted" % i)
+ _logger.debug("Index %d bilinear shifted", i)
self._progress = (100 * i) / total
def initializeHDF5File(self, fname):
diff --git a/PyMca5/PyMcaPlugins/KineticsPlugin.py b/PyMca5/PyMcaPlugins/KineticsPlugin.py
index 0c8dd3c..291c320 100644
--- a/PyMca5/PyMcaPlugins/KineticsPlugin.py
+++ b/PyMca5/PyMcaPlugins/KineticsPlugin.py
@@ -176,10 +176,9 @@ def getPlugin1DInstance(plotWindow, **kw):
return ob
if __name__ == "__main__":
- import sys
import os
from PyMca5.PyMcaGui import PyMcaQt as qt
- from PyMca5.PyMcaGui import PlotWindow
+ from PyMca5.PyMcaGui.pymca import ScanWindow
# first order, k = 4.820e-04
x = [0, 600, 1200, 1800, 2400, 3000, 3600]
y = [0.0365, 0.0274, 0.0206, 0.0157, 0.0117, 0.00860, 0.00640]
@@ -189,10 +188,11 @@ if __name__ == "__main__":
print("Expected slope: 0.000482")
sigmay = None
app = qt.QApplication([])
- plot = PlotWindow.PlotWindow()
- plot.setPluginDirectoryList([os.path.dirname(__file__)])
- plot.getPlugins()
- plot.addCurve(x, y, "Test Data")
+ plot = ScanWindow.ScanWindow()
+ plot.pluginsToolButton.setPluginDirectoryList([os.path.dirname(__file__)])
+ plot.pluginsToolButton.getPlugins()
+ plot.addCurve(x, y, "Test Data",
+ resetzoom=True)
plot.show()
plugin = getPlugin1DInstance(plot)
for method in plugin.getMethods():
diff --git a/PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py b/PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py
index d6bd9b5..b906356 100644
--- a/PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/LoadPositionersStackPlugin.py
@@ -43,6 +43,7 @@ Data loaded with this plugin can then be used by other tools, such as the
__authors__ = ["P. Knobel"]
__license__ = "MIT"
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui.io.hdf5.HDF5Widget import getGroupNameDialog
@@ -76,15 +77,15 @@ except ImportError:
# suppress errors and warnings if fabio is missing
if silx_open is not None:
- import logging
logging.getLogger("silx.io.fabioh5").setLevel(logging.CRITICAL)
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class LoadPositionersStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow)
self.methodDict = {'Load positioners': [self._loadFromFile,
"Load positioners from file"]}
@@ -129,11 +130,9 @@ class LoadPositionersStackPlugin(StackPluginBase.StackPluginBase):
getfilter=True,
currentfilter=filefilter[0])
if len(filename):
- if DEBUG:
- print("file name = %s file filter = %s" % (filename, ffilter))
+ _logger.debug("file name = %s file filter = %s", filename, ffilter)
else:
- if DEBUG:
- print("nothing selected")
+ _logger.debug("nothing selected")
return
filename = filename[0]
diff --git a/PyMca5/PyMcaPlugins/Medfilt2DPlugin.py b/PyMca5/PyMcaPlugins/Medfilt2DPlugin.py
new file mode 100644
index 0000000..dc79dfa
--- /dev/null
+++ b/PyMca5/PyMcaPlugins/Medfilt2DPlugin.py
@@ -0,0 +1,208 @@
+#/*##########################################################################
+# Copyright (C) 2004-2018 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+
+from PyMca5.PyMcaCore.Plugin2DBase import Plugin2DBase
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from silx.gui.plot import Plot2D
+from silx.math.medianfilter import medfilt2d
+
+
+class Medfilt2DPlugin(Plugin2DBase):
+ def __init__(self, plotWindow):
+ Plugin2DBase.__init__(self, plotWindow)
+ self.methods = {
+ "Median filter": [self._medfilt2D,
+ "Open a plot showing a filtered image",
+ None]
+ }
+ self.widget = None
+
+ def getMethods(self, plottype=None):
+ """
+
+ :return: A list with the NAMES associated to the callable methods
+ that are applicable to the specified type plot. The list can be empty.
+ :rtype: list[string]
+ """
+ return list(self.methods.keys())
+
+ def _getMethod(self, name):
+ method = self.methods.get(name)
+ if method is None:
+ raise NameError("method %s not found" % name)
+ return method
+
+ def getMethodToolTip(self, name):
+ """
+ Returns the help associated to the particular method name or None.
+
+ :param name: The method for which a tooltip is asked
+ :rtype: string
+ """
+ return self._getMethod(name)[1]
+
+ def getMethodPixmap(self, name):
+ """
+ :param name: The method for which a pixmap is asked
+ :rtype: QPixmap or None
+ """
+ return self._getMethod(name)[2]
+
+ def applyMethod(self, name):
+ """
+ The plugin is asked to apply the method associated to name.
+ """
+ return self._getMethod(name)[0]()
+
+ def _medfilt2D(self):
+ if self.widget is None:
+ self.widget = Plot2DMedFilt()
+ self.widget.show()
+
+ active_image = self._plotWindow.getActiveImage()
+ if active_image is None:
+ return
+ data = active_image.getData()
+ if data.ndim > 2:
+ raise NotImplementedError("Median filter not implemented for RGB images")
+ self.widget.setColormap(active_image.getColormap())
+ self.widget.setRawData(data)
+ self.widget.setLegend("medfilt2d(%s)" % active_image.getLegend())
+
+ def activeImageChanged(self, prev, new):
+ if new is None:
+ return
+ self._medfilt2D()
+
+
+class Plot2DMedFilt(Plot2D):
+ # TODO: we could allow setting different X- and Y-filter width.
+ def __init__(self, parent=None):
+ Plot2D.__init__(self, parent=parent)
+ self.toolBar().addSeparator()
+ label = qt.QLabel(self)
+ label.setText("Median filter width:")
+
+ self.spinbox = qt.QSpinBox(self)
+ self.spinbox.setMinimum(1)
+ self.spinbox.setValue(1)
+ self.spinbox.setSingleStep(2)
+ self.spinbox.valueChanged[int].connect(self._medfiltWidthChanged)
+ self.spinbox.setEnabled(False)
+
+ self.toolBar().addWidget(label)
+ self.toolBar().addWidget(self.spinbox)
+
+ self._data = None
+ self._legend = None
+ self._colormap = None
+
+ def setLegend(self, legend):
+ """
+
+ :param str legend:
+ :return:
+ """
+ self._legend = legend
+
+ def setRawData(self, data, legend=None):
+ """Set raw image data to be filtered.
+
+ :param numpy.ndarray data:
+ :param str legend:
+ :return:
+ """
+ if data is None:
+ self.spinbox.setEnabled(False)
+ self._data = None
+ return
+ if data.ndim != 2:
+ raise TypeError("Data must be a 2D array")
+ self._data = data
+ self.spinbox.setMaximum(max(data.shape))
+ self.spinbox.setEnabled(True)
+ self._applyFilter()
+
+ def setColormap(self, colormap):
+ self._colormap = colormap
+
+ @property
+ def medfilt_width(self):
+ return self.spinbox.value()
+
+ def _medfiltWidthChanged(self, width):
+ self._applyFilter()
+
+ def _applyFilter(self):
+ self.addImage(medfilt2d(self._data, kernel_size=self.medfilt_width),
+ colormap=self._colormap,
+ legend="medfilt2d(%s)" % self._legend)
+
+
+MENU_TEXT = "2D median filter"
+
+
+def getPlugin2DInstance(plotWindow, **kw):
+ """
+ """
+ ob = Medfilt2DPlugin(plotWindow)
+ return ob
+
+
+if __name__ == "__main__":
+ # python -m PyMca5.PyMcaPlugins.Medfilt2DPlugin
+ from PyMca5.PyMcaGui.PluginsToolButton import PluginsToolButton
+ from PyMca5 import PyMcaPlugins
+ import numpy
+ import os
+ from silx.test.utils import add_relative_noise
+ from silx.gui.plot import PlotWidget
+
+ # build a plot widget with a plugin toolbar button
+ app = qt.QApplication([])
+ master_plot = PlotWidget()
+ toolb = qt.QToolBar(master_plot)
+ plugins_tb_2d = PluginsToolButton(plot=master_plot,
+ parent=toolb,
+ method="getPlugin2DInstance")
+ plugins_tb_2d.getPlugins(
+ method="getPlugin2DInstance",
+ directoryList=[os.path.dirname(PyMcaPlugins.__file__)])
+ toolb.addWidget(plugins_tb_2d)
+ master_plot.addToolBar(toolb)
+ master_plot.show()
+
+ # add a noisy image
+ a, b = numpy.meshgrid(numpy.linspace(-10, 10, 500),
+ numpy.linspace(-10, 5, 400),
+ indexing="ij")
+ myimg = numpy.asarray(numpy.sin(a * b) / (a * b),
+ dtype='float32')
+ myimg = add_relative_noise(myimg,
+ max_noise=10.) # %
+ master_plot.addImage(myimg)
+
+ app.exec_()
diff --git a/PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py b/PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py
index f350a5c..cce25dc 100644
--- a/PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py
+++ b/PyMca5/PyMcaPlugins/MedianFilterScanDeglitchPlugin.py
@@ -37,8 +37,11 @@ from PyMca5 import Plugin1DBase
from PyMca5.PyMcaMath.PyMcaSciPy.signal import medfilt1d
from PyMca5.PyMcaGui import PyMcaQt as qt
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
+
-DEBUG = 0
class MedianFilterScanDeglitchPlugin(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw)
@@ -150,12 +153,10 @@ class MedianFilterScanDeglitchPlugin(Plugin1DBase.Plugin1DBase):
if not (self.width%2):
self.width += 1
if self._widget.buttonAll.isChecked():
- if DEBUG:
- print('AllChecked')
+ _logger.debug('AllChecked')
self.removeSpikesAll()
elif self._widget.buttonActive.isChecked():
- if DEBUG:
- print('ActiveChecked')
+ _logger.debug('ActiveChecked')
self.removeSpikesActive()
def removeSpikesAll(self):
@@ -190,7 +191,7 @@ class MedianFilterScanDeglitchPlugin(Plugin1DBase.Plugin1DBase):
self.addCurve(x,ynew,legend,info, replace=False, replot=True)
else:
self.addCurve(x,ynew,legend,info, replace=False, replot=False)
- #self._plotWindow.replot()
+
MENU_TEXT = "Remove glitches from curves"
def getPlugin1DInstance(plotWindow, **kw):
@@ -198,10 +199,10 @@ def getPlugin1DInstance(plotWindow, **kw):
return ob
if __name__ == "__main__":
- from PyMca5.PyMcaGui import PlotWindow
+ from silx.gui.plot import Plot1D
app = qt.QApplication([])
- sw = PlotWindow.PlotWindow()
+ sw = Plot1D()
x = numpy.linspace(0, 1999, 2000)
y0 = x/100. + 100.*numpy.exp(-(x-500)**2/1000.) + 50.*numpy.exp(-(x-1200)**2/5000.) + 100.*numpy.exp(-(x-1700)**2/500.) + 10 * numpy.random.random(2000)
@@ -213,6 +214,7 @@ if __name__ == "__main__":
sw.addCurve(x, y0, legend="Curve0")
sw.addCurve(x, y1, legend="Curve1")
+ sw.setActiveCurve("Curve0")
plugin = getPlugin1DInstance(sw)
plugin.configureFilter()
diff --git a/PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py b/PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py
index b414c56..b445588 100644
--- a/PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/MedianFilterStackPlugin.py
@@ -41,15 +41,18 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui.pymca import Median2DBrowser
from PyMca5.PyMcaGui import PyMca_Icons
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class MedianFilterStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Show':[self._showWidget,
"Image Browser with Median Filter",
@@ -58,8 +61,7 @@ class MedianFilterStackPlugin(StackPluginBase.StackPluginBase):
self.widget = None
def stackUpdated(self):
- if DEBUG:
- print("StackBrowserPlugin.stackUpdated() called")
+ _logger.debug("StackBrowserPlugin.stackUpdated() called")
if self.widget is None:
return
if self.widget.isHidden():
@@ -92,8 +94,7 @@ class MedianFilterStackPlugin(StackPluginBase.StackPluginBase):
self.widget.setBackgroundImage(self._getBackgroundImage())
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
diff --git a/PyMca5/PyMcaPlugins/MotorInfoPlugin.py b/PyMca5/PyMcaPlugins/MotorInfoPlugin.py
index ed55964..f3d9089 100644
--- a/PyMca5/PyMcaPlugins/MotorInfoPlugin.py
+++ b/PyMca5/PyMcaPlugins/MotorInfoPlugin.py
@@ -47,7 +47,10 @@ except ImportError:
print("MotorInfoPlugin importing from somewhere else")
import MotorInfoWindow
-DEBUG = 0
+import logging
+_logger = logging.getLogger(__name__)
+
+
class MotorInfo(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw)
@@ -86,11 +89,10 @@ class MotorInfo(Plugin1DBase.Plugin1DBase):
def _getLists(self):
curves = self.getAllCurves()
nCurves = len(curves)
- if DEBUG:
- print ("Received %d curve(s).." % nCurves)
+ _logger.debug("Received %d curve(s)..", nCurves)
legendList = [leg for (xvals, yvals, leg, info) in curves]
infoList = [info for (xvals, yvals, leg, info) in curves]
- motorValuesList = self._convertInfoDictionary( infoList )
+ motorValuesList = self._convertInfoDictionary(infoList)
return legendList, motorValuesList
def _convertInfoDictionary(self, infosList):
diff --git a/PyMca5/PyMcaPlugins/MotorInfoWindow.py b/PyMca5/PyMcaPlugins/MotorInfoWindow.py
index 696de9b..6c4fd5f 100644
--- a/PyMca5/PyMcaPlugins/MotorInfoWindow.py
+++ b/PyMca5/PyMcaPlugins/MotorInfoWindow.py
@@ -27,6 +27,7 @@ __author__ = "Tonn Rueter"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import IconDict
@@ -40,7 +41,7 @@ if hasattr(qt, 'QString'):
else:
QString = qt.safe_str
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class MotorInfoComboBox(qt.QComboBox):
@@ -184,17 +185,15 @@ class MotorInfoTable(TableWidget):
self.setItem(currentRow, 0, legend )
def updateTable(self, legList, motList):
- if DEBUG:
- print("updateTable received lengths = ", len(legList), len(motList))
- print("updateTable received legList = ", legList)
- print("updateTable received motList = ", motList)
+ _logger.debug("updateTable received lengths = %d %d", len(legList), len(motList))
+ _logger.debug("updateTable received legList = %s", legList)
+ _logger.debug("updateTable received motList = %s", motList)
if legList is None:
nItems = 0
else:
nItems = len(legList)
if self.legendsList == legList and self.motorsList == motList:
- if DEBUG:
- print("Ignoring update, no changes")
+ _logger.debug("Ignoring update, no changes")
else:
nRows = self.rowCount()
if nRows != nItems:
@@ -268,7 +267,7 @@ class MotorInfoDialog(qt.QWidget):
qt.QWidget.__init__(self, parent)
self.setWindowTitle("Motor Info Plugin")
if len(legends) != len(motorValues):
- print('Consistency error: legends and motorValues do not have same length!')
+ _logger.warning('Consistency error: legends and motorValues do not have same length!')
self.numCurves = len(legends)
# Buttons
self.buttonAddColumn = qt.QPushButton("Add", self)
diff --git a/PyMca5/PyMcaPlugins/MultipleScanToMeshPlugin.py b/PyMca5/PyMcaPlugins/MultipleScanToMeshPlugin.py
index 7da49c2..a18b06c 100644
--- a/PyMca5/PyMcaPlugins/MultipleScanToMeshPlugin.py
+++ b/PyMca5/PyMcaPlugins/MultipleScanToMeshPlugin.py
@@ -28,15 +28,16 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
import numpy
+import logging
from matplotlib.mlab import griddata
from PyMca5 import Plugin1DBase
from PyMca5.PyMcaGui import MaskImageWidget
from PyMca5.PyMcaGui import PyMcaQt as qt
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class MultipleScanToMeshPlugin(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
@@ -76,14 +77,11 @@ class MultipleScanToMeshPlugin(Plugin1DBase.Plugin1DBase):
"""
The plugin is asked to apply the method associated to name.
"""
- if DEBUG:
- self.methodDict[name][0]()
- else:
- try:
- self.methodDict[name][0]()
- except:
- print(sys.exc_info())
- raise
+ try:
+ self.methodDict[name][0]()
+ except:
+ _logger.error(sys.exc_info())
+ raise
def _rixsID26(self):
allCurves = self.getAllCurves()
@@ -264,7 +262,7 @@ if __name__ == "__main__":
#w.exec_()
#sys.exit(0)
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
x = numpy.arange(100.)
y = x * x
plot = Plot.Plot()
diff --git a/PyMca5/PyMcaPlugins/NNMAStackPlugin.py b/PyMca5/PyMcaPlugins/NNMAStackPlugin.py
index 3d96db5..40a7a41 100644
--- a/PyMca5/PyMcaPlugins/NNMAStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/NNMAStackPlugin.py
@@ -59,6 +59,7 @@ functions:
selectionMaskUpdated
"""
import numpy
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import CalculationThread
@@ -67,12 +68,13 @@ from PyMca5.PyMcaGui import StackPluginResultsWindow
from PyMca5.PyMcaGui import PyMca_Icons
qt = StackPluginResultsWindow.qt
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class NNMAStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Calculate': [self.calculate,
"Perform NNMA",
@@ -86,8 +88,7 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
self.thread = None
def stackUpdated(self):
- if DEBUG:
- print("NNMAStackPlugin.stackUpdated() called")
+ _logger.debug("NNMAStackPlugin.stackUpdated() called")
self.configurationWidget = None
self.widget = None
@@ -100,8 +101,7 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
self.widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
@@ -177,28 +177,23 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
self._executeFunctionAndParameters()
def _executeFunctionAndParameters(self):
- if DEBUG:
- print("NNMAStackPlugin _executeFunctionAndParameters")
+ _logger.debug("NNMAStackPlugin _executeFunctionAndParameters")
self.widget = None
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.finished.connect(self.threadFinished)
self.configurationWidget.show()
message = "Please wait. NNMA Calculation going on."
- if DEBUG:
- print("NNMAStackPlugin starting thread")
+ _logger.debug("NNMAStackPlugin starting thread")
self.thread.start()
- if DEBUG:
- print("NNMAStackPlugin waitingMessageDialog")
+ _logger.debug("NNMAStackPlugin waitingMessageDialog")
CalculationThread.waitingMessageDialog(self.thread,
message=message,
parent=self.configurationWidget)
- if DEBUG:
- print("NNMAStackPlugin waitingMessageDialog passed")
+ _logger.debug("NNMAStackPlugin waitingMessageDialog passed")
def actualCalculation(self):
- if DEBUG:
- print("NNMAStackPlugin actualCalculation")
+ _logger.debug("NNMAStackPlugin actualCalculation")
nnmaParameters = self.configurationWidget.getParameters()
self._status.setText("Calculation going on")
self.configurationWidget.setEnabled(False)
@@ -215,7 +210,7 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
stack = self.getStackDataObject()
if isinstance(stack, numpy.ndarray):
if stack.data.dtype not in [numpy.float, numpy.float32]:
- print("WARNING: Non floating point data")
+ _logger.warning("WARNING: Non floating point data")
text = "Calculation going on."
text += " WARNING: Non floating point data."
self._status.setText(text)
@@ -227,8 +222,7 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
return result
def threadFinished(self):
- if DEBUG:
- print("NNMAStackPlugin threadFinished")
+ _logger.debug("NNMAStackPlugin threadFinished")
result = self.thread.result
self.thread = None
if type(result) == type((1,)):
@@ -261,12 +255,10 @@ class NNMAStackPlugin(StackPluginBase.StackPluginBase):
vectorNames.append("NNMA Component %02d" % i)
vectorTitles.append("%g %% explained intensity" %\
eigenValues[i])
- if DEBUG:
- print("NNMAStackPlugin threadFinished. Create widget")
+ _logger.debug("NNMAStackPlugin threadFinished. Create widget")
self.widget = StackPluginResultsWindow.StackPluginResultsWindow(\
usetab=True)
- if DEBUG:
- print("NNMAStackPlugin threadFinished. Widget created")
+ _logger.debug("NNMAStackPlugin threadFinished. Widget created")
self.widget.buildAndConnectImageButtonBox(replace=True,
multiple=True)
qt = StackPluginResultsWindow.qt
diff --git a/PyMca5/PyMcaPlugins/PCAStackPlugin.py b/PyMca5/PyMcaPlugins/PCAStackPlugin.py
index e03fc90..27e5683 100644
--- a/PyMca5/PyMcaPlugins/PCAStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/PCAStackPlugin.py
@@ -48,6 +48,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import CalculationThread
@@ -57,12 +58,13 @@ from PyMca5.PyMcaGui import StackPluginResultsWindow
from PyMca5.PyMcaGui import PyMca_Icons
qt = StackPluginResultsWindow.qt
-DEBUG = 0
+_logger = logging.getLogger(__name__)
class PCAStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Calculate': [self.calculate, "Perform PCA", None],
'Show': [self._showWidget,
@@ -74,8 +76,7 @@ class PCAStackPlugin(StackPluginBase.StackPluginBase):
self.thread = None
def stackUpdated(self):
- if DEBUG:
- print("PCAStackPlugin.stackUpdated() called")
+ _logger.debug("PCAStackPlugin.stackUpdated() called")
self.configurationWidget = None
self.widget = None
@@ -88,8 +89,7 @@ class PCAStackPlugin(StackPluginBase.StackPluginBase):
self.widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
@@ -166,7 +166,7 @@ class PCAStackPlugin(StackPluginBase.StackPluginBase):
def _executeFunctionAndParameters(self):
self.widget = None
self.configurationWidget.show()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.result = self.actualCalculation()
@@ -223,7 +223,7 @@ class PCAStackPlugin(StackPluginBase.StackPluginBase):
stack = self.getStackDataObject()
if isinstance(stack, numpy.ndarray):
if stack.data.dtype not in [numpy.float, numpy.float32]:
- print("WARNING: Non floating point data")
+ _logger.warning("WARNING: Non floating point data")
text = "Calculation going on."
text += " WARNING: Non floating point data."
self._status.setText(text)
diff --git a/PyMca5/PyMcaPlugins/ROIStackPlugin.py b/PyMca5/PyMcaPlugins/ROIStackPlugin.py
index 0a73164..4b42fb7 100644
--- a/PyMca5/PyMcaPlugins/ROIStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/ROIStackPlugin.py
@@ -1,5 +1,5 @@
#/*##########################################################################
-# Copyright (C) 2004-2014 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 V.A. Sole, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -26,13 +26,16 @@
"""
This plugin opens a stack ROI window providing alternative views:
- - ICR Energy at Max.
- - ICR Energy at Min.
- - 3 energy slices
- - ICR Background
+ - Usual sum of counts in the region
+ - Channel/Energy at data Max in the region.
+ - Channel/Energy at data Min in the region.
+ - Map of the counts at the first channel of the region
+ - Map of the counts at the middle cahnnel of the region
+ - Map of the counts at the last channel of the region
+ - Background counts
This window also provides a median filter tool, with a configurable filter
-width, to smooth the stack image.
+width, to get rid of outlier pixel.
The mask of this plot widget is synchronized with the master stack widget.
@@ -42,15 +45,18 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui.pymca import StackROIWindow
from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class ROIStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Show':[self._showWidget,
"Show ROIs",
@@ -59,8 +65,7 @@ class ROIStackPlugin(StackPluginBase.StackPluginBase):
self.roiWindow = None
def stackUpdated(self):
- if DEBUG:
- print("ROIStackPlugin.stackUpdated() called")
+ _logger.debug("ROIStackPlugin.stackUpdated() called")
if self.roiWindow is None:
return
if self.roiWindow.isHidden():
@@ -86,8 +91,7 @@ class ROIStackPlugin(StackPluginBase.StackPluginBase):
self.stackUpdated()
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
diff --git a/PyMca5/PyMcaPlugins/RegularMeshPlugin.py b/PyMca5/PyMcaPlugins/RegularMeshPlugin.py
index a98c797..64bfb52 100644
--- a/PyMca5/PyMcaPlugins/RegularMeshPlugin.py
+++ b/PyMca5/PyMcaPlugins/RegularMeshPlugin.py
@@ -28,15 +28,15 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
-from numpy import cos, sin
import sys
+import logging
from PyMca5 import Plugin1DBase
-import os
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import MaskImageWidget
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class RegularMeshPlugins(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
@@ -76,14 +76,11 @@ class RegularMeshPlugins(Plugin1DBase.Plugin1DBase):
"""
The plugin is asked to apply the method associated to name.
"""
- if DEBUG:
- self.methodDict[name][0]()
- else:
- try:
- self.methodDict[name][0]()
- except:
- print(sys.exc_info())
- raise
+ try:
+ self.methodDict[name][0]()
+ except:
+ _logger.error(sys.exc_info())
+ raise
def _convert(self):
x, y, legend, info = self.getActiveCurve()
@@ -112,7 +109,7 @@ class RegularMeshPlugins(Plugin1DBase.Plugin1DBase):
#Didier's contribution: Try to do something if scan has been interrupted
if y.size < (int(item[6])+1) * (int(item[10])+1):
- print("WARNING: Incomplete mesh scan")
+ _logger.warning("WARNING: Incomplete mesh scan")
self._motor1 = numpy.resize(self._motor1,(y.size/(int(item[6])+1),1))
y = numpy.resize(y,((y.size/(int(item[6])+1)*(int(item[6])+1)),1))
@@ -130,8 +127,7 @@ class RegularMeshPlugins(Plugin1DBase.Plugin1DBase):
self._motor1 = self._x
self._motor1Mne = self._xLabel
except:
- if DEBUG:
- print("XLabel should be one of the scanned motors")
+ _logger.debug("XLabel should be one of the scanned motors")
self._legend = legend
self._info = info
@@ -162,7 +158,7 @@ def getPlugin1DInstance(plotWindow, **kw):
if __name__ == "__main__":
from PyMca5.PyMcaGraph import Plot
app = qt.QApplication([])
- DEBUG = 1
+ _logger.setLevel(logging.DEBUG)
x = numpy.arange(100.)
y = x * x
plot = Plot.Plot()
diff --git a/PyMca5/PyMcaPlugins/ReverseStackPlugin.py b/PyMca5/PyMcaPlugins/ReverseStackPlugin.py
index 2b3f65a..d74eed3 100644
--- a/PyMca5/PyMcaPlugins/ReverseStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/ReverseStackPlugin.py
@@ -40,13 +40,16 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5 import StackPluginBase
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class ReverseStackPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
text = "Replace current stack by one\n"
diff --git a/PyMca5/PyMcaPlugins/SilxRoiStackPlugin.py b/PyMca5/PyMcaPlugins/SilxRoiStackPlugin.py
index 978f5d5..7d1416a 100644
--- a/PyMca5/PyMcaPlugins/SilxRoiStackPlugin.py
+++ b/PyMca5/PyMcaPlugins/SilxRoiStackPlugin.py
@@ -1,5 +1,5 @@
# /*#########################################################################
-# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -26,10 +26,13 @@
"""
This plugin opens a stack ROI window providing alternative views:
- - ICR Energy at Max.
- - ICR Energy at Min.
- - 3 energy slices
- - ICR Background
+ - Usual sum of counts in the region
+ - Channel/Energy at data Max in the region.
+ - Channel/Energy at data Min in the region.
+ - Map of the counts at the first channel of the region
+ - Map of the counts at the middle cahnnel of the region
+ - Map of the counts at the last channel of the region
+ - Background counts
The background image can be subtracted from the other images to show
a net count.
diff --git a/PyMca5/PyMcaPlugins/StackAxesPlugin.py b/PyMca5/PyMcaPlugins/StackAxesPlugin.py
index ed1fe26..e096038 100644
--- a/PyMca5/PyMcaPlugins/StackAxesPlugin.py
+++ b/PyMca5/PyMcaPlugins/StackAxesPlugin.py
@@ -38,15 +38,18 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import PyMcaFileDialogs
from PyMca5.PyMcaGui import PyMca_Icons
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackAxesPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
text = "Replace current 1D axis by list of numbers found in ASCII file"
self.methodDict = {}
diff --git a/PyMca5/PyMcaPlugins/StackBrowserPlugin.py b/PyMca5/PyMcaPlugins/StackBrowserPlugin.py
index 1091af3..f265a59 100644
--- a/PyMca5/PyMcaPlugins/StackBrowserPlugin.py
+++ b/PyMca5/PyMcaPlugins/StackBrowserPlugin.py
@@ -23,7 +23,11 @@
# THE SOFTWARE.
#
#############################################################################*/
-"""
+__author__ = "V.A. Sole - ESRF Data Analysis"
+__contact__ = "sole@esrf.fr"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+__doc__ = """
This plugin open a plot window with a browser to browse all images in
the stack.
@@ -33,21 +37,20 @@ average of several consecutive frames rather than a single frame.
The plot has also mask tools synchronized with the mask in the master
window.
"""
-__author__ = "V.A. Sole - ESRF Data Analysis"
-__contact__ = "sole@esrf.fr"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui.pymca import StackBrowser
from PyMca5.PyMcaGui import PyMca_Icons
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackBrowserPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {'Show':[self._showWidget,
"Show Stack Image Browser",
@@ -56,8 +59,7 @@ class StackBrowserPlugin(StackPluginBase.StackPluginBase):
self.widget = None
def stackUpdated(self):
- if DEBUG:
- print("StackBrowserPlugin.stackUpdated() called")
+ _logger.debug("StackBrowserPlugin.stackUpdated() called")
if self.widget is None:
return
if self.widget.isHidden():
@@ -90,8 +92,7 @@ class StackBrowserPlugin(StackPluginBase.StackPluginBase):
self.widget.setBackgroundImage(self._getBackgroundImage())
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
diff --git a/PyMca5/PyMcaPlugins/StackNormalizationPlugin.py b/PyMca5/PyMcaPlugins/StackNormalizationPlugin.py
index de9caae..3fe8c26 100644
--- a/PyMca5/PyMcaPlugins/StackNormalizationPlugin.py
+++ b/PyMca5/PyMcaPlugins/StackNormalizationPlugin.py
@@ -54,6 +54,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5 import StackPluginBase
# Add support for normalization by data
from PyMca5.PyMca import PyMcaFileDialogs
@@ -66,11 +67,13 @@ try:
except:
HDF5 = False
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackNormalizationPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
text = "Stack/I0 where I0 is the active curve\n"
@@ -160,7 +163,7 @@ class StackNormalizationPlugin(StackPluginBase.StackPluginBase):
if edf.GetNumImages() > 1:
# TODO: A dialog showing the different images
# based on the external images browser needed
- print("WARNING: Taking first image")
+ _logger.warning("WARNING: Taking first image")
data = edf.GetData(0)
edf = None
elif ffilter.startswith("ASCII"):
diff --git a/PyMca5/PyMcaPlugins/StackROIBatchPlugin.py b/PyMca5/PyMcaPlugins/StackROIBatchPlugin.py
index 455abde..ac80c38 100644
--- a/PyMca5/PyMcaPlugins/StackROIBatchPlugin.py
+++ b/PyMca5/PyMcaPlugins/StackROIBatchPlugin.py
@@ -60,7 +60,7 @@ These plugins will be compatible with any stack window that provides the functio
import sys
import os
import numpy
-import time
+import logging
import traceback
from PyMca5 import StackPluginBase
from PyMca5.PyMcaCore import StackROIBatch
@@ -71,11 +71,14 @@ from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import ArraySave
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
class StackROIBatchPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
function = self.calculate
@@ -97,8 +100,7 @@ class StackROIBatchPlugin(StackPluginBase.StackPluginBase):
self.thread = None
def stackUpdated(self):
- if DEBUG:
- print("StackROIBatchPlugin.stackUpdated() called")
+ _logger.debug("StackROIBatchPlugin.stackUpdated() called")
self._widget = None
def selectionMaskUpdated(self):
@@ -110,8 +112,7 @@ class StackROIBatchPlugin(StackPluginBase.StackPluginBase):
self._widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
@@ -156,7 +157,7 @@ class StackROIBatchPlugin(StackPluginBase.StackPluginBase):
self._widget = None
if self.workerInstance is None:
self.workerInstance = StackROIBatch.StackROIBatch()
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.result = self.actualCalculation()
@@ -228,13 +229,13 @@ class StackROIBatchPlugin(StackPluginBase.StackPluginBase):
parameters = self.configurationWidget.getParameters()
outputDir = parameters["output_dir"]
if outputDir in [None, ""]:
- if DEBUG:
- print("Nothing to be saved")
+ _logger.debug("Nothing to be saved")
+ if _logger.getEffectiveLevel() == logging.DEBUG:
return
if parameters["file_root"] is None:
fileRoot = ""
else:
- fileRoot = parameters["file_root"].replace(" ","")
+ fileRoot = parameters["file_root"].replace(" ", "")
if fileRoot in [None, ""]:
fileRoot = "images"
if not os.path.exists(outputDir):
diff --git a/PyMca5/PyMcaPlugins/StackScanWindowPlugin.py b/PyMca5/PyMcaPlugins/StackScanWindowPlugin.py
index c898ab6..386cea9 100644
--- a/PyMca5/PyMcaPlugins/StackScanWindowPlugin.py
+++ b/PyMca5/PyMcaPlugins/StackScanWindowPlugin.py
@@ -34,15 +34,18 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy
+import logging
from PyMca5.PyMcaGui import ScanWindow
from PyMca5 import StackPluginBase
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class StackScanWindowPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
text = "Add active curve to plugin scan window\n"
@@ -90,7 +93,7 @@ class StackScanWindowPlugin(StackPluginBase.StackPluginBase):
x, y, legend, info = self.getActiveCurve()
if self.widget is None:
self.widget = ScanWindow.ScanWindow()
- self.widget.addCurve(x, y, legend=legend, replot=True, replace=replace)
+ self.widget.addCurve(x, y, legend=legend, resetzoom=True, replace=replace)
self.widget.show()
self.widget.raise_()
diff --git a/PyMca5/PyMcaPlugins/StackShowSpectra.py b/PyMca5/PyMcaPlugins/StackShowSpectra.py
index b50dbab..6d46f82 100644
--- a/PyMca5/PyMcaPlugins/StackShowSpectra.py
+++ b/PyMca5/PyMcaPlugins/StackShowSpectra.py
@@ -35,12 +35,15 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
from PyMca5 import StackPluginBase
from PyMca5.PyMca import ScanWindow
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
-DEBUG = 0
class ShowSpectra(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
function = self.showSpectra
@@ -112,7 +115,7 @@ class ShowSpectra(StackPluginBase.StackPluginBase):
if self.widget is None:
self.widget = ScanWindow.ScanWindow()
data = stack.data
- replot = False
+ resetzoom = False
if step in [None, 1]:
for i in range(data.shape[0]):
for j in range(data.shape[1]):
@@ -120,7 +123,8 @@ class ShowSpectra(StackPluginBase.StackPluginBase):
replace = True
else:
replace = False
- self.widget.addCurve(x, data[i, j], legend="Row %03d Col %03d" % (i, j), replace=replace, replot=replot)
+ self.widget.addCurve(x, data[i, j], legend="Row %03d Col %03d" % (i, j),
+ replace=replace, resetzoom=resetzoom)
else:
counter = 0
for i in range(data.shape[0]):
@@ -130,15 +134,16 @@ class ShowSpectra(StackPluginBase.StackPluginBase):
replace = True
else:
replace = False
- self.widget.addCurve(x, data[i, j],
- legend="Row %03d Col %03d" % (i, j),
- replace=replace, replot=replot)
+ self.widget.addCurve(
+ x, data[i, j],
+ legend="Row %03d Col %03d" % (i, j),
+ replace=replace, resetzoom=resetzoom)
counter += 1
self.widget.resetZoom()
self.widget.show()
self.widget.raise_()
-MENU_TEXT="Show Spectra"
+MENU_TEXT = "Show Spectra"
def getStackPluginInstance(plotWindow, **kw):
ob = ShowSpectra(plotWindow)
return ob
diff --git a/PyMca5/PyMcaPlugins/XASPlugin.py b/PyMca5/PyMcaPlugins/XASPlugin.py
index c1d049c..4f6c520 100644
--- a/PyMca5/PyMcaPlugins/XASPlugin.py
+++ b/PyMca5/PyMcaPlugins/XASPlugin.py
@@ -380,7 +380,7 @@ if __name__ == "__main__":
import sys
import os
from PyMca5.PyMcaGui import PyMcaQt as qt
- from PyMca5.PyMcaGui import PlotWindow
+ from PyMca5.PyMcaGui.pymca import ScanWindow
from PyMca5.PyMcaIO import specfilewrapper as specfile
from PyMca5.PyMcaDataDir import PYMCA_DATA_DIR
if len(sys.argv) > 1:
@@ -391,10 +391,11 @@ if __name__ == "__main__":
energy = data[0, :]
mu = data[1, :]
app = qt.QApplication([])
- plot = PlotWindow.PlotWindow()
- plot.setPluginDirectoryList([os.path.dirname(__file__)])
- plot.getPlugins()
- plot.addCurve(energy, mu, os.path.basename(fileName))
+ plot = ScanWindow.ScanWindow()
+ plot.pluginsToolButton.setPluginDirectoryList([os.path.dirname(__file__)])
+ plot.pluginsToolButton.getPlugins()
+ plot.addCurve(energy, mu, os.path.basename(fileName),
+ resetzoom=True)
plot.show()
plugin = getPlugin1DInstance(plot)
for method in plugin.getMethods():
diff --git a/PyMca5/PyMcaPlugins/XASStackBatchPlugin.py b/PyMca5/PyMcaPlugins/XASStackBatchPlugin.py
index db9d11f..64c59ef 100644
--- a/PyMca5/PyMcaPlugins/XASStackBatchPlugin.py
+++ b/PyMca5/PyMcaPlugins/XASStackBatchPlugin.py
@@ -59,8 +59,7 @@ These plugins will be compatible with any stack window that provides the functio
"""
import sys
import os
-import numpy
-import time
+import logging
import traceback
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import CalculationThread
@@ -71,11 +70,13 @@ from PyMca5.PyMcaGui import PyMca_Icons as PyMca_Icons
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMca import XASStackBatch
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class XASStackBatchPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
function = self.calculate
@@ -91,8 +92,7 @@ class XASStackBatchPlugin(StackPluginBase.StackPluginBase):
self.thread = None
def stackUpdated(self):
- if DEBUG:
- print("StackXASBatchPlugin.stackUpdated() called")
+ _logger.debug("StackXASBatchPlugin.stackUpdated() called")
if self._widget is not None:
self._widget.close()
self._widget = None
@@ -106,8 +106,7 @@ class XASStackBatchPlugin(StackPluginBase.StackPluginBase):
self._widget.setSelectionMask(mask)
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
@@ -150,7 +149,7 @@ class XASStackBatchPlugin(StackPluginBase.StackPluginBase):
def _executeFunctionAndParameters(self):
self._parameters = self.configurationWidget.getParameters()
self._widget = None
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
self.thread = CalculationThread.CalculationThread(\
calculation_method=self.actualCalculation)
self.thread.result = self.actualCalculation()
diff --git a/PyMca5/PyMcaPlugins/XASStackNormalizationPlugin.py b/PyMca5/PyMcaPlugins/XASStackNormalizationPlugin.py
index 05dbbf3..29ae7de 100644
--- a/PyMca5/PyMcaPlugins/XASStackNormalizationPlugin.py
+++ b/PyMca5/PyMcaPlugins/XASStackNormalizationPlugin.py
@@ -58,12 +58,15 @@ These plugins will be compatible with any stack window that provides the functio
selectionMaskUpdated
"""
import numpy
+import logging
+
+_logger = logging.getLogger(__name__)
try:
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import CalculationThread
except ImportError:
- print("XASStackNormalizationPlugin importing bases from somewhere else")
+ _logger.warning("XASStackNormalizationPlugin importing bases from somewhere else")
from . import StackPluginBase
from . import CalculationThread
@@ -72,11 +75,11 @@ from PyMca5.PyMcaGui import StackPluginResultsWindow
from PyMca5.PyMcaPhysics.xas import XASNormalization
from PyMca5.PyMcaGui.physics.xas import XASNormalizationWindow
-DEBUG = 0
class XASStackNormalizationPlugin(StackPluginBase.StackPluginBase):
def __init__(self, stackWindow, **kw):
- StackPluginBase.DEBUG = DEBUG
+ if _logger.getEffectiveLevel() == logging.DEBUG:
+ StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
self.methodDict = {}
text = "Replace current stack by a normalized one."
@@ -126,8 +129,7 @@ class XASStackNormalizationPlugin(StackPluginBase.StackPluginBase):
# own stuff
def mySlot(self, ddict):
- if DEBUG:
- print("mySlot ", ddict['event'], ddict.keys())
+ _logger.debug("mySlot %s %s", ddict['event'], ddict.keys())
if ddict['event'] == "selectionMaskChanged":
self.setStackSelectionMask(ddict['current'])
elif ddict['event'] == "addImageClicked":
diff --git a/PyMca5/PyMcaPlugins/XMCDPlugin.py b/PyMca5/PyMcaPlugins/XMCDPlugin.py
index dadf1a9..fd141af 100644
--- a/PyMca5/PyMcaPlugins/XMCDPlugin.py
+++ b/PyMca5/PyMcaPlugins/XMCDPlugin.py
@@ -32,8 +32,11 @@ from PyMca5 import Plugin1DBase
from PyMca5.PyMcaGui.pymca import XMCDWindow
from platform import node as gethostname
+import logging
+
+_logger = logging.getLogger(__name__)
+
-DEBUG = 0
class XMCDAnalysis(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw)
@@ -75,8 +78,7 @@ class XMCDAnalysis(Plugin1DBase.Plugin1DBase):
if guess.startswith(hostname):
beamline = 'ID08'
break
- if DEBUG:
- print('_createWidget -- beamline = "%s"' % beamline)
+ _logger.debug('_createWidget -- beamline = "%s"', beamline)
parent = None
self.widget = XMCDWindow.XMCDWidget(parent,
self._plotWindow,
@@ -106,13 +108,13 @@ if __name__ == "__main__":
info2 = {'MotorNames': 'PhaseD oxPS Motor10 Motor8',
'MotorValues': '2 0.44400576644 0.613870067852 0.901968648111'}
x = numpy.arange(100.,1100.)
- y0 = 10*x + 10000.*numpy.exp(-0.5*(x-500)**2/400) + 1500*numpy.random.random(1000.)
- y1 = 10*x + 10000.*numpy.exp(-0.5*(x-600)**2/400) + 1500*numpy.random.random(1000.)
- y2 = 10*x + 10000.*numpy.exp(-0.5*(x-400)**2/400) + 1500*numpy.random.random(1000.)
+ y0 = 10*x + 10000.*numpy.exp(-0.5*(x-500)**2/400) + 1500*numpy.random.random(1000)
+ y1 = 10*x + 10000.*numpy.exp(-0.5*(x-600)**2/400) + 1500*numpy.random.random(1000)
+ y2 = 10*x + 10000.*numpy.exp(-0.5*(x-400)**2/400) + 1500*numpy.random.random(1000)
- swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='zratio2', info=info2, replot=False, replace=False)
- swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='zratio0', info=info0, replot=False, replace=False)
- swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='zratio1', info=info1, replot=False, replace=False)
+ swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='zratio2', info=info2)
+ swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='zratio0', info=info0)
+ swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='zratio1', info=info1)
plugin = getPlugin1DInstance(swin)
plugin.applyMethod(plugin.getMethods()[0])
diff --git a/PyMca5/PyMcaPlugins/optional/JsonRpc1DPlugin.py b/PyMca5/PyMcaPlugins/optional/JsonRpc1DPlugin.py
index 974513d..7181d26 100644
--- a/PyMca5/PyMcaPlugins/optional/JsonRpc1DPlugin.py
+++ b/PyMca5/PyMcaPlugins/optional/JsonRpc1DPlugin.py
@@ -548,7 +548,7 @@ if __name__ == "__main__":
import time
import sys
import os.path
- from PyMca5.PyMcaGui.plotting.PlotWindow import PlotWindow
+ from PyMca5.PyMcaGui.pymca.ScanWindow import ScanWindow
if len(sys.argv) == 1 or \
sys.argv[1] not in ('plugin', 'demoServer', 'demoClient', 'auto'):
@@ -568,17 +568,17 @@ Options: plugin, demoServer demoClient, auto
app = qt.QApplication([])
# Create plot window
- plot = PlotWindow(roi=True)
+ plot = ScanWindow(roi=True)
plot.show()
# Load plugin
pluginDir = os.path.dirname(os.path.abspath(__file__))
pluginName = os.path.splitext(os.path.basename(__file__))[0]
- plot.setPluginDirectoryList([pluginDir])
- nbPlugins = plot.getPlugins() # Update plug-in list
+ plot.pluginsToolButton.setPluginDirectoryList([pluginDir])
+ nbPlugins = plot.pluginsToolButton.getPlugins() # Update plug-in list
assert nbPlugins >= 1
- plugin = plot.pluginInstanceDict[pluginName]
+ plugin = plot.pluginsToolButton.pluginInstanceDict[pluginName]
if sys.argv[1] == 'auto':
# Run automated demos
diff --git a/PyMca5/PyMcaPlugins/optional/TaurusPlugin1D.py b/PyMca5/PyMcaPlugins/optional/TaurusPlugin1D.py
index c2cd53d..491e794 100644
--- a/PyMca5/PyMcaPlugins/optional/TaurusPlugin1D.py
+++ b/PyMca5/PyMcaPlugins/optional/TaurusPlugin1D.py
@@ -1,5 +1,5 @@
#/*##########################################################################
-# Copyright (C) 2004-2015 V.A. Sole, T. Coutinho, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 V.A. Sole, T. Coutinho, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -37,10 +37,11 @@ __doc__ = """
You can also run it as a stand alone script.
"""
import numpy
-from PyMca5 import Plugin1DBase
+from PyMca5.PyMcaCore import Plugin1DBase
from PyMca5.PyMcaGui import PyMcaQt as qt
Qt = qt
from taurus import Attribute
+from taurus import Release
from taurus.core import TaurusEventType
from taurus.qt.qtcore.taurusqlistener import QObjectTaurusListener
from taurus.qt.qtgui.panel import TaurusModelChooser
@@ -75,6 +76,7 @@ class TaurusPlugin1D(Plugin1DBase.Plugin1DBase, QObjectTaurusListener):
def onSelectionChanged(self, models):
if self._oldModels in [None, []]:
+ self._attrDict = {}
for model in models:
try:
attr = Attribute(model)
@@ -83,6 +85,8 @@ class TaurusPlugin1D(Plugin1DBase.Plugin1DBase, QObjectTaurusListener):
attr = Attribute(str(model))
#force a read -> attr.read()
attr.addListener(self)
+ legend = qt.safe_str(attr.getNormalName())
+ self._attrDict[legend] = attr
self._oldModels = models
else:
keptModels = []
@@ -93,16 +97,20 @@ class TaurusPlugin1D(Plugin1DBase.Plugin1DBase, QObjectTaurusListener):
else:
newModels.append(model)
for model in self._oldModels:
- if model not in newModels:
+ if model not in keptModels:
attr = Attribute(model)
attr.removeListener(self)
- legend = attr.getNormalName()
+ legend = qt.safe_str(attr.getNormalName())
+ if legend in self._attrDict:
+ del self._attrDict[legend]
print("Trying to remove ", legend)
self.removeCurve(legend, replot=False)
for model in newModels:
attr = Attribute(model)
# attr.read()
attr.addListener(self)
+ legend = qt.safe_str(attr.getNormalName())
+ self._attrDict[legend] = attr
self._oldModels = keptModels + newModels
#Methods to be implemented by the plugin
@@ -145,9 +153,12 @@ class TaurusPlugin1D(Plugin1DBase.Plugin1DBase, QObjectTaurusListener):
if self._widget is None:
self._widget = TaurusModelChooser()
#self._adapter = TaurusPyMcaAdapter()
- Qt.QObject.connect(self._widget,
- Qt.SIGNAL("updateModels"),
- self.onSelectionChanged)
+ if Release.version_info >= (4,):
+ self._widget.updateModels.connect(self.onSelectionChanged)
+ else:
+ Qt.QObject.connect(self._widget,
+ Qt.SIGNAL("updateModels"),
+ self.onSelectionChanged)
self._widget.show()
MENU_TEXT = "Taurus Device Browser"
@@ -160,7 +171,7 @@ if __name__ == "__main__":
import os
from PyMca5.PyMcaGui import ScanWindow
plot = ScanWindow.ScanWindow()
- plot.setPluginDirectoryList([os.path.dirname(__file__)])
- plot.getPlugins()
+ plot.pluginsToolButton.setPluginDirectoryList([os.path.dirname(os.path.abspath(__file__))])
+ plot.pluginsToolButton.getPlugins()
plot.show()
app.exec_()
diff --git a/PyMca5/__init__.py b/PyMca5/__init__.py
index 9c131c6..16b2fbc 100644
--- a/PyMca5/__init__.py
+++ b/PyMca5/__init__.py
@@ -27,17 +27,21 @@ __author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__version__ = "5.3.2"
+__version__ = "5.4.0"
import os
import sys
+
from PyMca5.PyMcaDataDir import PYMCA_DATA_DIR
try:
from fisx.DataDir import FISX_DATA_DIR
except ImportError:
FISX_DATA_DIR = None
-DEBUG = 0
+import logging as _logging
+_logging.getLogger(__name__).addHandler(_logging.NullHandler())
+_logger = _logging.getLogger(__name__)
+
if sys.platform.startswith("win"):
import ctypes
@@ -123,7 +127,7 @@ def getDefaultUserPluginsDirectory():
else:
return None
except:
- print("WARNING: Cannot initialize plugins directory")
+ _logger.info("WARNING: Cannot initialize plugins directory")
return None
def getDefaultUserFitFunctionsDirectory():
@@ -157,7 +161,7 @@ def getUserDataFile(fileName, directory=""):
if not os.path.exists(userDataDir):
os.mkdir(userDataDir)
except:
- print("WARNING: cannot initialize user data directory")
+ _logger.info("WARNING: cannot initialize user data directory")
if userDataDir is None:
return fileName
@@ -168,12 +172,10 @@ def getUserDataFile(fileName, directory=""):
else:
userDataFile = os.path.join(userDataDir, baseName)
if os.path.exists(userDataFile):
- if DEBUG:
- print("Using user data file: %s" % userDataFile)
+ _logger.debug("Using user data file: %s", userDataFile)
return userDataFile
else:
- if DEBUG:
- print("Using data file: %s" % fileName)
+ _logger.debug("Using data file: %s", fileName)
return fileName
def getDataFile(fileName, directory=None):
@@ -188,8 +190,7 @@ def getDataFile(fileName, directory=None):
# return the input file name if exists
if os.path.exists(fileName):
- if DEBUG:
- print("Filename as supplied <%s>" % fileName)
+ _logger.debug("Filename as supplied <%s>", fileName)
return fileName
# the list of sub-directories where to look for the file
@@ -202,8 +203,7 @@ def getDataFile(fileName, directory=None):
for subdirectory in directoryList:
newFileName = getUserDataFile(fileName, directory=subdirectory)
if os.path.exists(newFileName):
- if DEBUG:
- print("Filename from user <%s>" % newFileName)
+ _logger.debug("Filename from user <%s>", newFileName)
return newFileName
# PyMca
@@ -212,8 +212,7 @@ def getDataFile(fileName, directory=None):
subdirectory,
os.path.basename(fileName))
if os.path.exists(newFileName):
- if DEBUG:
- print("Filename from PyMca Data Directory <%s>" % newFileName)
+ _logger.debug("Filename from PyMca Data Directory <%s>", newFileName)
return newFileName
# fisx
@@ -223,9 +222,8 @@ def getDataFile(fileName, directory=None):
subdirectory,
os.path.basename(fileName))
if os.path.exists(newFileName):
- if DEBUG:
- print("Filename from fisx Data Directory <%s>" % \
- newFileName)
+ _logger.debug("Filename from fisx Data Directory <%s>",
+ newFileName)
return newFileName
# file not found
@@ -241,7 +239,7 @@ if sys.platform.startswith("win"):
if os.getenv("MPLCONFIGDIR") is None:
os.environ['MPLCONFIGDIR'] = getDefaultSettingsDirectory()
except:
- print("WARNING: Could not set MPLCONFIGDIR.", sys.exc_info()[1])
+ _logger.info("WARNING: Could not set MPLCONFIGDIR. %s", sys.exc_info()[1])
# mandatory modules for backwards compatibility
from .PyMcaCore import Plugin1DBase, StackPluginBase, PyMcaDirs, DataObject
@@ -251,7 +249,7 @@ from .PyMcaCore import Plugin1DBase, StackPluginBase, PyMcaDirs, DataObject
try:
from .PyMcaIO import specfilewrapper, EdfFile, specfile, ConfigDict
except:
- print("WARNING importing IO directly")
+ _logger.info("WARNING importing IO directly")
from PyMcaIO import specfilewrapper, EdfFile, specfile, ConfigDict
from .PyMcaMath.fitting import SpecfitFuns, Gefit, Specfit
diff --git a/PyMca5/tests/ElementsTest.py b/PyMca5/tests/ElementsTest.py
index d518638..0bab872 100644
--- a/PyMca5/tests/ElementsTest.py
+++ b/PyMca5/tests/ElementsTest.py
@@ -2,7 +2,7 @@
#
# The PyMca X-Ray Fluorescence Toolkit
#
-# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -295,6 +295,19 @@ class testElements(unittest.TestCase):
self.assertTrue((100.0 * abs(yTest-yRef)/yRef) < 0.01)
energyIndex += 1
+ def testMaterialCompositionCalculation(self):
+ if DEBUG:
+ print()
+ print("Testing Material Composition Calculation (issue #298)")
+ mat1 = "Kapton"
+ mat2 = "Mylar"
+
+ c1 = self._elements.getMaterialMassFractions([mat1, mat2], [0.5, 0.5])
+ c2 = self._elements.getMaterialMassFractions([mat2, mat1], [0.5, 0.5])
+
+ for key in c1:
+ self.assertTrue(abs(c1[key] - c2[key]) < 1.0e-7,
+ "Inconsistent calculation for element %s" % key)
def getSuite(auto=True):
testSuite = unittest.TestSuite()
@@ -307,6 +320,7 @@ def getSuite(auto=True):
testSuite.addTest(testElements("testElementCrossSectionsReadout"))
testSuite.addTest(testElements("testElementCrossSectionsCalculation"))
testSuite.addTest(testElements("testMaterialCrossSectionsCalculation"))
+ testSuite.addTest(testElements("testMaterialCompositionCalculation"))
return testSuite
def test(auto=False):
diff --git a/PyMca5/tests/WidgetsTest.py b/PyMca5/tests/WidgetsTest.py
new file mode 100644
index 0000000..18b658f
--- /dev/null
+++ b/PyMca5/tests/WidgetsTest.py
@@ -0,0 +1,111 @@
+#/*##########################################################################
+# Copyright (C) 2004-2018 European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# 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.
+#
+#############################################################################*/
+
+import logging
+import os
+import sys
+import unittest
+import PyMca5.PyMcaGui.PyMcaQt as qt
+from silx.gui.test.utils import TestCaseQt
+
+from PyMca5.PyMcaGui.pymca import ScanWindow
+from PyMca5.PyMcaGui.pymca import McaWindow
+from PyMca5.PyMcaGui.physics.xrf import McaAdvancedFit
+
+
+_logger = logging.getLogger(__name__)
+
+
+class TestQtWrapper(unittest.TestCase):
+ """Minimalistic test to check that Qt has been loaded."""
+
+ def testQObject(self):
+ """Test that QObject is there."""
+ obj = qt.QObject()
+ self.assertTrue(obj is not None)
+
+
+class TestScanWindow(TestCaseQt):
+ def setUp(self):
+ super(TestScanWindow, self).setUp()
+
+ def testShow(self):
+ widget = ScanWindow.ScanWindow()
+ widget.show()
+ self.qapp.processEvents()
+
+
+class TestMcaWindow(TestCaseQt):
+ def setUp(self):
+ super(TestMcaWindow, self).setUp()
+
+ def testShow(self):
+ widget = McaWindow.McaWindow()
+ widget.show()
+ self.qapp.processEvents()
+
+
+class TestMcaAdvancedFit(TestCaseQt):
+ def setUp(self):
+ super(TestMcaAdvancedFit, self).setUp()
+
+ def testShow(self):
+ widget = McaAdvancedFit.McaAdvancedFit()
+ widget.show()
+ self.qapp.processEvents()
+
+
+def getSuite(auto=True):
+ test_suite = unittest.TestSuite()
+
+ with_qt_test = True
+ skip_msg = ""
+ if sys.platform.startswith('linux') and not os.environ.get('DISPLAY', ''):
+ # On Linux and no DISPLAY available (e.g., ssh without -X)
+ skip_msg = 'Widgets tests disabled (DISPLAY env. variable not set)'
+ with_qt_test = False
+
+ elif os.environ.get('WITH_QT_TEST', 'True') == 'False':
+ skip_msg = "Widgets tests skipped by WITH_QT_TEST env var"
+ with_qt_test = False
+
+ if not with_qt_test:
+ class SkipGUITest(unittest.TestCase):
+ def runTest(self):
+ self.skipTest(
+ skip_msg)
+ test_suite.addTest(SkipGUITest())
+ return test_suite
+
+ for TestCaseCls in (TestQtWrapper, TestScanWindow,
+ TestMcaWindow, TestMcaAdvancedFit):
+ test_suite.addTest(
+ unittest.defaultTestLoader.loadTestsFromTestCase(TestCaseCls))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='getSuite')
diff --git a/changelog.txt b/changelog.txt
index 2ff9a9d..0e68f5b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,22 @@
+VERSION 5.4.0
+-------------
+
+- Add training exercises to the tutorials
+
+- Support quantification accounting for live time when using HDF5 files
+
+- Add higher order excitations example to the training data
+
+- Use silx toolkit for graphics
+
+- Allow the user to select a particular Qt binding (--binding option, default is PyQt5)
+
+- Implement a user selectable logging level (--logging option, default is warning)
+
+- Correct handling of repeated elements in the sample matrix
+
+- Correct readout of lispix data
+
VERSION 5.3.2
-------------
diff --git a/cx_setup.py b/cx_setup.py
index 7852c38..8e43d06 100644
--- a/cx_setup.py
+++ b/cx_setup.py
@@ -145,8 +145,7 @@ MATPLOTLIB = True
try:
import pyopencl
OPENCL = True
- from PyMca5.PyMcaMath import sift
-except :
+except:
OPENCL = False
if sys.platform.lower().startswith("linux"):
@@ -170,7 +169,7 @@ elif h5py.version.version < '2.0.0':
'h5py._conv', 'h5py._proxy']
else:
H5PY_SPECIAL = True
-includes = []
+ includes = []
import fisx
FISX = True
@@ -182,14 +181,16 @@ includes.append('encodings.latin_1')
import PyMca5
import hdf5plugin
import silx
+import pkg_resources
SILX = True
special_modules = [os.path.dirname(PyMca5.__file__),
- os.path.dirname(matplotlib.__file__),
+ os.path.dirname(matplotlib.__file__),
os.path.dirname(ctypes.__file__),
os.path.dirname(fisx.__file__),
os.path.dirname(hdf5plugin.__file__),
- os.path.dirname(silx.__file__)]
+ os.path.dirname(silx.__file__),
+ os.path.dirname(pkg_resources.__file__)]
try:
import tomogui
diff --git a/doc/man/pymca.1 b/doc/man/pymca.1
index cfebe58..d055597 100644
--- a/doc/man/pymca.1
+++ b/doc/man/pymca.1
@@ -3,7 +3,7 @@
.\"
-.TH pymca 1 "March 2012" "ESRF" "PyMca X-Ray Fluorescence Toolkit"
+.TH pymca 1 "September 2018" "ESRF" "PyMca X-Ray Fluorescence Toolkit"
.SH NAME
@@ -50,7 +50,12 @@ Start the program using the selected graphics backend (mpl for matplotlib, gl fo
i
.B pymca --binding=XX
.P
-Start the program using the selected Qt binding. It has ot be one of PyQt5, PyQt4, PySide or PySide2.
+Start the program using the selected Qt binding. It has to be one of PyQt5 (default), PyQt4, PySide or PySide2.
+i
+.B pymca --logging=XX
+.P
+Set the logging level. Allowed values are, in increasing order of verbosity: critical, error, warning (default), info, debug.
+Alternatively, you can specify an integer in range 0 (critical) to 4 (debug).
.SH SEE ALSO
HDF5, h5py
diff --git a/doc/man/pymcaroitool.1 b/doc/man/pymcaroitool.1
index c7d9ec6..7f9d17d 100644
--- a/doc/man/pymcaroitool.1
+++ b/doc/man/pymcaroitool.1
@@ -43,7 +43,7 @@ Start the program with a file browser to select the input files.
.B pymcaroitool --binding=XX
.P
-Start the program using the selected Qt binding. It has ot be one of PyQt5, PyQt4, PySide or PySide2.
+Start the program using the selected Qt binding. It has to be one of PyQt5 (default), PyQt4, PySide or PySide2.
.B pymcaroitool file_0001.edf
.P
@@ -69,6 +69,13 @@ file_00200.edf
Load the double indexed files from row10_col0100.dat, row10_col0101.dat, ...
to row20_col0199.dat, row20_col0200.dat
+.B pymcaroitool --logging=XX
+.P
+Set the logging level. Allowed values are, in increasing order of verbosity: critical, error, warning (default), info, debug.
+Alternatively, you can specify a value in range 0 (critical) to 4 (debug).
+
+
+
.SH CAVEATS
If files f_000.xxx and f_001.xxx are present in the same directory, and
only one of them is selected, the program will always try to load both of
diff --git a/doc/source/customization/index.rst b/doc/source/customization/index.rst
index 02b2707..20a3a41 100644
--- a/doc/source/customization/index.rst
+++ b/doc/source/customization/index.rst
@@ -5,5 +5,5 @@ Customizing PyMca
.. toctree::
:maxdepth: 3
- settings
+ settings/index.rst
plugins/index.rst
diff --git a/doc/source/customization/plugins/plugins1d.rst b/doc/source/customization/plugins/plugins1d.rst
index 77bb7b9..14bd217 100644
--- a/doc/source/customization/plugins/plugins1d.rst
+++ b/doc/source/customization/plugins/plugins1d.rst
@@ -23,8 +23,8 @@ Overview
.. autofunction:: getPlugin1DInstance
-Builtin 1D plugins
-******************
+Built-in 1D plugins
+*******************
Background subtraction tools
++++++++++++++++++++++++++++
@@ -50,11 +50,15 @@ Alignment plugin
.. automodule:: PyMca5.PyMcaPlugins.AlignmentScanPlugin
+Advanced alignment plugin
++++++++++++++++++++++++++
+
+.. automodule:: PyMca5.PyMcaPlugins.AdvancedAlignmentScanPlugin
+
.. TODO: Kinetic tools
.. TODO: XASNormalization
-.. TODO: AdvancedAlignmentScanPlugin (see .html file in PYMCA_DOC_DIR)
Remove glitches from curves
+++++++++++++++++++++++++++
diff --git a/doc/source/customization/plugins/stackplugins.rst b/doc/source/customization/plugins/stackplugins.rst
index b9cc9fc..6bbd8fe 100644
--- a/doc/source/customization/plugins/stackplugins.rst
+++ b/doc/source/customization/plugins/stackplugins.rst
@@ -23,8 +23,8 @@ Stack plugin API
.. autofunction:: getStackPluginInstance
-Builtin stack plugins
-*********************
+Built-in stack plugins
+**********************
Alternative ROI options
+++++++++++++++++++++++
diff --git a/doc/source/customization/settings.rst b/doc/source/customization/settings.rst
deleted file mode 100644
index d39314a..0000000
--- a/doc/source/customization/settings.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Settings
---------
-
diff --git a/doc/source/customization/settings/img/settings_01.png b/doc/source/customization/settings/img/settings_01.png
new file mode 100644
index 0000000..027859a
--- /dev/null
+++ b/doc/source/customization/settings/img/settings_01.png
Binary files differ
diff --git a/doc/source/customization/settings/img/settings_02.png b/doc/source/customization/settings/img/settings_02.png
new file mode 100644
index 0000000..9cf15f1
--- /dev/null
+++ b/doc/source/customization/settings/img/settings_02.png
Binary files differ
diff --git a/doc/source/customization/settings/index.rst b/doc/source/customization/settings/index.rst
new file mode 100644
index 0000000..4f1302f
--- /dev/null
+++ b/doc/source/customization/settings/index.rst
@@ -0,0 +1,71 @@
+Settings
+========
+
+.. |img_01| image:: ./img/settings_01.png
+ :align: middle
+ :alt: Settings Directory
+
+.. |img_02| image:: ./img/settings_02.png
+ :align: middle
+ :alt: File mneu
+
+.. contents::
+ :local:
+
+PyMca allows a certain level of customization via user settings.
+
+Settings Directory
+------------------
+
+The first time *PyMca* is started, it creates a user accessible settings directory to allow user customization up to a certain extent.
+
+The location and name of this settings directory is different following the operation system.
+
+The typical layout of the directory is shown below
+
+|img_01|
+
+Windows
+.......
+
+The name of the folder is PyMca and it is located in the Documents folder of the user. The idea is that this folder should be easily accessible by the user and this location seems preferable to the use of a hidden folder.
+
+MacOS, Linux,...
+................
+
+The settings directory is created in the user $HOME directory.
+
+The name of the directory was PyMca in older versions of the program. Recent versionstry to use the more standard way of using a .pymca directory. Nevertheless, if they find a PyMca directory at he $HOME level, they will keep using it.
+
+
+GUI settings
+------------
+
+Graphical user interfaces are nice to start but sometimes they require a lot of interaction from the user.
+
+In an attempt to minimize the amount of user interaction, *PyMca* allows to save some settings like main window geometry, open files, last used directory, fit configuration, ROI table configuration...
+
+
+|img_02|
+
+
+This feature is accessible from the File menu either by choosing *File->Save default settings* or *File->Save->PyMca Configuration* This creates a .ini file in the user accessible settings folder of PyMca created when first using the program.
+
+The PyMca.ini file contains the default settings used by the application on start up. They can be bypassed by a fresh start of PyMca (typing *pymca -f* from the command line or selecting "*PyMca Fresh Start* from the Windows start menu).
+
+XRF Database
+------------
+
+The subdirectory data allows the user to modify the data used by *PyMca* when performing X-ray fluorescence calculations. It is enough to copy to this directory any of the original ASCII files contained in the `fisx_data <https://github.com/vasole/fisx/tree/master/fisx_data>`_ directory of the fisx module to force the program to use that file. The user can then proceed to edit the file and PyMca will use the modified file the next time is started.
+
+If you are interested in modifying the data used by *PyMca* the is an `exercise <../../training/xraydata/index.html>`_ to teach you how to proceed.
+
+CAUTION: At this point it is not advisable to modify the EADL97_* or the XCOM_CrossSections.dat files.
+
+CAUTION: Those files use unix line endings (LF) and not windows line endings (CR/LF). If you are under windows you have to make sure you do not use an editor modifying line endings. Convenient and free editors for windows are `Notepad++ <https://notepad-plus-plus.org>`_ or `Vim for windows <https://www.vim.org>`_
+
+User Plugins
+------------
+
+The subdirectory plugins contains the user plugins to be used in the application. Please refer to the plugins documentation for details.
+
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 4f1ce15..8ad93f2 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -14,7 +14,7 @@ The proper way to cite PyMca is:
V.A. Sole, E. Papillon, M. Cotte, Ph. Walter, J. Susini, A multiplatform code for the analysis of energy-dispersive X-ray fluorescence spectra, Spectrochim. Acta Part B 62 (2007) 63-68.
-Due to the copyright transfer to the publisher, the online availability of the article will depend on your subscription to ScienceDirect. The article doi is 10.1016/j.sab.2006.12.002. The abstract should be available in any case.
+Due to the copyright transfer to the publisher, the online availability of the article will depend on your subscription to ScienceDirect. The article `doi is 10.1016/j.sab.2006.12.002 <https://www.doi.org/10.1016/j.sab.2006.12.002>`_. The abstract should be available in any case.
The current version features:
@@ -36,6 +36,7 @@ Table of contents
overview.rst
install.rst
tutorials.rst
+ recipes.rst
changelog.rst
license.rst
faq.rst
diff --git a/doc/source/license.rst b/doc/source/license.rst
index b7261eb..a2b8857 100644
--- a/doc/source/license.rst
+++ b/doc/source/license.rst
@@ -1,7 +1,7 @@
License
=======
-The source code of *silx* is licensed under the `MIT <https://opensource.org/licenses/MIT>`_ license:
+The source code of *PyMca* is licensed under the `MIT <https://opensource.org/licenses/MIT>`_ license:
.. include:: ../../LICENSE
diff --git a/doc/source/recipes.rst b/doc/source/recipes.rst
new file mode 100644
index 0000000..5f887b6
--- /dev/null
+++ b/doc/source/recipes.rst
@@ -0,0 +1,7 @@
+Recipes
+=======
+
+.. toctree::
+
+ HOWTO Embed XRF fitting in a PyQt5 application <./recipes/xrfembedpyqt.rst>
+ HOWTO Write a stack of XRF spectra in HDF5 <./recipes/xrfhdf5stack.rst>
diff --git a/doc/source/recipes/recipescode/GenerateHDF5Stack.py b/doc/source/recipes/recipescode/GenerateHDF5Stack.py
new file mode 100644
index 0000000..6834f48
--- /dev/null
+++ b/doc/source/recipes/recipescode/GenerateHDF5Stack.py
@@ -0,0 +1,105 @@
+#/*##########################################################################
+#
+# Copyright (c) 2018 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.
+#
+#############################################################################*/
+__author__ = "V.A. Sole - ESRF Data Analysis"
+__contact__ = "sole@esrf.fr"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+__doc__ = """
+Script writing a stack of XRF data with calibration and live_time information
+"""
+
+import os
+import numpy
+import h5py
+
+# use a dummy 3D array generated using data supplied with PyMca
+from PyMca5 import PyMcaDataDir
+from PyMca5.PyMcaIO import specfilewrapper as specfile
+from PyMca5.PyMcaIO import ConfigDict
+
+dataDir = PyMcaDataDir.PYMCA_DATA_DIR
+spe = os.path.join(dataDir, "Steel.spe")
+cfg = os.path.join(dataDir, "Steel.cfg")
+sf = specfile.Specfile(spe)
+y = counts = sf[0].mca(1)
+x = channels = numpy.arange(y.size).astype(numpy.float)
+configuration = ConfigDict.ConfigDict()
+configuration.read(cfg)
+calibration = configuration["detector"]["zero"], \
+ configuration["detector"]["gain"], 0.0
+initialTime = configuration["concentrations"]["time"]
+
+# create the data
+nRows = 5
+nColumns = 10
+nTimes = 3
+data = numpy.zeros((nRows, nColumns, counts.size), dtype = numpy.float)
+live_time = numpy.zeros((nRows * nColumns), dtype=numpy.float)
+
+mcaIndex = 0
+for i in range(nRows):
+ for j in range(nColumns):
+ factor = (1 + mcaIndex % nTimes)
+ data[i, j] = counts * factor
+ live_time[i * nColumns + j] = initialTime * factor
+ mcaIndex += 1
+
+# now we have a 3D array containing the spectra in data (mandatory)
+# we have the channels (not mandatory)
+# we have the associated calibration (not mandatory)
+# we have the live_time (not mandatory)
+# and we are going to create an HDF5 with that information
+#
+# Just writing those data as a dataset in an HDF5 file would be enough for
+# using it in PyMca, but we can create a container group in order to associate
+# additional information (channels, live_time, calibration)
+# "instrument" can be replaced by, for instance, the beamline name
+# "detector" can be replaced by, for instance, "mca_0"
+#
+h5File = "Steel.h5"
+if os.path.exists(h5File):
+ os.remove(h5File)
+h5 = h5py.File(h5File, "w")
+h5["/entry/instrument/detector/calibration"] = calibration
+h5["/entry/instrument/detector/channels"] = channels
+h5["/entry/instrument/detector/data"] = data
+h5["/entry/instrument/detector/live_time"] = live_time
+
+# add nexus conventions (not needed)
+h5["/entry/title"] = u"Dummy generated map"
+h5["/entry"].attrs["NX_class"] = u"NXentry"
+h5["/entry/instrument"].attrs["NX_class"] = u"NXinstrument"
+h5["/entry/instrument/detector/"].attrs["NX_class"] = u"NXdetector"
+h5["/entry/instrument/detector/data"].attrs["interpretation"] = \
+ u"spectrum"
+# implement a default plot named measurement (not needed)
+h5["/entry/measurement/data"] = \
+ h5py.SoftLink("/entry/instrument/detector/data")
+h5["/entry/measurement"].attrs["NX_class"] = u"NXdata"
+h5["/entry/measurement"].attrs["signal"] = u"data"
+h5["/entry"].attrs["default"] = u"measurement"
+
+h5.flush()
+h5.close()
+h5 = None
diff --git a/doc/source/recipes/xrfembedpyqt.rst b/doc/source/recipes/xrfembedpyqt.rst
new file mode 100644
index 0000000..ddc5166
--- /dev/null
+++ b/doc/source/recipes/xrfembedpyqt.rst
@@ -0,0 +1,15 @@
+Embedding PyMca XRF fitting
+===========================
+
+Besides providing ready-to-use applications, PyMca is very modular and it allows to be used as a library.
+
+Let's say you have your own way of displaying your data into a PyQt5 (or PyQt4, PySide or PySide2)
+application. All you need to do to provide XRF fitting capabilities to it requires 4 lines of code.
+
+.. code-block:: python
+
+ from PyMca5.PyMca import McaAdvancedFit
+ widget = McaAdvancedFit.McaAdvancedFit()
+ widget.setData(channels, counts)
+ widget.show()
+
diff --git a/doc/source/recipes/xrfhdf5stack.rst b/doc/source/recipes/xrfhdf5stack.rst
new file mode 100644
index 0000000..8b7d512
--- /dev/null
+++ b/doc/source/recipes/xrfhdf5stack.rst
@@ -0,0 +1,87 @@
+HDF5 XRF Stack
+==============
+
+There is a recurrent cuestion concerning how one should write the spectra associated to a raster
+experiment to be compatible with PyMca.
+
+The solution is not unique, because PyMca can deal with (too) many data formats. For instance, if
+you have a map of 20000 spectra corresponding to a map of 100 rows per 200 columns, 20000 single-column
+ASCII files containing the measured counts would do the job. You would be "compatible" with PyMca but
+you would be missing relevant information known at acquisition time like live_time and calibration
+parameters.
+
+The most versatile file format supported by PyMca is without doubt HDF5. You can find information about it
+at the `HDF Group web site <https://portal.hdfgroup.org/display/HDF5/HDF5>`_
+
+Let's assume data is a 3-dimensional array or 20000 spectra corresponding to a raster scan of 100 rows per
+200 columns. If each spectrum has 2048 channels, the shape of that array will be (following C-convention)
+(100, 200, 2048). The simplest HDF5 file compatible with PyMca would contain a single 3-dimensional dataset
+and it could be written using the code snipset shown below.
+
+.. code-block:: python
+
+ import h5py
+ h5 = h5py.File("myfile.h5", "w")
+ h5["data"] = data
+ h5.flush()
+ h5.close()
+
+Obviously, besides a faster readout of the data by PyMca, one would not gain any information compared to
+the use of single-column ASCII files.
+
+PyMca will automatically look for information associated to a dataset provided that information is
+stored within the same container group in the file.
+
+If live_time is a one dimensional dataset with 20000 values corresponding to the actual measuring time
+associated to each spectrum, the simplest way to allow PyMca to use that information is to put it at
+the same level within the same group.
+
+If the channels associated to the data are different from 0,1,2,3, ..., 2046, 2047, they can be specified by
+a one dimensional dataset named channels.
+
+The calibration can be specified as a dataset containing three values (corresponding to a, b and c in the
+expression energy = a + b * ch + c * ch^2 and named calibration.
+
+.. code-block:: python
+
+ import h5py
+ h5 = h5py.File("myfile.h5", "w")
+ h5["/mca_0/data"] = data
+ h5["/mca_0/channels"] = channels
+ h5["/mca_0/calibration"] = calibration
+ h5["/mca_0/live_time"] = live_time
+ h5.flush()
+ h5.close()
+
+Additional conventions can be applied to improve the user experience when using the PyMca graphical user
+interface.
+
+The code below writes an HDF5 following NeXus conventions. Those conventions are attribute based, therefore
+the actual names of the different groups are free. You can :download:`download a script <./recipescode/GenerateHDF5Stack.py>` generating a file using these
+conventions.
+
+.. code-block:: python
+
+ h5File = "myfile.h5"
+ if os.path.exists(h5File):
+ os.remove(h5File)
+ h5 = h5py.File(h5File, "w")
+ h5["/entry/instrument/detector/calibration"] = calibration
+ h5["/entry/instrument/detector/channels"] = channels
+ h5["/entry/instrument/detector/data"] = data
+ h5["/entry/instrument/detector/live_time"] = live_time
+
+ # add nexus conventions (not needed)
+ h5["/entry/title"] = u"Dummy generated map"
+ h5["/entry"].attrs["NX_class"] = u"NXentry"
+ h5["/entry/instrument"].attrs["NX_class"] = u"NXinstrument"
+ h5["/entry/instrument/detector/"].attrs["NX_class"] = u"NXdetector"
+ h5["/entry/instrument/detector/data"].attrs["interpretation"] = u"spectrum"
+ # implement a default plot named measurement (not needed)
+ h5["/entry/measurement/data"] = h5py.SoftLink("/entry/instrument/detector/data")
+ h5["/entry/measurement"].attrs["NX_class"] = u"NXdata"
+ h5["/entry/measurement"].attrs["signal"] = u"data"
+ h5["/entry"].attrs["default"] = u"measurement"
+
+ h5.flush()
+ h5.close()
diff --git a/doc/source/training/matrix/img/matrix_01.png b/doc/source/training/matrix/img/matrix_01.png
new file mode 100644
index 0000000..c84eec6
--- /dev/null
+++ b/doc/source/training/matrix/img/matrix_01.png
Binary files differ
diff --git a/doc/source/training/matrix/img/matrix_02.png b/doc/source/training/matrix/img/matrix_02.png
new file mode 100644
index 0000000..81a26e9
--- /dev/null
+++ b/doc/source/training/matrix/img/matrix_02.png
Binary files differ
diff --git a/doc/source/training/matrix/img/matrix_03.png b/doc/source/training/matrix/img/matrix_03.png
new file mode 100644
index 0000000..3b5e147
--- /dev/null
+++ b/doc/source/training/matrix/img/matrix_03.png
Binary files differ
diff --git a/doc/source/training/matrix/img/matrix_04.png b/doc/source/training/matrix/img/matrix_04.png
new file mode 100644
index 0000000..ec2268f
--- /dev/null
+++ b/doc/source/training/matrix/img/matrix_04.png
Binary files differ
diff --git a/doc/source/training/matrix/img/tertiary_01.png b/doc/source/training/matrix/img/tertiary_01.png
new file mode 100644
index 0000000..fbf88d8
--- /dev/null
+++ b/doc/source/training/matrix/img/tertiary_01.png
Binary files differ
diff --git a/doc/source/training/matrix/img/tertiary_03.png b/doc/source/training/matrix/img/tertiary_03.png
new file mode 100644
index 0000000..5325dfc
--- /dev/null
+++ b/doc/source/training/matrix/img/tertiary_03.png
Binary files differ
diff --git a/doc/source/training/matrix/img/tertiary_04.png b/doc/source/training/matrix/img/tertiary_04.png
new file mode 100644
index 0000000..69af2c7
--- /dev/null
+++ b/doc/source/training/matrix/img/tertiary_04.png
Binary files differ
diff --git a/doc/source/training/matrix/index.rst b/doc/source/training/matrix/index.rst
new file mode 100644
index 0000000..c84732f
--- /dev/null
+++ b/doc/source/training/matrix/index.rst
@@ -0,0 +1,83 @@
+Automatic Sample Matrix Refinement
+==================================
+
+
+.. |img1| image:: ./img/matrix_01.png
+ :width: 400px
+ :align: middle
+ :alt: Fitted Steel Data
+
+.. |img2| image:: ./img/matrix_02.png
+ :width: 400px
+ :align: middle
+ :alt: The Single Layer Strategy Window
+
+.. |img3| image:: ./img/matrix_03.png
+ :width: 400px
+ :align: middle
+ :alt: Strategy Configured
+
+.. |img4| image:: ./img/matrix_04.png
+ :align: middle
+ :alt: Last Composition
+
+.. contents::
+ :local:
+
+Introduction
+------------
+
+The characterization of the experimental setup (excitation beam, filters, attenuators, detector, geometry) and theoretical peak ratios are not sufficient to appropriately quantify X-ray fluorescence spectra. Unless we are dealing with very thin samples (that means samples where self-attenuation or multiple excitation effects can be neglected), the sample itself plays a critical role. However, the sample composition is exactly what we want to know.
+
+Versions of PyMca older than 5.0 required the user to manually modify the initial guess of the sample composition if the obtained composition was very different from the initial guess.
+
+Exercise
+--------
+
+The goal of the exercise it to show the user one way to instruct the program to automatically update the initial sample composition guess.
+
+
+Preparation
+...........
+
+This starting point of this exercise is the same as the one of the previous exercise `Accounting for higher order excitations <../tertiary/index.html>`_
+
+In that exercise the reader was able to properly account for multiple order excitations in the sample. However, the actual composition of the sample was provided. A more realistic situation would be to know that we are dealing with a stainless steel sample of unknown composition. Despite the fact the spectrum itself tells us what elements are present, we are going to ask the program to perform a quantification starting from a pure Fe sample.
+
+As with the previous exercise, we have to make sure we have reached the situation shown below.
+
+|img1|
+
+
+Configuring the Fit Strategy
+............................
+
+To properly configure the program we'll have to follow these steps:
+
+- As usual, enter the fit configuration widget via the Configure button.
+- In the ATTENUATORS tab, enter (by typing) Fe as the Material of the Matrix. The program will automatically change the density. You can reset the value to the previous one if you want. It is a thick sample in any case and the results will not change.
+- Make sure we have selected the Consider Tertiary Excitation checkbox of the CONCENTRATIONS tab.
+- Move to the FIT tab of the configuration widget and select the Perform a fit using the selected strategy checkbox and click the SETUP button.
+
+You will be presented a screen similar to the screenshot below.
+
+|img2|
+
+Since you are there, please take a time to read the algorithm description.
+
+We are going to select a set of peak families and we are going to specify the chemical form in which they will be incorporated in the matrix. Since we are dealing with an alloy, we'll ask the program to incorporate the elements as pure metals. If we were dealing with a glass, we would have selected Si1O2 as completing material and incorporated the different elements in the form of oxides.
+
+We can directly select the peak families Cr K, Mn K, Fe Ka, Ni K. The idea is to select those peaks that give a high contribution to the spectrum and that we suspect they a present in the sample. For instance, if a experiment takes place in air, we can find an important contribution from Argon but the argon signal does not come from the sample and therefore should not be entered in the sample composition. You should manage to achieve the image below.
+
+|img3|
+
+Press OK to accept the strategy configuration and press OK again to finish the fit configuration.
+
+If you now carry out the fit you notice the fit takes longer due to the fit reconfiguration process associated to the matrix modifications.
+
+If you go to the CONCENTRATIONS tab, you will see that the obtained concentrations are quite acceptable despite about crude initial guess.
+
+If you are interested on knowing which was the last matrix composition used in the iterative process, you can obtain it by coming back to the ATTENUATORS tab of the fit configuration widget and selecting SingleLayerStrategyMaterial in the combo box of the Material Editor.
+
+|img4|
+
diff --git a/doc/source/training/quantification/img/quantification_01.png b/doc/source/training/quantification/img/quantification_01.png
new file mode 100644
index 0000000..db0e316
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_01.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_02.png b/doc/source/training/quantification/img/quantification_02.png
new file mode 100644
index 0000000..8edbd1f
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_02.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_03.png b/doc/source/training/quantification/img/quantification_03.png
new file mode 100644
index 0000000..88e0a8d
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_03.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_04.png b/doc/source/training/quantification/img/quantification_04.png
new file mode 100644
index 0000000..76b8855
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_04.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_05.png b/doc/source/training/quantification/img/quantification_05.png
new file mode 100644
index 0000000..180f910
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_05.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_06.png b/doc/source/training/quantification/img/quantification_06.png
new file mode 100644
index 0000000..9657e2e
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_06.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_07.png b/doc/source/training/quantification/img/quantification_07.png
new file mode 100644
index 0000000..0259224
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_07.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_08.png b/doc/source/training/quantification/img/quantification_08.png
new file mode 100644
index 0000000..134962b
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_08.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_09.png b/doc/source/training/quantification/img/quantification_09.png
new file mode 100644
index 0000000..74aa531
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_09.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_10.png b/doc/source/training/quantification/img/quantification_10.png
new file mode 100644
index 0000000..7b1af7c
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_10.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_11.png b/doc/source/training/quantification/img/quantification_11.png
new file mode 100644
index 0000000..6680735
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_11.png
Binary files differ
diff --git a/doc/source/training/quantification/img/quantification_12.png b/doc/source/training/quantification/img/quantification_12.png
new file mode 100644
index 0000000..05ebac3
--- /dev/null
+++ b/doc/source/training/quantification/img/quantification_12.png
Binary files differ
diff --git a/doc/source/training/quantification/index.rst b/doc/source/training/quantification/index.rst
new file mode 100644
index 0000000..1fc7f65
--- /dev/null
+++ b/doc/source/training/quantification/index.rst
@@ -0,0 +1,221 @@
+XRF Analysis
+============
+
+.. |img_01| image:: ./img/quantification_01.png
+ :width: 400px
+ :align: middle
+ :alt: XRF Spectrum
+
+.. |img_02| image:: ./img/quantification_02.png
+ :width: 400px
+ :align: middle
+ :alt: Calibration Widget
+
+.. |img_03| image:: ./img/quantification_03.png
+ :width: 400px
+ :align: middle
+ :alt: Calibrated Spectrum
+
+.. |img_04| image:: ./img/quantification_04.png
+ :width: 400px
+ :align: middle
+ :alt: Fit Region Selected
+
+.. |img_05| image:: ./img/quantification_05.png
+ :width: 400px
+ :align: middle
+ :alt: Fit Window
+
+.. |img_06| image:: ./img/quantification_06.png
+ :align: middle
+ :alt: Peak Identifier
+
+.. |img_07| image:: ./img/quantification_07.png
+ :width: 400px
+ :align: middle
+ :alt: Peak Family Selection
+
+.. |img_08| image:: ./img/quantification_08.png
+ :width: 400px
+ :align: middle
+ :alt: Initial Fit
+
+.. |img_09| image:: ./img/quantification_09.png
+ :width: 400px
+ :align: middle
+ :alt: Final Fit
+
+.. |img_10| image:: ./img/quantification_10.png
+ :width: 400px
+ :align: middle
+ :alt: Peaks Spectrum
+
+.. |img_11| image:: ./img/quantification_11.png
+ :width: 400px
+ :align: middle
+ :alt: Matrix Spectrum
+
+.. |img_12| image:: ./img/quantification_12.png
+ :width: 400px
+ :align: middle
+ :alt: One per cent Sc
+
+.. contents::
+ :local:
+
+Introduction
+------------
+
+Many synchrotron users performing X-ray fluorescence experiments are interested in imaging the distribution of elements in their samples. However, they tend to show little interest in learning how to perform quantitative X-ray fluorescence (XRF) analysis and that can lead to the obtention of wrong elemental distribution maps.
+
+One has to take into account that even for pure imaging experiments one needs to calibrate the spectra, to identify the different elements in the sample and, most of the times, perform some fitting in order to resolve overlapping peaks of different elements. At this point users might not be aware that the relative peak areas they are extracting may be wrong because they did not take into account the modification of the database peak ratios by the conditions of the experiment. Simply introducing the experimental conditions and a guestimate of the sample composition is often enough to properly extract the signal from the different elements.
+
+The additional step to take to go from pure qualitative to quantitative analysis is a very small one if a minimum of care was taken (for instance recording the acquisition time and incoming flux and a known sample has been measured).
+
+Exercise
+--------
+
+The objective of this exercise is to get familiar with x-ray fluorescence analysis. For this, we are going to work with a spectrum from a thin film standard although we'll make some simplifications.
+
+Step 1: Loading the data
+........................
+
+The data required for this exercise are supplied with PyMca and can be loaded into the program via the main window File menu following the sequence File->Open->Load Training Data->XRF Analysis.
+
+The format associated to that spectrum is the simplest that PyMca can read. It is just a single column of numbers corresponding to the counts in the different channels. Under that situation, PyMca does not know if those data belong to an XRF experiment or to something else and offers two different visualization modes. One generic and one specific to XRF.
+
+Your first task is to achieve the situation shown in the figure below where the data are present in the MCA tab of the main window in a semilogarithmic plot.
+
+|img_01|
+
+Step 2: Calibrating the data
+............................
+
+If it is your first time with PyMca, you should take a look at the `Calibration tutorial <http://www.esrf.fr/computing/bliss/downloads/pymca/calibrationtutorial.htm>`_
+
+The excitation energy was about 17.5 keV. Very often this is enough information for an initial calibration. However, this detector presented a very important offset and you will need an addition calibration point. Just imagine you have previously measured a cobalt sample and that you know that the peak around channel 1474 corresponds to the main emission line of Co.
+
+You may reach the situation illustrated below where the calibration window is shown. You have to press the OK button to validate the calibration.
+
+|img_02|
+
+At this point you should be back to the main window without any change respect to the previous situation. Prior to go any further, you should instruct PyMca about what calibration you intend to use. Unless you have changed the name of the calibration, choosing Internal in the calibration combo box should apply the just calculated one to the spectrum leading to the situation below.
+
+|img_03|
+
+Under the calibration combo box, following *Active curve uses*, you will see the calibration actually applied. It should be close to A=-0.5, B=-0.005 and C=0. (Hint: Make sure you have selected a first order calibration when calculating the calibration). If it is very different your calibration is wrong and you will experience a lot of difficulties later on.
+
+
+Step 3: Select your fit region
+..............................
+
+We already have a calibrated spectrum. The rest of the exercise will use the McaAdvancedFit window.
+
+Prior to reach that window, we should select the region of the sample we'd like to analyze. For that, we have to zoom in that region by pressing and dragging the mouse. PyMca implements a zoom stack, you can go back by pressing the mouse right button or by pressing the reset zoom icon.
+
+At the very least, you should always leave the cut at the low energy side corresponding to the low-level discriminator of your acquisition system out of the fitting region. Something around 1.0 keV should be OK in this case.
+
+PyMca (still!) implements a very poor description of the scattering peaks. Unless you absolutely need it, you will obtain better results by limiting the high energy side of the region to the rail of the scattered peaks. Something like 16.3 keV should be a good upper limit.
+
+|img_04|
+
+At this point we are ready to access the McaAdvancedFit window by pressing the fit icon and selecting the *Advanced* option.
+
+Step 4: Using the Peak Identifier
+.................................
+
+The first thing you will get is a message telling you that no peaks have been defined. PyMca has very good peak search routines and it could do a very good guess about the elements present. However, the author(s) consider that the responsibility should fall on the person carrying the analysis.
+
+In order to allow PyMca to give you some hints about what elements can be associated to a peak, you need to toggle the energy axis on. Your next target should be to obtain the image below.
+
+|img_05|
+
+If you now click on top of a peak, PyMca will show you the peaks that can be associated to that energy. If you click at around 6.9 keV. PyMca should show you the peak identifier.
+
+|img_06|
+
+You will be presented with a table of elements, peak families and rates within the family of all the elements emitting x-ray within the specified energy threshold around the selected energy.
+
+As a rule of thumb, you should aim at identifying the most intense peaks. Why? Because that can help you decide to what element they belong. For instance, the L3 lines are usually more intense than the L2 lines or L1 lines. If the program proposes you the L2 lines of one element and the L3 lines of other element, there are strong chances of having the element with the L3 lines because if it would be the element with the L2 lines there should be a stronger peak somewhere in the spectrum corresponding to the L3 lines of that element. Of course, that is to be considered as a hint. It may well happen that the intense L3 lines are hidden beneath the peak of another already identified element...
+
+Step 5: Fit Configuration
+.........................
+
+In this example you could already start adding peaks families to be fitted immediately because the sample is relatively thin and matrix effects are small. However, you should aim at doing the things properly and enter as much information as possible into the fit configuration.
+
+The experimental conditions are excitation energy around 17.5 keV, Si detector 450 micron thickness and Be window of 8 micron thickness. For the sake of simplicity assume the sample is 100 micron water and contains 500 ppm of Co. Incident beam angle is 0.1 degrees and fluorescence beam angle is 90 degrees. There is an air path between sample and detector window of 2 mm.
+
+To will enter the fit configuration by pressing the Configure button.
+
+To enter the experimental setup you will need to use the ATTENUATORS tab and the MATRIX tab. The incident beam energy is set into the BEAM tab.
+
+Concerning the FIT tab, at this point just make sure the *Stripping* check box is selected in order to have some baseline to be applied to your fit.
+
+If you have done that and you select the PEAKS tab, you will see the excitation energy in red. Below you will see the selection of the Co K lines as peaks to be fitted.
+
+|img_07|
+
+Press OK to accept the changes. You will be back to the fit window and by pressing the Fit icon or the Fit again! button you should obtain a fit similar to the one displayed below.
+
+|img_08|
+
+As you see the background still needs some adjustment. You can do it via the corresponding SETUP button at the FIT tab of the fit configuration widget.
+
+You should spend some time going to the fit configuration to add peaks and back to the fit window to perform fits. WARNING: It is advisable to save your fit configuration from the fit configuration widget via the Save button. That can save you a lot of time in case of problems because you could restart form that point.
+
+You can take the image below as encouragement.
+
+|img_09|
+
+If you need to take a look at the individual contributions of the different elements to the fitted spectrum, you can do so by selecting the *Peaks Spectrum* button.
+
+|img_10|
+
+If you want to highlight a particular element contribution, you should make the legends widget appear by pressing on Options and selecting Legends. It is not shown here in order not to make the exercise too simple (remember *No pain, no gain*).
+
+Hint. You should not need more than 18 elements to achieve the same fit quality.
+
+Step 6: Concentrations
+......................
+
+The additional step to calculate concentrations is very simple. One either needs to know some details about the system (flux, acquisition live time, solid angle) or to use an internal standard.
+
+If we have set the sample is water with 500 ppm of Co, we can go back to the fit configuration and select in the CONCENTRATIONS tab the *From matrix composition* check box. You can also enter Co as *Matrix Reference Element* if you wish.
+
+To get the concentrations is as easy as selecting the CONCENTRATIONS tab of the
+advanced fit window after performing a fit.
+
+Hint: If everything is OK, the concentrations of all the elements present in the sample should be in the vicinity of 500 ppm (0.0005 mass fraction).
+
+In real life you often do not have an internal standard. However, you could imagine that you have just measured a reference sample you have just prepared with a concentration of 500 ppm Co in water and that you want to calibrate your system. Then, obviously, the Co concentration given by the program is exactly 0.0005 because it is used as internal standard. To calibrate your system all what you have to do is to select the *From fundamental parameters* check box and modify the Active area, distance, time to match those of your experiment and finally play with the flux until the concentration of Co is back to 0.0005. From there on you will be ready to use your system without an internal standard. You would have removed the water-with-Co sample and measured our unknown sample.
+
+Step 7: Using the Matrix Spectrum
+.................................
+
+PyMca can be used to calculate the expected measured spectrum given the experimental conditions and the sample composition.
+
+If you have performed the previous steps, you just have to perform a fit and press the Matrix Spectrum button. You can see something similar to the figure below where besides the spectrum and the fit there is a spectrum corresponding to the matrix (in this case is shown in magenta but the colors may vary). In our case it is just Co what is shown.
+
+|img_11|
+
+We can use this PyMca feature to measure the thickness of layers or to estimate confidence limits. Let's take a look at the later.
+
+We go back to the fit configuration and select the Sc K-line as element family of peaks to be fitted and we perform a fit. If we go to the CONCENTRATIONS tab we'll see that PyMca reports a concentration of the order of some ppms. The question is, can we trust that information?
+
+A simple exercise is to add Sc at different amounts to the sample composition and to ask the program to calculate the matrix spectrum. We can start with a fairly large amount like 1 % to visualize where the signal should appear. Then we just have to repeat the exercise lowering the concentration until we reach a point below which we would not trust anything. The figure below shows the matrix spectrum with 1 % of Scandium.
+
+|img_12|
+
+After performing the exercise, you will easily conclude that the concentration of Sc in the sample, if any, it is below the detection limits of our system under the exact conditions of our experiment (including sample!).
+
+Step 8: Final Comments
+......................
+
+If you want, you can also observe how the changes on the calculated concentrations when changing the attenuation conditions:
+
+ - play with an air path between 1.0 mm and 100 mm (what happens at low energies?)
+ - play with a detector thickness between 10 micron and 1 mm (what happens with the concentrations at high energies?)
+
+The information to carry out this exercise is also available within PyMca. To access it, you just have to select the FILE tab of the widget appearing after a right click on the list shown after loading the file (right-mouse click on #S1 Unknown...) and *Show scan header* selection).
+
+
diff --git a/doc/source/training/tertiary/img/tertiary_01.png b/doc/source/training/tertiary/img/tertiary_01.png
new file mode 100644
index 0000000..fbf88d8
--- /dev/null
+++ b/doc/source/training/tertiary/img/tertiary_01.png
Binary files differ
diff --git a/doc/source/training/tertiary/img/tertiary_02.png b/doc/source/training/tertiary/img/tertiary_02.png
new file mode 100644
index 0000000..bfa82d7
--- /dev/null
+++ b/doc/source/training/tertiary/img/tertiary_02.png
Binary files differ
diff --git a/doc/source/training/tertiary/img/tertiary_03.png b/doc/source/training/tertiary/img/tertiary_03.png
new file mode 100644
index 0000000..5325dfc
--- /dev/null
+++ b/doc/source/training/tertiary/img/tertiary_03.png
Binary files differ
diff --git a/doc/source/training/tertiary/img/tertiary_04.png b/doc/source/training/tertiary/img/tertiary_04.png
new file mode 100644
index 0000000..69af2c7
--- /dev/null
+++ b/doc/source/training/tertiary/img/tertiary_04.png
Binary files differ
diff --git a/doc/source/training/tertiary/index.rst b/doc/source/training/tertiary/index.rst
new file mode 100644
index 0000000..3ed19a7
--- /dev/null
+++ b/doc/source/training/tertiary/index.rst
@@ -0,0 +1,65 @@
+Accounting for higher order excitations
+=======================================
+
+.. |img1| image:: ./img/tertiary_01.png
+ :width: 300px
+ :align: middle
+ :alt: Secondary Excitation Process
+
+.. |img2| image:: ./img/tertiary_02.png
+ :width: 400px
+ :align: middle
+ :alt: Fitted Steel Data
+
+.. |img3| image:: ./img/tertiary_03.png
+ :width: 400px
+ :align: middle
+ :alt: Analytical corrections
+
+.. |img4| image:: ./img/tertiary_04.png
+ :width: 400px
+ :align: middle
+ :alt: Monte Carlo corrections
+
+.. contents::
+ :local:
+
+Introduction
+------------
+
+It can happen that the X-rays emitted by a sample element j excite other element i present in the sample up to a non-negligible extent as compared to the direct excitation process. The figure below illustrates the case for secondary excitation.
+
+|img1|
+
+Obviously it may happen that the element i excite in turn other element up to a non-negligible amount and so son. PyMca can account for these processes using two totally different approaches. One based on the use of analytical formulae and one based on the use of a Monte Carlo code.
+
+The analytical approach implemented in PyMca makes use of the `formulation of D.K.G. de Boer <https://doi.org/10.1002/xrs.1300190312>`_ that is well adapted for its use with multiple-layer samples.
+
+The Monte Carlo approach uses the `XMI-MSIM code <https://doi.org/10.1016/j.sab.2012.03.011>`_ mainly developed by Tom Schoonjans and Laszlo Vincze The code can be freely downloaded `here <http://lvserver.ugent.be/xmi-msim/>`_
+
+Currently, PyMca simply evaluates the ratio between the expected measured signal considering primary excitation and the expected measured signal considering higher-order excitation. That ratio gives the correction to be applied to the concentrations calculated just considering primary excitation.
+
+Exercise
+--------
+
+We are going to learn how to account for secondary excitations using the spectrum from a stainless steel sample.
+
+The data are provided with PyMca. To access them, just start a new session of PyMca and, via the File menu, access the data following the sequence File -> Open -> Load Training Data -> Tertiary Excitation. At this point, PyMca will show you the spectrum in the MCA window.
+
+We are going to skip the usual procedure of calibrating the spectrum. Therefore we are going to press the fit icon and select the Advanced fit option to reach our usual McaAdvancedFit window where we perform our XRF analysis.
+
+A fit configuration file named Steel.cfg is also provided. As supplied, it only considers quantification following primary excitation. To load it, just press the Configure button, load the file from the file dialog that will appear after pressing the Load button and press OK to return to the McaAdvancedFit window. If you press the Fit Again! button or the fit icon, you should be able to obtain something similar to the figure below (please note the change to energy axis and logarithmic scale via the appropriate toolbar icons).
+
+|img2|
+
+At this point we can calculate the concentrations by selecting the CONCENTRATIONS tab. We can also select the DIAGNOSTICS tab. If we do so, we'll see that the program warns about secondary or tertiary excitation contributions when the correction is more than 1 %. You should see that neglecting secondary excitation would lead to overestimating the concentration of Cr in the sample by more than 60 % and that even tertiary excitation is not negligible.
+
+|img3|
+
+If XMI-MSIM is not installed, the MC Matrix Spectrum button will not be shown. If it is installed, you can also calculate the corrections using it. You just need to press the MC Matrix Spectrum button. You should get a window open where the output of the code will be shown. Under windows sometimes you need to use the 32-bit version of XMI-MSIM. The first time you run the XMI-MSIM code for a given detector and geometry it can take quite long. Subsequent runs are very fast for a Monte Carlo code. Besides showing the Monte Carlo calculated spectrum following 1 or 4 interactions in the sample, the logging window will show you the corrections we are interested on.
+
+|img4|
+
+Whether using the analytical formulas or the Monte Carlo approach, accounting for those corrections is as simple as selecting the appropriate option in the CONCENTRATIONS tab. You will see how the different concentrations are corrected following the selection of the appropriate checkbox to consider secondary, tertiary or Monte Carlo correction. If you know your samples require account for secondary or higher order excitations, you should select the appropriate checkbox of the CONCENTRATIONS tab of the fit configuration as part of the fir configuration itself.
+
+
diff --git a/doc/source/training/xraydata/img/xraydata_01.png b/doc/source/training/xraydata/img/xraydata_01.png
new file mode 100644
index 0000000..4601932
--- /dev/null
+++ b/doc/source/training/xraydata/img/xraydata_01.png
Binary files differ
diff --git a/doc/source/training/xraydata/img/xraydata_02.png b/doc/source/training/xraydata/img/xraydata_02.png
new file mode 100644
index 0000000..24dd553
--- /dev/null
+++ b/doc/source/training/xraydata/img/xraydata_02.png
Binary files differ
diff --git a/doc/source/training/xraydata/index.rst b/doc/source/training/xraydata/index.rst
new file mode 100644
index 0000000..4c6146c
--- /dev/null
+++ b/doc/source/training/xraydata/index.rst
@@ -0,0 +1,71 @@
+Customizing X-Ray Data
+======================
+
+.. |img_01| image:: ./img/xraydata_01.png
+ :align: middle
+ :alt: Initial data
+
+.. |img_02| image:: ./img/xraydata_02.png
+ :align: middle
+ :alt: Final data
+
+
+.. contents::
+ :local:
+
+Introduction
+------------
+
+A program for X-ray fluorescence analysis needs:
+
+- A database
+- A Physics engine
+- A set of algorithms for spectrum deconvolution
+- A user interface
+
+The developers of *PyMca* put the maximum degree of effort into correctness and transparency but they are not at the origin of the data used by the program. The theoretical data may not be reliable in some cases (in fact we know they are not!) and, since we do not have the time to perform a systematic study or to determine them ourselves, we have made sure the program can be modified by the user in order to adapt it to other data that the user may consider more reliable.
+
+Exercise
+--------
+
+The objective of this exercise is to teach you how to modify the theoretical data used by *PyMca*. For this, we are going to take the case of the L1-shell fluorescence yield of Pb and we are going to force *PyMca* to use a different value from the supplied default one.
+
+Step 1: Getting the data
+........................
+
+The L1-shell fluorescence yields are stored in the `LShellConstants.dat <https://github.com/vasole/fisx/blob/master/fisx_data/LShellConstants.dat>`_ file of the `fisx library <https://github.com/vasole/fisx>`_.
+
+As explained in the `Customizing PyMca section <../../customization/settings/index.html>`_, we have to download that file and put it into the data directory of the settings folder. You can do it by opening the `link <https://github.com/vasole/fisx/blob/master/fisx_data/LShellConstants.dat>`_ above in your browser, clicking on the button with the text Raw shown at the right side of the page and saving the file to the mentioned directory.
+
+Step 2: Initial verification
+............................
+
+In order to check the data *PyMca* is using, we can open the *Elements Info* tool available from the *Tools* option of the menu of the *PyMca* main window.
+
+We can click on the atomic symbol of Pb in order to display the information used by the program.
+
+|img_01|
+
+We should find a value of of 0.0932 for the lead L1-shell fluorescence yield. This value was obtained by interpolating the theoretical values in TABLE I from the article by M.H. Chen, B. Crasemann, H. Mark in *Widths and fluorescence yields of atomic L-shell vacancy states Physical Review A volume 24 number 1 (1981) 177-182*
+
+We are going to update that value with the value 0.128 recommended in Table 2 from the article by J.L. Campbell *Fluorescence yields and Coster-Kronig probabilities for the atomic L subshells. Part II: The L1 subshell revisited* with `doi:10.1016/j.adt.2008.08.002 <https://dx.doi.org/10.1016/j.adt.2008.08.002>`_
+
+DISCLAIMER: The goal of this exercise is to show you how to update the data used by the application. We are not endorsing the use of the data provided by Campbell because we have not made an exhaustive study for all the elements. Despite that, we have to say that Campbell has performed such systematic studies and the value Campbell recommends for lead is indeed much closer to the value used in our own research than the theoretical one. You SHOULD verify yourself if, when calculating concentrations using the L1, L2 and L3 lines of Pb, you find a) a systematic discrepancy of the value of the L1-derived concentrations respect to the concentration values derived from the L2 and L3 shells and b) if you can correct the discrepancy by changing the L1-shell fluorescence yield of lead.
+
+Step 3: Modifying the data
+..........................
+
+You need an editor not modifying line endings. That is usually not a problem for Linux or MacOS users. For windows users `Notepad++ <https://notepad-plus-plus.org>`_ or `Vim for windows <https://www.vim.org>`_ could be good choices.
+
+We just have to get to the line 93 of the file, replace the value 0.0932 by the value 0.128 and save the changes.
+
+Step 4: Final verification
+..........................
+
+We close *PyMca* if we did not do it yet and we start it again.
+
+If we repeat the operation described in the step 2 above, we should get now the modified value.
+
+|img_02|
+
+Please keep in mind the DISCLAIMER above.
diff --git a/doc/source/tutorials.rst b/doc/source/tutorials.rst
index 0ed1b9c..bc536ab 100644
--- a/doc/source/tutorials.rst
+++ b/doc/source/tutorials.rst
@@ -1,5 +1,5 @@
-Tutorials and sample code
-=========================
+Tutorials and Exercises
+=======================
.. toctree::
:hidden:
@@ -8,31 +8,50 @@ Tutorials and sample code
./xrf/strip-background/index.rst
./customization/index.rst
./hdf5/index.rst
+ ./training/quantification/index.rst
+ ./training/tertiary/index.rst
+ ./training/matrix/index.rst
+ ./training/xraydata/index.rst
-There are several tutorials explaining different aspects of the program.
+Things learned by practice usually require a greater effort than just reading or listening and tend to be better retained. Therefore we have prepared some `Exercises`_ to complement the usual set of `Tutorials`_ teaching different aspects of *PyMca*.
+
+Their combination should provide a good starting point to use the program.
+
+Tutorials
+---------
The `Getting Started tutorial <http://www.esrf.fr/computing/bliss/downloads/pymca/PyMcaCHESS.pdf>`_
is a very old tutorial written by Darren Dale and initially tailored to `CHESS <http://www.chess.cornell.edu>`_
-users but usefull to everybody starting to use PyMca. In case the previous link is down, you can try
+users but usefull to everybody starting to use *PyMca*. In case the previous link is down, you can try
this `alternative link <https://wiki.utep.edu/display/MASE6402MME4501/PyMCA+support>`_.
-:doc:`./hdf5/index` PyMca can deal with
-HDF5 files since version 4.4.0. You should take a look at the
-`HDF Group web site <https://portal.hdfgroup.org/display/HDF5/HDF5>`_ to know more about HDF.
-`NeXus <http://www.nexusformat.org>`_ files are only supported when using the HDF5 backend.
-
`Calibration tutorial <http://www.esrf.fr/computing/bliss/downloads/pymca/calibrationtutorial.htm>`_.
To be used if you still have some doubts about how to calibrate your spectra.
:doc:`./xrf/material-definition/index`. This tutorial will show you how to define your own materials.
+:doc:`./xrf/strip-background/index`. Description of the parameters defining your favorite background.
+
`ROI Imaging tutorial <http://www.esrf.fr/computing/bliss/downloads/pymca/roitooltutorial.htm>`_ .
-Introduction to the stack imaging capabilities of PyMca
+Introduction to the stack imaging capabilities of *PyMca*
`Kinetics tutorial <http://www.esrf.fr/computing/bliss/downloads/pymca/kineticstutorial.htm>`_ .
Illustration of the use of the ROI Imaging tool for kinetics studies.
-:doc:`./xrf/strip-background/index`. Description of the parameters defining your favorite background.
+:doc:`./hdf5/index` *PyMca* can deal with
+HDF5 files since version 4.4.0. You should take a look at the
+`HDF Group web site <https://portal.hdfgroup.org/display/HDF5/HDF5>`_ to know more about HDF.
+`NeXus <http://www.nexusformat.org>`_ files are only supported when using the HDF5 backend.
+
+:doc:`./customization/index` Description about how to provide customized settings and add-ons to *PyMca*.
+
+Exercises
+---------
+
+:doc:`./training/quantification/index`. The classical exercise to learn how to carry out XRF analysis with *PyMca*.
+
+:doc:`./training/tertiary/index`. Press-button exercise to show how to deal with secondary and higher order excitations in X-ray fluorescence quantification problems.
-:doc:`./customization/index` Description about how to add your own add-ons to PyMca.
+:doc:`./training/matrix/index`. This exercise shows the user one way to tell the program how to automatically update the sample composition.
+:doc:`./training/xraydata/index`. Exercise to teach the user how to modify the theoretical data used by *PyMca*.
diff --git a/package/debian8/changelog b/package/debian8/changelog
index bdc2a61..99ea4e2 100644
--- a/package/debian8/changelog
+++ b/package/debian8/changelog
@@ -1,3 +1,9 @@
+pymca (5.4.0-1) unstable; urgency=low
+
+ * New release 5.4.0
+
+ -- Pierre Knobel <pierre.knobel@esrf.fr> Fri, 14 Sep 2018 10:01:17 +0200
+
pymca (5.3.1-1) unstable; urgency=low
* New release 5.3.1
diff --git a/package/debian8/control b/package/debian8/control
index 886a215..adaa67a 100644
--- a/package/debian8/control
+++ b/package/debian8/control
@@ -6,27 +6,21 @@ Section: science
Testsuite: autopkgtest
Priority: extra
Build-Depends: cython,
- cython-dbg,
cython3,
- cython3-dbg,
dh-python,
debhelper (>= 9),
libglu1-mesa-dev,
libqhull-dev,
- python-all-dbg,
python-all-dev,
python-numpy,
- python-numpy-dbg,
python-setuptools,
python-sphinx,
- python-fisx (>= 1.1.2),
- python3-all-dbg,
+ python-fisx (>= 1.1.6),
python3-all-dev,
python3-numpy,
- python3-numpy-dbg,
python3-setuptools,
python3-sphinx,
- python3-fisx (>= 1.1.2),
+ python3-fisx (>= 1.1.6),
Standards-Version: 3.9.8
Vcs-Browser: https://anonscm.debian.org/cgit/debian-science/packages/pymca.git
Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/pymca.git
@@ -62,7 +56,7 @@ Package: python-pymca5
Architecture: any
Section: python
Depends: pymca-data (= ${source:Version}),
- python-fisx (>= 1.1.2),
+ python-fisx (>= 1.1.6),
python-matplotlib,
python-h5py,
python-silx,
@@ -93,47 +87,11 @@ Description: Applications and toolkit for X-ray fluorescence analysis -- Python
.
This is the Python 2 version of the package.
-Package: python-pymca5-dbg
-Architecture: any
-Section: debug
-Depends: python-fisx-dbg (>= 1.1.2),
- python-matplotlib-dbg,
- python-h5py-dbg,
- python-silx-dbg,
- python-opengl,
- python-pymca5 (= ${binary:Version}),
- python-qt4-dbg | python-pyqt5-dbg,
- python-qt4-gl-dbg | python-pyqt5.qtopengl-dbg,
- ${misc:Depends},
- ${python:Depends},
- ${shlibs:Depends}
-Recommends: python-dbg,
- python-mdp
-Description: Applications and toolkit for X-ray fluorescence analysis -- Python 2 debug
- PyMca is set of applications and Python libraries for analysis of
- X-ray fluorescence spectra.
- .
- The applications included in this package are:
- .
- * edfviewer - Display and inspection of data files in ESRF Data Format
- * elementsinfo - Displays element specific X-ray data
- * mca2edf - Converts files from SPEC MCA format to EDF
- * peakidentifier - Displays X-ray fluorescence peaks in a given energy range
- * pymcabatch - Batch fitting of spectra
- * pymcapostbatch - Post-processing of batch fitting results
- * pymca - Interactive data-analysis
- * pymcaroitool - Region-of-interest (ROI) imaging tool
- .
- The PyMca toolkit can read data files in SPEC, ESRF data file (EDF),
- OMNIC, HDF5, AIFIRA and SupaVisio formats.
- .
- This is the Python 2 debug version of the package.
-
Package: python3-pymca5
Architecture: any
Section: python
Depends: pymca-data (= ${source:Version}),
- python3-fisx (>= 1.1.2),
+ python3-fisx (>= 1.1.6),
python3-matplotlib,
python3-h5py,
python3-silx,
@@ -164,42 +122,6 @@ Description: Applications and toolkit for X-ray fluorescence analysis -- Python
.
This is the Python 3 version of the package.
-Package: python3-pymca5-dbg
-Architecture: any
-Section: debug
-Depends: python3-fisx-dbg (>= 1.1.2),
- python3-matplotlib-dbg,
- python3-h5py-dbg,
- python3-silx-dbg,
- python3-opengl,
- python3-pymca5 (= ${binary:Version}),
- python3-pyqt4-dbg | python3-pyqt5-dbg,
- python3-pyqt4.qtopengl-dbg | python3-pyqt5.qtopengl-dbg,
- ${misc:Depends},
- ${python3:Depends},
- ${shlibs:Depends}
-Recommends: python3-dbg,
- python3-mdp
-Description: Applications and toolkit for X-ray fluorescence analysis -- Python 3 debug
- PyMca is set of applications and Python libraries for analysis of
- X-ray fluorescence spectra.
- .
- The applications included in this package are:
- .
- * edfviewer - Display and inspection of data files in ESRF Data Format
- * elementsinfo - Displays element specific X-ray data
- * mca2edf - Converts files from SPEC MCA format to EDF
- * peakidentifier - Displays X-ray fluorescence peaks in a given energy range
- * pymcabatch - Batch fitting of spectra
- * pymcapostbatch - Post-processing of batch fitting results
- * pymca - Interactive data-analysis
- * pymcaroitool - Region-of-interest (ROI) imaging tool
- .
- The PyMca toolkit can read data files in SPEC, ESRF data file (EDF),
- OMNIC, HDF5, AIFIRA and SupaVisio formats.
- .
- This is the Python 3 debug version of the package.
-
Package: pymca-data
Architecture: all
Depends: ${misc:Depends}
diff --git a/package/debian9/changelog b/package/debian9/changelog
index bdc2a61..99ea4e2 100644
--- a/package/debian9/changelog
+++ b/package/debian9/changelog
@@ -1,3 +1,9 @@
+pymca (5.4.0-1) unstable; urgency=low
+
+ * New release 5.4.0
+
+ -- Pierre Knobel <pierre.knobel@esrf.fr> Fri, 14 Sep 2018 10:01:17 +0200
+
pymca (5.3.1-1) unstable; urgency=low
* New release 5.3.1
diff --git a/package/debian9/control b/package/debian9/control
index edccfe0..adaa67a 100644
--- a/package/debian9/control
+++ b/package/debian9/control
@@ -15,12 +15,12 @@ Build-Depends: cython,
python-numpy,
python-setuptools,
python-sphinx,
- python-fisx (>= 1.1.2),
+ python-fisx (>= 1.1.6),
python3-all-dev,
python3-numpy,
python3-setuptools,
python3-sphinx,
- python3-fisx (>= 1.1.2),
+ python3-fisx (>= 1.1.6),
Standards-Version: 3.9.8
Vcs-Browser: https://anonscm.debian.org/cgit/debian-science/packages/pymca.git
Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/pymca.git
@@ -56,7 +56,7 @@ Package: python-pymca5
Architecture: any
Section: python
Depends: pymca-data (= ${source:Version}),
- python-fisx (>= 1.1.2),
+ python-fisx (>= 1.1.6),
python-matplotlib,
python-h5py,
python-silx,
@@ -91,7 +91,7 @@ Package: python3-pymca5
Architecture: any
Section: python
Depends: pymca-data (= ${source:Version}),
- python3-fisx (>= 1.1.2),
+ python3-fisx (>= 1.1.6),
python3-matplotlib,
python3-h5py,
python3-silx,
diff --git a/requirements.txt b/requirements.txt
index 286cd04..e169738 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,12 +7,12 @@
--only-binary numpy,h5py,scipy,PyQt4,PyQt5,PySide
numpy >= 1.8
-fisx >= 1.1.2
+fisx >= 1.1.5
PyOpenGL # For PyMca5.Object3D module
h5py # For HDF5 file format support
matplotlib > 1.0 # For visualization
qtconsole # For interactive console plugin
-silx >= 0.7 # For NeXus NXdata support and nicer icons
+silx >= 0.8 # For NeXus NXdata support and nicer icons
# PyQt4, PyQt5 or PySide # For PyMca5.PyMcaGui
# Try to install a Qt binding from a wheel
diff --git a/setup.py b/setup.py
index b1fc4b8..a010c18 100644
--- a/setup.py
+++ b/setup.py
@@ -895,7 +895,7 @@ classifiers = ["Development Status :: 5 - Production/Stable",
# install requires for non-GUI usage
install_requires = ["numpy",
"matplotlib>1.0",
- "fisx>=1.1.4",
+ "fisx>=1.1.6",
"h5py"]
if use_gui():
# install requires with all easy-to-provide GUI functionality