Changeset b95d748 in sasview for src


Ignore:
Timestamp:
Oct 17, 2018 8:00:00 AM (6 years ago)
Author:
Piotr Rozyczko <piotr.rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
10d57f6
Parents:
345b3b3 (diff), dd545d1 (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_project_save

Location:
src/sas/qtgui
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/MainWindow/GuiManager.py

    re258c53 refaf022  
    136136        self.logDockWidget = QDockWidget("Log Explorer", self._workspace) 
    137137        self.logDockWidget.setObjectName("LogDockWidget") 
     138        self.logDockWidget.visibilityChanged.connect(self.updateLogContextMenus) 
     139 
    138140 
    139141        self.listWidget = QTextBrowser() 
     
    178180            logger.error("%s: could not load SasView models") 
    179181            logger.error(traceback.format_exc()) 
     182 
     183    def updateLogContextMenus(self, visible=False): 
     184        """ 
     185        Modify the View/Data Explorer menu item text on widget visibility 
     186        """ 
     187        if visible: 
     188            self._workspace.actionHide_LogExplorer.setText("Hide Log Explorer") 
     189        else: 
     190            self._workspace.actionHide_LogExplorer.setText("Show Log Explorer") 
    180191 
    181192    def updateContextMenus(self, visible=False): 
     
    433444        """ 
    434445        # disable not yet fully implemented actions 
    435         self._workspace.actionOpen_Analysis.setEnabled(False) 
    436         self._workspace.actionUndo.setEnabled(False) 
    437         self._workspace.actionRedo.setEnabled(False) 
    438         self._workspace.actionReset.setEnabled(False) 
    439         self._workspace.actionStartup_Settings.setEnabled(False) 
    440         self._workspace.actionImage_Viewer.setEnabled(False) 
    441         self._workspace.actionCombine_Batch_Fit.setEnabled(False) 
    442         self._workspace.actionFit_Results.setEnabled(False) 
     446        self._workspace.actionOpen_Analysis.setVisible(False) 
     447        self._workspace.actionUndo.setVisible(False) 
     448        self._workspace.actionRedo.setVisible(False) 
     449        self._workspace.actionReset.setVisible(False) 
     450        self._workspace.actionStartup_Settings.setVisible(False) 
     451        self._workspace.actionImage_Viewer.setVisible(False) 
     452        self._workspace.actionCombine_Batch_Fit.setVisible(False) 
     453        self._workspace.actionFit_Results.setVisible(False) 
    443454        # orientation viewer set to invisible SASVIEW-1132 
    444455        self._workspace.actionOrientation_Viewer.setVisible(False) 
     
    467478        self._workspace.actionCategory_Manager.triggered.connect(self.actionCategory_Manager) 
    468479        self._workspace.actionHide_DataExplorer.triggered.connect(self.actionHide_DataExplorer) 
     480        self._workspace.actionHide_LogExplorer.triggered.connect(self.actionHide_LogExplorer) 
    469481        # Tools 
    470482        self._workspace.actionData_Operation.triggered.connect(self.actionData_Operation) 
     
    654666        """ 
    655667        if self.dockedFilesWidget.isVisible(): 
    656             #self._workspace.actionHide_DataExplorer.setText("Show Data Explorer") 
    657668            self.dockedFilesWidget.setVisible(False) 
    658669        else: 
    659             #self._workspace.actionHide_DataExplorer.setText("Hide Data Explorer") 
    660670            self.dockedFilesWidget.setVisible(True) 
     671        pass 
     672 
     673    def actionHide_LogExplorer(self): 
     674        """ 
     675        Toggle Data Explorer vsibility 
     676        """ 
     677        if self.logDockWidget.isVisible(): 
     678            self.logDockWidget.setVisible(False) 
     679        else: 
     680            self.logDockWidget.setVisible(True) 
    661681        pass 
    662682 
  • src/sas/qtgui/MainWindow/UI/MainWindowUI.ui

    rfc5d2d7f refaf022  
    2525     <y>0</y> 
    2626     <width>915</width> 
    27      <height>26</height> 
     27     <height>21</height> 
    2828    </rect> 
    2929   </property> 
     
    7575    <addaction name="actionHide_Toolbar"/> 
    7676    <addaction name="actionHide_DataExplorer"/> 
     77    <addaction name="actionHide_LogExplorer"/> 
    7778    <addaction name="separator"/> 
    7879    <addaction name="actionStartup_Settings"/> 
     
    565566   </property> 
    566567  </action> 
     568  <action name="actionHide_LogExplorer"> 
     569   <property name="text"> 
     570    <string>Hide Log Explorer</string> 
     571   </property> 
     572  </action> 
    567573 </widget> 
    568574 <resources/> 
  • src/sas/qtgui/Perspectives/Fitting/ConsoleUpdate.py

    r7adc2a8 ra4ceeb7  
    147147                    model_name = str(self.result.model.name) 
    148148                if m_flag and d_flag: 
    149                     msg += "Data : %s \n" % (str(data_name))#, 
    150                                                      #str(model_name)) 
     149                    msg += "Data : %s \n" % (str(data_name)) 
    151150                msg += str(self.result) 
    152151                msg += "\n" 
    153             else: 
    154                 msg += "No result available\n" 
    155152 
    156153            logging.info(msg) 
  • src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py

    r345b3b3 rb95d748  
    102102 
    103103    def onParamCopy(self): 
    104         self.currentTab.onParameterCopy("") 
     104        self.currentTab.onCopyToClipboard("") 
    105105 
    106106    def onParamPaste(self): 
     
    108108 
    109109    def onExcelCopy(self): 
    110         self.currentTab.onParameterCopy("Excel") 
     110        self.currentTab.onCopyToClipboard("Excel") 
    111111 
    112112    def onLatexCopy(self): 
    113         self.currentTab.onParameterCopy("Latex") 
     113        self.currentTab.onCopyToClipboard("Latex") 
    114114 
    115115    def closeEvent(self, event): 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r3ab2105 rdd545d1  
    119119        self.tab_id = tab_id 
    120120 
     121        import sys 
     122        sys.excepthook = self.info 
     123 
    121124        # Globals 
    122125        self.initializeGlobals() 
     
    163166        self.label_17.setStyleSheet(new_font) 
    164167        self.label_19.setStyleSheet(new_font) 
     168 
     169    def info(self, type, value, tb): 
     170        logger.error("SasView threw exception: " + str(value)) 
     171        traceback.print_exception(type, value, tb) 
    165172 
    166173    @property 
     
    543550 
    544551        # Respond to change in parameters from the UI 
    545         self._model_model.itemChanged.connect(self.onMainParamsChange) 
    546         #self.constraintAddedSignal.connect(self.modifyViewOnConstraint) 
    547         self._poly_model.itemChanged.connect(self.onPolyModelChange) 
    548         self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     552        self._model_model.dataChanged.connect(self.onMainParamsChange) 
     553        self._poly_model.dataChanged.connect(self.onPolyModelChange) 
     554        self._magnet_model.dataChanged.connect(self.onMagnetModelChange) 
    549555        self.lstParams.selectionModel().selectionChanged.connect(self.onSelectionChanged) 
    550556 
     
    12071213        self.cbModel.addItems(sorted([model for (model, _) in model_list])) 
    12081214 
    1209     def onPolyModelChange(self, item): 
     1215    def onPolyModelChange(self, top, bottom): 
    12101216        """ 
    12111217        Callback method for updating the main model and sasmodel 
    12121218        parameters with the GUI values in the polydispersity view 
    12131219        """ 
     1220        item = self._poly_model.itemFromIndex(top) 
    12141221        model_column = item.column() 
    12151222        model_row = item.row() 
     
    12781285            self._model_model.blockSignals(False) 
    12791286 
    1280     def onMagnetModelChange(self, item): 
     1287    def onMagnetModelChange(self, top, bottom): 
    12811288        """ 
    12821289        Callback method for updating the sasmodel magnetic parameters with the GUI values 
    12831290        """ 
     1291        item = self._magnet_model.itemFromIndex(top) 
    12841292        model_column = item.column() 
    12851293        model_row = item.row() 
     
    17161724        # block signals temporarily, so we don't end up 
    17171725        # updating charts with every single model change on the end of fitting 
    1718         self._model_model.itemChanged.disconnect() 
     1726        self._model_model.dataChanged.disconnect() 
    17191727        self.iterateOverModel(updateFittedValues) 
    17201728        self.iterateOverModel(updatePolyValues) 
    1721         self._model_model.itemChanged.connect(self.onMainParamsChange) 
     1729        self._model_model.dataChanged.connect(self.onMainParamsChange) 
    17221730 
    17231731    def iterateOverPolyModel(self, func): 
     
    17711779        # block signals temporarily, so we don't end up 
    17721780        # updating charts with every single model change on the end of fitting 
    1773         self._poly_model.itemChanged.disconnect() 
     1781        self._poly_model.dataChanged.disconnect() 
    17741782        self.iterateOverPolyModel(updateFittedValues) 
    1775         self._poly_model.itemChanged.connect(self.onPolyModelChange) 
     1783        self._poly_model.dataChanged.connect(self.onPolyModelChange) 
    17761784 
    17771785        if self.has_poly_error_column: 
     
    18361844        # block signals temporarily, so we don't end up 
    18371845        # updating charts with every single model change on the end of fitting 
    1838         self._magnet_model.itemChanged.disconnect() 
     1846        self._magnet_model.dataChanged.disconnect() 
    18391847        self.iterateOverMagnetModel(updateFittedValues) 
    1840         self._magnet_model.itemChanged.connect(self.onMagnetModelChange) 
     1848        self._magnet_model.dataChanged.connect(self.onMagnetModelChange) 
    18411849 
    18421850        if self.has_magnet_error_column: 
     
    22722280        return False 
    22732281 
    2274     def onMainParamsChange(self, item): 
     2282    def onMainParamsChange(self, top, bottom): 
    22752283        """ 
    22762284        Callback method for updating the sasmodel parameters with the GUI values 
    22772285        """ 
     2286        item = self._model_model.itemFromIndex(top) 
     2287 
    22782288        model_column = item.column() 
    22792289 
     
    23012311        else: 
    23022312            parameter_name = str(self._model_model.data(name_index)) 
    2303  
    2304         # Update the parameter value - note: this supports +/-inf as well 
    2305         self.kernel_module.params[parameter_name] = value 
    23062313 
    23072314        # Update the parameter value - note: this supports +/-inf as well 
     
    31513158        # Update relevant models 
    31523159        self.setPolyModel() 
    3153         self.setMagneticModel() 
     3160        if self.canHaveMagnetism(): 
     3161            self.setMagneticModel() 
    31543162 
    31553163    def onShowSLDProfile(self): 
     
    34653473        #self._copy_parameters_state(self.fixed_param, self.state.fixed_param) 
    34663474 
    3467     def onParameterCopy(self, format=None): 
     3475    def onCopyToClipboard(self, format=None): 
     3476        """ 
     3477        Copy current fitting parameters into the clipboard 
     3478        using requested formatting: 
     3479        plain, excel, latex 
     3480        """ 
     3481        param_list = self.getFitParameters() 
     3482        if format=="": 
     3483            formatted_output = FittingUtilities.formatParameters(param_list) 
     3484        elif format == "Excel": 
     3485            formatted_output = FittingUtilities.formatParametersExcel(param_list[1:]) 
     3486        elif format == "Latex": 
     3487            formatted_output = FittingUtilities.formatParametersLatex(param_list[1:]) 
     3488        else: 
     3489            raise AttributeError("Bad parameter output format specifier.") 
     3490 
     3491        # Dump formatted_output to the clipboard 
     3492        cb = QtWidgets.QApplication.clipboard() 
     3493        cb.setText(formatted_output) 
     3494 
     3495    def getFitParameters(self, format=None): 
    34683496        """ 
    34693497        Copy current parameters into the clipboard 
     
    34723500        # first - regular params 
    34733501        param_list = [] 
    3474  
    34753502        param_list.append(['model_name', str(self.cbModel.currentText())]) 
     3503 
    34763504        def gatherParams(row): 
    34773505            """ 
     
    34793507            """ 
    34803508            param_name = str(self._model_model.item(row, 0).text()) 
     3509 
     3510            # Assure this is a parameter - must contain a checkbox 
     3511            if not self._model_model.item(row, 0).isCheckable(): 
     3512                # maybe it is a combobox item (multiplicity) 
     3513                try: 
     3514                    index = self._model_model.index(row, 1) 
     3515                    widget = self.lstParams.indexWidget(index) 
     3516                    if widget is None: 
     3517                        return 
     3518                    if isinstance(widget, QtWidgets.QComboBox): 
     3519                        # find the index of the combobox 
     3520                        current_index = widget.currentIndex() 
     3521                        param_list.append([param_name, 'None', str(current_index)]) 
     3522                except Exception as ex: 
     3523                    pass 
     3524                return 
     3525 
    34813526            param_checked = str(self._model_model.item(row, 0).checkState() == QtCore.Qt.Checked) 
     3527            # Value of the parameter. In some cases this is the text of the combobox choice. 
    34823528            param_value = str(self._model_model.item(row, 1).text()) 
    34833529            param_error = None 
     
    34863532            column_offset = 0 
    34873533            if self.has_error_column: 
    3488                 param_error = str(self._model_model.item(row, 2).text()) 
    34893534                column_offset = 1 
    3490  
    34913535            try: 
    34923536                param_min = str(self._model_model.item(row, 2+column_offset).text()) 
     
    34953539                pass 
    34963540 
    3497             param_list.append([param_name, param_checked, param_value, param_error, param_min, param_max]) 
     3541            param_list.append([param_name, param_checked, param_value, param_min, param_max]) 
    34983542 
    34993543        def gatherPolyParams(row): 
     
    35073551            column_offset = 0 
    35083552            if self.has_poly_error_column: 
    3509                 param_error = str(self._poly_model.item(row, 2).text()) 
    35103553                column_offset = 1 
    35113554            param_min   = str(self._poly_model.item(row, 2+column_offset).text()) 
     
    35143557            param_nsigs = str(self._poly_model.item(row, 5+column_offset).text()) 
    35153558            param_fun   = str(self._poly_model.item(row, 6+column_offset).text()).rstrip() 
     3559            index = self._poly_model.index(row, 6+column_offset) 
     3560            widget = self.lstPoly.indexWidget(index) 
     3561            if widget is not None and isinstance(widget, QtWidgets.QComboBox): 
     3562                param_fun = widget.currentText() 
    35163563            # width 
    35173564            name = param_name+".width" 
    3518             param_list.append([name, param_checked, param_value, param_error, 
    3519                                 param_npts, param_nsigs, param_min, param_max, param_fun]) 
     3565            param_list.append([name, param_checked, param_value, param_min, param_max, 
     3566                                param_npts, param_nsigs, param_fun]) 
    35203567 
    35213568        def gatherMagnetParams(row): 
     
    35293576            column_offset = 0 
    35303577            if self.has_magnet_error_column: 
    3531                 param_error = str(self._magnet_model.item(row, 2).text()) 
    35323578                column_offset = 1 
    35333579            param_min = str(self._magnet_model.item(row, 2+column_offset).text()) 
    35343580            param_max = str(self._magnet_model.item(row, 3+column_offset).text()) 
    3535             param_list.append([param_name, param_checked, param_value, param_error, param_min, param_max]) 
     3581            param_list.append([param_name, param_checked, param_value, param_min, param_max]) 
    35363582 
    35373583        self.iterateOverModel(gatherParams) 
     
    35413587            self.iterateOverMagnetModel(gatherMagnetParams) 
    35423588 
    3543         if format=="": 
    3544             formatted_output = FittingUtilities.formatParameters(param_list) 
    3545         elif format == "Excel": 
    3546             formatted_output = FittingUtilities.formatParametersExcel(param_list[1:]) 
    3547         elif format == "Latex": 
    3548             formatted_output = FittingUtilities.formatParametersLatex(param_list[1:]) 
    3549         else: 
    3550             raise AttributeError("Bad format specifier.") 
    3551  
    3552         # Dump formatted_output to the clipboard 
    3553         cb = QtWidgets.QApplication.clipboard() 
    3554         cb.setText(formatted_output) 
     3589        if self.kernel_module.is_multiplicity_model: 
     3590            param_list.append(['multiplicity', str(self.kernel_module.multiplicity)]) 
     3591 
     3592        # option tab 
     3593        param_list.append(['q_range_min', str(self.q_range_min)]) 
     3594        param_list.append(['q_range_max', str(self.q_range_max)]) 
     3595        param_list.append(['q_weighting', str(self.weighting)]) 
     3596 
     3597        # resolution 
     3598        smearing, accuracy, smearing_min, smearing_max = self.smearing_widget.state() 
     3599        index = self.smearing_widget.cbSmearing.currentIndex() 
     3600        param_list.append(['smearing', str(index)]) 
     3601        param_list.append(['smearing_min', str(smearing_min)]) 
     3602        param_list.append(['smearing_max', str(smearing_max)]) 
     3603 
     3604        # checkboxes, if required 
     3605        has_polydisp = self.chkPolydispersity.isChecked() 
     3606        has_magnetism = self.chkMagnetism.isChecked() 
     3607        has_chain = self.chkChainFit.isChecked() 
     3608        has_2D = self.chk2DView.isChecked() 
     3609        param_list.append(['polydisperse_params', str(has_polydisp)]) 
     3610        param_list.append(['magnetic_params', str(has_magnetism)]) 
     3611        param_list.append(['chainfit_params', str(has_chain)]) 
     3612        param_list.append(['2D_params', str(has_2D)]) 
     3613 
     3614        return param_list 
    35553615 
    35563616    def onParameterPaste(self): 
     
    35633623 
    35643624        context = {} 
    3565         # put the text into dictionary 
    35663625        lines = cb_text.split(':') 
    35673626        if lines[0] != 'sasview_parameter_values': 
    35683627            return False 
    35693628 
    3570         model = lines[1].split(',') 
    3571  
    3572         if model[0] != 'model_name': 
     3629        # put the text into dictionary 
     3630        line_dict = {} 
     3631        for line in lines[1:]: 
     3632            content = line.split(',') 
     3633            if len(content) > 1: 
     3634                line_dict[content[0]] = content[1:] 
     3635 
     3636        model = line_dict['model_name'][0] 
     3637 
     3638        if 'model_name' not in line_dict.keys(): 
    35733639            return False 
    35743640 
    3575         context['model_name'] = [model[1]] 
    3576         for line in lines[2:-1]: 
    3577             if len(line) != 0: 
    3578                 item = line.split(',') 
    3579                 check = item[1] 
    3580                 name = item[0] 
    3581                 value = item[2] 
    3582                 # Transfer the text to content[dictionary] 
    3583                 context[name] = [check, value] 
    3584  
    3585                 # limits 
    3586                 try: 
    3587                     limit_lo = item[3] 
    3588                     context[name].append(limit_lo) 
    3589                     limit_hi = item[4] 
    3590                     context[name].append(limit_hi) 
    3591                 except: 
    3592                     pass 
    3593  
    3594                 # Polydisp 
    3595                 if len(item) > 5: 
    3596                     value = item[5] 
    3597                     context[name].append(value) 
    3598                     try: 
    3599                         value = item[6] 
    3600                         context[name].append(value) 
    3601                         value = item[7] 
    3602                         context[name].append(value) 
    3603                     except IndexError: 
    3604                         pass 
    3605  
    3606         if str(self.cbModel.currentText()) != str(context['model_name'][0]): 
     3641        if 'multiplicity' in line_dict.keys(): 
     3642            multip = int(line_dict['multiplicity'][0], 0) 
     3643            # reset the model with multiplicity, so further updates are saved 
     3644            if self.kernel_module.is_multiplicity_model: 
     3645                self.kernel_module.multiplicity=multip 
     3646                self.updateMultiplicityCombo(multip) 
     3647 
     3648        if 'polydisperse_params' in line_dict.keys(): 
     3649            self.chkPolydispersity.setChecked(line_dict['polydisperse_params'][0]=='True') 
     3650        if 'magnetic_params' in line_dict.keys(): 
     3651            self.chkMagnetism.setChecked(line_dict['magnetic_params'][0]=='True') 
     3652        if 'chainfit_params' in line_dict.keys(): 
     3653            self.chkChainFit.setChecked(line_dict['chainfit_params'][0]=='True') 
     3654        if '2D_params' in line_dict.keys(): 
     3655            self.chk2DView.setChecked(line_dict['2D_params'][0]=='True') 
     3656 
     3657        # Create the context dictionary for parameters 
     3658        context['model_name'] = model 
     3659        for key, value in line_dict.items(): 
     3660            if len(value) > 2: 
     3661                context[key] = value 
     3662 
     3663        if str(self.cbModel.currentText()) != str(context['model_name']): 
    36073664            msg = QtWidgets.QMessageBox() 
    36083665            msg.setIcon(QtWidgets.QMessageBox.Information) 
     
    36163673                return 
    36173674 
     3675        if 'smearing' in line_dict.keys(): 
     3676            try: 
     3677                index = int(line_dict['smearing'][0]) 
     3678                self.smearing_widget.cbSmearing.setCurrentIndex(index) 
     3679            except ValueError: 
     3680                pass 
     3681        if 'smearing_min' in line_dict.keys(): 
     3682            try: 
     3683                self.smearing_widget.dq_l = float(line_dict['smearing_min'][0]) 
     3684            except ValueError: 
     3685                pass 
     3686        if 'smearing_max' in line_dict.keys(): 
     3687            try: 
     3688                self.smearing_widget.dq_r = float(line_dict['smearing_max'][0]) 
     3689            except ValueError: 
     3690                pass 
     3691 
     3692        if 'q_range_max' in line_dict.keys(): 
     3693            try: 
     3694                self.q_range_min = float(line_dict['q_range_min'][0]) 
     3695                self.q_range_max = float(line_dict['q_range_max'][0]) 
     3696            except ValueError: 
     3697                pass 
     3698        self.options_widget.updateQRange(self.q_range_min, self.q_range_max, self.npts) 
     3699 
    36183700        self.updateFullModel(context) 
    36193701        self.updateFullPolyModel(context) 
     3702        self.updateFullMagnetModel(context) 
     3703 
     3704    def updateMultiplicityCombo(self, multip): 
     3705        """ 
     3706        Find and update the multiplicity combobox 
     3707        """ 
     3708        index = self._model_model.index(self._n_shells_row, 1) 
     3709        widget = self.lstParams.indexWidget(index) 
     3710        if widget is not None and isinstance(widget, QtWidgets.QComboBox): 
     3711            widget.setCurrentIndex(widget.findText(str(multip))) 
     3712        self.current_shell_displayed = multip 
    36203713 
    36213714    def updateFullModel(self, param_dict): 
     
    36333726            if param_name not in list(param_dict.keys()): 
    36343727                return 
     3728            # Special case of combo box in the cell (multiplicity) 
     3729            param_line = param_dict[param_name] 
     3730            if len(param_line) == 1: 
     3731                # modify the shells value 
     3732                try: 
     3733                    combo_index = int(param_line[0]) 
     3734                except ValueError: 
     3735                    # quietly pass 
     3736                    return 
     3737                index = self._model_model.index(row, 1) 
     3738                widget = self.lstParams.indexWidget(index) 
     3739                if widget is not None and isinstance(widget, QtWidgets.QComboBox): 
     3740                    #widget.setCurrentIndex(combo_index) 
     3741                    return 
    36353742            # checkbox state 
    36363743            param_checked = QtCore.Qt.Checked if param_dict[param_name][0] == "True" else QtCore.Qt.Unchecked 
    36373744            self._model_model.item(row, 0).setCheckState(param_checked) 
    36383745 
    3639             # modify the param value 
    3640             param_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
    3641             self._model_model.item(row, 1).setText(param_repr) 
     3746            # parameter value can be either just a value or text on the combobox 
     3747            param_text = param_dict[param_name][1] 
     3748            index = self._model_model.index(row, 1) 
     3749            widget = self.lstParams.indexWidget(index) 
     3750            if widget is not None and isinstance(widget, QtWidgets.QComboBox): 
     3751                # Find the right index based on text 
     3752                combo_index = int(param_text, 0) 
     3753                widget.setCurrentIndex(combo_index) 
     3754            else: 
     3755                # modify the param value 
     3756                param_repr = GuiUtils.formatNumber(param_text, high=True) 
     3757                self._model_model.item(row, 1).setText(param_repr) 
    36423758 
    36433759            # Potentially the error column 
     
    36453761            if len(param_dict[param_name])>4 and self.has_error_column: 
    36463762                # error values are not editable - no need to update 
    3647                 #error_repr = GuiUtils.formatNumber(param_dict[param_name][2], high=True) 
    3648                 #self._model_model.item(row, 2).setText(error_repr) 
    36493763                ioffset = 1 
    36503764            # min/max 
     
    36593773            self.setFocus() 
    36603774 
    3661  
    3662  
    3663         # block signals temporarily, so we don't end up 
    3664         # updating charts with every single model change on the end of fitting 
    3665         self._model_model.blockSignals(True) 
    36663775        self.iterateOverModel(updateFittedValues) 
    3667         self._model_model.blockSignals(False) 
    3668  
    36693776 
    36703777    def updateFullPolyModel(self, param_dict): 
     
    37133820            self.setFocus() 
    37143821 
    3715         # block signals temporarily, so we don't end up 
    3716         # updating charts with every single model change on the end of fitting 
    3717         self._poly_model.blockSignals(True) 
    37183822        self.iterateOverPolyModel(updateFittedValues) 
    3719         self._poly_model.blockSignals(False) 
    3720  
    3721  
    3722  
     3823 
     3824    def updateFullMagnetModel(self, param_dict): 
     3825        """ 
     3826        Update the magnetism model with new parameters, create the errors column 
     3827        """ 
     3828        assert isinstance(param_dict, dict) 
     3829        if not dict: 
     3830            return 
     3831 
     3832        def updateFittedValues(row): 
     3833            # Utility function for main model update 
     3834            # internal so can use closure for param_dict 
     3835            if row >= self._magnet_model.rowCount(): 
     3836                return 
     3837            param_name = str(self._magnet_model.item(row, 0).text()).rsplit()[-1] 
     3838            if param_name not in list(param_dict.keys()): 
     3839                return 
     3840            # checkbox state 
     3841            param_checked = QtCore.Qt.Checked if param_dict[param_name][0] == "True" else QtCore.Qt.Unchecked 
     3842            self._magnet_model.item(row,0).setCheckState(param_checked) 
     3843 
     3844            # modify the param value 
     3845            param_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     3846            self._magnet_model.item(row, 1).setText(param_repr) 
     3847 
     3848            # Potentially the error column 
     3849            ioffset = 0 
     3850            if len(param_dict[param_name])>4 and self.has_magnet_error_column: 
     3851                ioffset = 1 
     3852            # min 
     3853            param_repr = GuiUtils.formatNumber(param_dict[param_name][2+ioffset], high=True) 
     3854            self._magnet_model.item(row, 2+ioffset).setText(param_repr) 
     3855            # max 
     3856            param_repr = GuiUtils.formatNumber(param_dict[param_name][3+ioffset], high=True) 
     3857            self._magnet_model.item(row, 3+ioffset).setText(param_repr) 
     3858 
     3859        self.iterateOverMagnetModel(updateFittedValues) 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    ra4b9b7a rd2007a8  
    10101010 
    10111011        # Change another parameter 
    1012         self.widget._model_model.item(2, 1).setText("3.0") 
     1012        self.widget._model_model.item(3, 1).setText("3.0") 
     1013 
    10131014        # Check that the stack is updated 
    10141015        self.assertEqual(len(self.widget.page_stack), 2) 
  • src/sas/qtgui/MainWindow/DataExplorer.py

    r3b95b3b r345b3b3  
    233233        filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 
    234234        if filename: 
    235             load_thread = threads.deferToThread(self.readProject, filename) 
    236             load_thread.addCallback(self.readProjectComplete) 
    237             load_thread.addErrback(self.readProjectFailed) 
    238  
    239     def loadFailed(self, reason): 
    240         """ 
    241         """ 
    242         print("file load FAILED: ", reason) 
    243         pass 
    244  
    245     def readProjectFailed(self, reason): 
    246         """ 
    247         """ 
    248         print("readProjectFailed FAILED: ", reason) 
    249         pass 
    250  
    251     def readProject(self, filename): 
    252         self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename)) 
    253         try: 
    254             manager = DataManager() 
    255             with open(filename, 'r') as infile: 
    256                 manager.load_from_readable(infile) 
    257  
    258             self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename)) 
    259             return manager 
    260  
    261         except: 
    262             self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename)) 
    263             raise 
    264  
    265     def readProjectComplete(self, manager): 
    266         self.model.clear() 
    267  
    268         self.manager.assign(manager) 
    269         self.model.beginResetModel() 
    270         for id, item in self.manager.get_all_data().items(): 
    271             self.updateModel(item.data, item.path) 
    272  
    273         self.model.endResetModel() 
     235            self.readProject(filename) 
    274236 
    275237    def saveProject(self): 
     
    285247        name_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 
    286248        filename = name_tuple[0] 
    287         if filename: 
    288             _, extension = os.path.splitext(filename) 
    289             if not extension: 
    290                 filename = '.'.join((filename, 'json')) 
    291             self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
    292             with open(filename, 'w') as outfile: 
    293                 self.manager.save_to_writable(outfile) 
     249        if not filename: 
     250            return 
     251        _, extension = os.path.splitext(filename) 
     252        if not extension: 
     253            filename = '.'.join((filename, 'json')) 
     254        self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
     255 
     256        with open(filename, 'w') as outfile: 
     257            self.saveDataToFile(outfile) 
     258 
     259    def allDataForModel(self, model): 
     260        # data model 
     261        all_data = {} 
     262        for i in range(model.rowCount()): 
     263            properties = {} 
     264            item = model.item(i) 
     265            data = GuiUtils.dataFromItem(item) 
     266            if data is None: continue 
     267            # Now, all plots under this item 
     268            filename = data.filename 
     269            is_checked = item.checkState() 
     270            properties['checked'] = is_checked 
     271            other_datas = GuiUtils.plotsFromFilename(filename, model) 
     272            # skip the main plot 
     273            other_datas = list(other_datas.values())[1:] 
     274            all_data[data.id] = [data, properties, other_datas] 
     275        return all_data 
     276 
     277    def saveDataToFile(self, outfile): 
     278        """ 
     279        Save every dataset to a json file 
     280        """ 
     281        data = self.allDataForModel(self.model) 
     282        theory = self.allDataForModel(self.theory_model) 
     283 
     284        all_data = {} 
     285        for key, value in data.items(): 
     286            all_data[key] = value 
     287        for key, value in theory.items(): 
     288            if key in all_data: 
     289                raise ValueError("Inconsistent data in Project file.") 
     290            all_data[key] = value 
     291 
     292        # perspectives 
     293        current_perspective = self._perspective() 
     294        try: 
     295            perspective_dump = current_perspective.getCurrentStateAsXml() 
     296        except Exception: 
     297            ex = "State of " + current_perspective.windowTitle() + \ 
     298                " cannot be saved." 
     299            logging.error(ex) 
     300        if perspective_dump is not None: 
     301            assert(isinstance(perspective_dump, dict)) 
     302            all_data['perspective'] = perspective_dump 
     303        # save datas 
     304        GuiUtils.saveData(outfile, all_data) 
     305        return 
     306 
     307    def readProject(self, filename): 
     308        """ 
     309        Read out datasets and fitpages from file 
     310        """ 
     311        with open(filename, 'r') as infile: 
     312            all_data = GuiUtils.readDataFromFile(infile) 
     313        # clear the model 
     314        self.model.clear() 
     315 
     316        #self.model.beginResetModel() 
     317        for key, value in all_data.items(): 
     318            # key - cardinal number of dataset 
     319            # value - main dataset, [dependant filesets] 
     320            # add the main index 
     321            new_data = value[0] 
     322            assert isinstance(new_data, (Data1D, Data2D)) 
     323            properties = value[1] 
     324            is_checked = properties['checked'] 
     325            new_item = GuiUtils.createModelItemWithPlot(new_data, new_data.filename) 
     326            new_item.setCheckState(is_checked) 
     327            model = self.theory_model 
     328            if new_data.is_data: 
     329                model = self.model 
     330            model.appendRow(new_item) 
     331            self.manager.add_data(data_list={new_data.id:new_data}) 
     332 
     333            # Add the underlying data 
     334            if not value[2]: 
     335                continue 
     336            for plot in value[2]: 
     337                assert isinstance(plot, (Data1D, Data2D)) 
     338                GuiUtils.updateModelItemWithPlot(new_item, plot, plot.name) 
    294339 
    295340    def deleteFile(self, event): 
     
    13941439        checkbox_item.setCheckable(True) 
    13951440        checkbox_item.setCheckState(QtCore.Qt.Checked) 
    1396         checkbox_item.setText(os.path.basename(p_file)) 
     1441        if p_file is not None: 
     1442            checkbox_item.setText(os.path.basename(p_file)) 
    13971443 
    13981444        # Add the actual Data1D/Data2D object 
  • src/sas/qtgui/MainWindow/DataManager.py

    re2e5f3d r345b3b3  
    2929from sas.qtgui.Plotting.PlotterData import Data1D 
    3030from sas.qtgui.Plotting.PlotterData import Data2D 
    31 from sas.qtgui.Plotting.Plottables import Plottable 
    3231from sas.qtgui.Plotting.Plottables import PlottableTheory1D 
    3332from sas.qtgui.Plotting.Plottables import PlottableFit1D 
  • src/sas/qtgui/Utilities/GuiUtils.py

    r63467b6 r345b3b3  
    1111import webbrowser 
    1212import urllib.parse 
     13import json 
     14from io import BytesIO 
    1315 
    1416import numpy as np 
     
    2628from sas.qtgui.Plotting.PlotterData import Data1D 
    2729from sas.qtgui.Plotting.PlotterData import Data2D 
     30from sas.qtgui.Plotting.Plottables import Plottable 
     31from sas.sascalc.dataloader.data_info import Sample, Source, Vector 
     32from sas.qtgui.Plotting.Plottables import View 
     33from sas.qtgui.Plotting.Plottables import PlottableTheory1D 
     34from sas.qtgui.Plotting.Plottables import PlottableFit1D 
     35from sas.qtgui.Plotting.Plottables import Text 
     36from sas.qtgui.Plotting.Plottables import Chisq 
     37from sas.qtgui.MainWindow.DataState import DataState 
     38 
    2839from sas.sascalc.dataloader.loader import Loader 
    2940from sas.qtgui.Utilities import CustomDir 
     
    286297    changeDataExplorerTabSignal = QtCore.pyqtSignal(int) 
    287298 
    288 def updateModelItemWithPlot(item, update_data, name=""): 
     299def updateModelItemWithPlot(item, update_data, name="", checkbox_state=None): 
    289300    """ 
    290301    Adds a checkboxed row named "name" to QStandardItem 
     
    311322            # Force redisplay 
    312323            return 
    313  
    314324    # Create the new item 
    315325    checkbox_item = createModelItemWithPlot(update_data, name) 
    316326 
     327    if checkbox_state is not None: 
     328        checkbox_item.setCheckState(checkbox_state) 
    317329    # Append the new row to the main item 
    318330    item.appendRow(checkbox_item) 
     
    11391151    return result 
    11401152 
     1153def saveData(fp, data): 
     1154    """ 
     1155    save content of data to fp (a .write()-supporting file-like object) 
     1156    """ 
     1157 
     1158    def add_type(dict, type): 
     1159        dict['__type__'] = type.__name__ 
     1160        return dict 
     1161 
     1162    def jdefault(o): 
     1163        """ 
     1164        objects that can't otherwise be serialized need to be converted 
     1165        """ 
     1166        # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples) 
     1167        if isinstance(o, (tuple, set)): 
     1168            content = { 'data': list(o) } 
     1169            return add_type(content, type(o)) 
     1170 
     1171        # "simple" types 
     1172        if isinstance(o, (Sample, Source, Vector)): 
     1173            return add_type(o.__dict__, type(o)) 
     1174        if isinstance(o, (Plottable, View)): 
     1175            return add_type(o.__dict__, type(o)) 
     1176 
     1177        # DataState 
     1178        if isinstance(o, (Data1D, Data2D)): 
     1179            # don't store parent 
     1180            content = o.__dict__.copy() 
     1181            #content.pop('parent') 
     1182            return add_type(content, type(o)) 
     1183 
     1184        # ndarray 
     1185        if isinstance(o, np.ndarray): 
     1186            buffer = BytesIO() 
     1187            np.save(buffer, o) 
     1188            buffer.seek(0) 
     1189            content = { 'data': buffer.read().decode('latin-1') } 
     1190            return add_type(content, type(o)) 
     1191 
     1192        # not supported 
     1193        logging.info("data cannot be serialized to json: %s" % type(o)) 
     1194        return None 
     1195 
     1196    json.dump(data, fp, indent=2, sort_keys=True, default=jdefault) 
     1197 
     1198def readDataFromFile(fp): 
     1199    ''' 
     1200    ''' 
     1201    supported = [ 
     1202        tuple, set, 
     1203        Sample, Source, Vector, 
     1204        Plottable, Data1D, Data2D, PlottableTheory1D, PlottableFit1D, Text, Chisq, View, 
     1205        DataState, np.ndarray] 
     1206 
     1207    lookup = dict((cls.__name__, cls) for cls in supported) 
     1208 
     1209    class TooComplexException(Exception): 
     1210        pass 
     1211 
     1212    def simple_type(cls, data, level): 
     1213        class Empty(object): 
     1214            def __init__(self): 
     1215                for key, value in data.items(): 
     1216                    setattr(self, key, generate(value, level)) 
     1217 
     1218        # create target object 
     1219        o = Empty() 
     1220        o.__class__ = cls 
     1221 
     1222        return o 
     1223 
     1224    def construct(type, data, level): 
     1225        try: 
     1226            cls = lookup[type] 
     1227        except KeyError: 
     1228            logging.info('unknown type: %s' % type) 
     1229            return None 
     1230 
     1231        # tuples and sets 
     1232        if cls in (tuple, set): 
     1233            # convert list to tuple/set 
     1234            return cls(generate(data['data'], level)) 
     1235 
     1236        # "simple" types 
     1237        if cls in (Sample, Source, Vector): 
     1238            return simple_type(cls, data, level) 
     1239        if issubclass(cls, Plottable) or (cls == View): 
     1240            return simple_type(cls, data, level) 
     1241 
     1242        # DataState 
     1243        if cls == DataState: 
     1244            o = simple_type(cls, data, level) 
     1245            o.parent = None # TODO: set to ??? 
     1246            return o 
     1247 
     1248        # ndarray 
     1249        if cls == np.ndarray: 
     1250            buffer = BytesIO() 
     1251            buffer.write(data['data'].encode('latin-1')) 
     1252            buffer.seek(0) 
     1253            return np.load(buffer) 
     1254 
     1255        logging.info('not implemented: %s, %s' % (type, cls)) 
     1256        return None 
     1257 
     1258    def generate(data, level): 
     1259        if level > 16: # recursion limit (arbitrary number) 
     1260            raise TooComplexException() 
     1261        else: 
     1262            level += 1 
     1263 
     1264        if isinstance(data, dict): 
     1265            try: 
     1266                type = data['__type__'] 
     1267            except KeyError: 
     1268                # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary 
     1269                o = {} 
     1270                for key, value in data.items(): 
     1271                    o[key] = generate(value, level) 
     1272                return o 
     1273 
     1274            return construct(type, data, level) 
     1275 
     1276        if isinstance(data, list): 
     1277            return [generate(item, level) for item in data] 
     1278 
     1279        return data 
     1280 
     1281    new_stored_data = {} 
     1282    for id, data in json.load(fp).items(): 
     1283        try: 
     1284            new_stored_data[id] = generate(data, 0) 
     1285        except TooComplexException: 
     1286            logging.info('unable to load %s' % id) 
     1287 
     1288    return new_stored_data 
     1289 
    11411290 
    11421291def enum(*sequential, **named): 
Note: See TracChangeset for help on using the changeset viewer.