Changeset 6b0c2f6 in sasview for src/sas


Ignore:
Timestamp:
Dec 24, 2017 10:42:41 AM (7 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
2109350
Parents:
378e808
Message:

Constraint validator - initial implementation + tests. SASVIEW-844

Location:
src/sas/qtgui
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/GUITests.py

    r0261bc1 r6b0c2f6  
    5656from Perspectives.Fitting.UnitTesting import FitPageTest 
    5757from Perspectives.Fitting.UnitTesting import FittingOptionsTest 
     58from Perspectives.Fitting.UnitTesting import MultiConstraintTest 
     59 
    5860#  Invariant 
    5961from Perspectives.Invariant.UnitTesting import InvariantPerspectiveTest 
    60 from Perspectives.Invariant.UnitTesting import InvariantDetailsTest 
    6162 
    6263 
     
    112113        unittest.makeSuite(FitPageTest.FitPageTest,                       'test'), 
    113114        unittest.makeSuite(FittingOptionsTest.FittingOptionsTest,         'test'), 
     115        unittest.makeSuite(MultiConstraintTest.MultiConstraintTest,       'test'), 
    114116        #  Invariant 
    115117        unittest.makeSuite(InvariantPerspectiveTest.InvariantPerspectiveTest,  'test'), 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r378e808 r6b0c2f6  
    8484    Main widget for selecting form and structure factor models 
    8585    """ 
     86    constraintAddedSignal = QtCore.pyqtSignal(list) 
    8687    def __init__(self, parent=None, data=None, tab_id=1): 
    8788 
     
    456457        # Respond to change in parameters from the UI 
    457458        self._model_model.itemChanged.connect(self.onMainParamsChange) 
     459        self.constraintAddedSignal.connect(self.modifyViewOnConstraint) 
    458460        self._poly_model.itemChanged.connect(self.onPolyModelChange) 
    459461        self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     
    510512 
    511513        # Define the callbacks 
    512         self.actionConstrain.triggered.connect(self.addConstraint) 
    513         self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstrain) 
     514        self.actionConstrain.triggered.connect(self.addSimpleConstraint) 
     515        self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstraint) 
    514516        self.actionSelect.triggered.connect(self.selectParameters) 
    515517        self.actionDeselect.triggered.connect(self.deselectParameters) 
    516518        return menu 
    517519 
    518     def showMultiConstrain(self): 
     520    def showMultiConstraint(self): 
    519521        """ 
    520522        Show the constraint widget and receive the expression 
    521523        """ 
    522524        from sas.qtgui.Perspectives.Fitting.MultiConstraint import MultiConstraint 
    523         params_list = [s.data() for s in self.lstParams.selectionModel().selectedRows()] 
     525        from .Constraints import Constraint 
     526        selected_rows = self.lstParams.selectionModel().selectedRows() 
     527 
     528        params_list = [s.data() for s in selected_rows] 
    524529        mc_widget = MultiConstraint(self, params=params_list) 
    525530        mc_widget.exec_() 
    526         constraint = mc_widget.txtConstraint.text() 
     531        constraint = Constraint() 
     532        c_text = mc_widget.txtConstraint.text() 
    527533        # Pass the constraint to the parser 
     534 
    528535        self.communicate.statusBarUpdateSignal.emit('Constraints added') 
     536        # Change the colour of the row 
    529537        pass 
    530538 
    531     def addConstraint(self): 
     539    def modifyViewOnConstraint(self, row): 
     540        """ 
     541        Add visual cues that the parameter is constrained 
     542        """ 
     543        value = self._model_model.item(row, 1).text() 
     544        # Set min/max to the value constrained 
     545        self._model_model.item(row,2).setText(value) 
     546        self._model_model.item(row,3).setText(value) 
     547        font = QtGui.QFont() 
     548        font.setItalic(True) 
     549        brush = QtGui.QBrush(QtGui.QColor('blue')) 
     550        self._model_model.blockSignals(True) 
     551        # Modify font and foreground of affected rows 
     552        for column in range(0, self._model_model.columnCount()): 
     553            self._model_model.item(row, column).setForeground(brush) 
     554            self._model_model.item(row, column).setFont(font) 
     555            self._model_model.item(row, column).setEditable(False) 
     556        self._model_model.blockSignals(False) 
     557 
     558    def addSimpleConstraint(self): 
    532559        """ 
    533560        Adds a constraint on a single parameter. 
    534561        """ 
     562        from .Constraints import Constraint 
     563        for row in self.selectedParameters(): 
     564            param = self._model_model.item(row, 0).text() 
     565            value = self._model_model.item(row, 1).text() 
     566            constraint = Constraint(param=param, value=value) 
     567            item = QtGui.QStandardItem() 
     568            item.setData(constraint) 
     569            self._model_model.item(row, 1).setChild(0, item) 
     570            #self.constraintAddedSignal.emit([row]) 
     571            self.modifyViewOnConstraint(row) 
    535572        self.communicate.statusBarUpdateSignal.emit('Constraint added') 
    536573        pass 
  • src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py

    • Property mode changed from 100755 to 100644
    r378e808 r6b0c2f6  
    22Widget for parameter constraints. 
    33""" 
     4from numpy import * 
     5 
    46from PyQt5 import QtCore 
    57from PyQt5 import QtGui 
     
    2325        self.setupTooltip() 
    2426 
     27        # Set param text control to the second parameter passed 
     28        self.txtConstraint.setText(self.params[1]) 
     29 
    2530        self.cmdOK.clicked.connect(self.accept) 
    2631        self.cmdRevert.clicked.connect(self.revert) 
     32        self.txtConstraint.editingFinished.connect(self.validateFormula) 
    2733 
    2834    def revert(self): 
     
    5258        self.txtConstraint.setToolTip(tooltip) 
    5359 
    54         pass 
     60    def validateFormula(self): 
     61        """ 
     62        Add visual cues when formula is incorrect 
     63        """ 
     64        formula_is_valid = False 
     65        formula_is_valid = self.validateConstraint(self.txtConstraint.text()) 
     66        if not formula_is_valid: 
     67            self.cmdOK.setEnabled(False) 
     68            self.txtConstraint.setStyleSheet("QLineEdit {background-color: red;}") 
     69        else: 
     70            self.cmdOK.setEnabled(True) 
     71            self.txtConstraint.setStyleSheet("QLineEdit {background-color: white;}") 
    5572 
     73    def validateConstraint(self, constraint_text): 
     74        """ 
     75        Ensure the constraint has proper form 
     76        """ 
     77        # 0. none or empty 
     78        if not constraint_text or not isinstance(constraint_text, str): 
     79            return False 
     80 
     81        param_str = str(self.params[1]) 
     82        constraint_text = constraint_text.strip() 
     83 
     84        # 1. just the parameter 
     85        if param_str == constraint_text: 
     86            return True 
     87 
     88        # 2. ensure the text contains parameter name 
     89        parameter_string_start = constraint_text.find(param_str) 
     90        has_parameter_name = (parameter_string_start > -1) 
     91        if not has_parameter_name: 
     92            return False 
     93        parameter_string_end = parameter_string_start + len(param_str) 
     94 
     95        # 3. parameter name should be a separate word, but can have "()[]*+-/" around 
     96        valid_neighbours = "()[]*+-/ " 
     97        has_only_parameter = False 
     98        start_loc = parameter_string_start -1 
     99        end_loc = parameter_string_end 
     100        if not any([constraint_text[start_loc] == char for char in valid_neighbours]): 
     101            return False 
     102        if end_loc < len(constraint_text): 
     103            if not any([constraint_text[end_loc] == char for char in valid_neighbours]): 
     104                return False 
     105 
     106        # 4. replace parameter name with "1" and try to evaluate the expression 
     107        try: 
     108            expression_to_evaluate = constraint_text.replace(param_str, "1.0") 
     109            eval(expression_to_evaluate) 
     110        except Exception: 
     111            # Too many cases to cover individually, just a blanket 
     112            # Exception should be sufficient 
     113            # Note that in current numpy things like sqrt(-1) don't 
     114            # raise but just return warnings 
     115            return False 
     116 
     117        return True 
     118 
     119 
     120 
Note: See TracChangeset for help on using the changeset viewer.