Changeset 8e2cd79 in sasview for src/sas/qtgui/Perspectives/Fitting


Ignore:
Timestamp:
Aug 3, 2018 6:30:04 AM (6 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
04972ea
Parents:
cf8d6c9
git-author:
Piotr Rozyczko <rozyczko@…> (08/03/18 05:57:48)
git-committer:
Piotr Rozyczko <rozyczko@…> (08/03/18 06:30:04)
Message:

Copy/paste fitting parameters SASVIEW-933

Location:
src/sas/qtgui/Perspectives/Fitting
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py

    r57be490 r8e2cd79  
    33from PyQt5 import QtCore 
    44from PyQt5 import QtGui 
    5 from PyQt5 import QtWidgets 
    65 
    76import numpy 
     
    9998                    continue 
    10099                width = kernel_module.getParam(p.name+'.width') 
    101                 type = kernel_module.getParam(p.name+'.type') 
     100                ptype = kernel_module.getParam(p.name+'.type') 
    102101 
    103102                item1_2 = QtGui.QStandardItem(str(width)) 
     
    107106                item1_4 = QtGui.QStandardItem() 
    108107                item1_4.setEditable(False) 
    109                 item1_5 = QtGui.QStandardItem(type) 
     108                item1_5 = QtGui.QStandardItem(ptype) 
    110109                item1_5.setEditable(False) 
    111110                poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5]) 
     
    434433    returning the modified (deep) copy of the kernel. 
    435434    """ 
    436     assert(isinstance(results, dict)) 
     435    assert isinstance(results, dict) 
    437436    local_kernel = copy.deepcopy(kernel) 
    438437 
     
    455454    for row in range(num_rows): 
    456455        param_name = model.item(row, 0).text() 
    457         checkbox_state = model.item(row,0).checkState() == QtCore.Qt.Checked 
    458         value= model.item(row, 1).text() 
     456        checkbox_state = model.item(row, 0).checkState() == QtCore.Qt.Checked 
     457        value = model.item(row, 1).text() 
    459458        column_shift = 0 
    460459        if model.columnCount() == 5: # no error column 
     
    485484    """ 
    486485    param = [] 
    487     if kernel_module is None:  
     486    if kernel_module is None: 
    488487        return None 
    489488    for param_name in list(kernel_module.params.keys()): 
     
    502501 
    503502    return param 
     503 
     504def formatParameters(parameters): 
     505    """ 
     506    Prepare the parameter string in the standard SasView layout 
     507    """ 
     508    assert parameters is not None 
     509    assert isinstance(parameters, list) 
     510    output_string = "sasview_parameter_values:" 
     511    for parameter in parameters: 
     512        output_string += ",".join([p for p in parameter if p is not None]) 
     513        output_string += ":" 
     514    return output_string 
     515 
     516def formatParametersExcel(parameters): 
     517    """ 
     518    Prepare the parameter string in the Excel format (tab delimited) 
     519    """ 
     520    assert parameters is not None 
     521    assert isinstance(parameters, list) 
     522    crlf = chr(13) + chr(10) 
     523    tab = chr(9) 
     524 
     525    output_string = "" 
     526    # names 
     527    names = "" 
     528    values = "" 
     529    for parameter in parameters: 
     530        names += parameter[0]+tab 
     531        # Add the error column if fitted 
     532        if parameter[1] == "True" and parameter[3] is not None: 
     533            names += parameter[0]+"_err"+tab 
     534 
     535        values += parameter[2]+tab 
     536        if parameter[1] == "True" and parameter[3] is not None: 
     537            values += parameter[3]+tab 
     538        # add .npts and .nsigmas when necessary 
     539        if parameter[0][-6:] == ".width": 
     540            names += parameter[0].replace('.width', '.nsigmas') + tab 
     541            names += parameter[0].replace('.width', '.npts') + tab 
     542            values += parameter[5] + tab + parameter[4] + tab 
     543 
     544    output_string = names + crlf + values 
     545    return output_string 
     546 
     547def formatParametersLatex(parameters): 
     548    """ 
     549    Prepare the parameter string in latex 
     550    """ 
     551    assert parameters is not None 
     552    assert isinstance(parameters, list) 
     553    output_string = r'\begin{table}' 
     554    output_string += r'\begin{tabular}[h]' 
     555 
     556    crlf = chr(13) + chr(10) 
     557    output_string += '{|' 
     558    output_string += 'l|l|'*len(parameters) 
     559    output_string += r'}\hline' 
     560    output_string += crlf 
     561 
     562    for index, parameter in enumerate(parameters): 
     563        name = parameter[0] # Parameter name 
     564        output_string += name.replace('_', r'\_')  # Escape underscores 
     565        # Add the error column if fitted 
     566        if parameter[1] == "True" and parameter[3] is not None: 
     567            output_string += ' & ' 
     568            output_string += parameter[0]+r'\_err' 
     569 
     570        if index < len(parameters) - 1: 
     571            output_string += ' & ' 
     572 
     573        # add .npts and .nsigmas when necessary 
     574        if parameter[0][-6:] == ".width": 
     575            output_string += parameter[0].replace('.width', '.nsigmas') + ' & ' 
     576            output_string += parameter[0].replace('.width', '.npts') 
     577 
     578            if index < len(parameters) - 1: 
     579                output_string += ' & ' 
     580 
     581    output_string += r'\\ \hline' 
     582    output_string += crlf 
     583 
     584    # Construct row of values and errors 
     585    for index, parameter in enumerate(parameters): 
     586        output_string += parameter[2] 
     587        if parameter[1] == "True" and parameter[3] is not None: 
     588            output_string += ' & ' 
     589            output_string += parameter[3] 
     590 
     591        if index < len(parameters) - 1: 
     592            output_string += ' & ' 
     593 
     594        # add .npts and .nsigmas when necessary 
     595        if parameter[0][-6:] == ".width": 
     596            output_string += parameter[5] + ' & ' 
     597            output_string += parameter[4] 
     598 
     599            if index < len(parameters) - 1: 
     600                output_string += ' & ' 
     601 
     602    output_string += r'\\ \hline' 
     603    output_string += crlf 
     604    output_string += r'\end{tabular}' 
     605    output_string += r'\end{table}' 
     606 
     607    return output_string 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    rdc71408 r8e2cd79  
    11import json 
    22import os 
    3 import copy 
    43from collections import defaultdict 
    54 
     
    7069    """ 
    7170    def __init__(self, parent=None): 
    72         QtGui.QStandardItemModel.__init__(self,parent) 
     71        QtGui.QStandardItemModel.__init__(self, parent) 
    7372 
    7473    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): 
     
    153152    def logic(self): 
    154153        # make sure the logic contains at least one element 
    155         assert(self._logic) 
     154        assert self._logic 
    156155        # logic connected to the currently shown data 
    157156        return self._logic[self.data_index] 
     
    208207        self.is_chain_fitting = False 
    209208        # Is the fit job running? 
    210         self.fit_started=False 
     209        self.fit_started = False 
    211210        # The current fit thread 
    212211        self.calc_fit = None 
     
    517516        self.communicate.saveAnalysisSignal.connect(self.savePageState) 
    518517        self.smearing_widget.smearingChangedSignal.connect(self.onSmearingOptionsUpdate) 
    519         #self.communicate.saveReportSignal.connect(self.saveReport) 
     518        self.communicate.copyFitParamsSignal.connect(self.onParameterCopy) 
     519        self.communicate.pasteFitParamsSignal.connect(self.onParameterPaste) 
    520520 
    521521    def modelName(self): 
     
    557557            return menu 
    558558        # Select for fitting 
    559         param_string = "parameter " if num_rows==1 else "parameters " 
    560         to_string = "to its current value" if num_rows==1 else "to their current values" 
     559        param_string = "parameter " if num_rows == 1 else "parameters " 
     560        to_string = "to its current value" if num_rows == 1 else "to their current values" 
    561561        has_constraints = any([self.rowHasConstraint(i) for i in rows]) 
    562562 
     
    613613        # There have to be only two rows selected. The caller takes care of that 
    614614        # but let's check the correctness. 
    615         assert(len(selected_rows)==2) 
     615        assert len(selected_rows) == 2 
    616616 
    617617        params_list = [s.data() for s in selected_rows] 
     
    680680        """ 
    681681        # Create a new item and add the Constraint object as a child 
    682         assert(isinstance(constraint, Constraint)) 
    683         assert(0<=row<=self._model_model.rowCount()) 
     682        assert isinstance(constraint, Constraint) 
     683        assert 0 <= row <= self._model_model.rowCount() 
    684684 
    685685        item = QtGui.QStandardItem() 
     
    732732        Delete constraints from selected parameters. 
    733733        """ 
    734         params =  [s.data() for s in self.lstParams.selectionModel().selectedRows() 
     734        params = [s.data() for s in self.lstParams.selectionModel().selectedRows() 
    735735                   if self.isCheckable(s.row())] 
    736736        for param in params: 
     
    783783        Finds out if row of the main model has a constraint child 
    784784        """ 
    785         item = self._model_model.item(row,1) 
     785        item = self._model_model.item(row, 1) 
    786786        if item.hasChildren(): 
    787787            c = item.child(0).data() 
     
    794794        Finds out if row of the main model has an active constraint child 
    795795        """ 
    796         item = self._model_model.item(row,1) 
     796        item = self._model_model.item(row, 1) 
    797797        if item.hasChildren(): 
    798798            c = item.child(0).data() 
     
    805805        Finds out if row of the main model has an active, nontrivial constraint child 
    806806        """ 
    807         item = self._model_model.item(row,1) 
     807        item = self._model_model.item(row, 1) 
    808808        if item.hasChildren(): 
    809809            c = item.child(0).data() 
     
    14401440        qmax = self.q_range_max 
    14411441        params_to_fit = self.parameters_to_fit 
    1442         if (not params_to_fit): 
     1442        if not params_to_fit: 
    14431443            raise ValueError('Fitting requires at least one parameter to optimize.') 
    14441444 
     
    15591559        self.has_error_column = True 
    15601560 
     1561    def iterateOverPolyModel(self, func): 
     1562        """ 
     1563        Take func and throw it inside the poly model row loop 
     1564        """ 
     1565        for row_i in range(self._poly_model.rowCount()): 
     1566            func(row_i) 
     1567 
    15611568    def updatePolyModelFromList(self, param_dict): 
    15621569        """ 
     
    15661573        if not dict: 
    15671574            return 
    1568  
    1569         def iterateOverPolyModel(func): 
    1570             """ 
    1571             Take func and throw it inside the poly model row loop 
    1572             """ 
    1573             for row_i in range(self._poly_model.rowCount()): 
    1574                 func(row_i) 
    15751575 
    15761576        def updateFittedValues(row_i): 
     
    16101610        # updating charts with every single model change on the end of fitting 
    16111611        self._poly_model.blockSignals(True) 
    1612         iterateOverPolyModel(updateFittedValues) 
     1612        self.iterateOverPolyModel(updateFittedValues) 
    16131613        self._poly_model.blockSignals(False) 
    16141614 
     
    16181618        self.lstPoly.itemDelegate().addErrorColumn() 
    16191619        error_column = [] 
    1620         iterateOverPolyModel(createErrorColumn) 
     1620        self.iterateOverPolyModel(createErrorColumn) 
    16211621 
    16221622        # switch off reponse to model change 
     
    16281628        self.has_poly_error_column = True 
    16291629 
     1630    def iterateOverMagnetModel(self, func): 
     1631        """ 
     1632        Take func and throw it inside the magnet model row loop 
     1633        """ 
     1634        for row_i in range(self._model_model.rowCount()): 
     1635            func(row_i) 
     1636 
    16301637    def updateMagnetModelFromList(self, param_dict): 
    16311638        """ 
     
    16371644        if self._magnet_model.rowCount() == 0: 
    16381645            return 
    1639  
    1640         def iterateOverMagnetModel(func): 
    1641             """ 
    1642             Take func and throw it inside the magnet model row loop 
    1643             """ 
    1644             for row_i in range(self._model_model.rowCount()): 
    1645                 func(row_i) 
    16461646 
    16471647        def updateFittedValues(row): 
     
    16761676        # updating charts with every single model change on the end of fitting 
    16771677        self._magnet_model.blockSignals(True) 
    1678         iterateOverMagnetModel(updateFittedValues) 
     1678        self.iterateOverMagnetModel(updateFittedValues) 
    16791679        self._magnet_model.blockSignals(False) 
    16801680 
     
    16841684        self.lstMagnetic.itemDelegate().addErrorColumn() 
    16851685        error_column = [] 
    1686         iterateOverMagnetModel(createErrorColumn) 
     1686        self.iterateOverMagnetModel(createErrorColumn) 
    16871687 
    16881688        # switch off reponse to model change 
     
    27932793        #self._copy_parameters_state(self.fixed_param, self.state.fixed_param) 
    27942794 
    2795  
     2795    def onParameterCopy(self, format=None): 
     2796        """ 
     2797        Copy current parameters into the clipboard 
     2798        """ 
     2799        # run a loop over all parameters and pull out 
     2800        # first - regular params 
     2801        param_list = [] 
     2802        def gatherParams(row): 
     2803            """ 
     2804            Create list of main parameters based on _model_model 
     2805            """ 
     2806            param_name = str(self._model_model.item(row, 0).text()) 
     2807            param_checked = str(self._model_model.item(row, 0).checkState() == QtCore.Qt.Checked) 
     2808            param_value = str(self._model_model.item(row, 1).text()) 
     2809            param_error = None 
     2810            column_offset = 0 
     2811            if self.has_error_column: 
     2812                param_error = str(self._model_model.item(row, 2).text()) 
     2813                column_offset = 1 
     2814            param_min = str(self._model_model.item(row, 2+column_offset).text()) 
     2815            param_max = str(self._model_model.item(row, 3+column_offset).text()) 
     2816            param_list.append([param_name, param_checked, param_value, param_error, param_min, param_max]) 
     2817 
     2818        def gatherPolyParams(row): 
     2819            """ 
     2820            Create list of polydisperse parameters based on _poly_model 
     2821            """ 
     2822            param_name = str(self._poly_model.item(row, 0).text()).split()[-1] 
     2823            param_checked = str(self._poly_model.item(row, 0).checkState() == QtCore.Qt.Checked) 
     2824            param_value = str(self._poly_model.item(row, 1).text()) 
     2825            param_error = None 
     2826            column_offset = 0 
     2827            if self.has_poly_error_column: 
     2828                param_error = str(self._poly_model.item(row, 2).text()) 
     2829                column_offset = 1 
     2830            param_min   = str(self._poly_model.item(row, 2+column_offset).text()) 
     2831            param_max   = str(self._poly_model.item(row, 3+column_offset).text()) 
     2832            param_npts  = str(self._poly_model.item(row, 4+column_offset).text()) 
     2833            param_nsigs = str(self._poly_model.item(row, 5+column_offset).text()) 
     2834            param_fun   = str(self._poly_model.item(row, 6+column_offset).text()).rstrip() 
     2835            # width 
     2836            name = param_name+".width" 
     2837            param_list.append([name, param_checked, param_value, param_error, 
     2838                                param_npts, param_nsigs, param_min, param_max, param_fun]) 
     2839 
     2840        def gatherMagnetParams(row): 
     2841            """ 
     2842            Create list of magnetic parameters based on _magnet_model 
     2843            """ 
     2844            param_name = str(self._magnet_model.item(row, 0).text()) 
     2845            param_checked = str(self._magnet_model.item(row, 0).checkState() == QtCore.Qt.Checked) 
     2846            param_value = str(self._magnet_model.item(row, 1).text()) 
     2847            param_error = None 
     2848            column_offset = 0 
     2849            if self.has_magnet_error_column: 
     2850                param_error = str(self._magnet_model.item(row, 2).text()) 
     2851                column_offset = 1 
     2852            param_min = str(self._magnet_model.item(row, 2+column_offset).text()) 
     2853            param_max = str(self._magnet_model.item(row, 3+column_offset).text()) 
     2854            param_list.append([param_name, param_checked, param_value, param_error, param_min, param_max]) 
     2855 
     2856        self.iterateOverModel(gatherParams) 
     2857        if self.chkPolydispersity.isChecked(): 
     2858            self.iterateOverPolyModel(gatherPolyParams) 
     2859        if self.chkMagnetism.isChecked() and self.chkMagnetism.isEnabled(): 
     2860            self.iterateOverMagnetModel(sgatherMagnetParams) 
     2861 
     2862        if format=="": 
     2863            formatted_output = FittingUtilities.formatParameters(param_list) 
     2864        elif format == "Excel": 
     2865            formatted_output = FittingUtilities.formatParametersExcel(param_list) 
     2866        elif format == "Latex": 
     2867            formatted_output = FittingUtilities.formatParametersLatex(param_list) 
     2868        else: 
     2869            raise AttributeError("Bad format specifier.") 
     2870 
     2871        # Dump formatted_output to the clipboard 
     2872        cb = QtWidgets.QApplication.clipboard() 
     2873        cb.setText(formatted_output) 
     2874 
     2875    def onParameterPaste(self): 
     2876        """ 
     2877        Use the clipboard to update fit state 
     2878        """ 
     2879        # Check if the clipboard contains right stuff 
     2880        cb = QtWidgets.QApplication.clipboard() 
     2881        cb_text = cb.text() 
     2882 
     2883        context = {} 
     2884        # put the text into dictionary 
     2885        lines = cb_text.split(':') 
     2886        if lines[0] != 'sasview_parameter_values': 
     2887            return False 
     2888        for line in lines[1:-1]: 
     2889            if len(line) != 0: 
     2890                item = line.split(',') 
     2891                check = item[1] 
     2892                name = item[0] 
     2893                value = item[2] 
     2894                # Transfer the text to content[dictionary] 
     2895                context[name] = [check, value] 
     2896 
     2897                # limits 
     2898                limit_lo = item[3] 
     2899                context[name].append(limit_lo) 
     2900                limit_hi = item[4] 
     2901                context[name].append(limit_hi) 
     2902 
     2903                # Polydisp 
     2904                if len(item) > 5: 
     2905                    value = item[5] 
     2906                    context[name].append(value) 
     2907                    try: 
     2908                        value = item[6] 
     2909                        context[name].append(value) 
     2910                        value = item[7] 
     2911                        context[name].append(value) 
     2912                    except IndexError: 
     2913                        pass 
     2914 
     2915        self.updateFullModel(context) 
     2916        self.updateFullPolyModel(context) 
     2917 
     2918    def updateFullModel(self, param_dict): 
     2919        """ 
     2920        Update the model with new parameters 
     2921        """ 
     2922        assert isinstance(param_dict, dict) 
     2923        if not dict: 
     2924            return 
     2925 
     2926        def updateFittedValues(row): 
     2927            # Utility function for main model update 
     2928            # internal so can use closure for param_dict 
     2929            param_name = str(self._model_model.item(row, 0).text()) 
     2930            if param_name not in list(param_dict.keys()): 
     2931                return 
     2932            # checkbox state 
     2933            param_checked = QtCore.Qt.Checked if param_dict[param_name][0] == "True" else QtCore.Qt.Unchecked 
     2934            self._model_model.item(row, 0).setCheckState(param_checked) 
     2935 
     2936            # modify the param value 
     2937            param_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     2938            self._model_model.item(row, 1).setText(param_repr) 
     2939 
     2940            # Potentially the error column 
     2941            ioffset = 0 
     2942            if len(param_dict[param_name])>4 and self.has_error_column: 
     2943                # error values are not editable - no need to update 
     2944                #error_repr = GuiUtils.formatNumber(param_dict[param_name][2], high=True) 
     2945                #self._model_model.item(row, 2).setText(error_repr) 
     2946                ioffset = 1 
     2947            # min/max 
     2948            param_repr = GuiUtils.formatNumber(param_dict[param_name][2+ioffset], high=True) 
     2949            self._model_model.item(row, 2+ioffset).setText(param_repr) 
     2950            param_repr = GuiUtils.formatNumber(param_dict[param_name][3+ioffset], high=True) 
     2951            self._model_model.item(row, 3+ioffset).setText(param_repr) 
     2952 
     2953        # block signals temporarily, so we don't end up 
     2954        # updating charts with every single model change on the end of fitting 
     2955        self._model_model.blockSignals(True) 
     2956        self.iterateOverModel(updateFittedValues) 
     2957        self._model_model.blockSignals(False) 
     2958 
     2959    def updateFullPolyModel(self, param_dict): 
     2960        """ 
     2961        Update the polydispersity model with new parameters, create the errors column 
     2962        """ 
     2963        assert isinstance(param_dict, dict) 
     2964        if not dict: 
     2965            return 
     2966 
     2967        def updateFittedValues(row): 
     2968            # Utility function for main model update 
     2969            # internal so can use closure for param_dict 
     2970            if row >= self._poly_model.rowCount(): 
     2971                return 
     2972            param_name = str(self._poly_model.item(row, 0).text()).rsplit()[-1] + '.width' 
     2973            if param_name not in list(param_dict.keys()): 
     2974                return 
     2975            # checkbox state 
     2976            param_checked = QtCore.Qt.Checked if param_dict[param_name][0] == "True" else QtCore.Qt.Unchecked 
     2977            self._poly_model.item(row,0).setCheckState(param_checked) 
     2978 
     2979            # modify the param value 
     2980            param_repr = GuiUtils.formatNumber(param_dict[param_name][1], high=True) 
     2981            self._poly_model.item(row, 1).setText(param_repr) 
     2982 
     2983            # Potentially the error column 
     2984            ioffset = 0 
     2985            if len(param_dict[param_name])>4 and self.has_poly_error_column: 
     2986                ioffset = 1 
     2987            # min 
     2988            param_repr = GuiUtils.formatNumber(param_dict[param_name][2+ioffset], high=True) 
     2989            self._poly_model.item(row, 2+ioffset).setText(param_repr) 
     2990            # max 
     2991            param_repr = GuiUtils.formatNumber(param_dict[param_name][3+ioffset], high=True) 
     2992            self._poly_model.item(row, 3+ioffset).setText(param_repr) 
     2993            # Npts 
     2994            param_repr = GuiUtils.formatNumber(param_dict[param_name][4+ioffset], high=True) 
     2995            self._poly_model.item(row, 4+ioffset).setText(param_repr) 
     2996            # Nsigs 
     2997            param_repr = GuiUtils.formatNumber(param_dict[param_name][5+ioffset], high=True) 
     2998            self._poly_model.item(row, 5+ioffset).setText(param_repr) 
     2999 
     3000            param_repr = GuiUtils.formatNumber(param_dict[param_name][5+ioffset], high=True) 
     3001            self._poly_model.item(row, 5+ioffset).setText(param_repr) 
     3002 
     3003        # block signals temporarily, so we don't end up 
     3004        # updating charts with every single model change on the end of fitting 
     3005        self._poly_model.blockSignals(True) 
     3006        self.iterateOverPolyModel(updateFittedValues) 
     3007        self._poly_model.blockSignals(False) 
     3008 
     3009 
  • src/sas/qtgui/Perspectives/Fitting/ViewDelegate.py

    rcf8d6c9 r8e2cd79  
    288288            rect = textRect.topLeft() 
    289289            y = rect.y() 
    290             y += 5.0 # magic value for rendering nice display in the table 
     290            y += 6.0 # magic value for rendering nice display in the table 
    291291            rect.setY(y) 
    292292            painter.translate(rect) 
Note: See TracChangeset for help on using the changeset viewer.