- Timestamp:
- Sep 21, 2018 5:41:31 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:
- c928e81
- Parents:
- 33d5956 (diff), d8d81ea (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. - git-author:
- Ingo Breßler <dev@…> (09/21/18 05:41:31)
- git-committer:
- GitHub <noreply@…> (09/21/18 05:41:31)
- Location:
- src/sas
- Files:
-
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/MainWindow/DataExplorer.py
r9ce69ec r30bed93 579 579 # Don't plot intermediate results, e.g. P(Q), S(Q) 580 580 match = GuiUtils.theory_plot_ID_pattern.match(plot.id) 581 # 2nd match group contains the identifier for the intermediate result, if present (e.g. "[P(Q)]") 581 # 2nd match group contains the identifier for the intermediate 582 # result, if present (e.g. "[P(Q)]") 582 583 if match and match.groups()[1] != None: 583 584 continue 584 # Don't include plots from different fitpages, but always include the original data 585 if fitpage_name in plot.name or filename in plot.name or filename == plot.filename: 585 # Don't include plots from different fitpages, 586 # but always include the original data 587 if (fitpage_name in plot.name 588 or filename in plot.name 589 or filename == plot.filename): 586 590 # Residuals get their own plot 587 591 if plot.plot_role == Data1D.ROLE_RESIDUAL: -
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
r8faac15 r30bed93 570 570 return residuals 571 571 572 def plotPolydispersities(model): 573 plots = [] 574 if model is None: 575 return plots 576 # test for model being a sasmodels.sasview_model.SasviewModel? 577 for name in model.dispersion.keys(): 578 xarr, yarr = model.get_weights(name) 579 if len(xarr) <= 1: # param name not found or no polydisp. 580 continue 581 # create Data1D as in residualsData1D() and fill x/y members 582 # similar to FittingLogic._create1DPlot() but different data/axes 583 data1d = Data1D(x=xarr, y=yarr) 584 xunit = model.details[name][0] 585 data1d.xaxis(r'\rm{{{}}}'.format(name.replace('_', '\_')), xunit) 586 data1d.yaxis(r'\rm{weight}', 'normalized') 587 data1d.scale = 'linear' 588 data1d.symbol = 'Line' 589 data1d.name = "{} polydispersity".format(name) 590 data1d.id = data1d.name # placeholder, has to be completed later 591 data1d.plot_role = Data1D.ROLE_RESIDUAL 592 plots.append(data1d) 593 return plots 594 572 595 def binary_encode(i, digits): 573 596 return [i >> d & 1 for d in range(digits)] -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r33d5956 r30bed93 58 58 DEFAULT_POLYDISP_FUNCTION = 'gaussian' 59 59 60 # CRUFT: remove when new release of sasmodels is available 61 # https://github.com/SasView/sasview/pull/181#discussion_r218135162 62 from sasmodels.sasview_model import SasviewModel 63 if not hasattr(SasviewModel, 'get_weights'): 64 def get_weights(self, name): 65 """ 66 Returns the polydispersity distribution for parameter *name* as *value* and *weight* arrays. 67 """ 68 # type: (str) -> Tuple(np.ndarray, np.ndarray) 69 _, x, w = self._get_weights(self._model_info.parameters[name]) 70 return x, w 71 72 SasviewModel.get_weights = get_weights 60 73 61 74 logger = logging.getLogger(__name__) … … 2488 2501 2489 2502 if self.data_is_loaded: 2490 # delete any plots associated with the data that were not updated (e.g. to remove beta(Q), S_eff(Q)) 2503 # delete any plots associated with the data that were not updated 2504 # (e.g. to remove beta(Q), S_eff(Q)) 2491 2505 GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 2492 2506 pass 2493 2507 else: 2494 # delete theory items for the model, in order to get rid of any redundant items, e.g. beta(Q), S_eff(Q) 2508 # delete theory items for the model, in order to get rid of any 2509 # redundant items, e.g. beta(Q), S_eff(Q) 2495 2510 self.communicate.deleteIntermediateTheoryPlotsSignal.emit(self.kernel_module.id) 2511 2512 # Create plots for parameters with enabled polydispersity 2513 for plot in FittingUtilities.plotPolydispersities(return_data.get('model', None)): 2514 data_id = fitted_data.id.split() 2515 plot.id = "{} [{}] {}".format(data_id[0], plot.name, " ".join(data_id[1:])) 2516 data_name = fitted_data.name.split() 2517 plot.name = " ".join([data_name[0], plot.name] + data_name[1:]) 2518 self.createNewIndex(plot) 2519 new_plots.append(plot) 2496 2520 2497 2521 # Create plots for intermediate product data -
src/sas/qtgui/Calculators/UnitTesting/SLDCalculatorTest.py
r144fe21 r9ce69ec 81 81 self.assertEqual(self.widget.ui.editMolecularFormula.styleSheet(), '') 82 82 self.assertEqual(self.widget.model.columnCount(), 1) 83 self.assertEqual(self.widget.model.rowCount(), 1 2)83 self.assertEqual(self.widget.model.rowCount(), 11) 84 84 self.assertEqual(self.widget.sizePolicy().Policy(), QtWidgets.QSizePolicy.Fixed) 85 85 86 86 def testSimpleEntry(self): 87 87 ''' Default compound calculations ''' 88 89 self.widget.show()90 88 91 89 self.widget.ui.editMassDensity.clear() … … 102 100 103 101 # Change mass density 104 self.widget.ui.edit Wavelength.clear()105 self.widget.ui.edit Wavelength.setText("666.0")102 self.widget.ui.editNeutronWavelength.clear() 103 self.widget.ui.editNeutronWavelength.setText("666.0") 106 104 107 105 # Send shift-tab to update the molar volume field … … 130 128 131 129 # Assure the mass density field is set 132 self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '43.4') 130 #self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '43.4') 131 self.assertEqual(self.widget.ui.editNeutronIncXs.text(), '2.89') 133 132 134 133 # Reset the widget 135 134 self.widget.modelReset() 136 135 137 136 self.assertEqual(self.widget.ui.editMolecularFormula.text(), "H2O") 138 137 self.assertEqual(self.widget.ui.editMassDensity.text(), "1") -
src/sas/qtgui/GUITests.py
r7dd309a rccd2b87 180 180 unittest.makeSuite(InvariantPerspectiveTest.InvariantPerspectiveTest, 'test'), 181 181 # Inversion 182 #unittest.makeSuite(InversionPerspectiveTest.InversionTest, 'test'),182 unittest.makeSuite(InversionPerspectiveTest.InversionTest, 'test'), 183 183 ) 184 184 return unittest.TestSuite(suites) -
src/sas/qtgui/MainWindow/GuiManager.py
r768387e0 rdee9e5f 12 12 from twisted.internet import reactor 13 13 # General SAS imports 14 from sas import get_local_config, get_custom_config 14 15 from sas.qtgui.Utilities.ConnectionProxy import ConnectionProxy 15 16 from sas.qtgui.Utilities.SasviewLogger import setup_qt_logging … … 136 137 self.aboutWidget = AboutBox() 137 138 self.categoryManagerWidget = CategoryManager(self._parent, manager=self) 138 self.welcomePanel = WelcomePanel()139 139 self.grid_window = None 140 140 self._workspace.toolBar.setVisible(LocalConfig.TOOLBAR_SHOW) … … 241 241 perspective_width = perspective_size.width() 242 242 self._current_perspective.resize(perspective_width, workspace_height-10) 243 # Resize the mdi area to match the widget within244 subwindow.resize(subwindow.minimumSizeHint())245 243 246 244 self._current_perspective.show() … … 388 386 self.communicate.statusBarUpdateSignal.emit(msg) 389 387 390 def showWelcomeMessage(self):388 def actionWelcome(self): 391 389 """ Show the Welcome panel """ 390 self.welcomePanel = WelcomePanel() 392 391 self._workspace.workspace.addSubWindow(self.welcomePanel) 393 392 self.welcomePanel.show() 393 394 def showWelcomeMessage(self): 395 """ Show the Welcome panel, when required """ 396 # Assure the welcome screen is requested 397 show_welcome_widget = True 398 custom_config = get_custom_config() 399 if hasattr(custom_config, "WELCOME_PANEL_SHOW"): 400 if isinstance(custom_config.WELCOME_PANEL_SHOW, bool): 401 show_welcome_widget = custom_config.WELCOME_PANEL_SHOW 402 else: 403 logging.warning("WELCOME_PANEL_SHOW has invalid value in custom_config.py") 404 if show_welcome_widget: 405 self.actionWelcome() 394 406 395 407 def addCallbacks(self): … … 478 490 self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge) 479 491 self._workspace.actionAbout.triggered.connect(self.actionAbout) 492 self._workspace.actionWelcomeWidget.triggered.connect(self.actionWelcome) 480 493 self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update) 481 494 … … 979 992 When setting a perspective, sets up the menu bar 980 993 """ 994 self._workspace.actionReport.setEnabled(False) 981 995 if isinstance(perspective, Perspectives.PERSPECTIVES["Fitting"]): 982 996 self.checkAnalysisOption(self._workspace.actionFitting) … … 988 1002 self._workspace.menubar.addAction(self._workspace.menuWindow.menuAction()) 989 1003 self._workspace.menubar.addAction(self._workspace.menuHelp.menuAction()) 1004 self._workspace.actionReport.setEnabled(True) 990 1005 991 1006 elif isinstance(perspective, Perspectives.PERSPECTIVES["Invariant"]): -
src/sas/qtgui/MainWindow/UI/MainWindowUI.ui
r768387e0 rfc5d2d7f 148 148 <addaction name="separator"/> 149 149 <addaction name="actionAbout"/> 150 <addaction name="actionWelcomeWidget"/> 151 <addaction name="separator"/> 150 152 <addaction name="actionCheck_for_update"/> 151 153 </widget> … … 558 560 </property> 559 561 </action> 562 <action name="actionWelcomeWidget"> 563 <property name="text"> 564 <string>Welcome to SasView</string> 565 </property> 566 </action> 560 567 </widget> 561 568 <resources/> -
src/sas/qtgui/Perspectives/Fitting/FittingOptions.py
rff3b293 r8873ab7 64 64 default_index = self.cbAlgorithm.findText(default_name) 65 65 self.cbAlgorithm.setCurrentIndex(default_index) 66 # previous algorithm choice 67 self.previous_index = default_index 66 68 67 69 # Assign appropriate validators … … 121 123 122 124 # Convert the name into widget instance 123 widget_to_activate = eval(widget_name) 125 try: 126 widget_to_activate = eval(widget_name) 127 except AttributeError: 128 # We don't yet have this optimizer. 129 # Show message 130 msg = "This algorithm has not yet been implemented in SasView.\n" 131 msg += "Please choose a different algorithm" 132 QtWidgets.QMessageBox.warning(self, 133 'Warning', 134 msg, 135 QtWidgets.QMessageBox.Ok) 136 # Move the index to previous position 137 self.cbAlgorithm.setCurrentIndex(self.previous_index) 138 return 139 124 140 index_for_this_id = self.stackedWidget.indexOf(widget_to_activate) 125 141 … … 133 149 # OK has to be reinitialized to True 134 150 self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True) 151 152 # keep reference 153 self.previous_index = index 135 154 136 155 def onApply(self): … … 143 162 # e.g. 'samples' for 'dream' is 'self.samples_dream' 144 163 widget_name = 'self.'+option+'_'+self.current_fitter_id 145 line_edit = eval(widget_name) 164 try: 165 line_edit = eval(widget_name) 166 except AttributeError: 167 # Skip bumps monitors 168 continue 146 169 if line_edit is None or not isinstance(line_edit, QtWidgets.QLineEdit): 147 170 continue … … 165 188 return 166 189 try: 167 new_value = widget.currentText() if isinstance(widget, QtWidgets.QComboBox) \ 168 else float(widget.text()) 190 if isinstance(widget, QtWidgets.QComboBox): 191 new_value = widget.currentText() 192 else: 193 try: 194 new_value = int(widget.text()) 195 except ValueError: 196 new_value = float(widget.text()) 197 #new_value = widget.currentText() if isinstance(widget, QtWidgets.QComboBox) \ 198 # else float(widget.text()) 169 199 self.config.values[self.current_fitter_id][option] = new_value 170 200 except ValueError: -
src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui
r305114c r1738173 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 463</width>10 <height> 234</height>9 <width>367</width> 10 <height>199</height> 11 11 </rect> 12 12 </property> … … 135 135 <widget class="QLabel" name="lblWarning"> 136 136 <property name="text"> 137 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are no r re-applied during size or angle polydispersity<br/>integrations. To do whichrequires creating a custom model.</p></body></html></string>137 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 138 138 </property> 139 139 </widget> -
src/sas/qtgui/Perspectives/Fitting/UI/FittingWidgetUI.ui
ra2e8ea5 rfc5d2d7f 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 566</width>9 <width>651</width> 10 10 <height>646</height> 11 11 </rect> -
src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui
raa88b76 r1738173 10 10 <x>0</x> 11 11 <y>0</y> 12 <width> 436</width>13 <height>2 17</height>12 <width>369</width> 13 <height>201</height> 14 14 </rect> 15 15 </property> … … 121 121 <widget class="QLabel" name="lblWarning"> 122 122 <property name="text"> 123 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are no r re-applied during size or angle polydispersity<br/>integrations. To do whichrequires creating a custom model.</p></body></html></string>123 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 124 124 </property> 125 125 </widget> -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r1a15ada r8faac15 397 397 header_tooltips = ['Select parameter for fitting', 398 398 'Enter polydispersity ratio (Std deviation/mean).\n'+ 399 'For angles this can be either std deviation or full width (for uniform distributions) in degrees', 400 'STD: standard deviation from the mean value', 399 'For angles this can be either std deviation or half width (for uniform distributions) in degrees', 401 400 'Enter minimum value for parameter', 402 401 'Enter maximum value for parameter', … … 620 619 # Set to 0 621 620 self.widget.lstParams.indexWidget(func_index).setCurrentIndex(0) 622 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) # 2 fewer rows than default621 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) 623 622 624 623 def testPlotTheory(self): … … 658 657 self.assertEqual(spy.count(), 0) 659 658 660 def testPlotData(self):659 def notestPlotData(self): 661 660 """ 662 661 See that data item can produce a chart -
src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py
raed0532 rdee9e5f 233 233 234 234 plot_data = GuiUtils.plotsFromCheckedItems(self._manager.filesWidget.model) 235 #self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id) 235 236 236 237 self._manager.filesWidget.plotData(plot_data) … … 347 348 extrapolated_data.name = title 348 349 extrapolated_data.title = title 350 extrapolated_data.style = "Line" 351 extrapolated_data.has_errors = False 352 extrapolated_data.plot_role = Data1D.ROLE_DEFAULT 349 353 350 354 # copy labels and units of axes for plotting … … 378 382 high_out_data.name = title 379 383 high_out_data.title = title 384 high_out_data.style = "Line" 385 high_out_data.has_errors = False 386 high_out_data.plot_role = Data1D.ROLE_DEFAULT 380 387 381 388 # copy labels and units of axes for plotting -
src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py
rb0ba43e r9f2f713 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 … … 155 157 logger.error(msg) 156 158 157 plotter = self.model.item(W.VARIABLE).text() 158 y_label = y_unit = "" 159 plotter = self.dependentVariable.currentText() 159 160 x_label = "D_{max}" 160 161 x_unit = "A" … … 188 189 y_unit = "a.u." 189 190 190 data = Data1D( xs, ys)191 data = Data1D(plotable_xs, ys) 191 192 if self.hasPlot: 192 self.plot.removePlot( None)193 self.plot.removePlot(data.name) 193 194 self.hasPlot = True 194 195 data.title = plotter -
src/sas/qtgui/Perspectives/Inversion/InversionLogic.py
r6da860a r3c4f02e 111 111 new_plot.title = title 112 112 113 new_plot.symbol = 'Line' 114 new_plot.hide_error = True 115 113 116 return new_plot 114 117 -
src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py
r855e7ad rdee9e5f 44 44 estimateSignal = QtCore.pyqtSignal(tuple) 45 45 estimateNTSignal = QtCore.pyqtSignal(tuple) 46 estimateDynamicNTSignal = QtCore.pyqtSignal(tuple) 47 estimateDynamicSignal = QtCore.pyqtSignal(tuple) 46 48 calculateSignal = QtCore.pyqtSignal(tuple) 47 49 … … 53 55 54 56 self._manager = parent 57 #Needed for Batch fitting 58 self._parent = parent 55 59 self.communicate = parent.communicator() 56 60 self.communicate.dataDeletedSignal.connect(self.removeData) … … 110 114 # Set up the Widget Map 111 115 self.setupMapper() 116 117 #Hidding calculate all buton 118 self.calculateAllButton.setVisible(False) 112 119 # Set base window state 113 120 self.setupWindow() … … 120 127 121 128 def allowBatch(self): 122 return True129 return False 123 130 124 131 def setClosable(self, value=True): … … 195 202 self.model.itemChanged.connect(self.model_changed) 196 203 self.estimateNTSignal.connect(self._estimateNTUpdate) 204 self.estimateDynamicNTSignal.connect(self._estimateDynamicNTUpdate) 205 self.estimateDynamicSignal.connect(self._estimateDynamicUpdate) 197 206 self.estimateSignal.connect(self._estimateUpdate) 198 207 self.calculateSignal.connect(self._calculateUpdate) 208 209 self.maxDistanceInput.textEdited.connect(self.performEstimateDynamic) 199 210 200 211 def setupMapper(self): … … 310 321 and not self.isCalculating) 311 322 self.removeButton.setEnabled(self.logic.data_is_loaded) 312 self.explorerButton.setEnabled(self.logic.data_is_loaded 313 and np.all(self.logic.data.dy != 0)) 323 self.explorerButton.setEnabled(self.logic.data_is_loaded) 314 324 self.stopButton.setVisible(self.isCalculating) 315 325 self.regConstantSuggestionButton.setEnabled( … … 454 464 # Create initial internal mappings 455 465 self.logic.data = GuiUtils.dataFromItem(data) 466 if not isinstance(self.logic.data, Data1D): 467 msg = "P(r) perspective works for 1D data only" 468 logger.warning(msg) 469 continue 456 470 # Estimate q range 457 471 qmin, qmax = self.logic.computeDataRange() 458 472 self._calculator.set_qmin(qmin) 459 473 self._calculator.set_qmax(qmax) 474 if np.size(self.logic.data.dy) == 0 or np.all(self.logic.data.dy) == 0: 475 self.logic.data.dy = self._calculator.add_errors(self.logic.data.y) 460 476 self.updateDataList(data) 461 477 self.populateDataComboBox(self.logic.data.filename, data) 462 478 self.dataList.setCurrentIndex(len(self.dataList) - 1) 463 self.setCurrentData(data) 479 #Checking for 1D again to mitigate the case when 2D data is last on the data list 480 if isinstance(self.logic.data, Data1D): 481 self.setCurrentData(data) 464 482 465 483 def updateDataList(self, dataRef): … … 502 520 self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 503 521 self.performEstimate() 522 523 def updateDynamicGuiValues(self): 524 pr = self._calculator 525 alpha = self._calculator.suggested_alpha 526 self.model.setItem(WIDGETS.W_MAX_DIST, 527 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 528 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 529 self.noOfTermsSuggestionButton.setText( 530 "{:n}".format(self.nTermsSuggested)) 531 532 self.enableButtons() 504 533 505 534 def updateGuiValues(self): … … 521 550 self.model.setItem(WIDGETS.W_MAX_DIST, 522 551 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 523 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha))524 self.noOfTermsSuggestionButton.setText(525 "{:n}".format(self.nTermsSuggested))526 552 527 553 if isinstance(pr.chi2, np.ndarray): … … 547 573 self.prPlot.plot_role = Data1D.ROLE_RESIDUAL 548 574 GuiUtils.updateModelItemWithPlot(self._data, self.prPlot, title) 575 self.communicate.plotRequestedSignal.emit([self._data,self.prPlot], None) 549 576 if self.dataPlot is not None: 550 577 title = self.dataPlot.name 551 578 self.dataPlot.plot_role = Data1D.ROLE_DEFAULT 579 self.dataPlot.symbol = "Line" 580 self.dataPlot.show_errors = False 552 581 GuiUtils.updateModelItemWithPlot(self._data, self.dataPlot, title) 553 if self.dataPlot is not None or self.prPlot is not None: 554 self.communicate.plotRequestedSignal.emit([self.logic.data], None) 582 self.communicate.plotRequestedSignal.emit([self._data,self.dataPlot], None) 555 583 self.enableButtons() 556 584 … … 636 664 637 665 pr = self._calculator.clone() 638 nfunc = self.getNFunc() 639 self.calcThread = CalcPr(pr, nfunc, 666 #Making sure that nfunc and alpha parameters are correctly initialized 667 pr.suggested_alpha = self._calculator.alpha 668 self.calcThread = CalcPr(pr, self.nTermsSuggested, 640 669 error_func=self._threadError, 641 670 completefn=self._calculateCompleted, … … 670 699 error_func=self._threadError, 671 700 completefn=self._estimateNTCompleted, 701 updatefn=None) 702 self.estimationThreadNT.queue() 703 self.estimationThreadNT.ready(2.5) 704 705 def performEstimateDynamicNT(self): 706 """ 707 Perform parameter estimation 708 """ 709 from .Thread import EstimateNT 710 711 self.updateCalculator() 712 713 # If a thread is already started, stop it 714 self.stopEstimateNTThread() 715 716 pr = self._calculator.clone() 717 # Skip the slit settings for the estimation 718 # It slows down the application and it doesn't change the estimates 719 pr.slit_height = 0.0 720 pr.slit_width = 0.0 721 nfunc = self.getNFunc() 722 723 self.estimationThreadNT = EstimateNT(pr, nfunc, 724 error_func=self._threadError, 725 completefn=self._estimateDynamicNTCompleted, 672 726 updatefn=None) 673 727 self.estimationThreadNT.queue() … … 696 750 self.estimationThread.ready(2.5) 697 751 752 def performEstimateDynamic(self): 753 """ 754 Perform parameter estimation 755 """ 756 from .Thread import EstimatePr 757 758 # If a thread is already started, stop it 759 self.stopEstimationThread() 760 761 self.estimationThread = EstimatePr(self._calculator.clone(), 762 self.getNFunc(), 763 error_func=self._threadError, 764 completefn=self._estimateDynamicCompleted, 765 updatefn=None) 766 self.estimationThread.queue() 767 self.estimationThread.ready(2.5) 768 698 769 def stopEstimationThread(self): 699 770 """ Stop the estimation thread if it exists and is running """ … … 708 779 ''' Send a signal to the main thread for model update''' 709 780 self.estimateSignal.emit((alpha, message, elapsed)) 781 782 def _estimateDynamicCompleted(self, alpha, message, elapsed): 783 ''' Send a signal to the main thread for model update''' 784 self.estimateDynamicSignal.emit((alpha, message, elapsed)) 710 785 711 786 def _estimateUpdate(self, output_tuple): … … 723 798 logger.info(message) 724 799 self.performEstimateNT() 800 self.performEstimateDynamicNT() 801 802 def _estimateDynamicUpdate(self, output_tuple): 803 """ 804 Parameter estimation completed, 805 display the results to the user 806 807 :param alpha: estimated best alpha 808 :param elapsed: computation time 809 """ 810 alpha, message, elapsed = output_tuple 811 self._calculator.alpha = alpha 812 self._calculator.elapsed += self._calculator.elapsed 813 if message: 814 logger.info(message) 815 self.performEstimateDynamicNT() 725 816 726 817 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 727 818 ''' Send a signal to the main thread for model update''' 728 819 self.estimateNTSignal.emit((nterms, alpha, message, elapsed)) 820 821 def _estimateDynamicNTCompleted(self, nterms, alpha, message, elapsed): 822 ''' Send a signal to the main thread for model update''' 823 self.estimateDynamicNTSignal.emit((nterms, alpha, message, elapsed)) 729 824 730 825 def _estimateNTUpdate(self, output_tuple): … … 750 845 self.startThread() 751 846 847 def _estimateDynamicNTUpdate(self, output_tuple): 848 """ 849 Parameter estimation completed, 850 display the results to the user 851 852 :param alpha: estimated best alpha 853 :param nterms: estimated number of terms 854 :param elapsed: computation time 855 """ 856 nterms, alpha, message, elapsed = output_tuple 857 self._calculator.elapsed += elapsed 858 self._calculator.suggested_alpha = alpha 859 self.nTermsSuggested = nterms 860 # Save useful info 861 self.updateDynamicGuiValues() 862 if message: 863 logger.info(message) 864 if self.isBatch: 865 self.acceptAlpha() 866 self.acceptNoTerms() 867 self.startThread() 868 752 869 def _calculateCompleted(self, out, cov, pr, elapsed): 753 870 ''' Send a signal to the main thread for model update''' -
src/sas/qtgui/Perspectives/Inversion/UI/DMaxExplorer.ui
r8f83719f rcfd61f2 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 394</width>10 <height> 426</height>9 <width>586</width> 10 <height>538</height> 11 11 </rect> 12 12 </property> … … 21 21 <property name="orientation"> 22 22 <enum>Qt::Vertical</enum> 23 </property>24 <property name="sizeHint" stdset="0">25 <size>26 <width>20</width>27 <height>305</height>28 </size>29 23 </property> 30 24 </spacer> -
src/sas/qtgui/Perspectives/Inversion/UI/TabbedInversionUI.ui
r72ecbdf2 r68dc2873 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 390</width>10 <height>4 09</height>9 <width>446</width> 10 <height>480</height> 11 11 </rect> 12 12 </property> … … 740 740 <widget class="QPushButton" name="calculateAllButton"> 741 741 <property name="enabled"> 742 <bool> true</bool>742 <bool>false</bool> 743 743 </property> 744 744 <property name="sizePolicy"> -
src/sas/qtgui/Perspectives/Inversion/UnitTesting/InversionPerspectiveTest.py
r144fe21 rccd2b87 99 99 def baseBatchState(self): 100 100 """ Testing the base batch fitting state """ 101 self.assert True(self.widget.allowBatch())101 self.assertFalse(self.widget.allowBatch()) 102 102 self.assertFalse(self.widget.isBatch) 103 103 self.assertFalse(self.widget.calculateAllButton.isEnabled()) … … 304 304 self.assertIsNotNone(self.widget.dmaxWindow) 305 305 self.assertTrue(self.widget.dmaxWindow.isVisible()) 306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "D ââExplorer")306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "Dmax Explorer") 307 307 308 308 -
src/sas/qtgui/Plotting/Plotter.py
r5b144c6 r863ebca 8 8 import numpy as np 9 9 from matplotlib.font_manager import FontProperties 10 10 11 from sas.qtgui.Plotting.PlotterData import Data1D 11 12 from sas.qtgui.Plotting.PlotterBase import PlotterBase … … 84 85 if self.data.ytransform is None: 85 86 self.data.ytransform = 'log10(y)' 86 87 #Added condition to Dmax explorer from P(r) perspective 88 if self.data._xaxis == 'D_{max}': 89 self.xscale = 'linear' 87 90 # Transform data if required. 88 91 if transform and (self.data.xtransform is not None or self.data.ytransform is not None): … … 222 225 self.contextMenu.addAction("Reset Graph Range") 223 226 # Add the title change for dialogs 224 #if self.parent:225 227 self.contextMenu.addSeparator() 226 228 self.actionWindowTitle = self.contextMenu.addAction("Window Title") -
src/sas/qtgui/Plotting/PlotterBase.py
r343d7fd r863ebca 110 110 111 111 self.contextMenu = QtWidgets.QMenu(self) 112 112 self.toolbar = NavigationToolbar(self.canvas, self) 113 layout.addWidget(self.toolbar) 113 114 if not quickplot: 114 115 # Add the toolbar 115 self.toolbar = NavigationToolbar(self.canvas, self) 116 layout.addWidget(self.toolbar) 116 self.toolbar.show() 117 117 # Notify PlotHelper about the new plot 118 118 self.upatePlotHelper() 119 else: 120 self.toolbar.hide() 119 121 120 122 self.setLayout(layout) … … 219 221 self.actionCopyToClipboard = self.contextMenu.addAction("Copy to Clipboard") 220 222 self.contextMenu.addSeparator() 223 self.actionToggleMenu = self.contextMenu.addAction("Toggle Navigation Menu") 224 self.contextMenu.addSeparator() 225 221 226 222 227 # Define the callbacks … … 224 229 self.actionPrintImage.triggered.connect(self.onImagePrint) 225 230 self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy) 231 self.actionToggleMenu.triggered.connect(self.onToggleMenu) 226 232 227 233 def createContextMenu(self): … … 371 377 self.manager.communicator.activeGraphName.emit((current_title, title)) 372 378 379 def onToggleMenu(self): 380 """ 381 Toggle navigation menu visibility in the chart 382 """ 383 if self.toolbar.isVisible(): 384 self.toolbar.hide() 385 else: 386 self.toolbar.show() 387 373 388 def offset_graph(self): 374 389 """ -
src/sas/qtgui/Plotting/UnitTesting/Plotter2DTest.py
r144fe21 r863ebca 146 146 self.plotter.createContextMenuQuick() 147 147 actions = self.plotter.contextMenu.actions() 148 self.assertEqual(len(actions), 7)148 self.assertEqual(len(actions), 9) 149 149 150 150 # Trigger Print Image and make sure the method is called … … 158 158 159 159 # Trigger Toggle Grid and make sure the method is called 160 self.assertEqual(actions[ 4].text(), "Toggle Grid On/Off")160 self.assertEqual(actions[6].text(), "Toggle Grid On/Off") 161 161 self.plotter.ax.grid = MagicMock() 162 actions[ 4].trigger()162 actions[6].trigger() 163 163 self.assertTrue(self.plotter.ax.grid.called) 164 164 165 165 # Trigger Change Scale and make sure the method is called 166 self.assertEqual(actions[ 6].text(), "Toggle Linear/Log Scale")167 FigureCanvas.draw_idle = MagicMock() 168 actions[ 6].trigger()166 self.assertEqual(actions[8].text(), "Toggle Linear/Log Scale") 167 FigureCanvas.draw_idle = MagicMock() 168 actions[8].trigger() 169 169 self.assertTrue(FigureCanvas.draw_idle.called) 170 170 -
src/sas/qtgui/Plotting/UnitTesting/PlotterBaseTest.py
r144fe21 r863ebca 84 84 self.assertTrue(PlotHelper.deletePlot.called) 85 85 86 def testOnImagePrint(self):86 def notestOnImagePrint(self): 87 87 ''' test the workspace print ''' 88 88 QtGui.QPainter.end = MagicMock() … … 124 124 125 125 actions = self.plotter.contextMenu.actions() 126 self.assertEqual(len(actions), 4)126 self.assertEqual(len(actions), 6) 127 127 128 128 # Trigger Print Image and make sure the method is called … … 146 146 # Make sure clipboard got updated. 147 147 self.assertTrue(self.clipboard_called) 148 149 # Trigger toggle navigation bar and make sure the method is called 150 self.assertEqual(actions[4].text(), "Toggle Navigation Menu") 151 isShown = self.plotter.toolbar.isVisible() 152 self.assertTrue(isShow) 153 actions[4].trigger() 154 isShown = self.plotter.toolbar.isVisible() 155 self.assertFalse(isShow) 156 actions[4].trigger() 157 isShown = self.plotter.toolbar.isVisible() 158 self.assertTrue(isShow) 159 148 160 149 161 def testOnWindowsTitle(self): -
src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py
r5b144c6 r863ebca 103 103 self.plotter.createContextMenuQuick() 104 104 actions = self.plotter.contextMenu.actions() 105 self.assertEqual(len(actions), 7)105 self.assertEqual(len(actions), 9) 106 106 107 107 # Trigger Print Image and make sure the method is called … … 115 115 116 116 # Trigger Toggle Grid and make sure the method is called 117 self.assertEqual(actions[ 4].text(), "Toggle Grid On/Off")117 self.assertEqual(actions[6].text(), "Toggle Grid On/Off") 118 118 self.plotter.ax.grid = MagicMock() 119 actions[ 4].trigger()119 actions[6].trigger() 120 120 self.assertTrue(self.plotter.ax.grid.called) 121 121 122 122 # Trigger Change Scale and make sure the method is called 123 self.assertEqual(actions[ 6].text(), "Change Scale")123 self.assertEqual(actions[8].text(), "Change Scale") 124 124 self.plotter.properties.exec_ = MagicMock(return_value=QtWidgets.QDialog.Rejected) 125 actions[ 6].trigger()125 actions[8].trigger() 126 126 self.assertTrue(self.plotter.properties.exec_.called) 127 127 -
src/sas/qtgui/Utilities/GridPanel.py
r3c6ecd9 r4fbf0db 54 54 # Fill in the table from input data 55 55 self.setupTable(widget=self.tblParams, data=output_data) 56 #TODO: This is not what was inteded to be. 56 57 if output_data is not None: 57 58 # Set a table tooltip describing the model 58 model_name = output_data[0][0].model.id59 model_name = list(output_data.keys())[0] 59 60 self.tabWidget.setTabToolTip(0, model_name) 60 61 … … 418 419 def __init__(self, parent = None, output_data=None): 419 420 420 super(BatchInversionOutputPanel, self).__init__(parent , output_data)421 super(BatchInversionOutputPanel, self).__init__(parent._parent, output_data) 421 422 _translate = QtCore.QCoreApplication.translate 422 423 self.setWindowTitle(_translate("GridPanelUI", "Batch P(r) Results")) 423 424 424 def setupTable(self, data):425 def setupTable(self, widget=None, data=None): 425 426 """ 426 427 Create tablewidget items and show them, based on params … … 433 434 'Calc. Time [sec]'] 434 435 436 if data is None: 437 return 435 438 keys = data.keys() 436 439 rows = len(keys) -
src/sas/qtgui/Utilities/GuiUtils.py
ra54bbf2b r9ce69ec 567 567 The assumption - data stored in SasView standard, in child 0 568 568 """ 569 return item.child(0).data() 569 try: 570 data = item.child(0).data() 571 except AttributeError: 572 data = None 573 return data 570 574 571 575 def openLink(url): -
src/sas/sascalc/pr/invertor.py
rb8080e1 reeea6a3 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 """ … … 268 282 A[i][j] = (Fourier transformed base function for point j) 269 283 270 We the mchoose a number of r-points, n_r, to evaluate the second284 We then choose a number of r-points, n_r, to evaluate the second 271 285 derivative of P(r) at. This is used as our regularization term. 272 286 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.