Changes in / [d8d81ea:30bed93] in sasview
- Location:
- src/sas
- Files:
-
- 27 edited
Legend:
- Unmodified
- Added
- Removed
-
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/DataExplorer.py
r3ae70f9 r9ce69ec 602 602 Forces display of charts for the given data set 603 603 """ 604 plot_to_show = data_list[0] 605 # passed plot is used ONLY to figure out its title, 606 # so all the charts related by it can be pulled from 607 # the data explorer indices. 608 filename = plot_to_show.filename 609 self.displayFile(filename=filename, is_data=plot_to_show.is_data, id=id) 604 # data_list = [QStandardItem, Data1D/Data2D] 605 plot_to_show = data_list[1] 606 plot_item = data_list[0] 607 608 # plots to show 609 new_plots = [] 610 611 # Check if this is merely a plot update 612 if self.updatePlot(plot_to_show): 613 return 614 615 # Residuals get their own plot 616 if plot_to_show.plot_role == Data1D.ROLE_RESIDUAL: 617 plot_to_show.yscale='linear' 618 self.plotData([(plot_item, plot_to_show)]) 619 elif plot_to_show.plot_role == Data1D.ROLE_DELETABLE: 620 # No plot 621 return 622 else: 623 # Plots with main data points on the same chart 624 # Get the main data plot 625 main_data = GuiUtils.dataFromItem(plot_item.parent()) 626 if main_data is None: 627 # Try the current item 628 main_data = GuiUtils.dataFromItem(plot_item) 629 if main_data is not None: 630 new_plots.append((plot_item, main_data)) 631 new_plots.append((plot_item, plot_to_show)) 632 633 if new_plots: 634 self.plotData(new_plots) 610 635 611 636 def addDataPlot2D(self, plot_set, item): -
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/FittingUtilities.py
r44deced r44deced 24 24 poly_header_tooltips = ['Select parameter for fitting', 25 25 'Enter polydispersity ratio (Std deviation/mean).\n'+ 26 'For angles this can be either std deviation or full width (for uniform distributions) in degrees', 27 'STD: standard deviation from the mean value', 26 'For angles this can be either std deviation or half width (for uniform distributions) in degrees', 28 27 'Enter minimum value for parameter', 29 28 'Enter maximum value for parameter', -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
rd8d81ea rd8d81ea 1085 1085 if not self.rowHasConstraint(row): 1086 1086 return 1087 constr = self.getConstraintForRow(row) 1087 1088 func = self.getConstraintForRow(row).func 1088 if func is not None: 1089 self.communicate.statusBarUpdateSignal.emit("Active constrain: "+func) 1089 if constr.func is not None: 1090 # inter-parameter constraint 1091 update_text = "Active constraint: "+func 1092 elif constr.param == rows[0].data(): 1093 # current value constraint 1094 update_text = "Value constrained to: " + str(constr.value) 1095 else: 1096 # ill defined constraint 1097 return 1098 self.communicate.statusBarUpdateSignal.emit(update_text) 1090 1099 1091 1100 def replaceConstraintName(self, old_name, new_name=""): … … 1124 1133 # Create default datasets if no data passed 1125 1134 self.createDefaultDataset() 1135 self.theory_item = None # ensure theory is recalc. before plot, see showTheoryPlot() 1126 1136 1127 1137 def respondToModelStructure(self, model=None, structure_factor=None): … … 1835 1845 self.cmdPlot.setText("Show Plot") 1836 1846 # Force data recalculation so existing charts are updated 1837 self.showPlot() 1847 if not self.data_is_loaded: 1848 self.showTheoryPlot() 1849 else: 1850 self.showPlot() 1838 1851 # This is an important processEvent. 1839 1852 # This allows charts to be properly updated in order 1840 1853 # of plots being applied. 1841 1854 QtWidgets.QApplication.processEvents() 1842 self.recalculatePlotData() 1855 self.recalculatePlotData() # recalc+plot theory again (2nd) 1843 1856 1844 1857 def onSmearingOptionsUpdate(self): … … 1856 1869 self.calculateQGridForModel() 1857 1870 1871 def showTheoryPlot(self): 1872 """ 1873 Show the current theory plot in MPL 1874 """ 1875 # Show the chart if ready 1876 if self.theory_item is None: 1877 self.recalculatePlotData() 1878 elif self.model_data: 1879 self._requestPlots(self.model_data.filename, self.theory_item.model()) 1880 1858 1881 def showPlot(self): 1859 1882 """ … … 1861 1884 """ 1862 1885 # Show the chart if ready 1863 data_to_show = self.data if self.data_is_loaded else self.model_data 1864 if data_to_show is not None: 1865 self.communicate.plotRequestedSignal.emit([data_to_show], self.tab_id) 1886 data_to_show = self.data 1887 # Any models for this page 1888 current_index = self.all_data[self.data_index] 1889 item = self._requestPlots(self.data.filename, current_index.model()) 1890 if item: 1891 # fit+data has not been shown - show just data 1892 self.communicate.plotRequestedSignal.emit([item, data_to_show], self.tab_id) 1893 1894 def _requestPlots(self, item_name, item_model): 1895 """ 1896 Emits plotRequestedSignal for all plots found in the given model under the provided item name. 1897 """ 1898 fitpage_name = "" if self.tab_id is None else "M"+str(self.tab_id) 1899 plots = GuiUtils.plotsFromFilename(item_name, item_model) 1900 # Has the fitted data been shown? 1901 data_shown = False 1902 item = None 1903 for item, plot in plots.items(): 1904 if fitpage_name in plot.name: 1905 data_shown = True 1906 self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id) 1907 # return the last data item seen, if nothing was plotted; supposed to be just data) 1908 return None if data_shown else item 1866 1909 1867 1910 def onOptionsUpdate(self): … … 2093 2136 self.kernel_module = self.models[model_name]() 2094 2137 2138 # Change the model name to a monicker 2139 self.kernel_module.name = self.modelName() 2140 2095 2141 # Explicitly add scale and background with default values 2096 2142 temp_undo_state = self.undo_supported … … 2125 2171 # Structure factor is the only selected model; build it and show all its params 2126 2172 self.kernel_module = self.models[structure_factor]() 2173 self.kernel_module.name = self.modelName() 2127 2174 s_params = self.kernel_module._model_info.parameters 2128 2175 s_params_orig = s_params … … 2135 2182 2136 2183 self.kernel_module = MultiplicationModel(p_kernel, s_kernel) 2184 # Modify the name to correspond to shown items 2185 self.kernel_module.name = self.modelName() 2137 2186 all_params = self.kernel_module._model_info.parameters.kernel_parameters 2138 2187 all_param_names = [param.name for param in all_params] … … 2440 2489 # Bring the GUI to normal state 2441 2490 self.enableInteractiveElements() 2442 2491 if return_data is None: 2492 self.calculateDataFailed("Results not available.") 2493 return 2443 2494 fitted_data = self.logic.new1DPlot(return_data, self.tab_id) 2495 2444 2496 residuals = self.calculateResiduals(fitted_data) 2445 2497 self.model_data = fitted_data -
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
raed0532 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.