source: sasview/src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py @ ecc5d043

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since ecc5d043 was baeac95, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 5 years ago

Added Edit to single page constraint SASVIEW-1043

  • Property mode set to 100644
File size: 5.5 KB
Line 
1"""
2Widget for parameter constraints.
3"""
4import os
5import webbrowser
6
7# numpy methods required for the validator! Don't remove.
8# pylint: disable=unused-import,unused-wildcard-import,redefined-builtin
9from numpy import *
10
11from PyQt5 import QtWidgets
12
13import sas.qtgui.Utilities.GuiUtils as GuiUtils
14
15# Local UI
16from sas.qtgui.Perspectives.Fitting.UI.MultiConstraintUI import Ui_MultiConstraintUI
17
18class MultiConstraint(QtWidgets.QDialog, Ui_MultiConstraintUI):
19    """
20    Logic class for interacting with MultiConstrainedUI view
21    """
22    def __init__(self, parent=None, params=None, constraint=None):
23        """
24        parent: ConstraintWidget object
25        params: tuple of strings describing model parameters
26        """
27        super(MultiConstraint, self).__init__()
28
29        self.setupUi(self)
30        self.setModal(True)
31        self.params = params
32        self.parent = parent
33        self.function = None
34
35        self.input_constraint = constraint
36        if self.input_constraint is not None:
37            variable = constraint.value
38            #variable = func[func.index('.')+1:]
39            self.function = constraint.func
40            self.params.append(variable)
41            self.model_name = constraint.value_ex
42        else:
43            self.model_name = self.params[1]
44
45        self.setupLabels()
46        self.setupTooltip()
47
48        # Set param text control to the second parameter passed
49        if self.input_constraint is None:
50            self.txtConstraint.setText(self.params[1])
51        else:
52            self.txtConstraint.setText(self.function)
53        self.cmdOK.clicked.connect(self.accept)
54        self.cmdHelp.clicked.connect(self.onHelp)
55        self.cmdRevert.clicked.connect(self.revert)
56        self.txtConstraint.editingFinished.connect(self.validateFormula)
57
58        # Default focus is on OK
59        self.cmdOK.setFocus()
60
61    def revert(self):
62        """
63        Swap parameters in the view
64        """
65        # Switch parameters
66        self.params[1], self.params[0] = self.params[0], self.params[1]
67        # change fully qualified param name (e.g. M1.sld -> M1.sld_solvent)
68        self.model_name = self.model_name.replace(self.params[0], self.params[1])
69        # Try to swap parameter names in the line edit
70        current_text = self.txtConstraint.text()
71        new_text = current_text.replace(self.params[0], self.params[1])
72        self.txtConstraint.setText(new_text)
73        # Update labels and tooltips
74        self.setupLabels()
75        self.setupTooltip()
76
77    def setupLabels(self):
78        """
79        Setup labels based on current parameters
80        """
81        l1 = str(self.params[0])
82        l2 = str(self.params[1])
83        self.txtParam1.setText(l1)
84        self.txtParam1_2.setText(l1)
85        self.txtParam2.setText(l2)
86
87    def setupTooltip(self):
88        """
89        Tooltip for txtConstraint
90        """
91        tooltip = "E.g.\n%s = 2.0 * (%s)\n" %(self.params[0], self.params[1])
92        tooltip += "%s = sqrt(%s) + 5"%(self.params[0], self.params[1])
93        self.txtConstraint.setToolTip(tooltip)
94
95    def validateFormula(self):
96        """
97        Add visual cues when formula is incorrect
98        """
99        formula_is_valid = False
100        formula_is_valid = self.validateConstraint(self.txtConstraint.text())
101        if not formula_is_valid:
102            self.cmdOK.setEnabled(False)
103            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}")
104        else:
105            self.cmdOK.setEnabled(True)
106            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}")
107
108    def validateConstraint(self, constraint_text):
109        """
110        Ensure the constraint has proper form
111        """
112        # 0. none or empty
113        if not constraint_text or not isinstance(constraint_text, str):
114            return False
115
116        param_str = self.model_name
117
118        # 1. just the parameter
119        if param_str == constraint_text:
120            return True
121
122        # 2. ensure the text contains parameter name
123        parameter_string_start = constraint_text.find(param_str)
124        if parameter_string_start < 0:
125            return False
126        parameter_string_end = parameter_string_start + len(param_str)
127
128        # 3. parameter name should be a separate word, but can have "()[]*+-/ " around
129        #valid_neighbours = "()[]*+-/ "
130        #start_loc = parameter_string_start -1
131        #end_loc = parameter_string_end
132        #if not any([constraint_text[start_loc] == ch for ch in valid_neighbours]):
133        #    return False
134        #if end_loc < len(constraint_text):
135        #    if not any([constraint_text[end_loc] == ch for ch in valid_neighbours]):
136        #        return False
137
138        # 4. replace parameter name with "1" and try to evaluate the expression
139        try:
140            expression_to_evaluate = constraint_text.replace(param_str, "1.0")
141            eval(expression_to_evaluate)
142        except Exception:
143            # Too many cases to cover individually, just a blanket
144            # Exception should be sufficient
145            # Note that in current numpy things like sqrt(-1) don't
146            # raise but just return warnings
147            return False
148
149        return True
150
151    def onHelp(self):
152        """
153        Display related help section
154        """
155        try:
156            help_location = GuiUtils.HELP_DIRECTORY_LOCATION + \
157            "/user/qtgui/Perspectives/Fitting/fitting_help.html#simultaneous-fits-with-constraints"
158            webbrowser.open('file://' + os.path.realpath(help_location))
159        except AttributeError:
160            # No manager defined - testing and standalone runs
161            pass
162
163
Note: See TracBrowser for help on using the repository browser.