Changeset 551f2bc in sasview
- Timestamp:
- Sep 13, 2018 12:14:58 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:
- 13da5f5
- Parents:
- 9b17efd (diff), 8b745c36 (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. - Location:
- src/sas
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/MainWindow/DataExplorer.py
r2b8286c r33b3e4d 574 574 new_plots = [] 575 575 for item, plot in plots.items(): 576 if self.updatePlot(plot) and filename !=plot.name:576 if self.updatePlot(plot) or filename not in plot.name: 577 577 continue 578 578 # Don't plot intermediate results, e.g. P(Q), S(Q) … … 583 583 # Don't include plots from different fitpages, but always include the original data 584 584 if fitpage_name in plot.name or filename == plot.name: 585 # 'sophisticated' test to generate standalone plot for residuals586 if 'esiduals' in plot.title:585 # Residuals get their own plot 586 if plot.plot_role == Data1D.ROLE_RESIDUAL: 587 587 plot.yscale='linear' 588 588 self.plotData([(item, plot)]) … … 686 686 687 687 # Update the active chart list 688 #self.active_plots[new_plot.data.id] = new_plot688 self.active_plots[new_plot.data.name] = new_plot 689 689 690 690 def appendPlot(self): … … 729 729 data_id = data.name 730 730 if data_id in ids_keys: 731 self.active_plots[data_id].replacePlot(data_id, data) 731 # We have data, let's replace data that needs replacing 732 if data.plot_role != Data1D.ROLE_DATA: 733 self.active_plots[data_id].replacePlot(data_id, data) 732 734 return True 733 735 elif data_id in ids_vals: 734 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 736 if data.plot_role != Data1D.ROLE_DATA: 737 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 735 738 return True 736 739 return False … … 946 949 self.context_menu.addAction(self.actionQuick3DPlot) 947 950 self.context_menu.addAction(self.actionEditMask) 951 #self.context_menu.addSeparator() 952 #self.context_menu.addAction(self.actionFreezeResults) 948 953 self.context_menu.addSeparator() 949 954 self.context_menu.addAction(self.actionDelete) … … 957 962 self.actionEditMask.triggered.connect(self.showEditDataMask) 958 963 self.actionDelete.triggered.connect(self.deleteItem) 964 self.actionFreezeResults.triggered.connect(self.freezeSelectedItems) 959 965 960 966 def onCustomContextMenu(self, position): … … 977 983 self.actionQuick3DPlot.setEnabled(is_2D) 978 984 self.actionEditMask.setEnabled(is_2D) 985 986 # Freezing 987 # check that the selection has inner items 988 freeze_enabled = False 989 if model_item.parent() is not None: 990 freeze_enabled = True 991 self.actionFreezeResults.setEnabled(freeze_enabled) 992 979 993 # Fire up the menu 980 994 self.context_menu.exec_(self.current_view.mapToGlobal(position)) … … 1112 1126 mask_editor.exec_() 1113 1127 1128 def freezeItem(self, item=None): 1129 """ 1130 Freeze given item 1131 """ 1132 if item is None: 1133 return 1134 self.model.beginResetModel() 1135 new_item = self.cloneTheory(item) 1136 self.model.appendRow(new_item) 1137 self.model.endResetModel() 1138 1139 def freezeSelectedItems(self): 1140 """ 1141 Freeze selected items 1142 """ 1143 indices = self.treeView.selectedIndexes() 1144 1145 proxy = self.treeView.model() 1146 model = proxy.sourceModel() 1147 1148 for index in indices: 1149 row_index = proxy.mapToSource(index) 1150 item_to_copy = model.itemFromIndex(row_index) 1151 if item_to_copy and item_to_copy.isCheckable(): 1152 self.freezeItem(item_to_copy) 1153 1114 1154 def deleteItem(self): 1115 1155 """ … … 1272 1312 1273 1313 # Caption for the theories 1274 checkbox_item.setChild(2, QtGui.QStandardItem(" THEORIES"))1314 checkbox_item.setChild(2, QtGui.QStandardItem("FIT RESULTS")) 1275 1315 1276 1316 # New row in the model -
src/sas/qtgui/MainWindow/DataManager.py
r4e255d1 ra54bbf2b 118 118 new_plot.path = path 119 119 new_plot.list_group_id = [] 120 # Assign the plot role to data 121 new_plot.plot_role = Data1D.ROLE_DATA 120 122 ##post data to plot 121 123 # plot data -
src/sas/qtgui/MainWindow/UI/DataExplorerUI.ui
rf4a6f2c r33b3e4d 508 508 </property> 509 509 </action> 510 <action name="actionFreezeResults"> 511 <property name="text"> 512 <string>Freeze Results</string> 513 </property> 514 </action> 510 515 </widget> 511 516 <resources/> -
src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
r2f14b5d r33b3e4d 415 415 </property> 416 416 </action> 417 417 <action name="actionEditMask"> 418 418 <property name="text"> 419 419 <string>Edit Mask</string> … … 549 549 <action name="actionFreeze_Theory"> 550 550 <property name="text"> 551 <string>Freeze Theory</string>551 <string>Freeze Fit Results</string> 552 552 </property> 553 553 </action> -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
r61f0c75 ra54bbf2b 154 154 new_plot.xaxis(_xaxis, _xunit) 155 155 new_plot.yaxis(_yaxis, _yunit) 156 157 if component is not None: 158 new_plot.plot_role = Data1D.ROLE_DELETABLE #deletable 156 159 157 160 return new_plot -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
rf3cc979 r8b745c36 128 128 129 129 # Find param in volume_params 130 poly_pars = parameters.form_volume_parameters130 poly_pars = copy.deepcopy(parameters.form_volume_parameters) 131 131 if is2D: 132 132 poly_pars += parameters.orientation_parameters -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
rf3cc979 r6889ba2 273 273 self.theory_item = None 274 274 275 # list column widths 276 self.lstParamHeaderSizes = {} 277 275 278 # signal communicator 276 279 self.communicate = self.parent.communicate … … 361 364 self.lstParams.customContextMenuRequested.connect(self.showModelContextMenu) 362 365 self.lstParams.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False) 366 # Column resize signals 367 self.lstParams.header().sectionResized.connect(self.onColumnWidthUpdate) 368 363 369 # Poly model displayed in poly list 364 370 self.lstPoly.setModel(self._poly_model) … … 1108 1114 self.SASModelToQModel(model, structure_factor) 1109 1115 1116 for column, width in self.lstParamHeaderSizes.items(): 1117 self.lstParams.setColumnWidth(column, width) 1118 1110 1119 # Update plot 1111 1120 self.updateData() … … 1669 1678 self._model_model.itemChanged.connect(self.onMainParamsChange) 1670 1679 1671 # Adjust the table cells width.1672 # TODO: find a way to dynamically adjust column width while resized expanding1673 self.lstParams.resizeColumnToContents(0)1674 self.lstParams.resizeColumnToContents(4)1675 self.lstParams.resizeColumnToContents(5)1676 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)1677 1678 1680 def iterateOverPolyModel(self, func): 1679 1681 """ … … 2014 2016 self.magnet_params = {} 2015 2017 self.setMagneticModel() 2016 2017 # Adjust the table cells width2018 self.lstParams.resizeColumnToContents(0)2019 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)2020 2018 2021 2019 # Now we claim the model has been loaded … … 2342 2340 2343 2341 # add polydisperse parameters if asked 2344 if self.chkPolydispersity.isChecked() :2342 if self.chkPolydispersity.isChecked() and self._poly_model.rowCount() > 0: 2345 2343 for key, value in self.poly_params.items(): 2346 2344 model.setParam(key, value) 2347 2345 # add magnetic params if asked 2348 2346 if self.chkMagnetism.isChecked(): 2349 for key, value in self.magnet_params.items() :2347 for key, value in self.magnet_params.items() and self._magnet_model.rowCount() > 0: 2350 2348 model.setParam(key, value) 2351 2349 … … 2481 2479 residuals_plot = FittingUtilities.plotResiduals(self.data, weighted_data) 2482 2480 residuals_plot.id = "Residual " + residuals_plot.id 2481 residuals_plot.plot_role = Data1D.ROLE_RESIDUAL 2483 2482 self.createNewIndex(residuals_plot) 2484 2483 return residuals_plot … … 2726 2725 fname_index = self._poly_model.index(row_index, self.lstPoly.itemDelegate().poly_filename) 2727 2726 self._poly_model.setData(fname_index, fname) 2727 2728 def onColumnWidthUpdate(self, index, old_size, new_size): 2729 """ 2730 Simple state update of the current column widths in the param list 2731 """ 2732 self.lstParamHeaderSizes[index] = new_size 2728 2733 2729 2734 def setMagneticModel(self): -
src/sas/qtgui/Plotting/Plotter2D.py
rfce6c55 r676a430 445 445 self.ymin, self.ymax)) 446 446 447 cbax = self.figure.add_axes([0.8 4, 0.2, 0.02, 0.7])447 cbax = self.figure.add_axes([0.88, 0.2, 0.02, 0.7]) 448 448 449 449 # Current labels for axes -
src/sas/qtgui/Plotting/PlotterData.py
rcee5c78 ra54bbf2b 17 17 """ 18 18 """ 19 ROLE_DATA=0 20 ROLE_DEFAULT=1 21 ROLE_DELETABLE=2 22 ROLE_RESIDUAL=3 19 23 def __init__(self, x=None, y=None, dx=None, dy=None): 20 24 """ … … 35 39 self.title = "" 36 40 self.scale = None 41 # plot_role: 42 # 0: data - no reload on param change 43 # 1: normal lifecycle (fit) 44 # 2: deletable on model change (Q(I), S(I)...) 45 # 3: separate chart on Show Plot (residuals) 46 self.plot_role = Data1D.ROLE_DEFAULT 37 47 38 48 def copy_from_datainfo(self, data1d): … … 184 194 self.title = "" 185 195 self.scale = None 196 # Always default 197 self.plot_role = Data1D.ROLE_DEFAULT 186 198 187 199 def copy_from_datainfo(self, data2d): -
src/sas/qtgui/Utilities/GuiUtils.py
r5d28d6b ra54bbf2b 322 322 assert isinstance(item, QtGui.QStandardItem) 323 323 324 # lists of plots names/ids for all deletable plots on item 324 325 names = [p.name for p in new_plots if p.name is not None] 325 326 ids = [p.id for p in new_plots if p.id is not None] … … 329 330 for index in range(item.rowCount()): 330 331 plot_item = item.child(index) 331 if plot_item.isCheckable(): 332 plot_data = plot_item.child(0).data() 333 if (plot_data.id is not None) and (plot_data.id not in ids) and (plot_data.name not in names): 334 items_to_delete.append(plot_item) 332 if not plot_item.isCheckable(): 333 continue 334 plot_data = plot_item.child(0).data() 335 if (plot_data.id is not None) and \ 336 (plot_data.id not in ids) and \ 337 (plot_data.name not in names) and \ 338 (plot_data.plot_role == Data1D.ROLE_DELETABLE): 339 items_to_delete.append(plot_item) 335 340 336 341 for plot_item in items_to_delete: -
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
r2b8286c r28965e9 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): … … 520 536 self.model.setItem(WIDGETS.W_MAX_DIST, 521 537 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 522 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha))523 self.noOfTermsSuggestionButton.setText(524 "{:n}".format(self.nTermsSuggested))525 538 526 539 if isinstance(pr.chi2, np.ndarray): … … 671 684 self.estimationThreadNT.ready(2.5) 672 685 686 def performEstimateDynamicNT(self): 687 """ 688 Perform parameter estimation 689 """ 690 from .Thread import EstimateNT 691 692 self.updateCalculator() 693 694 # If a thread is already started, stop it 695 self.stopEstimateNTThread() 696 697 pr = self._calculator.clone() 698 # Skip the slit settings for the estimation 699 # It slows down the application and it doesn't change the estimates 700 pr.slit_height = 0.0 701 pr.slit_width = 0.0 702 nfunc = self.getNFunc() 703 704 self.estimationThreadNT = EstimateNT(pr, nfunc, 705 error_func=self._threadError, 706 completefn=self._estimateDynamicNTCompleted, 707 updatefn=None) 708 self.estimationThreadNT.queue() 709 self.estimationThreadNT.ready(2.5) 710 673 711 def stopEstimateNTThread(self): 674 712 if (self.estimationThreadNT is not None and … … 693 731 self.estimationThread.ready(2.5) 694 732 733 def performEstimateDynamic(self): 734 """ 735 Perform parameter estimation 736 """ 737 from .Thread import EstimatePr 738 739 # If a thread is already started, stop it 740 self.stopEstimationThread() 741 742 self.estimationThread = EstimatePr(self._calculator.clone(), 743 self.getNFunc(), 744 error_func=self._threadError, 745 completefn=self._estimateDynamicCompleted, 746 updatefn=None) 747 self.estimationThread.queue() 748 self.estimationThread.ready(2.5) 749 695 750 def stopEstimationThread(self): 696 751 """ Stop the estimation thread if it exists and is running """ … … 705 760 ''' Send a signal to the main thread for model update''' 706 761 self.estimateSignal.emit((alpha, message, elapsed)) 762 763 def _estimateDynamicCompleted(self, alpha, message, elapsed): 764 ''' Send a signal to the main thread for model update''' 765 self.estimateDynamicSignal.emit((alpha, message, elapsed)) 707 766 708 767 def _estimateUpdate(self, output_tuple): … … 720 779 logger.info(message) 721 780 self.performEstimateNT() 781 self.performEstimateDynamicNT() 782 783 def _estimateDynamicUpdate(self, output_tuple): 784 """ 785 Parameter estimation completed, 786 display the results to the user 787 788 :param alpha: estimated best alpha 789 :param elapsed: computation time 790 """ 791 alpha, message, elapsed = output_tuple 792 self._calculator.alpha = alpha 793 self._calculator.elapsed += self._calculator.elapsed 794 if message: 795 logger.info(message) 796 self.performEstimateDynamicNT() 722 797 723 798 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 724 799 ''' Send a signal to the main thread for model update''' 725 800 self.estimateNTSignal.emit((nterms, alpha, message, elapsed)) 801 802 def _estimateDynamicNTCompleted(self, nterms, alpha, message, elapsed): 803 ''' Send a signal to the main thread for model update''' 804 self.estimateDynamicNTSignal.emit((nterms, alpha, message, elapsed)) 726 805 727 806 def _estimateNTUpdate(self, output_tuple): … … 747 826 self.startThread() 748 827 828 def _estimateDynamicNTUpdate(self, output_tuple): 829 """ 830 Parameter estimation completed, 831 display the results to the user 832 833 :param alpha: estimated best alpha 834 :param nterms: estimated number of terms 835 :param elapsed: computation time 836 """ 837 nterms, alpha, message, elapsed = output_tuple 838 self._calculator.elapsed += elapsed 839 self._calculator.suggested_alpha = alpha 840 self.nTermsSuggested = nterms 841 # Save useful info 842 self.updateDynamicGuiValues() 843 if message: 844 logger.info(message) 845 if self.isBatch: 846 self.acceptAlpha() 847 self.acceptNoTerms() 848 self.startThread() 849 749 850 def _calculateCompleted(self, out, cov, pr, elapsed): 750 851 ''' 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.