Changeset 8289ae3 in sasview


Ignore:
Timestamp:
Mar 23, 2018 8:24:10 AM (4 years ago)
Author:
krzywon
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:
ba4e3ba
Parents:
304e42f (diff), 8ac3551 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'ESS_GUI' into ESS_GUI_Pr

Files:
22 added
28 edited

Legend:

Unmodified
Added
Removed
  • setup.py

    • Property mode changed from 100644 to 100755
    r14ec91c5 r3b3b40b  
    351351    "src", "sas", "qtgui", "Utilities") 
    352352packages.append("sas.qtgui.Utilities") 
     353package_dir["sas.qtgui.UtilitiesUI"] = os.path.join( 
     354    "src", "sas", "qtgui", "Utilities","UI") 
     355packages.append("sas.qtgui.Utilities.UI") 
    353356 
    354357package_dir["sas.qtgui.Calculators"] = os.path.join( 
  • src/sas/qtgui/GUITests.py

    rda9a0722 r3b3b40b  
    4444from Utilities.UnitTesting import GuiUtilsTest 
    4545from Utilities.UnitTesting import SasviewLoggerTest 
     46from Utilities.UnitTesting import GridPanelTest 
     47from Utilities.UnitTesting import ModelEditorTest 
     48from Utilities.UnitTesting import PluginDefinitionTest 
     49from Utilities.UnitTesting import TabbedModelEditorTest 
    4650 
    4751# Unit Testing 
     
    99103        unittest.makeSuite(GuiUtilsTest.DoubleValidatorTest,      'test'), 
    100104        unittest.makeSuite(GuiUtilsTest.HashableStandardItemTest, 'test'), 
     105        unittest.makeSuite(GridPanelTest.BatchOutputPanelTest,    'test'), 
     106        unittest.makeSuite(ModelEditorTest.ModelEditorTest,            'test'), 
     107        unittest.makeSuite(PluginDefinitionTest.PluginDefinitionTest,  'test'), 
     108        unittest.makeSuite(TabbedModelEditorTest.TabbedModelEditorTest,'test'), 
    101109 
    102110        # Calculators 
  • src/sas/qtgui/MainWindow/DataExplorer.py

    re90988c r8ac3551  
    473473        Notify the gui manager about the new perspective chosen. 
    474474        """ 
    475         self.communicator.perspectiveChangedSignal.emit(self.cbFitting.currentText()) 
     475        self.communicator.perspectiveChangedSignal.emit(self.cbFitting.itemText(index)) 
    476476        self.chkBatch.setEnabled(self.parent.perspective().allowBatch()) 
    477477 
    478     def displayData(self, data_list): 
     478    def displayFile(self, filename=None, is_data=True): 
    479479        """ 
    480480        Forces display of charts for the given filename 
    481481        """ 
    482         plot_to_show = data_list[0] 
    483  
    484         # passed plot is used ONLY to figure out its title, 
    485         # so all the charts related by it can be pulled from  
    486         # the data explorer indices. 
    487         filename = plot_to_show.filename 
    488         model = self.model if plot_to_show.is_data else self.theory_model 
    489  
     482        model = self.model if is_data else self.theory_model 
    490483        # Now query the model item for available plots 
    491484        plots = GuiUtils.plotsFromFilename(filename, model) 
     
    506499        if new_plots: 
    507500            self.plotData(new_plots) 
     501 
     502    def displayData(self, data_list): 
     503        """ 
     504        Forces display of charts for the given data set 
     505        """ 
     506        plot_to_show = data_list[0] 
     507        # passed plot is used ONLY to figure out its title, 
     508        # so all the charts related by it can be pulled from  
     509        # the data explorer indices. 
     510        filename = plot_to_show.filename 
     511        self.displayFile(filename=filename, is_data=plot_to_show.is_data) 
    508512 
    509513    def addDataPlot2D(self, plot_set, item): 
     
    10271031        pass 
    10281032 
     1033    def onAnalysisUpdate(self, new_perspective=""): 
     1034        """ 
     1035        Update the perspective combo index based on passed string 
     1036        """ 
     1037        assert new_perspective in Perspectives.PERSPECTIVES.keys() 
     1038        self.cbFitting.blockSignals(True) 
     1039        self.cbFitting.setCurrentIndex(self.cbFitting.findText(new_perspective)) 
     1040        self.cbFitting.blockSignals(False) 
     1041        pass 
     1042 
    10291043    def loadComplete(self, output): 
    10301044        """ 
  • src/sas/qtgui/MainWindow/GuiManager.py

    r14ec91c5 r8ac3551  
    1919 
    2020import sas.qtgui.Utilities.ObjectLibrary as ObjectLibrary 
     21from sas.qtgui.Utilities.TabbedModelEditor import TabbedModelEditor 
     22from sas.qtgui.Utilities.PluginManager import PluginManager 
    2123from sas.qtgui.MainWindow.UI.AcknowledgementsUI import Ui_Acknowledgements 
    2224from sas.qtgui.MainWindow.AboutBox import AboutBox 
     
    4749    Main SasView window functionality 
    4850    """ 
    49  
    5051    def __init__(self, parent=None): 
    5152        """ 
     
    182183        Respond to change of the perspective signal 
    183184        """ 
    184  
    185         # Save users from themselves... 
    186         #if isinstance(self._current_perspective, Perspectives.PERSPECTIVES[str(perspective_name)]): 
    187         self.setupPerspectiveMenubarOptions(self._current_perspective) 
    188         #    return 
    189  
    190185        # Close the previous perspective 
    191186        self.clearPerspectiveMenubarOptions(self._current_perspective) 
     
    197192        # Default perspective 
    198193        self._current_perspective = Perspectives.PERSPECTIVES[str(perspective_name)](parent=self) 
     194 
     195        self.setupPerspectiveMenubarOptions(self._current_perspective) 
    199196 
    200197        subwindow = self._workspace.workspace.addSubWindow(self._current_perspective) 
     
    358355        self.communicate.updateTheoryFromPerspectiveSignal.connect(self.updateTheoryFromPerspective) 
    359356        self.communicate.plotRequestedSignal.connect(self.showPlot) 
     357        self.communicate.plotFromFilenameSignal.connect(self.showPlotFromFilename) 
    360358        self.communicate.updateModelFromDataOperationPanelSignal.connect(self.updateModelFromDataOperationPanel) 
    361359 
     
    406404        self._workspace.actionFit_Results.triggered.connect(self.actionFit_Results) 
    407405        self._workspace.actionChain_Fitting.triggered.connect(self.actionChain_Fitting) 
     406        self._workspace.actionAdd_Custom_Model.triggered.connect(self.actionAdd_Custom_Model) 
    408407        self._workspace.actionEdit_Custom_Model.triggered.connect(self.actionEdit_Custom_Model) 
     408        self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 
    409409        # Window 
    410410        self._workspace.actionCascade.triggered.connect(self.actionCascade) 
     
    417417        self._workspace.actionInversion.triggered.connect(self.actionInversion) 
    418418        self._workspace.actionInvariant.triggered.connect(self.actionInvariant) 
     419        self._workspace.actionCorfunc.triggered.connect(self.actionCorfunc) 
    419420        # Help 
    420421        self._workspace.actionDocumentation.triggered.connect(self.actionDocumentation) 
     
    662663        pass 
    663664 
     665    def actionAdd_Custom_Model(self): 
     666        """ 
     667        """ 
     668        self.model_editor = TabbedModelEditor(self) 
     669        self.model_editor.show() 
     670 
    664671    def actionEdit_Custom_Model(self): 
    665672        """ 
    666673        """ 
    667         print("actionEdit_Custom_Model TRIGGERED") 
    668         pass 
     674        self.model_editor = TabbedModelEditor(self, edit_only=True) 
     675        self.model_editor.show() 
     676 
     677    def actionManage_Custom_Models(self): 
     678        """ 
     679        """ 
     680        self.model_manager = PluginManager(self) 
     681        self.model_manager.show() 
    669682 
    670683    #============ ANALYSIS ================= 
     
    674687        """ 
    675688        self.perspectiveChanged("Fitting") 
     689        # Notify other widgets 
     690        self.filesWidget.onAnalysisUpdate("Fitting") 
    676691 
    677692    def actionInversion(self): 
     
    679694        Change to the Inversion perspective 
    680695        """ 
    681         # For now we'll just update the analysis menu status but when the inversion is implemented delete from here 
    682         self.checkAnalysisOption(self._workspace.actionInversion) 
    683         # to here and uncomment the following line 
    684696        self.perspectiveChanged("Inversion") 
     697        self.filesWidget.onAnalysisUpdate("Inversion") 
    685698 
    686699    def actionInvariant(self): 
     
    689702        """ 
    690703        self.perspectiveChanged("Invariant") 
     704        self.filesWidget.onAnalysisUpdate("Invariant") 
     705 
     706    def actionCorfunc(self): 
     707        """ 
     708        Change to the Corfunc perspective 
     709        """ 
     710        self.perspectiveChanged("Corfunc") 
     711        self.filesWidget.onAnalysisUpdate("Corfunc") 
    691712 
    692713    #============ WINDOW ================= 
     
    779800        self.filesWidget.model.appendRow(new_item) 
    780801        self._data_manager.add_data(new_datalist_item) 
     802 
     803    def showPlotFromFilename(self, filename): 
     804        """ 
     805        Pass the show plot request to the data explorer 
     806        """ 
     807        if hasattr(self, "filesWidget"): 
     808            self.filesWidget.displayFile(filename=filename, is_data=True) 
    781809 
    782810    def showPlot(self, plot): 
     
    828856        elif isinstance(perspective, Perspectives.PERSPECTIVES["Invariant"]): 
    829857            self.checkAnalysisOption(self._workspace.actionInvariant) 
    830         # elif isinstance(perspective, Perspectives.PERSPECTIVES["Inversion"]): 
    831         #     self.checkAnalysisOption(self._workspace.actionInversion) 
     858        elif isinstance(perspective, Perspectives.PERSPECTIVES["Inversion"]): 
     859            self.checkAnalysisOption(self._workspace.actionInversion) 
     860        elif isinstance(perspective, Perspectives.PERSPECTIVES["Corfunc"]): 
     861            self.checkAnalysisOption(self._workspace.actionCorfunc) 
  • src/sas/qtgui/MainWindow/MainWindow.py

    r8353d90 r8ac3551  
    3030        except Exception as ex: 
    3131            import logging 
    32             logging.error("Application failed with: ", ex) 
     32            logging.error("Application failed with: " + str(ex)) 
    3333            print("Application failed with: ", ex) 
    3434 
  • src/sas/qtgui/MainWindow/UI/MainWindowUI.ui

    r1543f0c r8ac3551  
    88    <y>0</y> 
    99    <width>915</width> 
    10     <height>527</height> 
     10    <height>762</height> 
    1111   </rect> 
    1212  </property> 
     
    2525     <y>0</y> 
    2626     <width>915</width> 
    27      <height>21</height> 
     27     <height>26</height> 
    2828    </rect> 
    2929   </property> 
     
    108108    <addaction name="actionChain_Fitting"/> 
    109109    <addaction name="separator"/> 
     110    <addaction name="actionAdd_Custom_Model"/> 
    110111    <addaction name="actionEdit_Custom_Model"/> 
     112    <addaction name="actionManage_Custom_Models"/> 
    111113   </widget> 
    112114   <widget class="QMenu" name="menuWindow"> 
     
    126128     <string>Analysis</string> 
    127129    </property> 
     130    <addaction name="actionCorfunc"/> 
    128131    <addaction name="actionFitting"/> 
     132    <addaction name="actionInvariant"/> 
    129133    <addaction name="actionInversion"/> 
    130     <addaction name="actionInvariant"/> 
    131134   </widget> 
    132135   <widget class="QMenu" name="menuHelp"> 
     
    505508   </property> 
    506509  </action> 
     510  <action name="actionAdd_Custom_Model"> 
     511   <property name="text"> 
     512    <string>Add Custom Model</string> 
     513   </property> 
     514  </action> 
     515  <action name="actionManage_Custom_Models"> 
     516   <property name="text"> 
     517    <string>Manage Custom Models</string> 
     518   </property> 
     519  </action> 
     520  <action name="actionCorfunc"> 
     521   <property name="checkable"> 
     522    <bool>true</bool> 
     523   </property> 
     524   <property name="text"> 
     525    <string>Correlation Function</string> 
     526   </property> 
     527  </action> 
    507528 </widget> 
    508529 <resources/> 
  • src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py

    re4c475b7 r8b480d27  
    111111 
    112112        # Disconnect all local slots 
    113         tab_object.disconnect() 
     113        #tab_object.disconnect() 
    114114 
    115115        # Reconnect tab signals to local slots 
     
    171171                    # No such tab! 
    172172                    return 
    173                 sim_fitter_list, fitter_id = tab_object.prepareFitters(fitter=sim_fitter_list[0], fit_id=fitter_id) 
     173                sim_fitter_list, fitter_id = \ 
     174                    tab_object.prepareFitters(fitter=sim_fitter_list[0], fit_id=fitter_id) 
    174175                page_ids.append([tab_object.page_id]) 
    175176        except ValueError: 
     
    178179                            "Not all tabs chosen for fitting have parameters selected for fitting." 
    179180            QtWidgets.QMessageBox.warning(self, 
    180                                            'Warning', 
    181                                             no_params_msg, 
    182                                             QtWidgets.QMessageBox.Ok) 
     181                                          'Warning', 
     182                                           no_params_msg, 
     183                                           QtWidgets.QMessageBox.Ok) 
    183184 
    184185            return 
     
    674675 
    675676        constraint.func = constraint_text 
     677        # param1 is the parameter we're constraining 
    676678        constraint.param = param1 
     679 
    677680        # Find the right tab 
    678681        constrained_tab = self.getObjectByName(model1) 
  • src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py

    r14ec91c5 r3b3b40b  
    88from bumps import fitters 
    99 
     10import sas.qtgui.Utilities.LocalConfig as LocalConfig 
    1011import sas.qtgui.Utilities.ObjectLibrary as ObjectLibrary 
    1112 
     
    116117        tab     = FittingWidget(parent=self.parent, data=data, tab_id=self.maxIndex+1) 
    117118        tab.is_batch_fitting = is_batch 
     119 
    118120        # Add this tab to the object library so it can be retrieved by scripting/jupyter 
    119121        tab_name = self.getTabName(is_batch=is_batch) 
     
    123125            self.updateFitDict(data, tab_name) 
    124126        self.maxIndex += 1 
    125         self.addTab(tab, tab_name) 
     127        icon = QtGui.QIcon() 
     128        if is_batch: 
     129            icon.addPixmap(QtGui.QPixmap("src/sas/qtgui/images/icons/layers.svg")) 
     130        self.addTab(tab, icon, tab_name) 
     131        # Show the new tab 
     132        self.setCurrentIndex(self.maxIndex-1) 
     133        # Notify listeners 
    126134        self.tabsModifiedSignal.emit() 
    127135 
     
    140148        ObjectLibrary.addObject(tab_name, tab) 
    141149        self.tabs.append(tab) 
    142         self.addTab(tab, tab_name) 
     150        icon = QtGui.QIcon() 
     151        icon.addPixmap(QtGui.QPixmap("src/sas/qtgui/images/icons/link.svg")) 
     152        self.addTab(tab, icon, tab_name) 
     153 
     154        # This will be the last tab, so set the index accordingly 
     155        self.setCurrentIndex(self.count()-1) 
    143156 
    144157    def updateFitDict(self, item_key, tab_name): 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    re4c475b7 r8b480d27  
    2424import sas.qtgui.Utilities.GuiUtils as GuiUtils 
    2525import sas.qtgui.Utilities.LocalConfig as LocalConfig 
     26from sas.qtgui.Utilities.GridPanel import BatchOutputPanel 
    2627from sas.qtgui.Utilities.CategoryInstaller import CategoryInstaller 
    2728from sas.qtgui.Plotting.PlotterData import Data1D 
     
    3637from sas.qtgui.Perspectives.Fitting.FittingLogic import FittingLogic 
    3738from sas.qtgui.Perspectives.Fitting import FittingUtilities 
     39from sas.qtgui.Perspectives.Fitting import ModelUtilities 
    3840from sas.qtgui.Perspectives.Fitting.SmearingWidget import SmearingWidget 
    3941from sas.qtgui.Perspectives.Fitting.OptionsWidget import OptionsWidget 
     
    5052CATEGORY_DEFAULT = "Choose category..." 
    5153CATEGORY_STRUCTURE = "Structure Factor" 
     54CATEGORY_CUSTOM = "Plugin Models" 
    5255STRUCTURE_DEFAULT = "None" 
    5356 
     
    8386    constraintAddedSignal = QtCore.pyqtSignal(list) 
    8487    newModelSignal = QtCore.pyqtSignal() 
     88    fittingFinishedSignal = QtCore.pyqtSignal(tuple) 
     89    batchFittingFinishedSignal = QtCore.pyqtSignal(tuple) 
     90 
    8591    def __init__(self, parent=None, data=None, tab_id=1): 
    8692 
     
    211217        self.page_stack = [] 
    212218        self.all_data = [] 
     219        # custom plugin models 
     220        # {model.name:model} 
     221        self.custom_models = self.customModels() 
    213222        # Polydisp widget table default index for function combobox 
    214223        self.orig_poly_index = 3 
     
    415424            self.onSelectModel() 
    416425 
     426    @classmethod 
     427    def customModels(cls): 
     428        """ Reads in file names in the custom plugin directory """ 
     429        return ModelUtilities._find_models() 
     430 
    417431    def initializeControls(self): 
    418432        """ 
     
    465479        self._poly_model.itemChanged.connect(self.onPolyModelChange) 
    466480        self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     481        self.lstParams.selectionModel().selectionChanged.connect(self.onSelectionChanged) 
     482 
     483        # Local signals 
     484        self.batchFittingFinishedSignal.connect(self.batchFitComplete) 
     485        self.fittingFinishedSignal.connect(self.fitComplete) 
    467486 
    468487        # Signals from separate tabs asking for replot 
    469488        self.options_widget.plot_signal.connect(self.onOptionsUpdate) 
     489 
     490        # Signals from other widgets 
     491        self.communicate.customModelDirectoryChanged.connect(self.onCustomModelChange) 
    470492 
    471493    def modelName(self): 
     
    576598        # widget.params[0] is the parameter we're constraining 
    577599        constraint.param = mc_widget.params[0] 
    578         # Function should have the model name preamble 
     600        # parameter should have the model name preamble 
    579601        model_name = self.kernel_module.name 
    580         constraint.func = model_name + "." + c_text 
     602        # param_used is the parameter we're using in constraining function 
     603        param_used = mc_widget.params[1] 
     604        # Replace param_used with model_name.param_used 
     605        updated_param_used = model_name + "." + param_used 
     606        new_func = c_text.replace(param_used, updated_param_used) 
     607        constraint.func = new_func 
    581608        # Which row is the constrained parameter in? 
    582609        row = self.getRowFromName(constraint.param) 
     
    677704        Delete constraints from selected parameters. 
    678705        """ 
    679         self.deleteConstraintOnParameter(param=None) 
     706        params =  [s.data() for s in self.lstParams.selectionModel().selectedRows() 
     707                   if self.isCheckable(s.row())] 
     708        for param in params: 
     709            self.deleteConstraintOnParameter(param=param) 
    680710 
    681711    def deleteConstraintOnParameter(self, param=None): 
     
    686716        max_col = self.lstParams.itemDelegate().param_max 
    687717        for row in range(self._model_model.rowCount()): 
     718            if not self.rowHasConstraint(row): 
     719                continue 
    688720            # Get the Constraint object from of the model item 
    689721            item = self._model_model.item(row, 1) 
    690             if not item.hasChildren(): 
    691                 continue 
    692             constraint = item.child(0).data() 
     722            constraint = self.getConstraintForRow(row) 
    693723            if constraint is None: 
    694724                continue 
     
    816846        return constraints 
    817847 
     848    def getConstraintsForFitting(self): 
     849        """ 
     850        Return a list of constraints in format ready for use in fiting 
     851        """ 
     852        # Get constraints 
     853        constraints = self.getComplexConstraintsForModel() 
     854        # See if there are any constraints across models 
     855        multi_constraints = [cons for cons in constraints if self.isConstraintMultimodel(cons[1])] 
     856 
     857        if multi_constraints: 
     858            # Let users choose what to do 
     859            msg = "The current fit contains constraints relying on other fit pages.\n" 
     860            msg += "Parameters with those constraints are:\n" +\ 
     861                '\n'.join([cons[0] for cons in multi_constraints]) 
     862            msg += "\n\nWould you like to remove these constraints or cancel fitting?" 
     863            msgbox = QtWidgets.QMessageBox(self) 
     864            msgbox.setIcon(QtWidgets.QMessageBox.Warning) 
     865            msgbox.setText(msg) 
     866            msgbox.setWindowTitle("Existing Constraints") 
     867            # custom buttons 
     868            button_remove = QtWidgets.QPushButton("Remove") 
     869            msgbox.addButton(button_remove, QtWidgets.QMessageBox.YesRole) 
     870            button_cancel = QtWidgets.QPushButton("Cancel") 
     871            msgbox.addButton(button_cancel, QtWidgets.QMessageBox.RejectRole) 
     872            retval = msgbox.exec_() 
     873            if retval == QtWidgets.QMessageBox.RejectRole: 
     874                # cancel fit 
     875                raise ValueError("Fitting cancelled") 
     876            else: 
     877                # remove constraint 
     878                for cons in multi_constraints: 
     879                    self.deleteConstraintOnParameter(param=cons[0]) 
     880                # re-read the constraints 
     881                constraints = self.getComplexConstraintsForModel() 
     882 
     883        return constraints 
     884 
    818885    def showModelDescription(self): 
    819886        """ 
     
    874941        self.respondToModelStructure(model=model, structure_factor=structure) 
    875942 
     943    def onCustomModelChange(self): 
     944        """ 
     945        Reload the custom model combobox 
     946        """ 
     947        self.custom_models = self.customModels() 
     948        self.readCustomCategoryInfo() 
     949        # See if we need to update the combo in-place 
     950        if self.cbCategory.currentText() != CATEGORY_CUSTOM: return 
     951 
     952        current_text = self.cbModel.currentText() 
     953        self.cbModel.blockSignals(True) 
     954        self.cbModel.clear() 
     955        self.cbModel.blockSignals(False) 
     956        self.enableModelCombo() 
     957        self.disableStructureCombo() 
     958        # Retrieve the list of models 
     959        model_list = self.master_category_dict[CATEGORY_CUSTOM] 
     960        # Populate the models combobox 
     961        self.cbModel.addItems(sorted([model for (model, _) in model_list])) 
     962        new_index = self.cbModel.findText(current_text) 
     963        if new_index != -1: 
     964            self.cbModel.setCurrentIndex(self.cbModel.findText(current_text)) 
     965 
     966    def onSelectionChanged(self): 
     967        """ 
     968        React to parameter selection 
     969        """ 
     970        rows = self.lstParams.selectionModel().selectedRows() 
     971        # Clean previous messages 
     972        self.communicate.statusBarUpdateSignal.emit("") 
     973        if len(rows) == 1: 
     974            # Show constraint, if present 
     975            row = rows[0].row() 
     976            if self.rowHasConstraint(row): 
     977                func = self.getConstraintForRow(row).func 
     978                if func is not None: 
     979                    self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 
     980 
    876981    def replaceConstraintName(self, old_name, new_name=""): 
    877982        """ 
     
    886991                    new_func = func.replace(old_name, new_name) 
    887992                    self._model_model.item(row, 1).child(0).data().func = new_func 
     993 
     994    def isConstraintMultimodel(self, constraint): 
     995        """ 
     996        Check if the constraint function text contains current model name 
     997        """ 
     998        current_model_name = self.kernel_module.name 
     999        if current_model_name in constraint: 
     1000            return False 
     1001        else: 
     1002            return True 
    8881003 
    8891004    def updateData(self): 
     
    11051220        except ValueError as ex: 
    11061221            # This should not happen! GUI explicitly forbids this situation 
    1107             self.communicate.statusBarUpdateSignal.emit('Fitting attempt without parameters.') 
     1222            self.communicate.statusBarUpdateSignal.emit(str(ex)) 
    11081223            return 
    11091224 
    11101225        # Create the fitting thread, based on the fitter 
    1111         completefn = self.batchFitComplete if self.is_batch_fitting else self.fitComplete 
     1226        completefn = self.batchFittingCompleted if self.is_batch_fitting else self.fittingCompleted 
    11121227 
    11131228        calc_fit = FitThread(handler=handler, 
     
    11461261        pass 
    11471262 
     1263    def batchFittingCompleted(self, result): 
     1264        """ 
     1265        Send the finish message from calculate threads to main thread 
     1266        """ 
     1267        self.batchFittingFinishedSignal.emit(result) 
     1268 
    11481269    def batchFitComplete(self, result): 
    11491270        """ 
     
    11521273        #re-enable the Fit button 
    11531274        self.setFittingStopped() 
     1275        # Show the grid panel 
     1276        self.grid_window = BatchOutputPanel(parent=self, output_data=result[0]) 
     1277        self.grid_window.show() 
     1278 
     1279    def fittingCompleted(self, result): 
     1280        """ 
     1281        Send the finish message from calculate threads to main thread 
     1282        """ 
     1283        self.fittingFinishedSignal.emit(result) 
    11541284 
    11551285    def fitComplete(self, result): 
     
    11621292 
    11631293        if result is None: 
    1164             msg = "Fitting failed after: %s s.\n" % GuiUtils.formatNumber(elapsed) 
     1294            msg = "Fitting failed." 
    11651295            self.communicate.statusBarUpdateSignal.emit(msg) 
    11661296            return 
     
    12281358        smearing, accuracy, smearing_min, smearing_max = self.smearing_widget.state() 
    12291359 
     1360        # Get the constraints. 
    12301361        constraints = self.getComplexConstraintsForModel() 
     1362        if fitter is None: 
     1363            # For single fits - check for inter-model constraints 
     1364            constraints = self.getConstraintsForFitting() 
     1365 
    12311366        smearer = None 
    12321367        handler = None 
     
    12421377                             constraints=constraints) 
    12431378            except ValueError as ex: 
    1244                 logging.error("Setting model parameters failed with: %s" % ex) 
    1245                 return 
     1379                raise ValueError("Setting model parameters failed with: %s" % ex) 
    12461380 
    12471381            qmin, qmax, _ = self.logic.computeRangeFromData(data) 
     
    14091543        if not dict: 
    14101544            return 
    1411         if self._model_model.rowCount() == 0: 
     1545        if self._magnet_model.rowCount() == 0: 
    14121546            return 
    14131547 
     
    15551689            self.models[model.name] = model 
    15561690 
     1691        self.readCustomCategoryInfo() 
     1692 
     1693    def readCustomCategoryInfo(self): 
     1694        """ 
     1695        Reads the custom model category 
     1696        """ 
     1697        #Looking for plugins 
     1698        self.plugins = list(self.custom_models.values()) 
     1699        plugin_list = [] 
     1700        for name, plug in self.custom_models.items(): 
     1701            self.models[name] = plug 
     1702            plugin_list.append([name, True]) 
     1703        self.master_category_dict[CATEGORY_CUSTOM] = plugin_list 
     1704 
    15571705    def regenerateModelDict(self): 
    15581706        """ 
     
    16621810        Setting model parameters into QStandardItemModel based on selected _model_ 
    16631811        """ 
    1664         kernel_module = generate.load_kernel_module(model_name) 
     1812        name = model_name 
     1813        if self.cbCategory.currentText() == CATEGORY_CUSTOM: 
     1814            # custom kernel load requires full path 
     1815            name = os.path.join(ModelUtilities.find_plugins_dir(), model_name+".py") 
     1816        kernel_module = generate.load_kernel_module(name) 
    16651817        self.model_parameters = modelinfo.make_parameter_table(getattr(kernel_module, 'parameters', [])) 
    16661818 
  • src/sas/qtgui/Perspectives/Fitting/ModelUtilities.py

    • Property mode changed from 100755 to 100644
    rb3e8629 r3b3b40b  
    179179    plugins = {} 
    180180    for filename in os.listdir(directory): 
     181 
    181182        name, ext = os.path.splitext(filename) 
    182183        if ext == '.py' and not name == '__init__': 
     
    184185            try: 
    185186                model = load_custom_model(path) 
    186                 model.name = PLUGIN_NAME_BASE + model.name 
     187                #model.name = PLUGIN_NAME_BASE + model.name 
    187188                plugins[model.name] = model 
    188189            except Exception: 
     
    415416    implement model 
    416417    """ 
    417     __modelmanager = ModelManagerBase() 
    418     cat_model_list = [__modelmanager.model_dictionary[model_name] for model_name \ 
    419                       in list(__modelmanager.model_dictionary.keys()) \ 
    420                       if model_name not in list(__modelmanager.stored_plugins.keys())] 
    421  
    422     CategoryInstaller.check_install(model_list=cat_model_list) 
     418    def __init__(self): 
     419        self.__modelmanager = ModelManagerBase() 
     420        self.cat_model_list = [self.__modelmanager.model_dictionary[model_name] for model_name \ 
     421                          in list(self.__modelmanager.model_dictionary.keys()) \ 
     422                          if model_name not in list(self.__modelmanager.stored_plugins.keys())] 
     423 
     424        CategoryInstaller.check_install(model_list=self.cat_model_list) 
     425 
    423426    def findModels(self): 
    424427        return self.__modelmanager.findModels() 
  • src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py

    r14ec91c5 r3b3b40b  
    114114 
    115115        # 3. parameter name should be a separate word, but can have "()[]*+-/ " around 
    116         valid_neighbours = "()[]*+-/ " 
    117         start_loc = parameter_string_start -1 
    118         end_loc = parameter_string_end 
    119         if not any([constraint_text[start_loc] == ch for ch in valid_neighbours]): 
    120             return False 
    121         if end_loc < len(constraint_text): 
    122             if not any([constraint_text[end_loc] == ch for ch in valid_neighbours]): 
    123                 return False 
     116        #valid_neighbours = "()[]*+-/ " 
     117        #start_loc = parameter_string_start -1 
     118        #end_loc = parameter_string_end 
     119        #if not any([constraint_text[start_loc] == ch for ch in valid_neighbours]): 
     120        #    return False 
     121        #if end_loc < len(constraint_text): 
     122        #    if not any([constraint_text[end_loc] == ch for ch in valid_neighbours]): 
     123        #        return False 
    124124 
    125125        # 4. replace parameter name with "1" and try to evaluate the expression 
  • src/sas/qtgui/Perspectives/Fitting/UI/FittingWidgetUI.ui

    re4c475b7 r3b3b40b  
    77    <x>0</x> 
    88    <y>0</y> 
    9     <width>568</width> 
     9    <width>680</width> 
    1010    <height>605</height> 
    1111   </rect> 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/ConstraintWidgetTest.py

    • Property mode changed from 100755 to 100644
    r725d9c06 r3b3b40b  
    2222if not QtWidgets.QApplication.instance(): 
    2323    app = QtWidgets.QApplication(sys.argv) 
    24 #app = QtWidgets.QApplication(sys.argv) 
    2524 
    2625class ConstraintWidgetTest(unittest.TestCase): 
     
    7170        # click on "batch" 
    7271        QTest.mouseClick(self.widget.btnBatch, QtCore.Qt.LeftButton) 
    73         app.processEvents() 
     72        QtWidgets.QApplication.processEvents() 
    7473        # See what the current type is now 
    7574        self.assertEqual(self.widget.currentType, "BatchPage") 
     
    7877        # Go back to single fit 
    7978        QTest.mouseClick(self.widget.btnSingle, QtCore.Qt.LeftButton) 
    80         app.processEvents() 
     79        QtWidgets.QApplication.processEvents() 
    8180        # See what the current type is now 
    8281        self.assertEqual(self.widget.currentType, "FitPage") 
  • src/sas/qtgui/Utilities/GuiUtils.py

    r63319b0 r3b3b40b  
    213213    plotRequestedSignal = QtCore.pyqtSignal(list) 
    214214 
     215    # Plot from file names 
     216    plotFromFilenameSignal = QtCore.pyqtSignal(str) 
     217 
    215218    # Plot update requested from a perspective 
    216219    plotUpdateSignal = QtCore.pyqtSignal(list) 
     
    236239    # Send result of Data Operation Utility panel to Data Explorer 
    237240    updateModelFromDataOperationPanelSignal = QtCore.pyqtSignal(QtGui.QStandardItem, dict) 
     241 
     242    # Notify about a new custom plugin being written/deleted/modified 
     243    customModelDirectoryChanged = QtCore.pyqtSignal() 
    238244 
    239245def updateModelItemWithPlot(item, update_data, name=""): 
     
    872878        raise TypeError 
    873879 
     880def findNextFilename(filename, directory): 
     881    """ 
     882    Finds the next available (non-existing) name for 'filename' in 'directory'. 
     883    plugin.py -> plugin (n).py  - for first 'n' for which the file doesn't exist 
     884    """ 
     885    basename, ext = os.path.splitext(filename) 
     886    # limit the number of copies 
     887    MAX_FILENAMES = 1000 
     888    # Start with (1) 
     889    number_ext = 1 
     890    proposed_filename = "" 
     891    found_filename = False 
     892    # Find the next available filename or exit if too many copies 
     893    while not found_filename or number_ext > MAX_FILENAMES: 
     894        proposed_filename = basename + " ("+str(number_ext)+")" + ext 
     895        if os.path.exists(os.path.join(directory, proposed_filename)): 
     896            number_ext += 1 
     897        else: 
     898            found_filename = True 
     899 
     900    return proposed_filename 
     901 
     902 
    874903class DoubleValidator(QtGui.QDoubleValidator): 
    875904    """ 
  • src/sas/qtgui/Utilities/LocalConfig.py

    rc3eb858 r3b3b40b  
    141141# Time out for updating sasview 
    142142UPDATE_TIMEOUT = 2 
     143 
     144# Logging levels to disable, if any 
     145DISABLE_LOGGING = logging.DEBUG 
     146 
    143147def printEVT(message): 
    144148    """ 
  • .gitignore

    r948484f r846a063  
    2929default_categories.json 
    3030/setup.cfg 
     31**/UI/*.py 
     32!**/UI/__init__.py 
    3133 
    3234# doc build 
  • run.py

    r4992ff2 rd744767  
    141141    sys.path.append(build_path) 
    142142 
     143    # Run the UI conversion tool 
     144    import sas.qtgui.convertUI 
     145 
     146 
    143147if __name__ == "__main__": 
    144148    # Need to add absolute path before actual prepare call, 
  • src/sas/qtgui/Perspectives/Inversion/InversionLogic.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py

    re90988c r304e42f  
    2929BACKGROUND_INPUT = 0.0 
    3030MAX_DIST = 140.0 
    31  
    32 # TODO: Modify plot references, don't just send new 
     31DICT_KEYS = ["Calculator", "PrPlot", "DataPlot", "DMaxWindow", 
     32             "Logic", "NFuncEst"] 
     33 
     34 
     35# TODO: Remove not working 
     36# TODO: Explore window not working 
    3337# TODO: Update help with batch capabilities 
    3438# TODO: Method to export results in some meaningful way 
     
    5054 
    5155        self._manager = parent 
    52         self._model_item = QtGui.QStandardItem() 
    5356        self.communicate = GuiUtils.Communicate() 
    5457 
    5558        self.logic = InversionLogic() 
    56  
    57         # Reference to Dmax window 
    58         self.dmaxWindow = None 
    5959 
    6060        # The window should not close 
    6161        self._allow_close = False 
    6262 
     63        # Visible data set items 
    6364        # current QStandardItem showing on the panel 
    6465        self._data = None 
    6566        # current Data1D as referenced by self._data 
    6667        self._data_set = None 
    67  
    68         # p(r) calculator 
     68        # Reference to Dmax window for self._data 
     69        self.dmaxWindow = None 
     70        # p(r) calculator for self._data 
    6971        self._calculator = Invertor() 
    70         self._last_calculator = None 
     72        # Default to background estimate 
     73        self._calculator.set_est_bck(True) 
     74        # plots of self._data 
     75        self.pr_plot = None 
     76        self.data_plot = None 
     77        # suggested nTerms 
     78        self.nTermsSuggested = NUMBER_OF_TERMS 
     79 
     80        # Calculation threads used by all data items 
    7181        self.calc_thread = None 
    7282        self.estimation_thread = None 
    7383 
    74         # Current data object in view 
    75         self._data_index = 0 
    76         # list mapping data to p(r) calculation 
     84        # Mapping for all data items 
     85        # list mapping data to all parameters 
    7786        self._data_list = {} 
    7887        if not isinstance(data, list): 
     
    8089        if data is not None: 
    8190            for datum in data_list: 
    82                 self._data_list[datum] = self._calculator.clone() 
    83  
    84         # dict of models for quick update after calculation 
    85         # {item:model} 
    86         self._models = {} 
    87  
    88         self.calculateAllButton.setEnabled(False) 
    89         self.calculateThisButton.setEnabled(False) 
    90  
    91         # plots for current data 
    92         self.pr_plot = None 
    93         self.data_plot = None 
    94         # plot references for all data in perspective 
    95         self.pr_plot_list = {} 
    96         self.data_plot_list = {} 
     91                self.updateDataList(datum) 
     92 
     93        self.enableButtons() 
    9794 
    9895        self.model = QtGui.QStandardItemModel(self) 
     
    158155 
    159156        self.backgroundInput.editingFinished.connect( 
    160             lambda: self._calculator.set_est_bck(int(is_float(self.backgroundInput.text())))) 
     157            lambda: self._calculator.set_background(is_float(self.backgroundInput.text()))) 
    161158        self.minQInput.editingFinished.connect( 
    162159            lambda: self._calculator.set_qmin(is_float(self.minQInput.text()))) 
     
    308305 
    309306    def displayChange(self): 
     307        """Switch to another item in the data list""" 
    310308        ref_item = self.dataList.itemData(self.dataList.currentIndex()) 
    311         self._model_item = ref_item 
     309        self.updateDataList(ref_item) 
    312310        self.setCurrentData(ref_item) 
    313         self.setCurrentModel(ref_item) 
    314  
    315     def removeData(self): 
    316         """Remove the existing data reference from the P(r) Persepective""" 
    317         self._data_list.pop(self._data) 
    318         self.pr_plot_list.pop(self._data) 
    319         self.data_plot_list.pop(self._data) 
    320         if self.dmaxWindow is not None: 
    321             self.dmaxWindow = None 
    322         self.dataList.removeItem(self.dataList.currentIndex()) 
    323         self.dataList.setCurrentIndex(0) 
    324         # Last file removed 
    325         if not self._data_list: 
    326             self._data = None 
    327             self.pr_plot = None 
    328             self._data_set = None 
    329             self.calculateThisButton.setEnabled(False) 
    330             self.calculateAllButton.setEnabled(False) 
    331             self.explorerButton.setEnabled(False) 
     311        self.updateGuiValues() 
    332312 
    333313    ###################################################################### 
    334314    # GUI Interaction Events 
    335  
    336     def setCurrentModel(self, ref_item): 
    337         '''update the current model with stored values''' 
    338         if ref_item in self._models: 
    339             self.model = self._models[ref_item] 
    340315 
    341316    def update_calculator(self): 
     
    355330            InversionWindow.__init__(self.parent(), list(self._data_list.keys())) 
    356331            exit(0) 
    357         # TODO: Only send plot first time - otherwise, update in complete 
    358332        if self.pr_plot is not None: 
    359333            title = self.pr_plot.name 
     
    363337            GuiUtils.updateModelItemWithPlot(self._data, self.data_plot, title) 
    364338        if self.dmaxWindow is not None: 
    365              self.dmaxWindow.pr_state = self._calculator 
    366              self.dmaxWindow.nfunc = self.getNFunc() 
    367  
     339            self.dmaxWindow.pr_state = self._calculator 
     340            self.dmaxWindow.nfunc = self.getNFunc() 
     341            self.dmaxWindow.modelChanged() 
    368342        self.mapper.toFirst() 
    369343 
     
    386360        if sender is self.estimateBgd: 
    387361            self.backgroundInput.setEnabled(False) 
     362            self._calculator.set_est_bck = True 
    388363        else: 
    389364            self.backgroundInput.setEnabled(True) 
     365            self._calculator.set_est_bck = False 
    390366 
    391367    def openExplorerWindow(self): 
     
    410386        if not isinstance(data_item, list): 
    411387            msg = "Incorrect type passed to the P(r) Perspective" 
    412             raise AttributeError 
     388            raise AttributeError(msg) 
    413389 
    414390        for data in data_item: 
     
    417393                return 
    418394            # Create initial internal mappings 
    419             self._data_list[data] = self._calculator.clone() 
    420395            self._data_set = GuiUtils.dataFromItem(data) 
    421             self.data_plot_list[data] = self.data_plot 
    422             self.pr_plot_list[data] = self.pr_plot 
     396            self.logic = InversionLogic(self._data_set) 
    423397            self.populateDataComboBox(self._data_set.filename, data) 
     398            # Estimate q range 
     399            qmin, qmax = self.logic.computeDataRange() 
     400            self._calculator.set_qmin(qmin) 
     401            self._calculator.set_qmax(qmax) 
     402            self.updateDataList(data) 
    424403            self.setCurrentData(data) 
    425  
    426404            # Estimate initial values from data 
    427405            self.performEstimate() 
    428             self.logic = InversionLogic(self._data_set) 
    429  
    430             # Estimate q range 
    431             qmin, qmax = self.logic.computeDataRange() 
    432             self.model.setItem(WIDGETS.W_QMIN, QtGui.QStandardItem("{:.4g}".format(qmin))) 
    433             self.model.setItem(WIDGETS.W_QMAX, QtGui.QStandardItem("{:.4g}".format(qmax))) 
    434             self._models[data] = self.model 
    435             self.model_item = data 
    436  
    437406        self.enableButtons() 
     407        self.updateGuiValues() 
     408 
     409    def updateDataList(self, dataRef): 
     410        """Save the current data state of the window into self._data_list""" 
     411        if dataRef is None: 
     412            return 
     413        self._data_list[dataRef] = { 
     414            DICT_KEYS[0]: self._calculator, 
     415            DICT_KEYS[1]: self.pr_plot, 
     416            DICT_KEYS[2]: self.data_plot, 
     417            DICT_KEYS[3]: self.dmaxWindow, 
     418            DICT_KEYS[4]: self.logic, 
     419            DICT_KEYS[5]: self.nTermsSuggested 
     420        } 
    438421 
    439422    def getNFunc(self): 
     
    448431 
    449432    def setCurrentData(self, data_ref): 
    450         """Get the current data and display as necessary""" 
    451  
     433        """Get the data by reference and display as necessary""" 
    452434        if data_ref is None: 
    453435            return 
    454  
    455436        if not isinstance(data_ref, QtGui.QStandardItem): 
    456437            msg = "Incorrect type passed to the P(r) Perspective" 
    457             raise AttributeError 
    458  
     438            raise AttributeError(msg) 
    459439        # Data references 
    460440        self._data = data_ref 
    461441        self._data_set = GuiUtils.dataFromItem(data_ref) 
    462         self._calculator = self._data_list[data_ref] 
    463         self.pr_plot = self.pr_plot_list[data_ref] 
    464         self.data_plot = self.data_plot_list[data_ref] 
     442        self._calculator = self._data_list[data_ref].get(DICT_KEYS[0]) 
     443        self.pr_plot = self._data_list[data_ref].get(DICT_KEYS[1]) 
     444        self.data_plot = self._data_list[data_ref].get(DICT_KEYS[2]) 
     445        self.dmaxWindow = self._data_list[data_ref].get(DICT_KEYS[3]) 
     446        self.logic = self._data_list[data_ref].get(DICT_KEYS[4]) 
     447        self.nTermsSuggested = self._data_list[data_ref].get(DICT_KEYS[5]) 
     448        self.updateGuiValues() 
     449 
     450    def updateGuiValues(self): 
     451        pr = self._calculator 
     452        out = self._calculator.out 
     453        cov = self._calculator.cov 
     454        elapsed = self._calculator.elapsed 
     455        alpha = self._calculator.suggested_alpha 
     456        nterms = self._calculator.nfunc 
     457        self.model.setItem(WIDGETS.W_QMIN, 
     458                           QtGui.QStandardItem("{:.4g}".format(pr.get_qmin()))) 
     459        self.model.setItem(WIDGETS.W_QMAX, 
     460                           QtGui.QStandardItem("{:.4g}".format(pr.get_qmax()))) 
     461        self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, 
     462                           QtGui.QStandardItem("{:.3f}".format(pr.background))) 
     463        self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, 
     464                           QtGui.QStandardItem("{:.3g}".format(pr.background))) 
     465        self.model.setItem(WIDGETS.W_COMP_TIME, 
     466                           QtGui.QStandardItem("{:.4g}".format(elapsed))) 
     467        if alpha != 0: 
     468            self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 
     469        self.regConstantSuggestionButton.setEnabled(alpha != self._calculator.alpha) 
     470        if nterms != self.nTermsSuggested: 
     471            self.noOfTermsSuggestionButton.setText( 
     472                "{:n}".format(self.nTermsSuggested)) 
     473        self.noOfTermsSuggestionButton.setEnabled(nterms != self.nTermsSuggested) 
     474        self.model.setItem(WIDGETS.W_COMP_TIME, 
     475                           QtGui.QStandardItem("{:.2g}".format(elapsed))) 
     476 
     477        if isinstance(pr.chi2, np.ndarray): 
     478            self.model.setItem(WIDGETS.W_CHI_SQUARED, 
     479                               QtGui.QStandardItem("{:.3g}".format(pr.chi2[0]))) 
     480        if out is not None: 
     481            self.model.setItem(WIDGETS.W_RG, 
     482                               QtGui.QStandardItem("{:.3g}".format(pr.rg(out)))) 
     483            self.model.setItem(WIDGETS.W_I_ZERO, 
     484                               QtGui.QStandardItem( 
     485                                   "{:.3g}".format(pr.iq0(out)))) 
     486            self.model.setItem(WIDGETS.W_OSCILLATION, QtGui.QStandardItem( 
     487                "{:.3g}".format(pr.oscillations(out)))) 
     488            self.model.setItem(WIDGETS.W_POS_FRACTION, QtGui.QStandardItem( 
     489                "{:.3g}".format(pr.get_positive(out)))) 
     490            if cov is not None: 
     491                self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, 
     492                                   QtGui.QStandardItem( 
     493                                       "{:.3g}".format( 
     494                                           pr.get_pos_err(out, cov)))) 
     495 
     496    def removeData(self): 
     497        """Remove the existing data reference from the P(r) Persepective""" 
     498        if self.dmaxWindow is not None: 
     499            self.dmaxWindow = None 
     500        self.dataList.removeItem(self.dataList.currentIndex()) 
     501        self._data_list.pop(self._data) 
     502        # Last file removed 
     503        if len(self._data_list) == 0: 
     504            self._data = None 
     505            self.pr_plot = None 
     506            self._data_set = None 
     507            self._calculator = Invertor() 
     508            self.logic = InversionLogic() 
     509            self.enableButtons() 
     510        self.dataList.setCurrentIndex(0) 
     511        self.updateGuiValues() 
    465512 
    466513    ###################################################################### 
    467514    # Thread Creators 
    468515    def startThreadAll(self): 
    469         for data_ref, pr in list(self._data_list.items()): 
    470             self._data_set = GuiUtils.dataFromItem(data_ref) 
    471             self._calculator = pr 
     516        for data_ref in self._data_list.keys(): 
     517            self.setCurrentData(data_ref) 
    472518            self.startThread() 
    473519 
     
    554600        """ 
    555601        alpha, message, elapsed = output_tuple 
    556         # Save useful info 
    557         self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.4g}".format(elapsed))) 
    558         self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 
    559         self.regConstantSuggestionButton.setEnabled(True) 
     602        self.updateGuiValues() 
    560603        if message: 
    561604            logging.info(message) 
     
    576619        """ 
    577620        nterms, alpha, message, elapsed = output_tuple 
     621        self._calculator.elapsed = elapsed 
     622        self._calculator.suggested_alpha = alpha 
     623        self.nTermsSuggested = nterms 
    578624        # Save useful info 
    579         self.noOfTermsSuggestionButton.setText("{:n}".format(nterms)) 
    580         self.noOfTermsSuggestionButton.setEnabled(True) 
    581         self.regConstantSuggestionButton.setText("{:.3g}".format(alpha)) 
    582         self.regConstantSuggestionButton.setEnabled(True) 
    583         self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.2g}".format(elapsed))) 
     625        self.updateGuiValues() 
    584626        if message: 
    585627            logging.info(message) 
     
    605647        pr.elapsed = elapsed 
    606648 
    607         # Show result on control panel 
    608         self.model.setItem(WIDGETS.W_RG, QtGui.QStandardItem("{:.3g}".format(pr.rg(out)))) 
    609         self.model.setItem(WIDGETS.W_I_ZERO, QtGui.QStandardItem("{:.3g}".format(pr.iq0(out)))) 
    610         self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, 
    611                            QtGui.QStandardItem("{:.3f}".format(pr.est_bck))) 
    612         self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, QtGui.QStandardItem("{:.3g}".format(pr.background))) 
    613         self.model.setItem(WIDGETS.W_CHI_SQUARED, QtGui.QStandardItem("{:.3g}".format(pr.chi2[0]))) 
    614         self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.2g}".format(elapsed))) 
    615         self.model.setItem(WIDGETS.W_OSCILLATION, QtGui.QStandardItem("{:.3g}".format(pr.oscillations(out)))) 
    616         self.model.setItem(WIDGETS.W_POS_FRACTION, QtGui.QStandardItem("{:.3g}".format(pr.get_positive(out)))) 
    617         self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, 
    618                            QtGui.QStandardItem("{:.3g}".format(pr.get_pos_err(out, cov)))) 
    619  
    620649        # Save Pr invertor 
    621650        self._calculator = pr 
    622         # Append data to data list 
    623         self._data_list[self._data] = self._calculator.clone() 
    624  
    625         # Update model dict 
    626         self._models[self.model_item] = self.model 
    627651 
    628652        # Create new P(r) and fit plots 
    629653        if self.pr_plot is None: 
    630654            self.pr_plot = self.logic.newPRPlot(out, self._calculator, cov) 
    631             self.pr_plot_list[self._data] = self.pr_plot 
    632         else: 
    633             # FIXME: this should update the existing plot, not create a new one 
    634             self.pr_plot = self.logic.newPRPlot(out, self._calculator, cov) 
    635             self.pr_plot_list[self._data] = self.pr_plot 
    636655        if self.data_plot is None: 
    637656            self.data_plot = self.logic.new1DPlot(out, self._calculator) 
    638             self.data_plot_list[self._data] = self.data_plot 
    639         else: 
    640             # FIXME: this should update the existing plot, not create a new one 
    641             self.data_plot = self.logic.new1DPlot(out, self._calculator) 
    642             self.data_plot_list[self._data] = self.data_plot 
     657        self.updateDataList(self._data) 
     658        self.updateGuiValues() 
    643659 
    644660    def _threadError(self, error): 
  • src/sas/qtgui/Perspectives/Inversion/InversionUtils.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/Inversion/Thread.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/Inversion/UI/TabbedInversionUI.ui

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/Inversion/UI/__init__.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/Inversion/__init__.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Perspectives/__init__.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Plotting/ConvertUnits.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Plotting/DataTransform.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Plotting/Slicers/Arc.py

    • Property mode changed from 100644 to 100755
Note: See TracChangeset for help on using the changeset viewer.