Changeset 1bd266b in sasview
- Timestamp:
- Sep 8, 2018 10:52:16 AM (6 years ago)
- 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:
- 4d959c8
- Parents:
- e908916 (diff), 5e0891b (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. - Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
.gitignore
rce1f491 r7cc38a7 16 16 *.pyproj 17 17 *.sln 18 .*.swp 18 19 .DS_Store 19 20 /.settings -
src/sas/qtgui/MainWindow/DataExplorer.py
r60d55a7 r0cd98a1 42 42 # Main model for keeping loaded data 43 43 self.model = QtGui.QStandardItemModel(self) 44 45 44 # Secondary model for keeping frozen data sets 46 45 self.theory_model = QtGui.QStandardItemModel(self) … … 98 97 self.communicator.plotUpdateSignal.connect(self.updatePlot) 99 98 self.communicator.maskEditorSignal.connect(self.showEditDataMask) 99 self.communicator.extMaskEditorSignal.connect(self.extShowEditDataMask) 100 100 101 101 self.cbgraph.editTextChanged.connect(self.enableGraphCombo) … … 598 598 plot2D.plot(plot_set) 599 599 self.addPlot(plot2D) 600 self.active_plots[plot2D.data. id] = plot2D600 self.active_plots[plot2D.data.name] = plot2D 601 601 #============================================ 602 602 # Experimental hook for silx charts … … 626 626 new_plot.plot(plot_set, transform=transform) 627 627 # active_plots may contain multiple charts 628 self.active_plots[plot_set. id] = new_plot628 self.active_plots[plot_set.name] = new_plot 629 629 elif isinstance(plot_set, Data2D): 630 630 self.addDataPlot2D(plot_set, item) … … 697 697 old_plot.plot() 698 698 # need this for lookup - otherwise this plot will never update 699 self.active_plots[plot_set. id] = old_plot699 self.active_plots[plot_set.name] = old_plot 700 700 701 701 def updatePlot(self, data): … … 711 711 712 712 ids_keys = list(self.active_plots.keys()) 713 ids_vals = [val.data. idfor val in self.active_plots.values()]714 715 data_id = data. id713 ids_vals = [val.data.name for val in self.active_plots.values()] 714 715 data_id = data.name 716 716 if data_id in ids_keys: 717 717 self.active_plots[data_id].replacePlot(data_id, data) … … 952 952 model = proxy.sourceModel() 953 953 954 if index.isValid(): 955 model_item = model.itemFromIndex(proxy.mapToSource(index)) 956 # Find the mapped index 957 orig_index = model_item.isCheckable() 958 if orig_index: 959 # Check the data to enable/disable actions 960 is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 961 self.actionQuick3DPlot.setEnabled(is_2D) 962 self.actionEditMask.setEnabled(is_2D) 963 # Fire up the menu 964 self.context_menu.exec_(self.current_view.mapToGlobal(position)) 954 if not index.isValid(): 955 return 956 model_item = model.itemFromIndex(proxy.mapToSource(index)) 957 # Find the mapped index 958 orig_index = model_item.isCheckable() 959 if not orig_index: 960 return 961 # Check the data to enable/disable actions 962 is_2D = isinstance(GuiUtils.dataFromItem(model_item), Data2D) 963 self.actionQuick3DPlot.setEnabled(is_2D) 964 self.actionEditMask.setEnabled(is_2D) 965 # Fire up the menu 966 self.context_menu.exec_(self.current_view.mapToGlobal(position)) 965 967 966 968 def showDataInfo(self): … … 1059 1061 self.new_plot.show() 1060 1062 1063 def extShowEditDataMask(self): 1064 self.showEditDataMask() 1065 1061 1066 def showEditDataMask(self, data=None): 1062 1067 """ 1063 1068 Mask Editor for 2D plots 1064 1069 """ 1065 if data is None or not isinstance(data, Data2D): 1066 index = self.current_view.selectedIndexes()[0] 1067 proxy = self.current_view.model() 1068 model = proxy.sourceModel() 1069 model_item = model.itemFromIndex(proxy.mapToSource(index)) 1070 1071 data = GuiUtils.dataFromItem(model_item) 1070 try: 1071 if data is None or not isinstance(data, Data2D): 1072 index = self.current_view.selectedIndexes()[0] 1073 proxy = self.current_view.model() 1074 model = proxy.sourceModel() 1075 model_item = model.itemFromIndex(proxy.mapToSource(index)) 1076 1077 data = GuiUtils.dataFromItem(model_item) 1078 1079 if data is None or not isinstance(data, Data2D): 1080 msg = QtWidgets.QMessageBox() 1081 msg.setIcon(QtWidgets.QMessageBox.Information) 1082 msg.setText("Error: cannot apply mask. \ 1083 Please select a 2D dataset.") 1084 msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 1085 msg.exec_() 1086 return 1087 except: 1088 msg = QtWidgets.QMessageBox() 1089 msg.setIcon(QtWidgets.QMessageBox.Information) 1090 msg.setText("Error: No dataset selected. \ 1091 Please select a 2D dataset.") 1092 msg.setStandardButtons(QtWidgets.QMessageBox.Cancel) 1093 msg.exec_() 1094 return 1072 1095 1073 1096 mask_editor = MaskEditor(self, data) -
src/sas/qtgui/MainWindow/GuiManager.py
rf84d793 r339e22b 422 422 self._workspace.actionExcel.triggered.connect(self.actionExcel) 423 423 self._workspace.actionLatex.triggered.connect(self.actionLatex) 424 425 424 # View 426 425 self._workspace.actionShow_Grid_Window.triggered.connect(self.actionShow_Grid_Window) … … 452 451 self._workspace.actionManage_Custom_Models.triggered.connect(self.actionManage_Custom_Models) 453 452 self._workspace.actionAddMult_Models.triggered.connect(self.actionAddMult_Models) 453 self._workspace.actionEditMask.triggered.connect(self.actionEditMask) 454 454 455 # Window 455 456 self._workspace.actionCascade.triggered.connect(self.actionCascade) … … 781 782 self.add_mult_editor.show() 782 783 784 def actionEditMask(self): 785 786 self.communicate.extMaskEditorSignal.emit() 787 783 788 #============ ANALYSIS ================= 784 789 def actionFitting(self): -
src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
rdda8f16 r2f14b5d 113 113 <addaction name="actionManage_Custom_Models"/> 114 114 <addaction name="actionAddMult_Models"/> 115 <addaction name="separator"/> 116 <addaction name="actionEditMask"/> 115 117 </widget> 116 118 <widget class="QMenu" name="menuWindow"> … … 413 415 </property> 414 416 </action> 417 <action name="actionEditMask"> 418 <property name="text"> 419 <string>Edit Mask</string> 420 </property> 421 </action> 415 422 <action name="actionCascade"> 416 423 <property name="text"> -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
rdcabba7 r9ba91b7 161 161 Create a new 1D data instance based on fitting results 162 162 """ 163 164 163 return self._create1DPlot(tab_id, return_data['x'], return_data['y'], 165 164 return_data['model'], return_data['data']) … … 212 211 (pq_plot, sq_plot). If either are unavailable, the corresponding plot is None. 213 212 """ 214 215 pq_plot = None 216 sq_plot = None 217 218 if return_data.get('pq_values', None) is not None: 219 pq_plot = self._create1DPlot(tab_id, return_data['x'], 220 return_data['pq_values'], return_data['model'], 221 return_data['data'], component="P(Q)") 222 if return_data.get('sq_values', None) is not None: 223 sq_plot = self._create1DPlot(tab_id, return_data['x'], 224 return_data['sq_values'], return_data['model'], 225 return_data['data'], component="S(Q)") 226 227 return pq_plot, sq_plot 213 plots = [] 214 for name, result in return_data['intermediate_results'].items(): 215 plots.append(self._create1DPlot(tab_id, return_data['x'], result, 216 return_data['model'], return_data['data'], 217 component=name)) 218 return plots 228 219 229 220 def computeDataRange(self): -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
rb69b549 r01b4877 167 167 return rows 168 168 169 def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None ):169 def addSimpleParametersToModel(parameters, is2D, parameters_original=None, model=None, view=None, row_num=None): 170 170 """ 171 171 Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic) … … 216 216 # Append to the model and use the combobox, if required 217 217 if None not in (model, view): 218 model.appendRow(row) 218 if row_num is None: 219 model.appendRow(row) 220 else: 221 model.insertRow(row_num, row) 222 row_num += 1 223 219 224 if cbox: 220 225 view.setIndexWidget(item2.index(), cbox) 226 221 227 rows.append(row) 222 228 -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
rf0365a2e r5e0891b 48 48 from sas.qtgui.Perspectives.Fitting.ReportPageLogic import ReportPageLogic 49 49 50 51 50 TAB_MAGNETISM = 4 52 51 TAB_POLY = 3 … … 188 187 189 188 # Overwrite data type descriptor 189 190 190 self.is2D = True if isinstance(self.logic.data, Data2D) else False 191 191 … … 563 563 When clicked on white space: model description 564 564 """ 565 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows()] 565 rows = [s.row() for s in self.lstParams.selectionModel().selectedRows() 566 if self.isCheckable(s.row())] 566 567 menu = self.showModelDescription() if not rows else self.modelContextMenu(rows) 567 568 try: … … 799 800 def getConstraintForRow(self, row): 800 801 """ 801 For the given row, return its constraint, if any 802 """ 803 if self.isCheckable(row): 804 item = self._model_model.item(row, 1) 805 try: 806 return item.child(0).data() 807 except AttributeError: 808 # return none when no constraints 809 pass 810 return None 802 For the given row, return its constraint, if any (otherwise None) 803 """ 804 if not self.isCheckable(row): 805 return None 806 item = self._model_model.item(row, 1) 807 try: 808 return item.child(0).data() 809 except AttributeError: 810 return None 811 811 812 812 def rowHasConstraint(self, row): … … 814 814 Finds out if row of the main model has a constraint child 815 815 """ 816 if self.isCheckable(row): 817 item = self._model_model.item(row, 1) 818 if item.hasChildren(): 819 c = item.child(0).data() 820 if isinstance(c, Constraint): 821 return True 816 if not self.isCheckable(row): 817 return False 818 item = self._model_model.item(row, 1) 819 if not item.hasChildren(): 820 return False 821 c = item.child(0).data() 822 if isinstance(c, Constraint): 823 return True 822 824 return False 823 825 … … 826 828 Finds out if row of the main model has an active constraint child 827 829 """ 828 if self.isCheckable(row): 829 item = self._model_model.item(row, 1) 830 if item.hasChildren(): 831 c = item.child(0).data() 832 if isinstance(c, Constraint) and c.active: 833 return True 830 if not self.isCheckable(row): 831 return False 832 item = self._model_model.item(row, 1) 833 if not item.hasChildren(): 834 return False 835 c = item.child(0).data() 836 if isinstance(c, Constraint) and c.active: 837 return True 834 838 return False 835 839 … … 838 842 Finds out if row of the main model has an active, nontrivial constraint child 839 843 """ 840 if self.isCheckable(row): 841 item = self._model_model.item(row, 1) 842 if item.hasChildren(): 843 c = item.child(0).data() 844 if isinstance(c, Constraint) and c.func and c.active: 845 return True 844 if not self.isCheckable(row): 845 return False 846 item = self._model_model.item(row, 1) 847 if not item.hasChildren(): 848 return False 849 c = item.child(0).data() 850 if isinstance(c, Constraint) and c.func and c.active: 851 return True 846 852 return False 847 853 … … 1053 1059 # Show constraint, if present 1054 1060 row = rows[0].row() 1055 if self.rowHasConstraint(row): 1056 func = self.getConstraintForRow(row).func 1057 if func is not None: 1058 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1061 if not self.rowHasConstraint(row): 1062 return 1063 func = self.getConstraintForRow(row).func 1064 if func is not None: 1065 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1059 1066 1060 1067 def replaceConstraintName(self, old_name, new_name=""): … … 1807 1814 # Force data recalculation so existing charts are updated 1808 1815 self.showPlot() 1816 # This is an important processEvent. 1817 # This allows charts to be properly updated in order 1818 # of plots being applied. 1819 QtWidgets.QApplication.processEvents() 1809 1820 self.recalculatePlotData() 1810 1821 … … 2091 2102 return 2092 2103 2104 product_params = None 2105 2093 2106 if self.kernel_module is None: 2094 2107 # Structure factor is the only selected model; build it and show all its params … … 2096 2109 s_params = self.kernel_module._model_info.parameters 2097 2110 s_params_orig = s_params 2098 2099 2111 else: 2100 2112 s_kernel = self.models[structure_factor]() … … 2113 2125 if "radius_effective_mode" in all_param_names: 2114 2126 # Show all parameters 2127 # In this case, radius_effective is NOT pruned by sasmodels.product 2115 2128 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len]) 2116 2129 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters) 2130 product_params = modelinfo.ParameterTable( 2131 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2117 2132 else: 2118 2133 # Ensure radius_effective is not displayed 2119 2134 s_params_orig = modelinfo.ParameterTable(s_kernel._model_info.parameters.kernel_parameters[1:]) 2120 2135 if "radius_effective" in all_param_names: 2136 # In this case, radius_effective is NOT pruned by sasmodels.product 2121 2137 s_params = modelinfo.ParameterTable(all_params[p_pars_len+1:p_pars_len+s_pars_len]) 2138 product_params = modelinfo.ParameterTable( 2139 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len:]) 2122 2140 else: 2141 # In this case, radius_effective is pruned by sasmodels.product 2123 2142 s_params = modelinfo.ParameterTable(all_params[p_pars_len:p_pars_len+s_pars_len-1]) 2143 product_params = modelinfo.ParameterTable( 2144 self.kernel_module._model_info.parameters.kernel_parameters[p_pars_len+s_pars_len-1:]) 2124 2145 2125 2146 # Add heading row … … 2129 2150 # Any renamed parameters are stored as data in the relevant item, for later handling 2130 2151 FittingUtilities.addSimpleParametersToModel( 2131 s_params, 2132 self.is2D, 2133 s_params_orig, 2134 self._model_model, 2135 self.lstParams) 2152 parameters=s_params, 2153 is2D=self.is2D, 2154 parameters_original=s_params_orig, 2155 model=self._model_model, 2156 view=self.lstParams) 2157 2158 # Insert product-only params into QModel 2159 if product_params: 2160 prod_rows = FittingUtilities.addSimpleParametersToModel( 2161 parameters=product_params, 2162 is2D=self.is2D, 2163 parameters_original=None, 2164 model=self._model_model, 2165 view=self.lstParams, 2166 row_num=2) 2167 2168 # Since this all happens after shells are dealt with and we've inserted rows, fix this counter 2169 self._n_shells_row += len(prod_rows) 2136 2170 2137 2171 def haveParamsToFit(self): … … 2394 2428 2395 2429 # Create plots for intermediate product data 2396 pq_data, sq_data = self.logic.new1DProductPlots(return_data, self.tab_id) 2397 if pq_data is not None: 2398 pq_data.symbol = "Line" 2399 self.createNewIndex(pq_data) 2400 # self.communicate.plotUpdateSignal.emit([pq_data]) 2401 new_plots.append(pq_data) 2402 if sq_data is not None: 2403 sq_data.symbol = "Line" 2404 self.createNewIndex(sq_data) 2405 # self.communicate.plotUpdateSignal.emit([sq_data]) 2406 new_plots.append(sq_data) 2430 plots = self.logic.new1DProductPlots(return_data, self.tab_id) 2431 for plot in plots: 2432 plot.symbol = "Line" 2433 self.createNewIndex(plot) 2434 new_plots.append(plot) 2407 2435 2408 2436 for plot in new_plots: … … 2805 2833 self._num_shell_params = len(new_rows) 2806 2834 self.current_shell_displayed = index 2835 2836 # Change 'n' in the parameter model, thereby updating the underlying model 2837 self._model_model.item(self._n_shells_row, 1).setText(str(index)) 2807 2838 2808 2839 # Update relevant models … … 3149 3180 formatted_output = FittingUtilities.formatParameters(param_list) 3150 3181 elif format == "Excel": 3151 formatted_output = FittingUtilities.formatParametersExcel(param_list )3182 formatted_output = FittingUtilities.formatParametersExcel(param_list[1:]) 3152 3183 elif format == "Latex": 3153 formatted_output = FittingUtilities.formatParametersLatex(param_list )3184 formatted_output = FittingUtilities.formatParametersLatex(param_list[1:]) 3154 3185 else: 3155 3186 raise AttributeError("Bad format specifier.") … … 3316 3347 self._poly_model.blockSignals(False) 3317 3348 3349 3350 -
src/sas/qtgui/Perspectives/Fitting/ModelThread.py
rdcabba7 r5181e9b 164 164 index = (self.qmin <= self.data.x) & (self.data.x <= self.qmax) 165 165 166 intermediate_results = None 167 166 168 # If we use a smearer, also return the unsmeared model 167 169 unsmeared_output = None … … 174 176 mask = self.data.x[first_bin:last_bin+1] 175 177 unsmeared_output = numpy.zeros((len(self.data.x))) 176 unsmeared_output[first_bin:last_bin+1] = self.model.evalDistribution(mask) 178 179 return_data = self.model.calculate_Iq(mask) 180 if isinstance(return_data, tuple): 181 # see sasmodels beta_approx: SasviewModel.calculate_Iq 182 # TODO: implement intermediate results in smearers 183 return_data, _ = return_data 184 unsmeared_output[first_bin:last_bin+1] = return_data 177 185 output = self.smearer(unsmeared_output, first_bin, last_bin) 178 186 … … 193 201 unsmeared_error=unsmeared_error 194 202 else: 195 output[index] = self.model.evalDistribution(self.data.x[index]) 196 197 sq_values = None 198 pq_values = None 199 s_model = None 200 p_model = None 201 if isinstance(self.model, MultiplicationModel): 202 s_model = self.model.s_model 203 p_model = self.model.p_model 204 elif hasattr(self.model, "calc_composition_models"): 205 results = self.model.calc_composition_models(self.data.x[index]) 206 if results is not None: 207 pq_values, sq_values = results 208 209 if pq_values is None or sq_values is None: 210 if p_model is not None and s_model is not None: 211 sq_values = numpy.zeros((len(self.data.x))) 212 pq_values = numpy.zeros((len(self.data.x))) 213 sq_values[index] = s_model.evalDistribution(self.data.x[index]) 214 pq_values[index] = p_model.evalDistribution(self.data.x[index]) 203 return_data = self.model.calculate_Iq(self.data.x[index]) 204 if isinstance(return_data, tuple): 205 # see sasmodels beta_approx: SasviewModel.calculate_Iq 206 return_data, intermediate_results = return_data 207 output[index] = return_data 208 209 if intermediate_results: 210 # the model returns a callable which is then used to retrieve the data 211 intermediate_results = intermediate_results() 212 else: 213 # TODO: this conditional branch needs refactoring 214 sq_values = None 215 pq_values = None 216 s_model = None 217 p_model = None 218 219 if isinstance(self.model, MultiplicationModel): 220 s_model = self.model.s_model 221 p_model = self.model.p_model 222 223 elif hasattr(self.model, "calc_composition_models"): 224 results = self.model.calc_composition_models(self.data.x[index]) 225 if results is not None: 226 pq_values, sq_values = results 227 228 if pq_values is None or sq_values is None: 229 if p_model is not None and s_model is not None: 230 sq_values = numpy.zeros((len(self.data.x))) 231 pq_values = numpy.zeros((len(self.data.x))) 232 sq_values[index] = s_model.evalDistribution(self.data.x[index]) 233 pq_values[index] = p_model.evalDistribution(self.data.x[index]) 234 235 if pq_values is not None and sq_values is not None: 236 intermediate_results = { 237 "P(Q)": pq_values, 238 "S(Q)": sq_values 239 } 240 else: 241 intermediate_results = {} 215 242 216 243 elapsed = time.time() - self.starttime … … 223 250 source = self.source, unsmeared_output = unsmeared_output, 224 251 unsmeared_data = unsmeared_data, unsmeared_error = unsmeared_error, 225 pq_values = pq_values, sq_values = sq_values)252 intermediate_results = intermediate_results) 226 253 227 254 if LocalConfig.USING_TWISTED: -
src/sas/qtgui/Perspectives/Fitting/UI/OptionsWidgetUI.ui
r79bd268 r309fa1b 32 32 <item row="0" column="1"> 33 33 <widget class="QLineEdit" name="txtMinRange"> 34 <property name="minimumSize"> 35 <size> 36 <width>80</width> 37 <height>0</height> 38 </size> 39 </property> 34 40 <property name="toolTip"> 35 41 <string><html><head/><body><p>Minimum value of Q.</p></body></html></string> … … 54 60 <item row="1" column="1"> 55 61 <widget class="QLineEdit" name="txtMaxRange"> 62 <property name="minimumSize"> 63 <size> 64 <width>80</width> 65 <height>0</height> 66 </size> 67 </property> 56 68 <property name="toolTip"> 57 69 <string><html><head/><body><p>Maximum value of Q.</p></body></html></string> -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingLogicTest.py
re752ab8 rbfb5d9e 99 99 data.name = "boop" 100 100 data.id = "poop" 101 return_data = (data.x,data.y, 7, None, None, 102 0, True, 0.0, 1, data, 103 data, False, None, 104 None, None, None, 105 None, None) 101 # Condensed return data (new1DPlot only uses these fields) 102 return_data = dict(x = data.x, 103 y = data.y, 104 model = data, 105 data = data) 106 # return_data = (data.x,data.y, 7, None, None, 107 # 0, True, 0.0, 1, data, 108 # data, False, None, 109 # None, None, None, 110 # None, None) 106 111 107 112 new_plot = self.logic.new1DPlot(return_data=return_data, tab_id=0) … … 139 144 qmin, qmax, npts = self.logic.computeDataRange() 140 145 141 return_data = (x_0, data, 7, data, None, 142 True, 0.0, 1, 0, qmin, qmax, 143 0.1, False, None) 146 # Condensed return data (new2DPlot only uses these fields) 147 return_data = dict(image = x_0, 148 data = data, 149 page_id = 7, 150 model = data) 151 # return_data = (x_0, data, 7, data, None, 152 # True, 0.0, 1, 0, qmin, qmax, 153 # 0.1, False, None) 144 154 145 155 new_plot = self.logic.new2DPlot(return_data=return_data) -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingOptionsTest.py
r725d9c06 rbfb5d9e 38 38 # The combo box 39 39 self.assertIsInstance(self.widget.cbAlgorithm, QtWidgets.QComboBox) 40 self.assertEqual(self.widget.cbAlgorithm.count(), 5)40 self.assertEqual(self.widget.cbAlgorithm.count(), 6) 41 41 self.assertEqual(self.widget.cbAlgorithm.itemText(0), 'Nelder-Mead Simplex') 42 42 self.assertEqual(self.widget.cbAlgorithm.itemText(4), 'Levenberg-Marquardt') -
src/sas/qtgui/Plotting/Plotter.py
rc2f3ca2 r0cd98a1 182 182 183 183 # Update the list of data sets (plots) in chart 184 self.plot_dict[self._data. id] = self.data185 186 self.plot_lines[self._data. id] = line184 self.plot_dict[self._data.name] = self.data 185 186 self.plot_lines[self._data.name] = line 187 187 188 188 # Now add the legend with some customizations. … … 201 201 # refresh canvas 202 202 self.canvas.draw() 203 # This is an important processEvent.204 # This allows charts to be properly updated in order205 # of plots being applied.206 QtWidgets.QApplication.processEvents()207 203 208 204 def createContextMenu(self): … … 420 416 This effectlvely refreshes the chart with changes to one of its plots 421 417 """ 422 import logging423 418 self.removePlot(id) 424 419 self.plot(data=new_plot) -
src/sas/qtgui/Utilities/GuiUtils.py
r6da3e3d r339e22b 265 265 # Mask Editor requested 266 266 maskEditorSignal = QtCore.pyqtSignal(Data2D) 267 268 #second Mask Editor for external 269 extMaskEditorSignal = QtCore.pyqtSignal() 267 270 268 271 # Fitting parameter copy to clipboard -
src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py
rb0ba43e re908916 42 42 self.parent = parent 43 43 44 self.setWindowTitle("D ââExplorer")44 self.setWindowTitle("Dmax Explorer") 45 45 46 46 self.pr_state = pr_state … … 116 116 bck = [] 117 117 chi2 = [] 118 118 plotable_xs = [] #Introducing this to make sure size of x and y for plotting is the same.8 119 119 try: 120 120 dmin = float(self.model.item(W.DMIN).text()) … … 128 128 129 129 original = self.pr_state.d_max 130 130 131 for x in xs: 131 132 self.pr_state.d_max = x … … 140 141 bck.append(self.pr_state.background) 141 142 chi2.append(self.pr_state.chi2) 143 plotable_xs.append(x) 142 144 except Exception as ex: 143 145 # This inversion failed, skip this D_max value … … 188 190 y_unit = "a.u." 189 191 190 data = Data1D( xs, ys)192 data = Data1D(plotable_xs, ys) 191 193 if self.hasPlot: 192 194 self.plot.removePlot(None) -
src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py
r3c6ecd9 r34cf92c 43 43 estimateSignal = QtCore.pyqtSignal(tuple) 44 44 estimateNTSignal = QtCore.pyqtSignal(tuple) 45 estimateDynamicNTSignal = QtCore.pyqtSignal(tuple) 46 estimateDynamicSignal = QtCore.pyqtSignal(tuple) 45 47 calculateSignal = QtCore.pyqtSignal(tuple) 46 48 … … 194 196 self.model.itemChanged.connect(self.model_changed) 195 197 self.estimateNTSignal.connect(self._estimateNTUpdate) 198 self.estimateDynamicNTSignal.connect(self._estimateDynamicNTUpdate) 199 self.estimateDynamicSignal.connect(self._estimateDynamicUpdate) 196 200 self.estimateSignal.connect(self._estimateUpdate) 197 201 self.calculateSignal.connect(self._calculateUpdate) 202 203 self.maxDistanceInput.textEdited.connect(self.performEstimateDynamic) 198 204 199 205 def setupMapper(self): … … 309 315 and not self.isCalculating) 310 316 self.removeButton.setEnabled(self.logic.data_is_loaded) 311 self.explorerButton.setEnabled(self.logic.data_is_loaded 312 and np.all(self.logic.data.dy != 0)) 317 self.explorerButton.setEnabled(self.logic.data_is_loaded) 313 318 self.stopButton.setVisible(self.isCalculating) 314 319 self.regConstantSuggestionButton.setEnabled( … … 501 506 self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 502 507 self.performEstimate() 508 509 def updateDynamicGuiValues(self): 510 pr = self._calculator 511 alpha = self._calculator.suggested_alpha 512 self.model.setItem(WIDGETS.W_MAX_DIST, 513 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 514 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 515 self.noOfTermsSuggestionButton.setText( 516 "{:n}".format(self.nTermsSuggested)) 517 518 self.enableButtons() 503 519 504 520 def updateGuiValues(self): … … 641 657 self.calcThread.ready(2.5) 642 658 659 #Perform estimate should be done on value enter this should solve delay problem 660 self.performEstimate() 661 643 662 def stopCalcThread(self): 644 663 """ Stops a thread if it exists and is running """ … … 667 686 error_func=self._threadError, 668 687 completefn=self._estimateNTCompleted, 688 updatefn=None) 689 self.estimationThreadNT.queue() 690 self.estimationThreadNT.ready(2.5) 691 692 def performEstimateDynamicNT(self): 693 """ 694 Perform parameter estimation 695 """ 696 from .Thread import EstimateNT 697 698 self.updateCalculator() 699 700 # If a thread is already started, stop it 701 self.stopEstimateNTThread() 702 703 pr = self._calculator.clone() 704 # Skip the slit settings for the estimation 705 # It slows down the application and it doesn't change the estimates 706 pr.slit_height = 0.0 707 pr.slit_width = 0.0 708 nfunc = self.getNFunc() 709 710 self.estimationThreadNT = EstimateNT(pr, nfunc, 711 error_func=self._threadError, 712 completefn=self._estimateDynamicNTCompleted, 669 713 updatefn=None) 670 714 self.estimationThreadNT.queue() … … 693 737 self.estimationThread.ready(2.5) 694 738 739 def performEstimateDynamic(self): 740 """ 741 Perform parameter estimation 742 """ 743 from .Thread import EstimatePr 744 745 # If a thread is already started, stop it 746 self.stopEstimationThread() 747 748 self.estimationThread = EstimatePr(self._calculator.clone(), 749 self.getNFunc(), 750 error_func=self._threadError, 751 completefn=self._estimateDynamicCompleted, 752 updatefn=None) 753 self.estimationThread.queue() 754 self.estimationThread.ready(2.5) 755 695 756 def stopEstimationThread(self): 696 757 """ Stop the estimation thread if it exists and is running """ … … 705 766 ''' Send a signal to the main thread for model update''' 706 767 self.estimateSignal.emit((alpha, message, elapsed)) 768 769 def _estimateDynamicCompleted(self, alpha, message, elapsed): 770 ''' Send a signal to the main thread for model update''' 771 self.estimateDynamicSignal.emit((alpha, message, elapsed)) 707 772 708 773 def _estimateUpdate(self, output_tuple): … … 721 786 self.performEstimateNT() 722 787 788 def _estimateDynamicUpdate(self, output_tuple): 789 """ 790 Parameter estimation completed, 791 display the results to the user 792 793 :param alpha: estimated best alpha 794 :param elapsed: computation time 795 """ 796 alpha, message, elapsed = output_tuple 797 self._calculator.alpha = alpha 798 self._calculator.elapsed += self._calculator.elapsed 799 if message: 800 logger.info(message) 801 self.performEstimateDynamicNT() 802 723 803 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 724 804 ''' Send a signal to the main thread for model update''' 725 805 self.estimateNTSignal.emit((nterms, alpha, message, elapsed)) 806 807 def _estimateDynamicNTCompleted(self, nterms, alpha, message, elapsed): 808 ''' Send a signal to the main thread for model update''' 809 self.estimateDynamicNTSignal.emit((nterms, alpha, message, elapsed)) 726 810 727 811 def _estimateNTUpdate(self, output_tuple): … … 747 831 self.startThread() 748 832 833 def _estimateDynamicNTUpdate(self, output_tuple): 834 """ 835 Parameter estimation completed, 836 display the results to the user 837 838 :param alpha: estimated best alpha 839 :param nterms: estimated number of terms 840 :param elapsed: computation time 841 """ 842 nterms, alpha, message, elapsed = output_tuple 843 self._calculator.elapsed += elapsed 844 self._calculator.suggested_alpha = alpha 845 self.nTermsSuggested = nterms 846 # Save useful info 847 self.updateDynamicGuiValues() 848 if message: 849 logger.info(message) 850 if self.isBatch: 851 self.acceptAlpha() 852 self.acceptNoTerms() 853 self.startThread() 854 749 855 def _calculateCompleted(self, out, cov, pr, elapsed): 750 856 ''' Send a signal to the main thread for model update''' -
src/sas/sascalc/pr/invertor.py
rb8080e1 r6701a0b 71 71 A[j][i] = (Fourier transformed base function for point j) 72 72 73 We the mchoose a number of r-points, n_r, to evaluate the second73 We then choose a number of r-points, n_r, to evaluate the second 74 74 derivative of P(r) at. This is used as our regularization term. 75 75 For a vector r of length n_r, the following n_r rows are set to :: … … 144 144 x, y, err, d_max, q_min, q_max and alpha 145 145 """ 146 if 146 if name == 'x': 147 147 if 0.0 in value: 148 148 msg = "Invertor: one of your q-values is zero. " … … 227 227 return None 228 228 229 def add_errors(self, yvalues): 230 """ 231 Adds errors to data set is they are not avaialble 232 :return: 233 """ 234 stats_errors = np.zeros(len(yvalues)) 235 for i in range(len(yvalues)): 236 # Scale the error so that we can fit over several decades of Q 237 scale = 0.05 * np.sqrt(yvalues[i]) 238 min_err = 0.01 * yvalues[i] 239 stats_errors[i] = scale * np.sqrt(np.fabs(yvalues[i])) + min_err 240 logger.warning("Simulated errors have been added to the data set\n") 241 return stats_errors 242 229 243 def clone(self): 230 244 """ … … 244 258 invertor.x = self.x 245 259 invertor.y = self.y 246 invertor.err = self.err 260 if np.size(self.err) == 0 or np.all(self.err) == 0: 261 invertor.err = self.add_errors(self.y) 262 else: 263 invertor.err = self.err 247 264 invertor.est_bck = self.est_bck 248 265 invertor.background = self.background … … 268 285 A[i][j] = (Fourier transformed base function for point j) 269 286 270 We the mchoose a number of r-points, n_r, to evaluate the second287 We then choose a number of r-points, n_r, to evaluate the second 271 288 derivative of P(r) at. This is used as our regularization term. 272 289 For a vector r of length n_r, the following n_r rows are set to ::
Note: See TracChangeset
for help on using the changeset viewer.