#/*##########################################################################
# 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.
#
#############################################################################*/
__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os.path
import numpy
from . import SimpleFitControlWidget
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaIO import ConfigDict
from PyMca5.PyMcaGui import PyMca_Icons as Icons
from PyMca5 import PyMcaDirs
#strip background handling
from . import Parameters
from PyMca5.PyMcaGui.math.StripBackgroundWidget import StripBackgroundDialog
DEBUG = 0
[docs]class SimpleFitConfigurationGui(qt.QDialog):
def __init__(self, parent = None, fit=None):
qt.QDialog.__init__(self, parent)
self.setWindowTitle("PyMca - Simple Fit Configuration")
self.setWindowIcon(qt.QIcon(qt.QPixmap(Icons.IconDict["gioconda16"])))
self.mainLayout = qt.QVBoxLayout(self)
self.mainLayout.setContentsMargins(2, 2, 2, 2)
self.mainLayout.setSpacing(2)
self.tabWidget = qt.QTabWidget(self)
self.fitControlWidget = SimpleFitControlWidget.SimpleFitControlWidget(self)
self.fitControlWidget.sigFitControlSignal.connect(self._fitControlSlot)
self.tabWidget.insertTab(0, self.fitControlWidget, "FIT")
self.fitFunctionWidgetStack = qt.QWidget(self)
self.fitFunctionWidgetStack.mainLayout = qt.QStackedLayout(self.fitFunctionWidgetStack)
self.fitFunctionWidgetStack.mainLayout.setContentsMargins(0, 0, 0, 0)
self.fitFunctionWidgetStack.mainLayout.setSpacing(0)
self.tabWidget.insertTab(1, self.fitFunctionWidgetStack, "FUNCTION")
self.backgroundWidgetStack = qt.QWidget(self)
self.backgroundWidgetStack.mainLayout = qt.QStackedLayout(self.backgroundWidgetStack)
self.backgroundWidgetStack.mainLayout.setContentsMargins(0, 0, 0, 0)
self.backgroundWidgetStack.mainLayout.setSpacing(0)
self.tabWidget.insertTab(2, self.backgroundWidgetStack, "BACKGROUND")
self.mainLayout.addWidget(self.tabWidget)
self._stripDialog = None
self.buildAndConnectActions()
self.mainLayout.addWidget(qt.VerticalSpacer(self))
self._fitFunctionWidgets = {}
self._backgroundWidgets = {}
self.setSimpleFitInstance(fit)
#input output directory
self.initDir = None
def _fitControlSlot(self, ddict):
if DEBUG:
print("FitControlSignal", ddict)
event = ddict['event']
if event == "stripSetupCalled":
if self._stripDialog is None:
self._stripDialog = StripBackgroundDialog()
self._stripDialog.setWindowIcon(qt.QIcon(\
qt.QPixmap(Icons.IconDict["gioconda16"])))
pars = self.__getConfiguration("FIT")
if self.simpleFitInstance is None:
return
xmin = pars['xmin']
xmax = pars['xmax']
idx = (self.simpleFitInstance._x0 >= xmin) & (self.simpleFitInstance._x0 <= xmax)
x = self.simpleFitInstance._x0[idx] * 1
y = self.simpleFitInstance._y0[idx] * 1
self._stripDialog.setParameters(pars)
self._stripDialog.setData(x, y)
ret = self._stripDialog.exec_()
if not ret:
return
pars = self._stripDialog.getParameters()
self.fitControlWidget.setConfiguration(pars)
if event == "fitFunctionChanged":
functionName = ddict['fit_function']
if functionName in [None, "None", "NONE"]:
functionName = "None"
instance = self._fitFunctionWidgets.get(functionName, None)
if instance is None:
instance = qt.QWidget(self.fitFunctionWidgetStack)
self.fitFunctionWidgetStack.mainLayout.addWidget(instance)
self._fitFunctionWidgets[functionName] = instance
self.fitFunctionWidgetStack.mainLayout.setCurrentWidget(instance)
return
fun = self.simpleFitInstance._fitConfiguration['functions'][functionName]
instance = self._fitFunctionWidgets.get(functionName, None)
if instance is None:
widget = fun.get('widget', None)
if widget is None:
instance = self._buildDefaultWidget(functionName, background=False)
else:
instance = widget(self.fitFunctionWidgetStack)
self.fitFunctionWidgetStack.mainLayout.addWidget(instance)
self._fitFunctionWidgets[functionName] = instance
if hasattr(instance, 'configure'):
configureMethod = fun['configure']
if configureMethod is not None:
#make sure it is up-to-date
fun['configuration'].update(configureMethod())
instance.configure(fun)
self.fitFunctionWidgetStack.mainLayout.setCurrentWidget(instance)
if event == "backgroundFunctionChanged":
functionName = ddict['background_function']
if functionName in [None, "None", "NONE"]:
functionName = "None"
instance = self._backgroundWidgets.get(functionName, None)
if instance is None:
instance = qt.QWidget(self.backgroundWidgetStack)
self.backgroundWidgetStack.mainLayout.addWidget(instance)
self._backgroundWidgets[functionName] = instance
self.backgroundWidgetStack.mainLayout.setCurrentWidget(instance)
return
fun = self.simpleFitInstance._fitConfiguration['functions'][functionName]
instance = self._backgroundWidgets.get(functionName, None)
if instance is None:
widget = fun.get('widget', None)
if widget is None:
instance = self._buildDefaultWidget(functionName, background=True)
else:
instance = widget(self.backgroundWidgetStack)
self.backgroundWidgetStack.mainLayout.addWidget(instance)
self._backgroundWidgets[functionName] = instance
if hasattr(instance, 'configure'):
configureMethod = fun['configure']
if configureMethod is not None:
#make sure it is up-to-date
fun['configuration'].update(configureMethod())
instance.configure(fun)
self.backgroundWidgetStack.mainLayout.setCurrentWidget(instance)
def _buildDefaultWidget(self, functionName, background=False):
functionDescription = self.simpleFitInstance._fitConfiguration['functions']\
[functionName]
#if we here that means the function does not provide a widget
#if the function does not provide an authomatic estimate
#the user has to fill the default parameters in the default table
estimate = functionDescription['estimate']
if estimate is None:
if background:
widget = DefaultParametersWidget(self.backgroundWidgetStack,
self.simpleFitInstance, background=background)
widget.setConfiguration(functionDescription)
self.backgroundWidgetStack.mainLayout.addWidget(widget)
else:
widget = DefaultParametersWidget(self.fitFunctionWidgetStack,
self.simpleFitInstance,
background=background)
widget.setConfiguration(functionDescription)
self.fitFunctionWidgetStack.mainLayout.addWidget(widget)
else:
text = "%s is automatically configured and estimated" % functionName
if background:
widget = DummyWidget(self.backgroundWidgetStack, text=text)
self.backgroundWidgetStack.mainLayout.addWidget(widget)
else:
widget = DummyWidget(self.fitFunctionWidgetStack, text=text)
self.fitFunctionWidgetStack.mainLayout.addWidget(widget)
return widget
[docs] def buildAndConnectActions(self):
buts= qt.QGroupBox(self)
buts.layout = qt.QHBoxLayout(buts)
load= qt.QPushButton(buts)
load.setAutoDefault(False)
load.setText("Load")
save= qt.QPushButton(buts)
save.setAutoDefault(False)
save.setText("Save")
reject= qt.QPushButton(buts)
reject.setAutoDefault(False)
reject.setText("Cancel")
accept= qt.QPushButton(buts)
accept.setAutoDefault(False)
accept.setText("OK")
buts.layout.addWidget(load)
buts.layout.addWidget(save)
buts.layout.addWidget(reject)
buts.layout.addWidget(accept)
self.mainLayout.addWidget(buts)
load.clicked.connect(self.load)
save.clicked.connect(self.save)
reject.clicked.connect(self.reject)
accept.clicked.connect(self.accept)
[docs] def setSimpleFitInstance(self, fitInstance):
self.simpleFitInstance = fitInstance
if self.simpleFitInstance is not None:
self.setConfiguration(self.simpleFitInstance.getConfiguration())
[docs] def setConfiguration(self, ddict):
currentConfig = self.simpleFitInstance.getConfiguration()
currentFiles = []
for functionName in currentConfig['functions'].keys():
fname = currentConfig['functions'][functionName]['file']
if fname not in currentFiles:
currentFiles.append(fname)
if 'functions' in ddict:
#make sure new modules are imported
for functionName in ddict['functions'].keys():
fileName = ddict['functions'][functionName]['file']
if fileName not in currentFiles:
try:
if DEBUG:
print("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")
continue
print("Cannot import file %s" % fileName)
print(sys.exc_info()[1])
if 'fit' in ddict:
self.fitControlWidget.setConfiguration(ddict['fit'])
fitFunction = ddict['fit']['fit_function']
background = ddict['fit']['background_function']
if fitFunction not in self._fitFunctionWidgets.keys():
self._fitControlSlot({'event':'fitFunctionChanged',
'fit_function':fitFunction})
if background not in self._backgroundWidgets.keys():
self._fitControlSlot({'event':'backgroundFunctionChanged',
'background_function':background})
#fit function
fname = ddict['fit']['fit_function']
widget = self._fitFunctionWidgets[fname]
if fname not in [None, "None", "NONE"]:
if fname in ddict['functions']:
#if currentConfig['functions'][fname]['widget'] is not None:
widget.setConfiguration(ddict['functions'][fname])
self.fitFunctionWidgetStack.mainLayout.setCurrentWidget(widget)
#background function
fname = ddict['fit']['background_function']
widget = self._backgroundWidgets[fname]
if fname not in [None, "None", "NONE"]:
if fname in ddict['functions']:
#if currentConfig['functions'][fname]['widget'] is not None:
widget.setConfiguration(ddict['functions'][fname])
self.backgroundWidgetStack.mainLayout.setCurrentWidget(widget)
[docs] def getConfiguration(self):
oldConfiguration = self.simpleFitInstance.getConfiguration()
ddict = {}
for name in ['fit']:
ddict[name] = self.__getConfiguration(name)
#fit function
fname = ddict['fit']['fit_function']
ddict['functions'] = {}
widget = self._fitFunctionWidgets[fname]
if fname not in [None, "None", "NONE"]:
ddict['functions'][fname]={}
ddict['functions'][fname]['file'] = \
oldConfiguration['functions'][fname]['file']
ddict['functions'][fname]['configuration'] =\
oldConfiguration['functions'][fname]['configuration']
newConfig = widget.getConfiguration()
if 'configuration' in newConfig:
ddict['functions'][fname]['configuration'].update(\
newConfig['configuration'])
else:
ddict['functions'][fname]['configuration'].update(newConfig)
#background function
fname = ddict['fit']['background_function']
widget = self._backgroundWidgets[fname]
if fname not in [None, "None", "NONE"]:
ddict['functions'][fname]={}
ddict['functions'][fname]['file'] = \
oldConfiguration['functions'][fname]['file']
ddict['functions'][fname]['configuration'] =\
oldConfiguration['functions'][fname]['configuration']
newConfig = widget.getConfiguration()
if 'configuration' in newConfig:
ddict['functions'][fname]['configuration'].update(\
newConfig['configuration'])
else:
ddict['functions'][fname]['configuration'].update(newConfig)
return ddict
def __getConfiguration(self, name):
if name in ['fit', 'FIT']:
return self.fitControlWidget.getConfiguration()
[docs] def load(self):
if PyMcaDirs.nativeFileDialogs:
filedialog = qt.QFileDialog(self)
filedialog.setFileMode(filedialog.ExistingFiles)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(Icons.IconDict["gioconda16"])))
initdir = os.path.curdir
if self.initDir is not None:
if os.path.isdir(self.initDir):
initdir = self.initDir
filename = filedialog.getOpenFileName(
self,
"Choose fit configuration file",
initdir,
"Fit configuration files (*.cfg)\nAll Files (*)")
filename = qt.safe_str(filename)
if len(filename):
self.loadConfiguration(filename)
self.initDir = os.path.dirname(filename)
else:
filedialog = qt.QFileDialog(self)
filedialog.setFileMode(filedialog.ExistingFiles)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(Icons.IconDict["gioconda16"])))
initdir = os.path.curdir
if self.initDir is not None:
if os.path.isdir(self.initDir):
initdir = self.initDir
filename = filedialog.getOpenFileName(
self,
"Choose fit configuration file",
initdir,
"Fit configuration files (*.cfg)\nAll Files (*)")
filename = qt.safe_str(filename)
if len(filename):
self.loadConfiguration(filename)
self.initDir = os.path.dirname(filename)
[docs] def save(self):
if self.initDir is None:
self.initDir = PyMcaDirs.outputDir
if PyMcaDirs.nativeFileDialogs:
filedialog = qt.QFileDialog(self)
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(Icons.IconDict["gioconda16"])))
initdir = os.path.curdir
if self.initDir is not None:
if os.path.isdir(self.initDir):
initdir = self.initDir
filename = filedialog.getSaveFileName(
self,
"Enter output fit configuration file",
initdir,
"Fit configuration files (*.cfg)\nAll Files (*)")
filename = qt.safe_str(filename)
if len(filename):
if len(filename) < 4:
filename = filename+".cfg"
elif filename[-4:] != ".cfg":
filename = filename+".cfg"
self.saveConfiguration(filename)
self.initDir = os.path.dirname(filename)
else:
filedialog = qt.QFileDialog(self)
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(Icons.IconDict["gioconda16"])))
initdir = os.path.curdir
if self.initDir is not None:
if os.path.isdir(self.initDir):
initdir = self.initDir
filename = filedialog.getSaveFileName(
self,
"Enter output fit configuration file",
initdir,
"Fit configuration files (*.cfg)\nAll Files (*)")
filename = qt.safe_str(filename)
if len(filename):
if len(filename) < 4:
filename = filename+".cfg"
elif filename[-4:] != ".cfg":
filename = filename+".cfg"
self.saveConfiguration(filename)
self.initDir = os.path.dirname(filename)
PyMcaDirs.outputDir = os.path.dirname(filename)
[docs] def loadConfiguration(self, filename):
cfg= ConfigDict.ConfigDict()
try:
cfg.read(filename)
self.initDir = os.path.dirname(filename)
self.setConfiguration(cfg)
except:
if DEBUG:
raise
qt.QMessageBox.critical(self, "Load Parameters",
"ERROR while loading parameters from\n%s"%filename,
qt.QMessageBox.Ok,
qt.QMessageBox.NoButton,
qt.QMessageBox.NoButton)
[docs] def saveConfiguration(self, filename):
cfg = ConfigDict.ConfigDict(self.getConfiguration())
if DEBUG:
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)
[docs]def test():
app = qt.QApplication(sys.argv)
app.lastWindowClosed.conenct(app.quit)
wid = SimpleFitConfigurationGui()
ddict = {}
ddict['fit'] = {}
ddict['fit']['use_limits'] = 1
ddict['fit']['xmin'] = 1
ddict['fit']['xmax'] = 1024
wid.setConfiguration(ddict)
wid.exec_()
print(wid.getConfiguration())
sys.exit()
if __name__=="__main__":
DEBUG = 1
test()