Changeset 30bed93 in sasview for src/sas/qtgui/Perspectives
- Timestamp:
- Sep 21, 2018 5:41:31 AM (6 years ago)
- Branches:
- ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
- Children:
- c928e81
- Parents:
- 33d5956 (diff), d8d81ea (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Ingo Breßler <dev@…> (09/21/18 05:41:31)
- git-committer:
- GitHub <noreply@…> (09/21/18 05:41:31)
- Location:
- src/sas/qtgui/Perspectives
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
r8faac15 r30bed93 570 570 return residuals 571 571 572 def plotPolydispersities(model): 573 plots = [] 574 if model is None: 575 return plots 576 # test for model being a sasmodels.sasview_model.SasviewModel? 577 for name in model.dispersion.keys(): 578 xarr, yarr = model.get_weights(name) 579 if len(xarr) <= 1: # param name not found or no polydisp. 580 continue 581 # create Data1D as in residualsData1D() and fill x/y members 582 # similar to FittingLogic._create1DPlot() but different data/axes 583 data1d = Data1D(x=xarr, y=yarr) 584 xunit = model.details[name][0] 585 data1d.xaxis(r'\rm{{{}}}'.format(name.replace('_', '\_')), xunit) 586 data1d.yaxis(r'\rm{weight}', 'normalized') 587 data1d.scale = 'linear' 588 data1d.symbol = 'Line' 589 data1d.name = "{} polydispersity".format(name) 590 data1d.id = data1d.name # placeholder, has to be completed later 591 data1d.plot_role = Data1D.ROLE_RESIDUAL 592 plots.append(data1d) 593 return plots 594 572 595 def binary_encode(i, digits): 573 596 return [i >> d & 1 for d in range(digits)] -
src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
r33d5956 r30bed93 58 58 DEFAULT_POLYDISP_FUNCTION = 'gaussian' 59 59 60 # CRUFT: remove when new release of sasmodels is available 61 # https://github.com/SasView/sasview/pull/181#discussion_r218135162 62 from sasmodels.sasview_model import SasviewModel 63 if not hasattr(SasviewModel, 'get_weights'): 64 def get_weights(self, name): 65 """ 66 Returns the polydispersity distribution for parameter *name* as *value* and *weight* arrays. 67 """ 68 # type: (str) -> Tuple(np.ndarray, np.ndarray) 69 _, x, w = self._get_weights(self._model_info.parameters[name]) 70 return x, w 71 72 SasviewModel.get_weights = get_weights 60 73 61 74 logger = logging.getLogger(__name__) … … 2488 2501 2489 2502 if self.data_is_loaded: 2490 # delete any plots associated with the data that were not updated (e.g. to remove beta(Q), S_eff(Q)) 2503 # delete any plots associated with the data that were not updated 2504 # (e.g. to remove beta(Q), S_eff(Q)) 2491 2505 GuiUtils.deleteRedundantPlots(self.all_data[self.data_index], new_plots) 2492 2506 pass 2493 2507 else: 2494 # delete theory items for the model, in order to get rid of any redundant items, e.g. beta(Q), S_eff(Q) 2508 # delete theory items for the model, in order to get rid of any 2509 # redundant items, e.g. beta(Q), S_eff(Q) 2495 2510 self.communicate.deleteIntermediateTheoryPlotsSignal.emit(self.kernel_module.id) 2511 2512 # Create plots for parameters with enabled polydispersity 2513 for plot in FittingUtilities.plotPolydispersities(return_data.get('model', None)): 2514 data_id = fitted_data.id.split() 2515 plot.id = "{} [{}] {}".format(data_id[0], plot.name, " ".join(data_id[1:])) 2516 data_name = fitted_data.name.split() 2517 plot.name = " ".join([data_name[0], plot.name] + data_name[1:]) 2518 self.createNewIndex(plot) 2519 new_plots.append(plot) 2496 2520 2497 2521 # Create plots for intermediate product data -
src/sas/qtgui/Perspectives/Fitting/FittingOptions.py
rff3b293 r8873ab7 64 64 default_index = self.cbAlgorithm.findText(default_name) 65 65 self.cbAlgorithm.setCurrentIndex(default_index) 66 # previous algorithm choice 67 self.previous_index = default_index 66 68 67 69 # Assign appropriate validators … … 121 123 122 124 # Convert the name into widget instance 123 widget_to_activate = eval(widget_name) 125 try: 126 widget_to_activate = eval(widget_name) 127 except AttributeError: 128 # We don't yet have this optimizer. 129 # Show message 130 msg = "This algorithm has not yet been implemented in SasView.\n" 131 msg += "Please choose a different algorithm" 132 QtWidgets.QMessageBox.warning(self, 133 'Warning', 134 msg, 135 QtWidgets.QMessageBox.Ok) 136 # Move the index to previous position 137 self.cbAlgorithm.setCurrentIndex(self.previous_index) 138 return 139 124 140 index_for_this_id = self.stackedWidget.indexOf(widget_to_activate) 125 141 … … 133 149 # OK has to be reinitialized to True 134 150 self.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(True) 151 152 # keep reference 153 self.previous_index = index 135 154 136 155 def onApply(self): … … 143 162 # e.g. 'samples' for 'dream' is 'self.samples_dream' 144 163 widget_name = 'self.'+option+'_'+self.current_fitter_id 145 line_edit = eval(widget_name) 164 try: 165 line_edit = eval(widget_name) 166 except AttributeError: 167 # Skip bumps monitors 168 continue 146 169 if line_edit is None or not isinstance(line_edit, QtWidgets.QLineEdit): 147 170 continue … … 165 188 return 166 189 try: 167 new_value = widget.currentText() if isinstance(widget, QtWidgets.QComboBox) \ 168 else float(widget.text()) 190 if isinstance(widget, QtWidgets.QComboBox): 191 new_value = widget.currentText() 192 else: 193 try: 194 new_value = int(widget.text()) 195 except ValueError: 196 new_value = float(widget.text()) 197 #new_value = widget.currentText() if isinstance(widget, QtWidgets.QComboBox) \ 198 # else float(widget.text()) 169 199 self.config.values[self.current_fitter_id][option] = new_value 170 200 except ValueError: -
src/sas/qtgui/Perspectives/Fitting/UI/ComplexConstraintUI.ui
r305114c r1738173 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 463</width>10 <height> 234</height>9 <width>367</width> 10 <height>199</height> 11 11 </rect> 12 12 </property> … … 135 135 <widget class="QLabel" name="lblWarning"> 136 136 <property name="text"> 137 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are no r re-applied during size or angle polydispersity<br/>integrations. To do whichrequires creating a custom model.</p></body></html></string>137 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 138 138 </property> 139 139 </widget> -
src/sas/qtgui/Perspectives/Fitting/UI/FittingWidgetUI.ui
ra2e8ea5 rfc5d2d7f 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 566</width>9 <width>651</width> 10 10 <height>646</height> 11 11 </rect> -
src/sas/qtgui/Perspectives/Fitting/UI/MultiConstraintUI.ui
raa88b76 r1738173 10 10 <x>0</x> 11 11 <y>0</y> 12 <width> 436</width>13 <height>2 17</height>12 <width>369</width> 13 <height>201</height> 14 14 </rect> 15 15 </property> … … 121 121 <widget class="QLabel" name="lblWarning"> 122 122 <property name="text"> 123 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are no r re-applied during size or angle polydispersity<br/>integrations. To do whichrequires creating a custom model.</p></body></html></string>123 <string><html><head/><body><p><span style=" color:#ff0000;">Warning! Polydisperse parameter selected.<br/></span>Constraints involving polydisperse parameters only apply to<br/>starting values and are not re-applied during size or angle polydispersity<br/>integrations. To do so requires creating a custom model.</p></body></html></string> 124 124 </property> 125 125 </widget> -
src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py
r1a15ada r8faac15 397 397 header_tooltips = ['Select parameter for fitting', 398 398 'Enter polydispersity ratio (Std deviation/mean).\n'+ 399 'For angles this can be either std deviation or full width (for uniform distributions) in degrees', 400 'STD: standard deviation from the mean value', 399 'For angles this can be either std deviation or half width (for uniform distributions) in degrees', 401 400 'Enter minimum value for parameter', 402 401 'Enter maximum value for parameter', … … 620 619 # Set to 0 621 620 self.widget.lstParams.indexWidget(func_index).setCurrentIndex(0) 622 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) # 2 fewer rows than default621 self.assertEqual(self.widget._model_model.rowCount(), last_row - 2) 623 622 624 623 def testPlotTheory(self): … … 658 657 self.assertEqual(spy.count(), 0) 659 658 660 def testPlotData(self):659 def notestPlotData(self): 661 660 """ 662 661 See that data item can produce a chart -
src/sas/qtgui/Perspectives/Invariant/InvariantPerspective.py
raed0532 rdee9e5f 233 233 234 234 plot_data = GuiUtils.plotsFromCheckedItems(self._manager.filesWidget.model) 235 #self.communicate.plotRequestedSignal.emit([item, plot], self.tab_id) 235 236 236 237 self._manager.filesWidget.plotData(plot_data) … … 347 348 extrapolated_data.name = title 348 349 extrapolated_data.title = title 350 extrapolated_data.style = "Line" 351 extrapolated_data.has_errors = False 352 extrapolated_data.plot_role = Data1D.ROLE_DEFAULT 349 353 350 354 # copy labels and units of axes for plotting … … 378 382 high_out_data.name = title 379 383 high_out_data.title = title 384 high_out_data.style = "Line" 385 high_out_data.has_errors = False 386 high_out_data.plot_role = Data1D.ROLE_DEFAULT 380 387 381 388 # copy labels and units of axes for plotting -
src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py
rb0ba43e r9f2f713 42 42 self.parent = parent 43 43 44 self.setWindowTitle("D ââExplorer")44 self.setWindowTitle("Dmax Explorer") 45 45 46 46 self.pr_state = pr_state … … 116 116 bck = [] 117 117 chi2 = [] 118 118 plotable_xs = [] #Introducing this to make sure size of x and y for plotting is the same.8 119 119 try: 120 120 dmin = float(self.model.item(W.DMIN).text()) … … 128 128 129 129 original = self.pr_state.d_max 130 130 131 for x in xs: 131 132 self.pr_state.d_max = x … … 140 141 bck.append(self.pr_state.background) 141 142 chi2.append(self.pr_state.chi2) 143 plotable_xs.append(x) 142 144 except Exception as ex: 143 145 # This inversion failed, skip this D_max value … … 155 157 logger.error(msg) 156 158 157 plotter = self.model.item(W.VARIABLE).text() 158 y_label = y_unit = "" 159 plotter = self.dependentVariable.currentText() 159 160 x_label = "D_{max}" 160 161 x_unit = "A" … … 188 189 y_unit = "a.u." 189 190 190 data = Data1D( xs, ys)191 data = Data1D(plotable_xs, ys) 191 192 if self.hasPlot: 192 self.plot.removePlot( None)193 self.plot.removePlot(data.name) 193 194 self.hasPlot = True 194 195 data.title = plotter -
src/sas/qtgui/Perspectives/Inversion/InversionLogic.py
r6da860a r3c4f02e 111 111 new_plot.title = title 112 112 113 new_plot.symbol = 'Line' 114 new_plot.hide_error = True 115 113 116 return new_plot 114 117 -
src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py
r855e7ad rdee9e5f 44 44 estimateSignal = QtCore.pyqtSignal(tuple) 45 45 estimateNTSignal = QtCore.pyqtSignal(tuple) 46 estimateDynamicNTSignal = QtCore.pyqtSignal(tuple) 47 estimateDynamicSignal = QtCore.pyqtSignal(tuple) 46 48 calculateSignal = QtCore.pyqtSignal(tuple) 47 49 … … 53 55 54 56 self._manager = parent 57 #Needed for Batch fitting 58 self._parent = parent 55 59 self.communicate = parent.communicator() 56 60 self.communicate.dataDeletedSignal.connect(self.removeData) … … 110 114 # Set up the Widget Map 111 115 self.setupMapper() 116 117 #Hidding calculate all buton 118 self.calculateAllButton.setVisible(False) 112 119 # Set base window state 113 120 self.setupWindow() … … 120 127 121 128 def allowBatch(self): 122 return True129 return False 123 130 124 131 def setClosable(self, value=True): … … 195 202 self.model.itemChanged.connect(self.model_changed) 196 203 self.estimateNTSignal.connect(self._estimateNTUpdate) 204 self.estimateDynamicNTSignal.connect(self._estimateDynamicNTUpdate) 205 self.estimateDynamicSignal.connect(self._estimateDynamicUpdate) 197 206 self.estimateSignal.connect(self._estimateUpdate) 198 207 self.calculateSignal.connect(self._calculateUpdate) 208 209 self.maxDistanceInput.textEdited.connect(self.performEstimateDynamic) 199 210 200 211 def setupMapper(self): … … 310 321 and not self.isCalculating) 311 322 self.removeButton.setEnabled(self.logic.data_is_loaded) 312 self.explorerButton.setEnabled(self.logic.data_is_loaded 313 and np.all(self.logic.data.dy != 0)) 323 self.explorerButton.setEnabled(self.logic.data_is_loaded) 314 324 self.stopButton.setVisible(self.isCalculating) 315 325 self.regConstantSuggestionButton.setEnabled( … … 454 464 # Create initial internal mappings 455 465 self.logic.data = GuiUtils.dataFromItem(data) 466 if not isinstance(self.logic.data, Data1D): 467 msg = "P(r) perspective works for 1D data only" 468 logger.warning(msg) 469 continue 456 470 # Estimate q range 457 471 qmin, qmax = self.logic.computeDataRange() 458 472 self._calculator.set_qmin(qmin) 459 473 self._calculator.set_qmax(qmax) 474 if np.size(self.logic.data.dy) == 0 or np.all(self.logic.data.dy) == 0: 475 self.logic.data.dy = self._calculator.add_errors(self.logic.data.y) 460 476 self.updateDataList(data) 461 477 self.populateDataComboBox(self.logic.data.filename, data) 462 478 self.dataList.setCurrentIndex(len(self.dataList) - 1) 463 self.setCurrentData(data) 479 #Checking for 1D again to mitigate the case when 2D data is last on the data list 480 if isinstance(self.logic.data, Data1D): 481 self.setCurrentData(data) 464 482 465 483 def updateDataList(self, dataRef): … … 502 520 self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 503 521 self.performEstimate() 522 523 def updateDynamicGuiValues(self): 524 pr = self._calculator 525 alpha = self._calculator.suggested_alpha 526 self.model.setItem(WIDGETS.W_MAX_DIST, 527 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 528 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 529 self.noOfTermsSuggestionButton.setText( 530 "{:n}".format(self.nTermsSuggested)) 531 532 self.enableButtons() 504 533 505 534 def updateGuiValues(self): … … 521 550 self.model.setItem(WIDGETS.W_MAX_DIST, 522 551 QtGui.QStandardItem("{:.4g}".format(pr.get_dmax()))) 523 self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha))524 self.noOfTermsSuggestionButton.setText(525 "{:n}".format(self.nTermsSuggested))526 552 527 553 if isinstance(pr.chi2, np.ndarray): … … 547 573 self.prPlot.plot_role = Data1D.ROLE_RESIDUAL 548 574 GuiUtils.updateModelItemWithPlot(self._data, self.prPlot, title) 575 self.communicate.plotRequestedSignal.emit([self._data,self.prPlot], None) 549 576 if self.dataPlot is not None: 550 577 title = self.dataPlot.name 551 578 self.dataPlot.plot_role = Data1D.ROLE_DEFAULT 579 self.dataPlot.symbol = "Line" 580 self.dataPlot.show_errors = False 552 581 GuiUtils.updateModelItemWithPlot(self._data, self.dataPlot, title) 553 if self.dataPlot is not None or self.prPlot is not None: 554 self.communicate.plotRequestedSignal.emit([self.logic.data], None) 582 self.communicate.plotRequestedSignal.emit([self._data,self.dataPlot], None) 555 583 self.enableButtons() 556 584 … … 636 664 637 665 pr = self._calculator.clone() 638 nfunc = self.getNFunc() 639 self.calcThread = CalcPr(pr, nfunc, 666 #Making sure that nfunc and alpha parameters are correctly initialized 667 pr.suggested_alpha = self._calculator.alpha 668 self.calcThread = CalcPr(pr, self.nTermsSuggested, 640 669 error_func=self._threadError, 641 670 completefn=self._calculateCompleted, … … 670 699 error_func=self._threadError, 671 700 completefn=self._estimateNTCompleted, 701 updatefn=None) 702 self.estimationThreadNT.queue() 703 self.estimationThreadNT.ready(2.5) 704 705 def performEstimateDynamicNT(self): 706 """ 707 Perform parameter estimation 708 """ 709 from .Thread import EstimateNT 710 711 self.updateCalculator() 712 713 # If a thread is already started, stop it 714 self.stopEstimateNTThread() 715 716 pr = self._calculator.clone() 717 # Skip the slit settings for the estimation 718 # It slows down the application and it doesn't change the estimates 719 pr.slit_height = 0.0 720 pr.slit_width = 0.0 721 nfunc = self.getNFunc() 722 723 self.estimationThreadNT = EstimateNT(pr, nfunc, 724 error_func=self._threadError, 725 completefn=self._estimateDynamicNTCompleted, 672 726 updatefn=None) 673 727 self.estimationThreadNT.queue() … … 696 750 self.estimationThread.ready(2.5) 697 751 752 def performEstimateDynamic(self): 753 """ 754 Perform parameter estimation 755 """ 756 from .Thread import EstimatePr 757 758 # If a thread is already started, stop it 759 self.stopEstimationThread() 760 761 self.estimationThread = EstimatePr(self._calculator.clone(), 762 self.getNFunc(), 763 error_func=self._threadError, 764 completefn=self._estimateDynamicCompleted, 765 updatefn=None) 766 self.estimationThread.queue() 767 self.estimationThread.ready(2.5) 768 698 769 def stopEstimationThread(self): 699 770 """ Stop the estimation thread if it exists and is running """ … … 708 779 ''' Send a signal to the main thread for model update''' 709 780 self.estimateSignal.emit((alpha, message, elapsed)) 781 782 def _estimateDynamicCompleted(self, alpha, message, elapsed): 783 ''' Send a signal to the main thread for model update''' 784 self.estimateDynamicSignal.emit((alpha, message, elapsed)) 710 785 711 786 def _estimateUpdate(self, output_tuple): … … 723 798 logger.info(message) 724 799 self.performEstimateNT() 800 self.performEstimateDynamicNT() 801 802 def _estimateDynamicUpdate(self, output_tuple): 803 """ 804 Parameter estimation completed, 805 display the results to the user 806 807 :param alpha: estimated best alpha 808 :param elapsed: computation time 809 """ 810 alpha, message, elapsed = output_tuple 811 self._calculator.alpha = alpha 812 self._calculator.elapsed += self._calculator.elapsed 813 if message: 814 logger.info(message) 815 self.performEstimateDynamicNT() 725 816 726 817 def _estimateNTCompleted(self, nterms, alpha, message, elapsed): 727 818 ''' Send a signal to the main thread for model update''' 728 819 self.estimateNTSignal.emit((nterms, alpha, message, elapsed)) 820 821 def _estimateDynamicNTCompleted(self, nterms, alpha, message, elapsed): 822 ''' Send a signal to the main thread for model update''' 823 self.estimateDynamicNTSignal.emit((nterms, alpha, message, elapsed)) 729 824 730 825 def _estimateNTUpdate(self, output_tuple): … … 750 845 self.startThread() 751 846 847 def _estimateDynamicNTUpdate(self, output_tuple): 848 """ 849 Parameter estimation completed, 850 display the results to the user 851 852 :param alpha: estimated best alpha 853 :param nterms: estimated number of terms 854 :param elapsed: computation time 855 """ 856 nterms, alpha, message, elapsed = output_tuple 857 self._calculator.elapsed += elapsed 858 self._calculator.suggested_alpha = alpha 859 self.nTermsSuggested = nterms 860 # Save useful info 861 self.updateDynamicGuiValues() 862 if message: 863 logger.info(message) 864 if self.isBatch: 865 self.acceptAlpha() 866 self.acceptNoTerms() 867 self.startThread() 868 752 869 def _calculateCompleted(self, out, cov, pr, elapsed): 753 870 ''' Send a signal to the main thread for model update''' -
src/sas/qtgui/Perspectives/Inversion/UI/DMaxExplorer.ui
r8f83719f rcfd61f2 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 394</width>10 <height> 426</height>9 <width>586</width> 10 <height>538</height> 11 11 </rect> 12 12 </property> … … 21 21 <property name="orientation"> 22 22 <enum>Qt::Vertical</enum> 23 </property>24 <property name="sizeHint" stdset="0">25 <size>26 <width>20</width>27 <height>305</height>28 </size>29 23 </property> 30 24 </spacer> -
src/sas/qtgui/Perspectives/Inversion/UI/TabbedInversionUI.ui
r72ecbdf2 r68dc2873 7 7 <x>0</x> 8 8 <y>0</y> 9 <width> 390</width>10 <height>4 09</height>9 <width>446</width> 10 <height>480</height> 11 11 </rect> 12 12 </property> … … 740 740 <widget class="QPushButton" name="calculateAllButton"> 741 741 <property name="enabled"> 742 <bool> true</bool>742 <bool>false</bool> 743 743 </property> 744 744 <property name="sizePolicy"> -
src/sas/qtgui/Perspectives/Inversion/UnitTesting/InversionPerspectiveTest.py
r144fe21 rccd2b87 99 99 def baseBatchState(self): 100 100 """ Testing the base batch fitting state """ 101 self.assert True(self.widget.allowBatch())101 self.assertFalse(self.widget.allowBatch()) 102 102 self.assertFalse(self.widget.isBatch) 103 103 self.assertFalse(self.widget.calculateAllButton.isEnabled()) … … 304 304 self.assertIsNotNone(self.widget.dmaxWindow) 305 305 self.assertTrue(self.widget.dmaxWindow.isVisible()) 306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "D ââExplorer")306 self.assertTrue(self.widget.dmaxWindow.windowTitle() == "Dmax Explorer") 307 307 308 308
Note: See TracChangeset
for help on using the changeset viewer.