- Timestamp:
- Sep 21, 2018 10:34:54 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:
- 80a327d
- Parents:
- 6fbb859 (diff), dad086f (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:
-
- 35 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
r2b8286c r30bed93 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): 577 # Don't create plots which are already displayed 577 578 continue 578 579 # Don't plot intermediate results, e.g. P(Q), S(Q) 579 580 match = GuiUtils.theory_plot_ID_pattern.match(plot.id) 580 # 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)]") 581 583 if match and match.groups()[1] != None: 582 584 continue 583 # Don't include plots from different fitpages, but always include the original data 584 if fitpage_name in plot.name or filename == plot.name: 585 # 'sophisticated' test to generate standalone plot for residuals 586 if 'esiduals' in plot.title: 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): 590 # Residuals get their own plot 591 if plot.plot_role == Data1D.ROLE_RESIDUAL: 587 592 plot.yscale='linear' 588 593 self.plotData([(item, plot)]) … … 597 602 Forces display of charts for the given data set 598 603 """ 599 plot_to_show = data_list[0] 600 # passed plot is used ONLY to figure out its title, 601 # so all the charts related by it can be pulled from 602 # the data explorer indices. 603 filename = plot_to_show.filename 604 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) 605 635 606 636 def addDataPlot2D(self, plot_set, item): … … 686 716 687 717 # Update the active chart list 688 #self.active_plots[new_plot.data.id] = new_plot718 self.active_plots[new_plot.data.name] = new_plot 689 719 690 720 def appendPlot(self): … … 700 730 # old plot data 701 731 plot_id = str(self.cbgraph.currentText()) 702 703 assert plot_id in PlotHelper.currentPlots(), "No such plot: %s"%(plot_id) 732 try: 733 assert plot_id in PlotHelper.currentPlots(), "No such plot: %s"%(plot_id) 734 except: 735 return 704 736 705 737 old_plot = PlotHelper.plotById(plot_id) … … 729 761 data_id = data.name 730 762 if data_id in ids_keys: 731 self.active_plots[data_id].replacePlot(data_id, data) 763 # We have data, let's replace data that needs replacing 764 if data.plot_role != Data1D.ROLE_DATA: 765 self.active_plots[data_id].replacePlot(data_id, data) 732 766 return True 733 767 elif data_id in ids_vals: 734 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 768 if data.plot_role != Data1D.ROLE_DATA: 769 list(self.active_plots.values())[ids_vals.index(data_id)].replacePlot(data_id, data) 735 770 return True 736 771 return False … … 946 981 self.context_menu.addAction(self.actionQuick3DPlot) 947 982 self.context_menu.addAction(self.actionEditMask) 983 #self.context_menu.addSeparator() 984 #self.context_menu.addAction(self.actionFreezeResults) 948 985 self.context_menu.addSeparator() 949 986 self.context_menu.addAction(self.actionDelete) … … 957 994 self.actionEditMask.triggered.connect(self.showEditDataMask) 958 995 self.actionDelete.triggered.connect(self.deleteItem) 996 self.actionFreezeResults.triggered.connect(self.freezeSelectedItems) 959 997 960 998 def onCustomContextMenu(self, position): … … 977 1015 self.actionQuick3DPlot.setEnabled(is_2D) 978 1016 self.actionEditMask.setEnabled(is_2D) 1017 1018 # Freezing 1019 # check that the selection has inner items 1020 freeze_enabled = False 1021 if model_item.parent() is not None: 1022 freeze_enabled = True 1023 self.actionFreezeResults.setEnabled(freeze_enabled) 1024 979 1025 # Fire up the menu 980 1026 self.context_menu.exec_(self.current_view.mapToGlobal(position)) … … 1112 1158 mask_editor.exec_() 1113 1159 1160 def freezeItem(self, item=None): 1161 """ 1162 Freeze given item 1163 """ 1164 if item is None: 1165 return 1166 self.model.beginResetModel() 1167 new_item = self.cloneTheory(item) 1168 self.model.appendRow(new_item) 1169 self.model.endResetModel() 1170 1171 def freezeSelectedItems(self): 1172 """ 1173 Freeze selected items 1174 """ 1175 indices = self.treeView.selectedIndexes() 1176 1177 proxy = self.treeView.model() 1178 model = proxy.sourceModel() 1179 1180 for index in indices: 1181 row_index = proxy.mapToSource(index) 1182 item_to_copy = model.itemFromIndex(row_index) 1183 if item_to_copy and item_to_copy.isCheckable(): 1184 self.freezeItem(item_to_copy) 1185 1114 1186 def deleteItem(self): 1115 1187 """ … … 1272 1344 1273 1345 # Caption for the theories 1274 checkbox_item.setChild(2, QtGui.QStandardItem(" THEORIES"))1346 checkbox_item.setChild(2, QtGui.QStandardItem("FIT RESULTS")) 1275 1347 1276 1348 # 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/GuiManager.py
r5b144c6 rdad086f 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 … … 118 119 self.dockedFilesWidget.setWidget(self.filesWidget) 119 120 120 # Disable maximize/minimize and close buttons 121 self.dockedFilesWidget.setFeatures(QDockWidget.NoDockWidgetFeatures) 122 123 #self._workspace.workspace.addDockWidget(Qt.LeftDockWidgetArea, self.dockedFilesWidget) 121 # Modify menu items on widget visibility change 122 self.dockedFilesWidget.visibilityChanged.connect(self.updateContextMenus) 123 124 124 self._workspace.addDockWidget(Qt.LeftDockWidgetArea, self.dockedFilesWidget) 125 125 self._workspace.resizeDocks([self.dockedFilesWidget], [305], Qt.Horizontal) … … 137 137 self.aboutWidget = AboutBox() 138 138 self.categoryManagerWidget = CategoryManager(self._parent, manager=self) 139 self.welcomePanel = WelcomePanel()140 139 self.grid_window = None 141 140 self._workspace.toolBar.setVisible(LocalConfig.TOOLBAR_SHOW) … … 165 164 logger.error(traceback.format_exc()) 166 165 166 def updateContextMenus(self, visible=False): 167 """ 168 Modify the View/Data Explorer menu item text on widget visibility 169 """ 170 if visible: 171 self._workspace.actionHide_DataExplorer.setText("Hide Data Explorer") 172 else: 173 self._workspace.actionHide_DataExplorer.setText("Show Data Explorer") 174 167 175 def statusBarSetup(self): 168 176 """ … … 233 241 perspective_width = perspective_size.width() 234 242 self._current_perspective.resize(perspective_width, workspace_height-10) 235 # Resize the mdi area to match the widget within236 subwindow.resize(subwindow.minimumSizeHint())237 243 238 244 self._current_perspective.show() … … 380 386 self.communicate.statusBarUpdateSignal.emit(msg) 381 387 382 def showWelcomeMessage(self):388 def actionWelcome(self): 383 389 """ Show the Welcome panel """ 390 self.welcomePanel = WelcomePanel() 384 391 self._workspace.workspace.addSubWindow(self.welcomePanel) 385 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() 386 406 387 407 def addCallbacks(self): … … 405 425 Trigger definitions for all menu/toolbar actions. 406 426 """ 427 # disable not yet fully implemented actions 428 self._workspace.actionOpen_Analysis.setEnabled(False) 429 self._workspace.actionUndo.setEnabled(False) 430 self._workspace.actionRedo.setEnabled(False) 431 self._workspace.actionReset.setEnabled(False) 432 self._workspace.actionStartup_Settings.setEnabled(False) 433 self._workspace.actionImage_Viewer.setEnabled(False) 434 self._workspace.actionCombine_Batch_Fit.setEnabled(False) 435 self._workspace.actionFit_Results.setEnabled(False) 436 407 437 # File 408 438 self._workspace.actionLoadData.triggered.connect(self.actionLoadData) … … 427 457 self._workspace.actionStartup_Settings.triggered.connect(self.actionStartup_Settings) 428 458 self._workspace.actionCategory_Manager.triggered.connect(self.actionCategory_Manager) 459 self._workspace.actionHide_DataExplorer.triggered.connect(self.actionHide_DataExplorer) 429 460 # Tools 430 461 self._workspace.actionData_Operation.triggered.connect(self.actionData_Operation) … … 469 500 self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge) 470 501 self._workspace.actionAbout.triggered.connect(self.actionAbout) 502 self._workspace.actionWelcomeWidget.triggered.connect(self.actionWelcome) 471 503 self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update) 472 504 … … 617 649 pass 618 650 651 def actionHide_DataExplorer(self): 652 """ 653 Toggle Data Explorer vsibility 654 """ 655 if self.dockedFilesWidget.isVisible(): 656 #self._workspace.actionHide_DataExplorer.setText("Show Data Explorer") 657 self.dockedFilesWidget.setVisible(False) 658 else: 659 #self._workspace.actionHide_DataExplorer.setText("Hide Data Explorer") 660 self.dockedFilesWidget.setVisible(True) 661 pass 662 619 663 def actionStartup_Settings(self): 620 664 """ … … 958 1002 When setting a perspective, sets up the menu bar 959 1003 """ 1004 self._workspace.actionReport.setEnabled(False) 960 1005 if isinstance(perspective, Perspectives.PERSPECTIVES["Fitting"]): 961 1006 self.checkAnalysisOption(self._workspace.actionFitting) … … 967 1012 self._workspace.menubar.addAction(self._workspace.menuWindow.menuAction()) 968 1013 self._workspace.menubar.addAction(self._workspace.menuHelp.menuAction()) 1014 self._workspace.actionReport.setEnabled(True) 969 1015 970 1016 elif isinstance(perspective, Perspectives.PERSPECTIVES["Invariant"]): -
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 rfc5d2d7f 74 74 <addaction name="separator"/> 75 75 <addaction name="actionHide_Toolbar"/> 76 <addaction name="actionHide_DataExplorer"/> 76 77 <addaction name="separator"/> 77 78 <addaction name="actionStartup_Settings"/> … … 147 148 <addaction name="separator"/> 148 149 <addaction name="actionAbout"/> 150 <addaction name="actionWelcomeWidget"/> 151 <addaction name="separator"/> 149 152 <addaction name="actionCheck_for_update"/> 150 153 </widget> … … 415 418 </property> 416 419 </action> 417 420 <action name="actionEditMask"> 418 421 <property name="text"> 419 422 <string>Edit Mask</string> … … 549 552 <action name="actionFreeze_Theory"> 550 553 <property name="text"> 551 <string>Freeze Theory</string> 554 <string>Freeze Fit Results</string> 555 </property> 556 </action> 557 <action name="actionHide_DataExplorer"> 558 <property name="text"> 559 <string>Hide Data Explorer</string> 560 </property> 561 </action> 562 <action name="actionWelcomeWidget"> 563 <property name="text"> 564 <string>Welcome to SasView</string> 552 565 </property> 553 566 </action> -
src/sas/qtgui/MainWindow/UnitTesting/GuiManagerTest.py
r144fe21 r768387e0 53 53 self.assertIsInstance(self.manager.dockedFilesWidget, QDockWidget) 54 54 self.assertIsInstance(self.manager.dockedFilesWidget.widget(), DataExplorerWindow) 55 self.assertEqual(self.manager.dockedFilesWidget.features(), QDockWidget.NoDockWidgetFeatures)56 55 self.assertEqual(self.manager._workspace.dockWidgetArea(self.manager.dockedFilesWidget), Qt.LeftDockWidgetArea) 57 56 -
src/sas/qtgui/Perspectives/Fitting/ComplexConstraint.py
raed0532 r305114c 13 13 import webbrowser 14 14 15 from sas.qtgui.Perspectives.Fitting import FittingUtilities 15 16 import sas.qtgui.Utilities.GuiUtils as GuiUtils 16 17 ALLOWED_OPERATORS = ['=','<','>','>=','<='] … … 32 33 self.operator = '=' 33 34 35 self.warning = self.lblWarning.text() 34 36 self.setupData() 37 self.setupSignals() 35 38 self.setupWidgets() 36 self.setupSignals()37 39 self.setupTooltip() 38 39 self.setFixedSize(self.minimumSizeHint())40 40 41 41 # Default focus is on OK … … 101 101 # Find out the signal source 102 102 source = self.sender().objectName() 103 param1 = self.cbParam1.currentText() 104 param2 = self.cbParam2.currentText() 103 105 if source == "cbParam1": 104 self.txtParam.setText(self.tab_names[0] + ":" + self.cbParam1.currentText())106 self.txtParam.setText(self.tab_names[0] + ":" + param1) 105 107 else: 106 self.txtConstraint.setText(self.tab_names[1] + "." + self.cbParam2.currentText()) 108 self.txtConstraint.setText(self.tab_names[1] + "." + param2) 109 # Check if any of the parameters are polydisperse 110 params_list = [param1, param2] 111 all_pars = [tab.model_parameters for tab in self.tabs] 112 is2Ds = [tab.is2D for tab in self.tabs] 113 txt = "" 114 for pars, is2D in zip(all_pars, is2Ds): 115 if any([FittingUtilities.isParamPolydisperse(p, pars, is2D) for p in params_list]): 116 # no parameters are pd - reset the text to not show the warning 117 txt = self.warning 118 self.lblWarning.setText(txt) 119 107 120 108 121 def onOperatorChange(self, index): -
src/sas/qtgui/Perspectives/Fitting/FittingLogic.py
r5a96a72 radf1c2a 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/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
r01b4877 r30bed93 23 23 24 24 poly_header_tooltips = ['Select parameter for fitting', 25 'Enter polydispersity ratio (S TD/mean). '26 ' STD: standard deviation from the mean value',25 'Enter polydispersity ratio (Std deviation/mean).\n'+ 26 'For angles this can be either std deviation or half width (for uniform distributions) in degrees', 27 27 'Enter minimum value for parameter', 28 28 'Enter maximum value for parameter', … … 128 128 129 129 # Find param in volume_params 130 for p in parameters.form_volume_parameters: 130 poly_pars = copy.deepcopy(parameters.form_volume_parameters) 131 if is2D: 132 poly_pars += parameters.orientation_parameters 133 for p in poly_pars: 131 134 if p.name != param.name: 132 135 continue … … 567 570 return residuals 568 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 569 595 def binary_encode(i, digits): 570 596 return [i >> d & 1 for d in range(digits)] … … 777 803 778 804 return output_string 805 806 def isParamPolydisperse(param_name, kernel_params, is2D=False): 807 """ 808 Simple lookup for polydispersity for the given param name 809 """ 810 parameters = kernel_params.form_volume_parameters 811 if is2D: 812 parameters += kernel_params.orientation_parameters 813 has_poly = False 814 for param in parameters: 815 if param.name==param_name and param.polydisperse: 816 has_poly = True 817 break 818 return has_poly 819 -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r6fbb859 radf1c2a 28 28 from sas.qtgui.Plotting.PlotterData import Data1D 29 29 from sas.qtgui.Plotting.PlotterData import Data2D 30 from sas.qtgui.Plotting.Plotter import PlotterWidget 30 31 31 32 from sas.qtgui.Perspectives.Fitting.UI.FittingWidgetUI import Ui_FittingWidgetUI … … 57 58 DEFAULT_POLYDISP_FUNCTION = 'gaussian' 58 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 59 73 60 74 logger = logging.getLogger(__name__) … … 273 287 self.theory_item = None 274 288 289 # list column widths 290 self.lstParamHeaderSizes = {} 291 275 292 # signal communicator 276 293 self.communicate = self.parent.communicate … … 361 378 self.lstParams.customContextMenuRequested.connect(self.showModelContextMenu) 362 379 self.lstParams.setAttribute(QtCore.Qt.WA_MacShowFocusRect, False) 380 # Column resize signals 381 self.lstParams.header().sectionResized.connect(self.onColumnWidthUpdate) 382 363 383 # Poly model displayed in poly list 364 384 self.lstPoly.setModel(self._poly_model) … … 642 662 # Create and display the widget for param1 and param2 643 663 mc_widget = MultiConstraint(self, params=params_list) 664 # Check if any of the parameters are polydisperse 665 if not np.any([FittingUtilities.isParamPolydisperse(p, self.model_parameters, is2D=self.is2D) for p in params_list]): 666 # no parameters are pd - reset the text to not show the warning 667 mc_widget.lblWarning.setText("") 644 668 if mc_widget.exec_() != QtWidgets.QDialog.Accepted: 645 669 return … … 1061 1085 if not self.rowHasConstraint(row): 1062 1086 return 1087 constr = self.getConstraintForRow(row) 1063 1088 func = self.getConstraintForRow(row).func 1064 if func is not None: 1065 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) 1066 1099 1067 1100 def replaceConstraintName(self, old_name, new_name=""): … … 1100 1133 # Create default datasets if no data passed 1101 1134 self.createDefaultDataset() 1135 self.theory_item = None # ensure theory is recalc. before plot, see showTheoryPlot() 1102 1136 1103 1137 def respondToModelStructure(self, model=None, structure_factor=None): … … 1107 1141 # kernel parameters -> model_model 1108 1142 self.SASModelToQModel(model, structure_factor) 1143 1144 for column, width in self.lstParamHeaderSizes.items(): 1145 self.lstParams.setColumnWidth(column, width) 1109 1146 1110 1147 # Update plot … … 1219 1256 if model_column in [delegate.poly_pd, delegate.poly_error, delegate.poly_min, delegate.poly_max]: 1220 1257 row = self.getRowFromName(parameter_name) 1221 param_item = self._model_model.item(row) 1258 param_item = self._model_model.item(row).child(0).child(0, model_column) 1259 if param_item is None: 1260 return 1222 1261 self._model_model.blockSignals(True) 1223 param_item. child(0).child(0, model_column).setText(item.text())1262 param_item.setText(item.text()) 1224 1263 self._model_model.blockSignals(False) 1225 1264 … … 1366 1405 self.communicate.statusBarUpdateSignal.emit('Fitting started...') 1367 1406 self.fit_started = True 1407 1368 1408 # Disable some elements 1369 self. setFittingStarted()1409 self.disableInteractiveElements() 1370 1410 1371 1411 def stopFit(self): … … 1376 1416 return 1377 1417 self.calc_fit.stop() 1378 #self.fit_started=False1379 1418 #re-enable the Fit button 1380 self. setFittingStopped()1419 self.enableInteractiveElements() 1381 1420 1382 1421 msg = "Fitting cancelled." … … 1392 1431 """ 1393 1432 """ 1394 self. setFittingStopped()1433 self.enableInteractiveElements() 1395 1434 msg = "Fitting failed with: "+ str(reason) 1396 1435 self.communicate.statusBarUpdateSignal.emit(msg) … … 1409 1448 """ 1410 1449 #re-enable the Fit button 1411 self. setFittingStopped()1450 self.enableInteractiveElements() 1412 1451 1413 1452 if len(result) == 0: … … 1481 1520 """ 1482 1521 #re-enable the Fit button 1483 self. setFittingStopped()1522 self.enableInteractiveElements() 1484 1523 1485 1524 if len(result) == 0: … … 1666 1705 self.iterateOverModel(updatePolyValues) 1667 1706 self._model_model.itemChanged.connect(self.onMainParamsChange) 1668 1669 # Adjust the table cells width.1670 # TODO: find a way to dynamically adjust column width while resized expanding1671 self.lstParams.resizeColumnToContents(0)1672 self.lstParams.resizeColumnToContents(4)1673 self.lstParams.resizeColumnToContents(5)1674 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)1675 1707 1676 1708 def iterateOverPolyModel(self, func): … … 1813 1845 self.cmdPlot.setText("Show Plot") 1814 1846 # Force data recalculation so existing charts are updated 1815 self.showPlot() 1847 if not self.data_is_loaded: 1848 self.showTheoryPlot() 1849 else: 1850 self.showPlot() 1816 1851 # This is an important processEvent. 1817 1852 # This allows charts to be properly updated in order 1818 1853 # of plots being applied. 1819 1854 QtWidgets.QApplication.processEvents() 1820 self.recalculatePlotData() 1855 self.recalculatePlotData() # recalc+plot theory again (2nd) 1821 1856 1822 1857 def onSmearingOptionsUpdate(self): … … 1834 1869 self.calculateQGridForModel() 1835 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 1836 1881 def showPlot(self): 1837 1882 """ … … 1839 1884 """ 1840 1885 # Show the chart if ready 1841 data_to_show = self.data if self.data_is_loaded else self.model_data 1842 if data_to_show is not None: 1843 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 1844 1909 1845 1910 def onOptionsUpdate(self): … … 2013 2078 self.setMagneticModel() 2014 2079 2015 # Adjust the table cells width2016 self.lstParams.resizeColumnToContents(0)2017 self.lstParams.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Expanding)2018 2019 2080 # Now we claim the model has been loaded 2020 2081 self.model_is_loaded = True … … 2075 2136 self.kernel_module = self.models[model_name]() 2076 2137 2138 # Change the model name to a monicker 2139 self.kernel_module.name = self.modelName() 2140 2077 2141 # Explicitly add scale and background with default values 2078 2142 temp_undo_state = self.undo_supported … … 2107 2171 # Structure factor is the only selected model; build it and show all its params 2108 2172 self.kernel_module = self.models[structure_factor]() 2173 self.kernel_module.name = self.modelName() 2109 2174 s_params = self.kernel_module._model_info.parameters 2110 2175 s_params_orig = s_params … … 2117 2182 2118 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() 2119 2186 all_params = self.kernel_module._model_info.parameters.kernel_parameters 2120 2187 all_param_names = [param.name for param in all_params] … … 2404 2471 2405 2472 # add polydisperse parameters if asked 2406 if self.chkPolydispersity.isChecked() :2473 if self.chkPolydispersity.isChecked() and self._poly_model.rowCount() > 0: 2407 2474 for key, value in self.poly_params.items(): 2408 2475 model.setParam(key, value) 2409 2476 # add magnetic params if asked 2410 2477 if self.chkMagnetism.isChecked(): 2411 for key, value in self.magnet_params.items() :2478 for key, value in self.magnet_params.items() and self._magnet_model.rowCount() > 0: 2412 2479 model.setParam(key, value) 2413 2480 … … 2427 2494 weight = FittingUtilities.getWeight(data=data, is2d=self.is2D, flag=self.weighting) 2428 2495 2496 # Disable buttons/table 2497 self.disableInteractiveElements() 2429 2498 # Awful API to a backend method. 2430 2499 calc_thread = self.methodCalculateForData()(data=data, … … 2468 2537 Thread returned error 2469 2538 """ 2539 # Bring the GUI to normal state 2540 self.enableInteractiveElements() 2470 2541 print("Calculate Data failed with ", reason) 2471 2542 … … 2480 2551 Plot the current 1D data 2481 2552 """ 2553 # Bring the GUI to normal state 2554 self.enableInteractiveElements() 2555 if return_data is None: 2556 self.calculateDataFailed("Results not available.") 2557 return 2482 2558 fitted_data = self.logic.new1DPlot(return_data, self.tab_id) 2559 2483 2560 residuals = self.calculateResiduals(fitted_data) 2484 2561 self.model_data = fitted_data … … 2488 2565 2489 2566 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)) 2567 # delete any plots associated with the data that were not updated 2568 # (e.g. to remove beta(Q), S_eff(Q)) 2491 2569 GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 2492 2570 pass 2493 2571 else: 2494 # delete theory items for the model, in order to get rid of any redundant items, e.g. beta(Q), S_eff(Q) 2572 # delete theory items for the model, in order to get rid of any 2573 # redundant items, e.g. beta(Q), S_eff(Q) 2495 2574 self.communicate.deleteIntermediateTheoryPlotsSignal.emit(self.kernel_module.id) 2575 2576 # Create plots for parameters with enabled polydispersity 2577 for plot in FittingUtilities.plotPolydispersities(return_data.get('model', None)): 2578 data_id = fitted_data.id.split() 2579 plot.id = "{} [{}] {}".format(data_id[0], plot.name, " ".join(data_id[1:])) 2580 data_name = fitted_data.name.split() 2581 plot.name = " ".join([data_name[0], plot.name] + data_name[1:]) 2582 self.createNewIndex(plot) 2583 new_plots.append(plot) 2496 2584 2497 2585 # Create plots for intermediate product data … … 2540 2628 Plot the current 2D data 2541 2629 """ 2630 # Bring the GUI to normal state 2631 self.enableInteractiveElements() 2632 2542 2633 fitted_data = self.logic.new2DPlot(return_data) 2543 2634 residuals = self.calculateResiduals(fitted_data) … … 2574 2665 residuals_plot = FittingUtilities.plotResiduals(self.data, weighted_data) 2575 2666 residuals_plot.id = "Residual " + residuals_plot.id 2667 residuals_plot.plot_role = Data1D.ROLE_RESIDUAL 2576 2668 self.createNewIndex(residuals_plot) 2577 2669 return residuals_plot … … 2609 2701 Thread threw an exception. 2610 2702 """ 2703 # Bring the GUI to normal state 2704 self.enableInteractiveElements() 2611 2705 # TODO: remimplement thread cancellation 2612 2706 logger.error("".join(traceback.format_exception(etype, value, tb))) … … 2820 2914 self._poly_model.setData(fname_index, fname) 2821 2915 2916 def onColumnWidthUpdate(self, index, old_size, new_size): 2917 """ 2918 Simple state update of the current column widths in the param list 2919 """ 2920 self.lstParamHeaderSizes[index] = new_size 2921 2822 2922 def setMagneticModel(self): 2823 2923 """ … … 2891 2991 2892 2992 func = QtWidgets.QComboBox() 2893 # Available range of shells displayed in the combobox2894 func.addItems([str(i) for i in range(param_length+1)])2895 2896 # Respond to index change2897 func.currentIndexChanged.connect(self.modifyShellsInList)2898 2993 2899 2994 # cell 2: combobox 2900 2995 item2 = QtGui.QStandardItem() 2901 self._model_model.appendRow([item1, item2]) 2996 2997 # cell 3: min value 2998 item3 = QtGui.QStandardItem() 2999 3000 # cell 4: max value 3001 item4 = QtGui.QStandardItem() 3002 3003 # cell 4: SLD button 3004 item5 = QtGui.QStandardItem() 3005 button = QtWidgets.QPushButton() 3006 button.setText("Show SLD Profile") 3007 3008 self._model_model.appendRow([item1, item2, item3, item4, item5]) 2902 3009 2903 3010 # Beautify the row: span columns 2-4 2904 3011 shell_row = self._model_model.rowCount() 2905 3012 shell_index = self._model_model.index(shell_row-1, 1) 3013 button_index = self._model_model.index(shell_row-1, 4) 2906 3014 2907 3015 self.lstParams.setIndexWidget(shell_index, func) 3016 self.lstParams.setIndexWidget(button_index, button) 2908 3017 self._n_shells_row = shell_row - 1 2909 3018 … … 2918 3027 logger.error("Could not find %s in kernel parameters.", param_name) 2919 3028 default_shell_count = shell_par.default 3029 shell_min = 0 3030 shell_max = 0 3031 try: 3032 shell_min = int(shell_par.limits[0]) 3033 shell_max = int(shell_par.limits[1]) 3034 except IndexError as ex: 3035 # no info about limits 3036 pass 3037 item3.setText(str(shell_min)) 3038 item4.setText(str(shell_max)) 3039 3040 # Respond to index change 3041 func.currentTextChanged.connect(self.modifyShellsInList) 3042 3043 # Respond to button press 3044 button.clicked.connect(self.onShowSLDProfile) 3045 3046 # Available range of shells displayed in the combobox 3047 func.addItems([str(i) for i in range(shell_min, shell_max+1)]) 2920 3048 2921 3049 # Add default number of shells to the model 2922 func.setCurrent Index(default_shell_count)2923 2924 def modifyShellsInList(self, index):3050 func.setCurrentText(str(default_shell_count)) 3051 3052 def modifyShellsInList(self, text): 2925 3053 """ 2926 3054 Add/remove additional multishell parameters … … 2929 3057 first_row = self._n_shells_row + 1 2930 3058 remove_rows = self._num_shell_params 2931 3059 try: 3060 index = int(text) 3061 except ValueError: 3062 # bad text on the control! 3063 index = 0 3064 logger.error("Multiplicity incorrect! Setting to 0") 3065 self.kernel_module.multiplicity = index 2932 3066 if remove_rows > 1: 2933 3067 self._model_model.removeRows(first_row, remove_rows) … … 2956 3090 self.setMagneticModel() 2957 3091 2958 def setFittingStarted(self): 2959 """ 2960 Set buttion caption on fitting start 3092 def onShowSLDProfile(self): 3093 """ 3094 Show a quick plot of SLD profile 3095 """ 3096 # get profile data 3097 x, y = self.kernel_module.getProfile() 3098 y *= 1.0e6 3099 profile_data = Data1D(x=x, y=y) 3100 profile_data.name = "SLD" 3101 profile_data.scale = 'linear' 3102 profile_data.symbol = 'Line' 3103 profile_data.hide_error = True 3104 profile_data._xaxis = "R(\AA)" 3105 profile_data._yaxis = "SLD(10^{-6}\AA^{-2})" 3106 3107 plotter = PlotterWidget(self, quickplot=True) 3108 plotter.data = profile_data 3109 plotter.showLegend = True 3110 plotter.plot(hide_error=True, marker='-') 3111 3112 self.plot_widget = QtWidgets.QWidget() 3113 self.plot_widget.setWindowTitle("Scattering Length Density Profile") 3114 layout = QtWidgets.QVBoxLayout() 3115 layout.addWidget(plotter) 3116 self.plot_widget.setLayout(layout) 3117 self.plot_widget.show() 3118 3119 def setInteractiveElements(self, enabled=True): 3120 """ 3121 Switch interactive GUI elements on/off 3122 """ 3123 assert isinstance(enabled, bool) 3124 3125 self.lstParams.setEnabled(enabled) 3126 self.lstPoly.setEnabled(enabled) 3127 self.lstMagnetic.setEnabled(enabled) 3128 3129 self.cbCategory.setEnabled(enabled) 3130 self.cbModel.setEnabled(enabled) 3131 self.cbStructureFactor.setEnabled(enabled) 3132 3133 self.chkPolydispersity.setEnabled(enabled) 3134 self.chkMagnetism.setEnabled(enabled) 3135 self.chk2DView.setEnabled(enabled) 3136 3137 def enableInteractiveElements(self): 3138 """ 3139 Set buttion caption on fitting/calculate finish 3140 Enable the param table(s) 3141 """ 3142 # Notify the user that fitting is available 3143 self.cmdFit.setStyleSheet('QPushButton {color: black;}') 3144 self.cmdFit.setText("Fit") 3145 self.fit_started = False 3146 self.setInteractiveElements(True) 3147 3148 def disableInteractiveElements(self): 3149 """ 3150 Set buttion caption on fitting/calculate start 3151 Disable the param table(s) 2961 3152 """ 2962 3153 # Notify the user that fitting is being run … … 2964 3155 self.cmdFit.setStyleSheet('QPushButton {color: red;}') 2965 3156 self.cmdFit.setText('Stop fit') 2966 2967 def setFittingStopped(self): 2968 """ 2969 Set button caption on fitting stop 2970 """ 2971 # Notify the user that fitting is available 2972 self.cmdFit.setStyleSheet('QPushButton {color: black;}') 2973 self.cmdFit.setText("Fit") 2974 self.fit_started = False 3157 self.setInteractiveElements(False) 2975 3158 2976 3159 def readFitPage(self, fp): -
src/sas/qtgui/Perspectives/Fitting/MultiConstraint.py
raed0532 r305114c 28 28 29 29 self.setupUi(self) 30 self.setFixedSize(self.minimumSizeHint())31 30 self.setModal(True) 32 31 self.params = params -
src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui
ra90c9c5 r1738173 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 406</width>10 <height>1 67</height>9 <width>367</width> 10 <height>199</height> 11 11 </rect> 12 12 </property> … … 21 21 </property> 22 22 <layout class="QGridLayout" name="gridLayout"> 23 <item row="1" column="0"> 24 <layout class="QHBoxLayout" name="horizontalLayout_2"> 25 <item> 26 <widget class="QLabel" name="txtParam"> 27 <property name="sizePolicy"> 28 <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> 29 <horstretch>0</horstretch> 30 <verstretch>0</verstretch> 31 </sizepolicy> 32 </property> 33 <property name="text"> 34 <string>param1</string> 35 </property> 36 </widget> 37 </item> 38 <item> 39 <widget class="QLabel" name="txtOperator"> 40 <property name="text"> 41 <string>=</string> 42 </property> 43 </widget> 44 </item> 45 <item> 46 <widget class="QLineEdit" name="txtConstraint"> 47 <property name="text"> 48 <string/> 49 </property> 50 </widget> 51 </item> 52 </layout> 53 </item> 23 54 <item row="0" column="0"> 24 55 <layout class="QHBoxLayout" name="horizontalLayout"> … … 98 129 </layout> 99 130 </item> 100 <item row="1" column="0">101 <spacer name="verticalSpacer">102 <property name="orientation">103 <enum>Qt::Vertical</enum>104 </property>105 <property name="sizeHint" stdset="0">106 <size>107 <width>20</width>108 <height>25</height>109 </size>110 </property>111 </spacer>112 </item>113 <item row="2" column="0">114 <layout class="QHBoxLayout" name="horizontalLayout_2">115 <item>116 <widget class="QLabel" name="txtParam">117 <property name="sizePolicy">118 <sizepolicy hsizetype="Minimum" vsizetype="Preferred">119 <horstretch>0</horstretch>120 <verstretch>0</verstretch>121 </sizepolicy>122 </property>123 <property name="text">124 <string>param1</string>125 </property>126 </widget>127 </item>128 <item>129 <widget class="QLabel" name="txtOperator">130 <property name="text">131 <string>=</string>132 </property>133 </widget>134 </item>135 <item>136 <widget class="QLineEdit" name="txtConstraint">137 <property name="text">138 <string/>139 </property>140 </widget>141 </item>142 </layout>143 </item>144 131 </layout> 145 132 </widget> 146 133 </item> 147 134 <item row="1" column="0"> 135 <widget class="QLabel" name="lblWarning"> 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 not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 138 </property> 139 </widget> 140 </item> 141 <item row="2" column="0"> 142 <spacer name="verticalSpacer_2"> 143 <property name="orientation"> 144 <enum>Qt::Vertical</enum> 145 </property> 146 <property name="sizeHint" stdset="0"> 147 <size> 148 <width>20</width> 149 <height>9</height> 150 </size> 151 </property> 152 </spacer> 153 </item> 154 <item row="3" column="0"> 148 155 <layout class="QHBoxLayout" name="horizontalLayout_3"> 149 156 <item> -
src/sas/qtgui/Perspectives/Fitting/UI/FittingWidgetUI.ui
ra2e8ea5 rc928e81 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 566</width>10 <height> 646</height>9 <width>651</width> 10 <height>540</height> 11 11 </rect> 12 12 </property> -
src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui
ra90c9c5 r1738173 10 10 <x>0</x> 11 11 <y>0</y> 12 <width> 426</width>13 <height> 162</height>12 <width>369</width> 13 <height>201</height> 14 14 </rect> 15 15 </property> 16 16 <property name="sizePolicy"> 17 <sizepolicy hsizetype="Minimum" vsizetype="Minimum ">17 <sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding"> 18 18 <horstretch>0</horstretch> 19 19 <verstretch>0</verstretch> … … 119 119 </item> 120 120 <item row="2" column="0"> 121 <widget class="QLabel" name="lblWarning"> 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 not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 124 </property> 125 </widget> 126 </item> 127 <item row="3" column="0"> 121 128 <spacer name="verticalSpacer"> 122 129 <property name="orientation"> … … 131 138 </spacer> 132 139 </item> 133 <item row=" 3" column="0">140 <item row="4" column="0"> 134 141 <layout class="QHBoxLayout" name="horizontalLayout_2"> 135 142 <item> -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
rf712bf30 r8faac15 393 393 394 394 # Test tooltips 395 self.assertEqual(len(self.widget._poly_model.header_tooltips), 8)395 self.assertEqual(len(self.widget._poly_model.header_tooltips), 9) 396 396 397 397 header_tooltips = ['Select parameter for fitting', 398 'Enter polydispersity ratio (STD/mean). '399 'STD: standard deviation from the mean value',400 401 402 403 404 405 398 'Enter polydispersity ratio (Std deviation/mean).\n'+ 399 'For angles this can be either std deviation or half width (for uniform distributions) in degrees', 400 'Enter minimum value for parameter', 401 'Enter maximum value for parameter', 402 'Enter number of points for parameter', 403 'Enter number of sigmas parameter', 404 'Select distribution function', 405 'Select filename with user-definable distribution'] 406 406 for column, tooltip in enumerate(header_tooltips): 407 407 self.assertEqual(self.widget._poly_model.headerData( column, … … 619 619 # Set to 0 620 620 self.widget.lstParams.indexWidget(func_index).setCurrentIndex(0) 621 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) 622 622 623 623 def testPlotTheory(self): … … 657 657 self.assertEqual(spy.count(), 0) 658 658 659 def testPlotData(self):659 def notestPlotData(self): 660 660 """ 661 661 See that data item can produce a chart … … 908 908 self.assertFalse(self.widget.tabFitting.isTabEnabled(4)) 909 909 910 def testReadFitPage2D(self): 910 # to be fixed after functionality is ready 911 def notestReadFitPage2D(self): 911 912 """ 912 913 Read in the fitpage object and restore state -
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
r2b8286c rdee9e5f 14 14 # pr inversion calculation elements 15 15 from sas.sascalc.pr.invertor import Invertor 16 from sas.qtgui.Plotting.PlotterData import Data1D 16 17 # Batch calculation display 17 18 from sas.qtgui.Utilities.GridPanel import BatchInversionOutputPanel … … 43 44 estimateSignal = QtCore.pyqtSignal(tuple) 44 45 estimateNTSignal = QtCore.pyqtSignal(tuple) 46 estimateDynamicNTSignal = QtCore.pyqtSignal(tuple) 47 estimateDynamicSignal = QtCore.pyqtSignal(tuple) 45 48 calculateSignal = QtCore.pyqtSignal(tuple) 46 49 … … 52 55 53 56 self._manager = parent 57 #Needed for Batch fitting 58 self._parent = parent 54 59 self.communicate = parent.communicator() 55 60 self.communicate.dataDeletedSignal.connect(self.removeData) … … 109 114 # Set up the Widget Map 110 115 self.setupMapper() 116 117 #Hidding calculate all buton 118 self.calculateAllButton.setVisible(False) 111 119 # Set base window state 112 120 self.setupWindow() … … 119 127 120 128 def allowBatch(self): 121 return True129 return False 122 130 123 131 def setClosable(self, value=True): … … 194 202 self.model.itemChanged.connect(self.model_changed) 195 203 self.estimateNTSignal.connect(self._estimateNTUpdate) 204 self.estimateDynamicNTSignal.connect(self._estimateDynamicNTUpdate) 205 self.estimateDynamicSignal.connect(self._estimateDynamicUpdate) 196 206 self.estimateSignal.connect(self._estimateUpdate) 197 207 self.calculateSignal.connect(self._calculateUpdate) 208 209 self.maxDistanceInput.textEdited.connect(self.performEstimateDynamic) 198 210 199 211 def setupMapper(self): … … 309 321 and not self.isCalculating) 310 322 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)) 323 self.explorerButton.setEnabled(self.logic.data_is_loaded) 313 324 self.stopButton.setVisible(self.isCalculating) 314 325 self.regConstantSuggestionButton.setEnabled( … … 453 464 # Create initial internal mappings 454 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 455 470 # Estimate q range 456 471 qmin, qmax = self.logic.computeDataRange() 457 472 self._calculator.set_qmin(qmin) 458 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) 459 476 self.updateDataList(data) 460 477 self.populateDataComboBox(self.logic.data.filename, data) 461 478 self.dataList.setCurrentIndex(len(self.dataList) - 1) 462 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) 463 482 464 483 def updateDataList(self, dataRef): … … 501 520 self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 502 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() 503 533 504 534 def updateGuiValues(self): … … 520 550 self.model.setItem(WIDGETS.W_MAX_DIST, 521 551 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 552 526 553 if isinstance(pr.chi2, np.ndarray): … … 544 571 if self.prPlot is not None: 545 572 title = self.prPlot.name 573 self.prPlot.plot_role = Data1D.ROLE_RESIDUAL 546 574 GuiUtils.updateModelItemWithPlot(self._data, self.prPlot, title) 547 self.communicate.plotRequestedSignal.emit([self. prPlot], None)575 self.communicate.plotRequestedSignal.emit([self._data,self.prPlot], None) 548 576 if self.dataPlot is not None: 549 577 title = self.dataPlot.name 578 self.dataPlot.plot_role = Data1D.ROLE_DEFAULT 579 self.dataPlot.symbol = "Line" 580 self.dataPlot.show_errors = False 550 581 GuiUtils.updateModelItemWithPlot(self._data, self.dataPlot, title) 551 self.communicate.plotRequestedSignal.emit([self. dataPlot], None)582 self.communicate.plotRequestedSignal.emit([self._data,self.dataPlot], None) 552 583 self.enableButtons() 553 584 … … 633 664 634 665 pr = self._calculator.clone() 635 nfunc = self.getNFunc() 636 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, 637 669 error_func=self._threadError, 638 670 completefn=self._calculateCompleted, … … 667 699 error_func=self._threadError, 668 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, 669 726 updatefn=None) 670 727 self.estimationThreadNT.queue() … … 693 750 self.estimationThread.ready(2.5) 694 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 695 769 def stopEstimationThread(self): 696 770 """ Stop the estimation thread if it exists and is running """ … … 705 779 ''' Send a signal to the main thread for model update''' 706 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)) 707 785 708 786 def _estimateUpdate(self, output_tuple): … … 720 798 logger.info(message) 721 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() 722 816 723 817 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 724 818 ''' Send a signal to the main thread for model update''' 725 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)) 726 824 727 825 def _estimateNTUpdate(self, output_tuple): … … 747 845 self.startThread() 748 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 749 869 def _calculateCompleted(self, out, cov, pr, elapsed): 750 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/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/PlotterBase.py
rd9150d8 r863ebca 10 10 11 11 import matplotlib.pyplot as plt 12 from matplotlib import rcParams 12 13 13 14 DEFAULT_CMAP = pylab.cm.jet … … 29 30 self.manager = manager 30 31 self.quickplot = quickplot 32 33 # Set auto layout so x/y axis captions don't get cut off 34 rcParams.update({'figure.autolayout': True}) 31 35 32 36 #plt.style.use('ggplot') … … 106 110 107 111 self.contextMenu = QtWidgets.QMenu(self) 108 112 self.toolbar = NavigationToolbar(self.canvas, self) 113 layout.addWidget(self.toolbar) 109 114 if not quickplot: 110 115 # Add the toolbar 111 self.toolbar = NavigationToolbar(self.canvas, self) 112 layout.addWidget(self.toolbar) 116 self.toolbar.show() 113 117 # Notify PlotHelper about the new plot 114 118 self.upatePlotHelper() 119 else: 120 self.toolbar.hide() 115 121 116 122 self.setLayout(layout) … … 215 221 self.actionCopyToClipboard = self.contextMenu.addAction("Copy to Clipboard") 216 222 self.contextMenu.addSeparator() 223 self.actionToggleMenu = self.contextMenu.addAction("Toggle Navigation Menu") 224 self.contextMenu.addSeparator() 225 217 226 218 227 # Define the callbacks … … 220 229 self.actionPrintImage.triggered.connect(self.onImagePrint) 221 230 self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy) 231 self.actionToggleMenu.triggered.connect(self.onToggleMenu) 222 232 223 233 def createContextMenu(self): … … 367 377 self.manager.communicator.activeGraphName.emit((current_title, title)) 368 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 369 388 def offset_graph(self): 370 389 """ -
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/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
r5d28d6b r9ce69ec 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: … … 562 567 The assumption - data stored in SasView standard, in child 0 563 568 """ 564 return item.child(0).data() 569 try: 570 data = item.child(0).data() 571 except AttributeError: 572 data = None 573 return data 565 574 566 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.