Changes in / [3c6ecd9:80468f6] in sasview


Ignore:
Files:
3 deleted
18 edited

Legend:

Unmodified
Added
Removed
  • .gitignore

    r846a063 r948484f  
    2929default_categories.json 
    3030/setup.cfg 
    31 **/UI/*.py 
    32 !**/UI/__init__.py 
    3331 
    3432# doc build 
  • run.py

    ra3221b6 ra3221b6  
    141141    sys.path.append(build_path) 
    142142 
    143     # Run the UI conversion tool 
    144     import sas.qtgui.convertUI 
    145  
    146  
    147143if __name__ == "__main__": 
    148144    # Need to add absolute path before actual prepare call, 
  • src/sas/qtgui/Perspectives/Inversion/DMaxExplorerWidget.py

    rb0ba43e rf4480f0  
    88 
    99# global 
     10import sys 
     11import os 
    1012import logging 
    1113import numpy as np 
     
    4042        super(DmaxWindow, self).__init__() 
    4143        self.setupUi(self) 
    42         self.parent = parent 
    4344 
    4445        self.setWindowTitle("Dₐₓ Explorer") 
     
    4950 
    5051        self.plot = PlotterWidget(self, self) 
    51         self.hasPlot = False 
     52        self.hasPlot = None 
    5253        self.verticalLayout.insertWidget(0, self.plot) 
    5354 
    5455        # Let's choose the Standard Item Model. 
    5556        self.model = QtGui.QStandardItemModel(self) 
    56         self.mapper = QtWidgets.QDataWidgetMapper(self) 
     57        self.mapper = None 
    5758 
    5859        # Add validators on line edits 
    5960        self.setupValidators() 
    6061 
    61         # Connect buttons to slots. 
    62         # Needs to be done early so default values propagate properly. 
     62        # # Connect buttons to slots. 
     63        # # Needs to be done early so default values propagate properly. 
    6364        self.setupSlots() 
    6465 
     
    8182 
    8283    def setupModel(self): 
    83         self.model.blockSignals(True) 
    8484        self.model.setItem(W.NPTS, QtGui.QStandardItem(str(self.nfunc))) 
    85         self.model.blockSignals(False) 
    86         self.model.blockSignals(True) 
    8785        self.model.setItem(W.DMIN, QtGui.QStandardItem("{:.1f}".format(0.9*self.pr_state.d_max))) 
    88         self.model.blockSignals(False) 
    89         self.model.blockSignals(True) 
    9086        self.model.setItem(W.DMAX, QtGui.QStandardItem("{:.1f}".format(1.1*self.pr_state.d_max))) 
    91         self.model.blockSignals(False) 
    92         self.model.blockSignals(True) 
    9387        self.model.setItem(W.VARIABLE, QtGui.QStandardItem( "χ²/dof")) 
    94         self.model.blockSignals(False) 
    9588 
    9689    def setupMapper(self): 
     90        self.mapper = QtWidgets.QDataWidgetMapper(self) 
    9791        self.mapper.setOrientation(QtCore.Qt.Vertical) 
    9892        self.mapper.setModel(self.model) 
     
    117111        chi2 = [] 
    118112 
    119         try: 
    120             dmin = float(self.model.item(W.DMIN).text()) 
    121             dmax = float(self.model.item(W.DMAX).text()) 
    122             npts = float(self.model.item(W.NPTS).text()) 
    123             xs = np.linspace(dmin, dmax, npts) 
    124         except ValueError as e: 
    125             msg = ("An input value is not correctly formatted. Please check {}" 
    126                    .format(e.message)) 
    127             logger.error(msg) 
     113        xs = np.linspace(float(self.model.item(W.DMIN).text()), 
     114                         float(self.model.item(W.DMAX).text()), 
     115                         float(self.model.item(W.NPTS).text())) 
    128116 
    129117        original = self.pr_state.d_max 
     
    144132                msg = "ExploreDialog: inversion failed " 
    145133                msg += "for D_max=%s\n%s" % (str(x), ex) 
     134                print(msg) 
    146135                logger.error(msg) 
    147136 
     
    153142            msg = "ExploreDialog: inversion failed " 
    154143            msg += "for D_max=%s\n%s" % (str(x), ex) 
     144            print(msg) 
    155145            logger.error(msg) 
    156146 
     
    161151        if plotter == "χ²/dof": 
    162152            ys = chi2 
    163             y_label = "\\chi^2/dof" 
     153            y_label = "\chi^2/dof" 
    164154            y_unit = "a.u." 
    165155        elif plotter == "I(Q=0)": 
    166156            ys = iq0 
    167157            y_label = "I(q=0)" 
    168             y_unit = "\\AA^{-1}" 
     158            y_unit = "\AA^{-1}" 
    169159        elif plotter == "Rg": 
    170160            ys = rg 
    171161            y_label = "R_g" 
    172             y_unit = "\\AA" 
     162            y_unit = "\AA" 
    173163        elif plotter == "Oscillation parameter": 
    174164            ys = osc 
     
    178168            ys = bck 
    179169            y_label = "Bckg" 
    180             y_unit = "\\AA^{-1}" 
     170            y_unit = "\AA^{-1}" 
    181171        elif plotter == "Positive Fraction": 
    182172            ys = pos 
     
    185175        else: 
    186176            ys = pos_err 
    187             y_label = "P^{+}_{1\\sigma}" 
     177            y_label = "P^{+}_{1\sigma}" 
    188178            y_unit = "a.u." 
    189179 
     
    198188        data._yunit = y_unit 
    199189        self.plot.plot(data=data, marker="-") 
    200  
    201     def closeEvent(self, event): 
    202         """Override close event""" 
    203         self.parent.dmaxWindow = None 
    204         event.accept() 
  • src/sas/qtgui/Perspectives/Inversion/InversionLogic.py

    • Property mode changed from 100644 to 100755
    r6da860a rfa81e94  
    11import math 
    2 import logging 
     2import pylab 
    33import numpy as np 
    44 
     
    1212GROUP_ID_IQ_DATA = r"$I_{obs}(q)$" 
    1313GROUP_ID_PR_FIT = r"$P_{fit}(r)$" 
    14 PR_PLOT_PTS = 51 
    15  
    16 logger = logging.getLogger(__name__) 
    1714 
    1815 
     
    2320    """ 
    2421 
     22    # TODO: Add way to change this value 
     23    _pr_n_pts = 51 
     24 
    2525    def __init__(self, data=None): 
    2626        self._data = data 
     
    3737        """ data setter """ 
    3838        self._data = value 
    39         self.data_is_loaded = (self._data is not None) 
     39        self.data_is_loaded = True 
    4040 
    4141    def isLoadedData(self): 
     
    6363            maxq = pr.q_max 
    6464 
    65         x = np.arange(minq, maxq, maxq / 301.0) 
     65        x = pylab.arange(minq, maxq, maxq / 301.0) 
    6666        y = np.zeros(len(x)) 
    6767        err = np.zeros(len(x)) 
     
    7373            except: 
    7474                err[i] = 1.0 
    75                 logger.log(("Error getting error", value, x[i])) 
     75                print(("Error getting error", value, x[i])) 
    7676 
    7777        new_plot = Data1D(x, y) 
     
    8989        # If we have used slit smearing, plot the smeared I(q) too 
    9090        if pr.slit_width > 0 or pr.slit_height > 0: 
    91             x = np.arange(minq, maxq, maxq / 301.0) 
     91            x = pylab.arange(minq, maxq, maxq / 301.0) 
    9292            y = np.zeros(len(x)) 
    9393            err = np.zeros(len(x)) 
     
    9999                except: 
    100100                    err[i] = 1.0 
    101                     logger.log(("Error getting error", value, x[i])) 
     101                    print(("Error getting error", value, x[i])) 
    102102 
    103103            new_plot = Data1D(x, y) 
     
    113113        return new_plot 
    114114 
     115    def update1DPlot(self, plot, out, pr, q=None): 
     116        """ 
     117        Create a new 1D data instance based on fitting results 
     118        """ 
     119 
     120        qtemp = pr.x 
     121        if q is not None: 
     122            qtemp = q 
     123 
     124        # Make a plot 
     125        maxq = max(qtemp) 
     126 
     127        minq = min(qtemp) 
     128 
     129        # Check for user min/max 
     130        if pr.q_min is not None and maxq >= pr.q_min >= minq: 
     131            minq = pr.q_min 
     132        if pr.q_max is not None and maxq >= pr.q_max >= minq: 
     133            maxq = pr.q_max 
     134 
     135        x = pylab.arange(minq, maxq, maxq / 301.0) 
     136        y = np.zeros(len(x)) 
     137        err = np.zeros(len(x)) 
     138        for i in range(len(x)): 
     139            value = pr.iq(out, x[i]) 
     140            y[i] = value 
     141            try: 
     142                err[i] = math.sqrt(math.fabs(value)) 
     143            except: 
     144                err[i] = 1.0 
     145                print(("Error getting error", value, x[i])) 
     146 
     147        plot.x = x 
     148        plot.y = y 
     149 
     150        # If we have used slit smearing, plot the smeared I(q) too 
     151        if pr.slit_width > 0 or pr.slit_height > 0: 
     152            x = pylab.arange(minq, maxq, maxq / 301.0) 
     153            y = np.zeros(len(x)) 
     154            err = np.zeros(len(x)) 
     155            for i in range(len(x)): 
     156                value = pr.iq_smeared(pr.out, x[i]) 
     157                y[i] = value 
     158                try: 
     159                    err[i] = math.sqrt(math.fabs(value)) 
     160                except: 
     161                    err[i] = 1.0 
     162                    print(("Error getting error", value, x[i])) 
     163 
     164            plot.x = x 
     165            plot.y = y 
     166 
     167        return plot 
     168 
    115169    def newPRPlot(self, out, pr, cov=None): 
    116170        """ 
    117171        """ 
    118172        # Show P(r) 
    119         x = np.arange(0.0, pr.d_max, pr.d_max / PR_PLOT_PTS) 
     173        x = pylab.arange(0.0, pr.d_max, pr.d_max / self._pr_n_pts) 
    120174 
    121175        y = np.zeros(len(x)) 
     
    138192 
    139193            y[i] = value 
     194 
     195        # if self._normalize_output == True: 
     196        #     y = y / total 
     197        #     dy = dy / total 
     198        # elif self._scale_output_unity == True: 
     199        #     y = y / pmax 
     200        #     dy = dy / pmax 
    140201 
    141202        if cov2 is None: 
     
    148209        new_plot.title = "P(r) fit" 
    149210        new_plot.id = PR_FIT_LABEL 
    150         new_plot.scale = "linear" 
     211        # Make sure that the plot is linear 
     212        new_plot.xtransform = "x" 
     213        new_plot.ytransform = "y" 
    151214        new_plot.group_id = GROUP_ID_PR_FIT 
    152215 
    153216        return new_plot 
     217 
     218    def updatePRPlot(self, plot, out, pr, cov=None): 
     219        x = pylab.arange(0.0, pr.d_max, pr.d_max / self._pr_n_pts) 
     220 
     221        y = np.zeros(len(x)) 
     222        dy = np.zeros(len(x)) 
     223 
     224        total = 0.0 
     225        pmax = 0.0 
     226        cov2 = np.ascontiguousarray(cov) 
     227 
     228        for i in range(len(x)): 
     229            if cov2 is None: 
     230                value = pr.pr(out, x[i]) 
     231            else: 
     232                (value, dy[i]) = pr.pr_err(out, cov2, x[i]) 
     233            total += value * pr.d_max / len(x) 
     234 
     235            # keep track of the maximum P(r) value 
     236            if value > pmax: 
     237                pmax = value 
     238 
     239            y[i] = value 
     240 
     241        # if self._normalize_output == True: 
     242        #     y = y / total 
     243        #     dy = dy / total 
     244        # elif self._scale_output_unity == True: 
     245        #     y = y / pmax 
     246        #     dy = dy / pmax 
     247        plot.x = x 
     248        plot.y = y 
     249 
     250        if cov2 is not None: 
     251            plot.dy = dy 
     252 
     253        return plot 
    154254 
    155255    def computeDataRange(self): 
  • src/sas/qtgui/Perspectives/Inversion/InversionPerspective.py

    rb0ba43e raed0532  
     1import sys 
    12import logging 
     3import pylab 
    24import numpy as np 
    35 
     
    1315 
    1416# pr inversion calculation elements 
     17from sas.sascalc.dataloader.data_info import Data1D 
    1518from sas.sascalc.pr.invertor import Invertor 
    16 # Batch calculation display 
    17 from sas.qtgui.Utilities.GridPanel import BatchInversionOutputPanel 
    18  
    1919 
    2020def is_float(value): 
     
    2525        return 0.0 
    2626 
    27  
    2827NUMBER_OF_TERMS = 10 
    2928REGULARIZATION = 0.0001 
    3029BACKGROUND_INPUT = 0.0 
    3130MAX_DIST = 140.0 
    32 DICT_KEYS = ["Calculator", "PrPlot", "DataPlot"] 
    33  
    34 logger = logging.getLogger(__name__) 
    35  
    36  
     31 
     32# TODO: Modify plot references, don't just send new 
     33# TODO: Update help with batch capabilities 
     34# TODO: Method to export results in some meaningful way 
    3735class InversionWindow(QtWidgets.QDialog, Ui_PrInversion): 
    3836    """ 
     
    5250 
    5351        self._manager = parent 
    54         self.communicate = parent.communicator() 
    55         self.communicate.dataDeletedSignal.connect(self.removeData) 
     52        self._model_item = QtGui.QStandardItem() 
     53        self.communicate = GuiUtils.Communicate() 
    5654 
    5755        self.logic = InversionLogic() 
    5856 
     57        # Reference to Dmax window 
     58        self.dmaxWindow = None 
     59 
    5960        # The window should not close 
    60         self._allowClose = False 
    61  
    62         # Visible data items 
     61        self._allow_close = False 
     62 
    6363        # current QStandardItem showing on the panel 
    6464        self._data = None 
    65         # Reference to Dmax window for self._data 
    66         self.dmaxWindow = None 
    67         # p(r) calculator for self._data 
     65        # current Data1D as referenced by self._data 
     66        self._data_set = None 
     67 
     68        # p(r) calculator 
    6869        self._calculator = Invertor() 
    69         # Default to background estimate 
    70         self._calculator.est_bck = True 
    71         # plots of self._data 
    72         self.prPlot = None 
    73         self.dataPlot = None 
    74         # suggested nTerms 
    75         self.nTermsSuggested = NUMBER_OF_TERMS 
    76  
    77         # Calculation threads used by all data items 
    78         self.calcThread = None 
    79         self.estimationThread = None 
    80         self.estimationThreadNT = None 
    81         self.isCalculating = False 
    82  
    83         # Mapping for all data items 
    84         # Dictionary mapping data to all parameters 
    85         self._dataList = {} 
     70        self._last_calculator = None 
     71        self.calc_thread = None 
     72        self.estimation_thread = None 
     73 
     74        # Current data object in view 
     75        self._data_index = 0 
     76        # list mapping data to p(r) calculation 
     77        self._data_list = {} 
    8678        if not isinstance(data, list): 
    8779            data_list = [data] 
    8880        if data is not None: 
    8981            for datum in data_list: 
    90                 self.updateDataList(datum) 
    91  
    92         self.dataDeleted = False 
     82                self._data_list[datum] = self._calculator.clone() 
     83 
     84        # dict of models for quick update after calculation 
     85        # {item:model} 
     86        self._models = {} 
     87 
     88        self.calculateAllButton.setEnabled(False) 
     89        self.calculateThisButton.setEnabled(False) 
     90 
     91        # plots for current data 
     92        self.pr_plot = None 
     93        self.data_plot = None 
     94        # plot references for all data in perspective 
     95        self.pr_plot_list = {} 
     96        self.data_plot_list = {} 
    9397 
    9498        self.model = QtGui.QStandardItemModel(self) 
    9599        self.mapper = QtWidgets.QDataWidgetMapper(self) 
    96  
    97         # Batch fitting parameters 
    98         self.isBatch = False 
    99         self.batchResultsWindow = None 
    100         self.batchResults = {} 
    101         self.batchComplete = [] 
    102100 
    103101        # Add validators 
     
    126124        """ 
    127125        assert isinstance(value, bool) 
    128         self._allowClose = value 
    129  
    130     def isClosable(self): 
    131         """ 
    132         Allow outsiders close this widget 
    133         """ 
    134         return self._allowClose 
     126        self._allow_close = value 
    135127 
    136128    def closeEvent(self, event): 
     
    138130        Overwrite QDialog close method to allow for custom widget close 
    139131        """ 
    140         # Close report widgets before closing/minimizing main widget 
    141         self.closeDMax() 
    142         self.closeBatchResults() 
    143         if self._allowClose: 
     132        if self._allow_close: 
    144133            # reset the closability flag 
    145134            self.setClosable(value=False) 
     
    152141            self.setWindowState(QtCore.Qt.WindowMinimized) 
    153142 
    154     def closeDMax(self): 
    155         if self.dmaxWindow is not None: 
    156             self.dmaxWindow.close() 
    157  
    158     def closeBatchResults(self): 
    159         if self.batchResultsWindow is not None: 
    160             self.batchResultsWindow.close() 
    161  
    162143    ###################################################################### 
    163144    # Initialization routines 
     
    168149        self.calculateAllButton.clicked.connect(self.startThreadAll) 
    169150        self.calculateThisButton.clicked.connect(self.startThread) 
    170         self.stopButton.clicked.connect(self.stopCalculation) 
    171151        self.removeButton.clicked.connect(self.removeData) 
    172152        self.helpButton.clicked.connect(self.help) 
     
    177157        self.explorerButton.clicked.connect(self.openExplorerWindow) 
    178158 
    179         self.backgroundInput.textChanged.connect( 
    180             lambda: self.set_background(self.backgroundInput.text())) 
    181         self.minQInput.textChanged.connect( 
     159        self.backgroundInput.editingFinished.connect( 
     160            lambda: self._calculator.set_est_bck(int(is_float(self.backgroundInput.text())))) 
     161        self.minQInput.editingFinished.connect( 
    182162            lambda: self._calculator.set_qmin(is_float(self.minQInput.text()))) 
    183         self.regularizationConstantInput.textChanged.connect( 
     163        self.regularizationConstantInput.editingFinished.connect( 
    184164            lambda: self._calculator.set_alpha(is_float(self.regularizationConstantInput.text()))) 
    185         self.maxDistanceInput.textChanged.connect( 
     165        self.maxDistanceInput.editingFinished.connect( 
    186166            lambda: self._calculator.set_dmax(is_float(self.maxDistanceInput.text()))) 
    187         self.maxQInput.textChanged.connect( 
     167        self.maxQInput.editingFinished.connect( 
    188168            lambda: self._calculator.set_qmax(is_float(self.maxQInput.text()))) 
    189         self.slitHeightInput.textChanged.connect( 
     169        self.slitHeightInput.editingFinished.connect( 
    190170            lambda: self._calculator.set_slit_height(is_float(self.slitHeightInput.text()))) 
    191         self.slitWidthInput.textChanged.connect( 
    192             lambda: self._calculator.set_slit_width(is_float(self.slitWidthInput.text()))) 
     171        self.slitWidthInput.editingFinished.connect( 
     172            lambda: self._calculator.set_slit_width(is_float(self.slitHeightInput.text()))) 
    193173 
    194174        self.model.itemChanged.connect(self.model_changed) 
     
    247227        Update boxes with initial values 
    248228        """ 
    249         bgd_item = QtGui.QStandardItem(str(BACKGROUND_INPUT)) 
    250         self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, bgd_item) 
    251         blank_item = QtGui.QStandardItem("") 
    252         self.model.setItem(WIDGETS.W_QMIN, blank_item) 
    253         blank_item = QtGui.QStandardItem("") 
    254         self.model.setItem(WIDGETS.W_QMAX, blank_item) 
    255         blank_item = QtGui.QStandardItem("") 
    256         self.model.setItem(WIDGETS.W_SLIT_WIDTH, blank_item) 
    257         blank_item = QtGui.QStandardItem("") 
    258         self.model.setItem(WIDGETS.W_SLIT_HEIGHT, blank_item) 
    259         no_terms_item = QtGui.QStandardItem(str(NUMBER_OF_TERMS)) 
    260         self.model.setItem(WIDGETS.W_NO_TERMS, no_terms_item) 
    261         reg_item = QtGui.QStandardItem(str(REGULARIZATION)) 
    262         self.model.setItem(WIDGETS.W_REGULARIZATION, reg_item) 
    263         max_dist_item = QtGui.QStandardItem(str(MAX_DIST)) 
    264         self.model.setItem(WIDGETS.W_MAX_DIST, max_dist_item) 
    265         blank_item = QtGui.QStandardItem("") 
    266         self.model.setItem(WIDGETS.W_RG, blank_item) 
    267         blank_item = QtGui.QStandardItem("") 
    268         self.model.setItem(WIDGETS.W_I_ZERO, blank_item) 
    269         bgd_item = QtGui.QStandardItem(str(BACKGROUND_INPUT)) 
    270         self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, bgd_item) 
    271         blank_item = QtGui.QStandardItem("") 
    272         self.model.setItem(WIDGETS.W_COMP_TIME, blank_item) 
    273         blank_item = QtGui.QStandardItem("") 
    274         self.model.setItem(WIDGETS.W_CHI_SQUARED, blank_item) 
    275         blank_item = QtGui.QStandardItem("") 
    276         self.model.setItem(WIDGETS.W_OSCILLATION, blank_item) 
    277         blank_item = QtGui.QStandardItem("") 
    278         self.model.setItem(WIDGETS.W_POS_FRACTION, blank_item) 
    279         blank_item = QtGui.QStandardItem("") 
    280         self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, blank_item) 
     229        item = QtGui.QStandardItem("") 
     230        self.model.setItem(WIDGETS.W_FILENAME, item) 
     231        item = QtGui.QStandardItem(str(BACKGROUND_INPUT)) 
     232        self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, item) 
     233        item = QtGui.QStandardItem("") 
     234        self.model.setItem(WIDGETS.W_QMIN, item) 
     235        item = QtGui.QStandardItem("") 
     236        self.model.setItem(WIDGETS.W_QMAX, item) 
     237        item = QtGui.QStandardItem("") 
     238        self.model.setItem(WIDGETS.W_SLIT_WIDTH, item) 
     239        item = QtGui.QStandardItem("") 
     240        self.model.setItem(WIDGETS.W_SLIT_HEIGHT, item) 
     241        item = QtGui.QStandardItem(str(NUMBER_OF_TERMS)) 
     242        self.model.setItem(WIDGETS.W_NO_TERMS, item) 
     243        item = QtGui.QStandardItem(str(REGULARIZATION)) 
     244        self.model.setItem(WIDGETS.W_REGULARIZATION, item) 
     245        item = QtGui.QStandardItem(str(MAX_DIST)) 
     246        self.model.setItem(WIDGETS.W_MAX_DIST, item) 
     247        item = QtGui.QStandardItem("") 
     248        self.model.setItem(WIDGETS.W_RG, item) 
     249        item = QtGui.QStandardItem("") 
     250        self.model.setItem(WIDGETS.W_I_ZERO, item) 
     251        item = QtGui.QStandardItem("") 
     252        self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, item) 
     253        item = QtGui.QStandardItem("") 
     254        self.model.setItem(WIDGETS.W_COMP_TIME, item) 
     255        item = QtGui.QStandardItem("") 
     256        self.model.setItem(WIDGETS.W_CHI_SQUARED, item) 
     257        item = QtGui.QStandardItem("") 
     258        self.model.setItem(WIDGETS.W_OSCILLATION, item) 
     259        item = QtGui.QStandardItem("") 
     260        self.model.setItem(WIDGETS.W_POS_FRACTION, item) 
     261        item = QtGui.QStandardItem("") 
     262        self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, item) 
    281263 
    282264    def setupWindow(self): 
     
    302284        Enable buttons when data is present, else disable them 
    303285        """ 
    304         self.calculateAllButton.setEnabled(len(self._dataList) > 1 
    305                                            and not self.isBatch 
    306                                            and not self.isCalculating) 
    307         self.calculateThisButton.setEnabled(self.logic.data_is_loaded 
    308                                             and not self.isBatch 
    309                                             and not self.isCalculating) 
     286        self.calculateAllButton.setEnabled(self.logic.data_is_loaded) 
     287        self.calculateThisButton.setEnabled(self.logic.data_is_loaded) 
    310288        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)) 
    313         self.stopButton.setVisible(self.isCalculating) 
    314         self.regConstantSuggestionButton.setEnabled( 
    315             self.logic.data_is_loaded and 
    316             self._calculator.suggested_alpha != self._calculator.alpha) 
    317         self.noOfTermsSuggestionButton.setEnabled( 
    318             self.logic.data_is_loaded and 
    319             self._calculator.nfunc != self.nTermsSuggested) 
     289        self.explorerButton.setEnabled(self.logic.data_is_loaded) 
    320290 
    321291    def populateDataComboBox(self, filename, data_ref): 
     
    337307            self.regConstantSuggestionButton.text())) 
    338308 
    339     def displayChange(self, data_index=0): 
    340         """Switch to another item in the data list""" 
    341         if self.dataDeleted: 
    342             return 
    343         self.updateDataList(self._data) 
    344         self.setCurrentData(self.dataList.itemData(data_index)) 
     309    def displayChange(self): 
     310        ref_item = self.dataList.itemData(self.dataList.currentIndex()) 
     311        self._model_item = ref_item 
     312        self.setCurrentData(ref_item) 
     313        self.setCurrentModel(ref_item) 
     314 
     315    def removeData(self): 
     316        """Remove the existing data reference from the P(r) Persepective""" 
     317        self._data_list.pop(self._data) 
     318        self.pr_plot_list.pop(self._data) 
     319        self.data_plot_list.pop(self._data) 
     320        if self.dmaxWindow is not None: 
     321            self.dmaxWindow = None 
     322        self.dataList.removeItem(self.dataList.currentIndex()) 
     323        self.dataList.setCurrentIndex(0) 
     324        # Last file removed 
     325        if not self._data_list: 
     326            self._data = None 
     327            self.pr_plot = None 
     328            self._data_set = None 
     329            self.calculateThisButton.setEnabled(False) 
     330            self.calculateAllButton.setEnabled(False) 
     331            self.explorerButton.setEnabled(False) 
    345332 
    346333    ###################################################################### 
    347334    # GUI Interaction Events 
    348335 
    349     def updateCalculator(self): 
     336    def setCurrentModel(self, ref_item): 
     337        '''update the current model with stored values''' 
     338        if ref_item in self._models: 
     339            self.model = self._models[ref_item] 
     340 
     341    def update_calculator(self): 
    350342        """Update all p(r) params""" 
    351         self._calculator.set_x(self.logic.data.x) 
    352         self._calculator.set_y(self.logic.data.y) 
    353         self._calculator.set_err(self.logic.data.dy) 
    354         self.set_background(self.backgroundInput.text()) 
    355  
    356     def set_background(self, value): 
    357         self._calculator.background = is_float(value) 
     343        self._calculator.set_x(self._data_set.x) 
     344        self._calculator.set_y(self._data_set.y) 
     345        self._calculator.set_err(self._data_set.dy) 
    358346 
    359347    def model_changed(self): 
     
    362350            msg = "Unable to update P{r}. The connection between the main GUI " 
    363351            msg += "and P(r) was severed. Attempting to restart P(r)." 
    364             logger.warning(msg) 
     352            logging.warning(msg) 
    365353            self.setClosable(True) 
    366354            self.close() 
    367             InversionWindow.__init__(self.parent(), list(self._dataList.keys())) 
     355            InversionWindow.__init__(self.parent(), list(self._data_list.keys())) 
    368356            exit(0) 
     357        # TODO: Only send plot first time - otherwise, update in complete 
     358        if self.pr_plot is not None: 
     359            title = self.pr_plot.name 
     360            GuiUtils.updateModelItemWithPlot(self._data, self.pr_plot, title) 
     361        if self.data_plot is not None: 
     362            title = self.data_plot.name 
     363            GuiUtils.updateModelItemWithPlot(self._data, self.data_plot, title) 
    369364        if self.dmaxWindow is not None: 
    370             self.dmaxWindow.nfunc = self.getNFunc() 
    371             self.dmaxWindow.pr_state = self._calculator 
    372         self.mapper.toLast() 
     365             self.dmaxWindow.pr_state = self._calculator 
     366             self.dmaxWindow.nfunc = self.getNFunc() 
     367 
     368        self.mapper.toFirst() 
    373369 
    374370    def help(self): 
     
    387383        Toggle the background between manual and estimated 
    388384        """ 
    389         if self.estimateBgd.isChecked(): 
    390             self.manualBgd.setChecked(False) 
     385        sender = self.sender() 
     386        if sender is self.estimateBgd: 
    391387            self.backgroundInput.setEnabled(False) 
    392             self._calculator.set_est_bck = True 
    393         elif self.manualBgd.isChecked(): 
    394             self.estimateBgd.setChecked(False) 
     388        else: 
    395389            self.backgroundInput.setEnabled(True) 
    396             self._calculator.set_est_bck = False 
    397         else: 
    398             pass 
    399390 
    400391    def openExplorerWindow(self): 
     
    403394        """ 
    404395        from .DMaxExplorerWidget import DmaxWindow 
    405         self.dmaxWindow = DmaxWindow(pr_state=self._calculator, 
    406                                      nfunc=self.getNFunc(), 
    407                                      parent=self) 
     396        self.dmaxWindow = DmaxWindow(self._calculator, self.getNFunc(), self) 
    408397        self.dmaxWindow.show() 
    409  
    410     def showBatchOutput(self): 
    411         """ 
    412         Display the batch output in tabular form 
    413         :param output_data: Dictionary mapping filename -> P(r) instance 
    414         """ 
    415         if self.batchResultsWindow is None: 
    416             self.batchResultsWindow = BatchInversionOutputPanel( 
    417                 parent=self, output_data=self.batchResults) 
    418         else: 
    419             self.batchResultsWindow.setupTable(self.batchResults) 
    420         self.batchResultsWindow.show() 
    421  
    422     def stopCalculation(self): 
    423         """ Stop all threads, return to the base state and update GUI """ 
    424         self.stopCalcThread() 
    425         self.stopEstimationThread() 
    426         self.stopEstimateNTThread() 
    427         # Show any batch calculations that successfully completed 
    428         if self.isBatch and self.batchResultsWindow is not None: 
    429             self.showBatchOutput() 
    430         self.isBatch = False 
    431         self.isCalculating = False 
    432         self.updateGuiValues() 
    433398 
    434399    ###################################################################### 
     
    445410        if not isinstance(data_item, list): 
    446411            msg = "Incorrect type passed to the P(r) Perspective" 
    447             raise AttributeError(msg) 
     412            raise AttributeError 
    448413 
    449414        for data in data_item: 
    450             if data in self._dataList.keys(): 
     415            if data in self._data_list.keys(): 
    451416                # Don't add data if it's already in 
    452                 continue 
     417                return 
    453418            # Create initial internal mappings 
    454             self.logic.data = GuiUtils.dataFromItem(data) 
     419            self._data_list[data] = self._calculator.clone() 
     420            self._data_set = GuiUtils.dataFromItem(data) 
     421            self.data_plot_list[data] = self.data_plot 
     422            self.pr_plot_list[data] = self.pr_plot 
     423            self.populateDataComboBox(self._data_set.filename, data) 
     424            self.setCurrentData(data) 
     425 
     426            # Estimate initial values from data 
     427            self.performEstimate() 
     428            self.logic = InversionLogic(self._data_set) 
     429 
    455430            # Estimate q range 
    456431            qmin, qmax = self.logic.computeDataRange() 
    457             self._calculator.set_qmin(qmin) 
    458             self._calculator.set_qmax(qmax) 
    459             self.updateDataList(data) 
    460             self.populateDataComboBox(self.logic.data.filename, data) 
    461         self.dataList.setCurrentIndex(len(self.dataList) - 1) 
    462         self.setCurrentData(data) 
    463  
    464     def updateDataList(self, dataRef): 
    465         """Save the current data state of the window into self._data_list""" 
    466         if dataRef is None: 
    467             return 
    468         self._dataList[dataRef] = { 
    469             DICT_KEYS[0]: self._calculator, 
    470             DICT_KEYS[1]: self.prPlot, 
    471             DICT_KEYS[2]: self.dataPlot 
    472         } 
    473         # Update batch results window when finished 
    474         self.batchResults[self.logic.data.filename] = self._calculator 
    475         if self.batchResultsWindow is not None: 
    476             self.showBatchOutput() 
     432            self.model.setItem(WIDGETS.W_QMIN, QtGui.QStandardItem("{:.4g}".format(qmin))) 
     433            self.model.setItem(WIDGETS.W_QMAX, QtGui.QStandardItem("{:.4g}".format(qmax))) 
     434            self._models[data] = self.model 
     435            self.model_item = data 
     436 
     437        self.enableButtons() 
    477438 
    478439    def getNFunc(self): 
     
    481442            nfunc = int(self.noOfTermsInput.text()) 
    482443        except ValueError: 
    483             logger.error("Incorrect number of terms specified: %s" 
    484                           %self.noOfTermsInput.text()) 
     444            logging.error("Incorrect number of terms specified: %s" %self.noOfTermsInput.text()) 
    485445            self.noOfTermsInput.setText(str(NUMBER_OF_TERMS)) 
    486446            nfunc = NUMBER_OF_TERMS 
     
    488448 
    489449    def setCurrentData(self, data_ref): 
    490         """Get the data by reference and display as necessary""" 
     450        """Get the current data and display as necessary""" 
     451 
    491452        if data_ref is None: 
    492453            return 
     454 
    493455        if not isinstance(data_ref, QtGui.QStandardItem): 
    494456            msg = "Incorrect type passed to the P(r) Perspective" 
    495             raise AttributeError(msg) 
     457            raise AttributeError 
     458 
    496459        # Data references 
    497460        self._data = data_ref 
    498         self.logic.data = GuiUtils.dataFromItem(data_ref) 
    499         self._calculator = self._dataList[data_ref].get(DICT_KEYS[0]) 
    500         self.prPlot = self._dataList[data_ref].get(DICT_KEYS[1]) 
    501         self.dataPlot = self._dataList[data_ref].get(DICT_KEYS[2]) 
    502         self.performEstimate() 
    503  
    504     def updateGuiValues(self): 
    505         pr = self._calculator 
    506         out = self._calculator.out 
    507         cov = self._calculator.cov 
    508         elapsed = self._calculator.elapsed 
    509         alpha = self._calculator.suggested_alpha 
    510         self.model.setItem(WIDGETS.W_QMIN, 
    511                            QtGui.QStandardItem("{:.4g}".format(pr.get_qmin()))) 
    512         self.model.setItem(WIDGETS.W_QMAX, 
    513                            QtGui.QStandardItem("{:.4g}".format(pr.get_qmax()))) 
    514         self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, 
    515                            QtGui.QStandardItem("{:.3g}".format(pr.background))) 
    516         self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, 
    517                            QtGui.QStandardItem("{:.3g}".format(pr.background))) 
    518         self.model.setItem(WIDGETS.W_COMP_TIME, 
    519                            QtGui.QStandardItem("{:.4g}".format(elapsed))) 
    520         self.model.setItem(WIDGETS.W_MAX_DIST, 
    521                            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  
    526         if isinstance(pr.chi2, np.ndarray): 
    527             self.model.setItem(WIDGETS.W_CHI_SQUARED, 
    528                                QtGui.QStandardItem("{:.3g}".format(pr.chi2[0]))) 
    529         if out is not None: 
    530             self.model.setItem(WIDGETS.W_RG, 
    531                                QtGui.QStandardItem("{:.3g}".format(pr.rg(out)))) 
    532             self.model.setItem(WIDGETS.W_I_ZERO, 
    533                                QtGui.QStandardItem( 
    534                                    "{:.3g}".format(pr.iq0(out)))) 
    535             self.model.setItem(WIDGETS.W_OSCILLATION, QtGui.QStandardItem( 
    536                 "{:.3g}".format(pr.oscillations(out)))) 
    537             self.model.setItem(WIDGETS.W_POS_FRACTION, QtGui.QStandardItem( 
    538                 "{:.3g}".format(pr.get_positive(out)))) 
    539             if cov is not None: 
    540                 self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, 
    541                                    QtGui.QStandardItem( 
    542                                        "{:.3g}".format( 
    543                                            pr.get_pos_err(out, cov)))) 
    544         if self.prPlot is not None: 
    545             title = self.prPlot.name 
    546             GuiUtils.updateModelItemWithPlot(self._data, self.prPlot, title) 
    547             self.communicate.plotRequestedSignal.emit([self.prPlot]) 
    548         if self.dataPlot is not None: 
    549             title = self.dataPlot.name 
    550             GuiUtils.updateModelItemWithPlot(self._data, self.dataPlot, title) 
    551             self.communicate.plotRequestedSignal.emit([self.dataPlot]) 
    552         self.enableButtons() 
    553  
    554     def removeData(self, data_list=None): 
    555         """Remove the existing data reference from the P(r) Persepective""" 
    556         self.dataDeleted = True 
    557         self.batchResults = {} 
    558         if not data_list: 
    559             data_list = [self._data] 
    560         self.closeDMax() 
    561         for data in data_list: 
    562             self._dataList.pop(data) 
    563         self._data = None 
    564         length = len(self.dataList) 
    565         for index in reversed(range(length)): 
    566             if self.dataList.itemData(index) in data_list: 
    567                 self.dataList.removeItem(index) 
    568         # Last file removed 
    569         self.dataDeleted = False 
    570         if len(self._dataList) == 0: 
    571             self.prPlot = None 
    572             self.dataPlot = None 
    573             self.logic.data = None 
    574             self._calculator = Invertor() 
    575             self.closeBatchResults() 
    576             self.nTermsSuggested = NUMBER_OF_TERMS 
    577             self.noOfTermsSuggestionButton.setText("{:n}".format( 
    578                 self.nTermsSuggested)) 
    579             self.regConstantSuggestionButton.setText("{:-3.2g}".format( 
    580                 REGULARIZATION)) 
    581             self.updateGuiValues() 
    582             self.setupModel() 
    583         else: 
    584             self.dataList.setCurrentIndex(0) 
    585             self.updateGuiValues() 
     461        self._data_set = GuiUtils.dataFromItem(data_ref) 
     462        self._calculator = self._data_list[data_ref] 
     463        self.pr_plot = self.pr_plot_list[data_ref] 
     464        self.data_plot = self.data_plot_list[data_ref] 
    586465 
    587466    ###################################################################### 
    588467    # Thread Creators 
    589  
    590468    def startThreadAll(self): 
    591         self.isCalculating = True 
    592         self.isBatch = True 
    593         self.batchComplete = [] 
    594         self.calculateAllButton.setText("Calculating...") 
    595         self.enableButtons() 
    596         self.batchResultsWindow = BatchInversionOutputPanel( 
    597             parent=self, output_data=self.batchResults) 
    598         self.performEstimate() 
    599  
    600     def startNextBatchItem(self): 
    601         self.isBatch = False 
    602         for index in range(len(self._dataList)): 
    603             if index not in self.batchComplete: 
    604                 self.dataList.setCurrentIndex(index) 
    605                 self.isBatch = True 
    606                 # Add the index before calculating in case calculation fails 
    607                 self.batchComplete.append(index) 
    608                 break 
    609         if self.isBatch: 
    610             self.performEstimate() 
    611         else: 
    612             # If no data sets left, end batch calculation 
    613             self.isCalculating = False 
    614             self.batchComplete = [] 
    615             self.calculateAllButton.setText("Calculate All") 
    616             self.showBatchOutput() 
    617             self.enableButtons() 
     469        for data_ref, pr in list(self._data_list.items()): 
     470            self._data_set = GuiUtils.dataFromItem(data_ref) 
     471            self._calculator = pr 
     472            self.startThread() 
    618473 
    619474    def startThread(self): 
     
    624479 
    625480        # Set data before running the calculations 
    626         self.isCalculating = True 
    627         self.enableButtons() 
    628         self.updateCalculator() 
    629         # Disable calculation buttons to prevent thread interference 
    630  
    631         # If the thread is already started, stop it 
    632         self.stopCalcThread() 
    633  
     481        self.update_calculator() 
     482 
     483        # If a thread is already started, stop it 
     484        if self.calc_thread is not None and self.calc_thread.isrunning(): 
     485            self.calc_thread.stop() 
    634486        pr = self._calculator.clone() 
    635487        nfunc = self.getNFunc() 
    636         self.calcThread = CalcPr(pr, nfunc, 
    637                                  error_func=self._threadError, 
    638                                  completefn=self._calculateCompleted, 
    639                                  updatefn=None) 
    640         self.calcThread.queue() 
    641         self.calcThread.ready(2.5) 
    642  
    643     def stopCalcThread(self): 
    644         """ Stops a thread if it exists and is running """ 
    645         if self.calcThread is not None and self.calcThread.isrunning(): 
    646             self.calcThread.stop() 
     488        self.calc_thread = CalcPr(pr, nfunc, 
     489                                  error_func=self._threadError, 
     490                                  completefn=self._calculateCompleted, 
     491                                  updatefn=None) 
     492        self.calc_thread.queue() 
     493        self.calc_thread.ready(2.5) 
    647494 
    648495    def performEstimateNT(self): 
     
    652499        from .Thread import EstimateNT 
    653500 
    654         self.updateCalculator() 
    655  
    656501        # If a thread is already started, stop it 
    657         self.stopEstimateNTThread() 
    658  
     502        if (self.estimation_thread is not None and 
     503                self.estimation_thread.isrunning()): 
     504            self.estimation_thread.stop() 
    659505        pr = self._calculator.clone() 
    660506        # Skip the slit settings for the estimation 
     
    664510        nfunc = self.getNFunc() 
    665511 
    666         self.estimationThreadNT = EstimateNT(pr, nfunc, 
    667                                              error_func=self._threadError, 
    668                                              completefn=self._estimateNTCompleted, 
    669                                              updatefn=None) 
    670         self.estimationThreadNT.queue() 
    671         self.estimationThreadNT.ready(2.5) 
    672  
    673     def stopEstimateNTThread(self): 
    674         if (self.estimationThreadNT is not None and 
    675                 self.estimationThreadNT.isrunning()): 
    676             self.estimationThreadNT.stop() 
     512        self.estimation_thread = EstimateNT(pr, nfunc, 
     513                                            error_func=self._threadError, 
     514                                            completefn=self._estimateNTCompleted, 
     515                                            updatefn=None) 
     516        self.estimation_thread.queue() 
     517        self.estimation_thread.ready(2.5) 
    677518 
    678519    def performEstimate(self): 
     
    682523        from .Thread import EstimatePr 
    683524 
     525        self.startThread() 
     526 
    684527        # If a thread is already started, stop it 
    685         self.stopEstimationThread() 
    686  
    687         self.estimationThread = EstimatePr(self._calculator.clone(), 
    688                                            self.getNFunc(), 
    689                                            error_func=self._threadError, 
    690                                            completefn=self._estimateCompleted, 
    691                                            updatefn=None) 
    692         self.estimationThread.queue() 
    693         self.estimationThread.ready(2.5) 
    694  
    695     def stopEstimationThread(self): 
    696         """ Stop the estimation thread if it exists and is running """ 
    697         if (self.estimationThread is not None and 
    698                 self.estimationThread.isrunning()): 
    699             self.estimationThread.stop() 
     528        if (self.estimation_thread is not None and 
     529                self.estimation_thread.isrunning()): 
     530            self.estimation_thread.stop() 
     531        pr = self._calculator.clone() 
     532        nfunc = self.getNFunc() 
     533        self.estimation_thread = EstimatePr(pr, nfunc, 
     534                                            error_func=self._threadError, 
     535                                            completefn=self._estimateCompleted, 
     536                                            updatefn=None) 
     537        self.estimation_thread.queue() 
     538        self.estimation_thread.ready(2.5) 
    700539 
    701540    ###################################################################### 
     
    715554        """ 
    716555        alpha, message, elapsed = output_tuple 
    717         self._calculator.alpha = alpha 
    718         self._calculator.elapsed += self._calculator.elapsed 
     556        # Save useful info 
     557        self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.4g}".format(elapsed))) 
     558        self.regConstantSuggestionButton.setText("{:-3.2g}".format(alpha)) 
     559        self.regConstantSuggestionButton.setEnabled(True) 
    719560        if message: 
    720             logger.info(message) 
     561            logging.info(message) 
    721562        self.performEstimateNT() 
    722563 
     
    735576        """ 
    736577        nterms, alpha, message, elapsed = output_tuple 
    737         self._calculator.elapsed += elapsed 
    738         self._calculator.suggested_alpha = alpha 
    739         self.nTermsSuggested = nterms 
    740578        # Save useful info 
    741         self.updateGuiValues() 
     579        self.noOfTermsSuggestionButton.setText("{:n}".format(nterms)) 
     580        self.noOfTermsSuggestionButton.setEnabled(True) 
     581        self.regConstantSuggestionButton.setText("{:.3g}".format(alpha)) 
     582        self.regConstantSuggestionButton.setEnabled(True) 
     583        self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.2g}".format(elapsed))) 
    742584        if message: 
    743             logger.info(message) 
    744         if self.isBatch: 
    745             self.acceptAlpha() 
    746             self.acceptNoTerms() 
    747             self.startThread() 
     585            logging.info(message) 
    748586 
    749587    def _calculateCompleted(self, out, cov, pr, elapsed): 
     
    767605        pr.elapsed = elapsed 
    768606 
     607        # Show result on control panel 
     608        self.model.setItem(WIDGETS.W_RG, QtGui.QStandardItem("{:.3g}".format(pr.rg(out)))) 
     609        self.model.setItem(WIDGETS.W_I_ZERO, QtGui.QStandardItem("{:.3g}".format(pr.iq0(out)))) 
     610        self.model.setItem(WIDGETS.W_BACKGROUND_INPUT, 
     611                           QtGui.QStandardItem("{:.3f}".format(pr.est_bck))) 
     612        self.model.setItem(WIDGETS.W_BACKGROUND_OUTPUT, QtGui.QStandardItem("{:.3g}".format(pr.background))) 
     613        self.model.setItem(WIDGETS.W_CHI_SQUARED, QtGui.QStandardItem("{:.3g}".format(pr.chi2[0]))) 
     614        self.model.setItem(WIDGETS.W_COMP_TIME, QtGui.QStandardItem("{:.2g}".format(elapsed))) 
     615        self.model.setItem(WIDGETS.W_OSCILLATION, QtGui.QStandardItem("{:.3g}".format(pr.oscillations(out)))) 
     616        self.model.setItem(WIDGETS.W_POS_FRACTION, QtGui.QStandardItem("{:.3g}".format(pr.get_positive(out)))) 
     617        self.model.setItem(WIDGETS.W_SIGMA_POS_FRACTION, 
     618                           QtGui.QStandardItem("{:.3g}".format(pr.get_pos_err(out, cov)))) 
     619 
    769620        # Save Pr invertor 
    770621        self._calculator = pr 
    771  
    772         # Update P(r) and fit plots 
    773         self.prPlot = self.logic.newPRPlot(out, self._calculator, cov) 
    774         self.prPlot.filename = self.logic.data.filename 
    775         self.dataPlot = self.logic.new1DPlot(out, self._calculator) 
    776         self.dataPlot.filename = self.logic.data.filename 
    777  
    778         # Udpate internals and GUI 
    779         self.updateDataList(self._data) 
    780         if self.isBatch: 
    781             self.batchComplete.append(self.dataList.currentIndex()) 
    782             self.startNextBatchItem() 
     622        # Append data to data list 
     623        self._data_list[self._data] = self._calculator.clone() 
     624 
     625        # Update model dict 
     626        self._models[self.model_item] = self.model 
     627 
     628        # Create new P(r) and fit plots 
     629        if self.pr_plot is None: 
     630            self.pr_plot = self.logic.newPRPlot(out, self._calculator, cov) 
     631            self.pr_plot_list[self._data] = self.pr_plot 
    783632        else: 
    784             self.isCalculating = False 
    785         self.updateGuiValues() 
     633            # FIXME: this should update the existing plot, not create a new one 
     634            self.pr_plot = self.logic.newPRPlot(out, self._calculator, cov) 
     635            self.pr_plot_list[self._data] = self.pr_plot 
     636        if self.data_plot is None: 
     637            self.data_plot = self.logic.new1DPlot(out, self._calculator) 
     638            self.data_plot_list[self._data] = self.data_plot 
     639        else: 
     640            # FIXME: this should update the existing plot, not create a new one 
     641            self.data_plot = self.logic.new1DPlot(out, self._calculator) 
     642            self.data_plot_list[self._data] = self.data_plot 
    786643 
    787644    def _threadError(self, error): 
     
    789646            Call-back method for calculation errors 
    790647        """ 
    791         logger.error(error) 
    792         if self.isBatch: 
    793             self.startNextBatchItem() 
    794         else: 
    795             self.stopCalculation() 
     648        logging.warning(error) 
  • src/sas/qtgui/Perspectives/Inversion/InversionUtils.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Perspectives/Inversion/Thread.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Perspectives/Inversion/UI/TabbedInversionUI.ui

    • Property mode changed from 100644 to 100755
    r72ecbdf2 r8f83719f  
    317317           <widget class="QLabel" name="label_22"> 
    318318            <property name="text"> 
    319              <string/> 
     319             <string>      </string> 
    320320            </property> 
    321321           </widget> 
     
    754754     </item> 
    755755     <item> 
    756       <widget class="QPushButton" name="stopButton"> 
    757        <property name="text"> 
    758         <string>Stop P(r)</string> 
    759        </property> 
    760       </widget> 
    761      </item> 
    762      <item> 
    763756      <spacer name="horizontalSpacer"> 
    764757       <property name="orientation"> 
  • src/sas/qtgui/Perspectives/Inversion/UI/__init__.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Perspectives/Inversion/UnitTesting/InversionPerspectiveTest.py

    r72ecbdf2 r50bfab0  
    1 import time 
     1import sys 
    22import unittest 
     3import logging 
    34from unittest.mock import MagicMock 
    45 
    56from PyQt5 import QtGui, QtWidgets 
     7from PyQt5.QtTest import QTest 
     8from PyQt5 import QtCore 
    69 
    7 from sas.qtgui.Utilities.GuiUtils import * 
     10import sas.qtgui.path_prepare 
    811from sas.qtgui.Perspectives.Inversion.InversionPerspective import InversionWindow 
    9 from sas.qtgui.Perspectives.Inversion.InversionUtils import WIDGETS 
     12from sas.sascalc.dataloader.loader import Loader 
    1013from sas.qtgui.Plotting.PlotterData import Data1D 
    1114 
     15from sas.qtgui.MainWindow.DataManager import DataManager 
     16import sas.qtgui.Utilities.LocalConfig 
    1217import sas.qtgui.Utilities.GuiUtils as GuiUtils 
    1318 
     
    1520app = QtWidgets.QApplication(sys.argv) 
    1621 
    17  
    18 class dummy_manager(object): 
    19     HELP_DIRECTORY_LOCATION = "html" 
    20     communicate = Communicate() 
    21  
    22     def communicator(self): 
    23         return self.communicate 
    24  
    25  
    2622class InversionTest(unittest.TestCase): 
    27     """ Test the Inversion Perspective GUI """ 
    28  
     23    '''Test the Inversion Interface''' 
    2924    def setUp(self): 
    30         """ Create the InversionWindow """ 
    31         self.widget = InversionWindow(dummy_manager()) 
    32         self.widget.show() 
    33         self.fakeData1 = GuiUtils.HashableStandardItem("A") 
    34         self.fakeData2 = GuiUtils.HashableStandardItem("B") 
    35         reference_data1 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
    36         reference_data1.filename = "Test A" 
    37         reference_data2 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
    38         reference_data2.filename = "Test B" 
    39         GuiUtils.updateModelItem(self.fakeData1, reference_data1) 
    40         GuiUtils.updateModelItem(self.fakeData2, reference_data2) 
     25        '''Create the InversionWindow''' 
     26        self.widget = InversionWindow(None) 
    4127 
    4228    def tearDown(self): 
    43         """ Destroy the InversionWindow """ 
    44         self.widget.setClosable(False) 
     29        '''Destroy the InversionWindow''' 
    4530        self.widget.close() 
    4631        self.widget = None 
    4732 
    48     def removeAllData(self): 
    49         """ Cleanup method to restore widget to its base state """ 
    50         if len(self.widget.dataList) > 0: 
    51             remove_me = list(self.widget._dataList.keys()) 
    52             self.widget.removeData(remove_me) 
    53  
    54     def baseGUIState(self): 
    55         """ Testing base state of Inversion """ 
    56         # base class information 
     33    def testDefaults(self): 
     34        '''Test the GUI in its default state''' 
    5735        self.assertIsInstance(self.widget, QtWidgets.QWidget) 
    5836        self.assertEqual(self.widget.windowTitle(), "P(r) Inversion Perspective") 
    59         self.assertFalse(self.widget.isClosable()) 
    60         self.assertFalse(self.widget.isCalculating) 
    61         # mapper 
     37        self.assertEqual(self.widget.model.columnCount(), 1) 
     38        self.assertEqual(self.widget.model.rowCount(), 22) 
     39        self.assertFalse(self.widget.calculateAllButton.isEnabled()) 
     40        self.assertFalse(self.widget.calculateThisButton.isEnabled()) 
    6241        self.assertIsInstance(self.widget.mapper, QtWidgets.QDataWidgetMapper) 
     42        # make sure the model is assigned and at least the data is mapped 
     43        self.assertEqual(self.widget.mapper.model(), self.widget.model) 
    6344        self.assertNotEqual(self.widget.mapper.mappedSection(self.widget.dataList), -1) 
     45 
    6446        # validators 
    6547        self.assertIsInstance(self.widget.noOfTermsInput.validator(), QtGui.QIntValidator) 
     
    7052        self.assertIsInstance(self.widget.slitHeightInput.validator(), QtGui.QDoubleValidator) 
    7153        self.assertIsInstance(self.widget.slitWidthInput.validator(), QtGui.QDoubleValidator) 
     54 
    7255        # model 
    7356        self.assertEqual(self.widget.model.rowCount(), 22) 
    74         self.assertEqual(self.widget.model.columnCount(), 1) 
    75         self.assertEqual(self.widget.mapper.model(), self.widget.model) 
    76         # buttons 
    77         self.assertFalse(self.widget.calculateThisButton.isEnabled()) 
    78         self.assertFalse(self.widget.removeButton.isEnabled()) 
    79         self.assertTrue(self.widget.stopButton.isEnabled()) 
    80         self.assertFalse(self.widget.stopButton.isVisible()) 
    81         self.assertFalse(self.widget.regConstantSuggestionButton.isEnabled()) 
    82         self.assertFalse(self.widget.noOfTermsSuggestionButton.isEnabled()) 
    83         self.assertFalse(self.widget.explorerButton.isEnabled()) 
    84         self.assertTrue(self.widget.helpButton.isEnabled()) 
    85         # extra windows and charts 
    86         self.assertIsNone(self.widget.dmaxWindow) 
    87         self.assertIsNone(self.widget.prPlot) 
    88         self.assertIsNone(self.widget.dataPlot) 
    89         # threads 
    90         self.assertIsNone(self.widget.calcThread) 
    91         self.assertIsNone(self.widget.estimationThread) 
    92         self.assertIsNone(self.widget.estimationThreadNT) 
    9357 
    94     def baseBatchState(self): 
    95         """ Testing the base batch fitting state """ 
    96         self.assertTrue(self.widget.allowBatch()) 
    97         self.assertFalse(self.widget.isBatch) 
    98         self.assertIsNone(self.widget.batchResultsWindow) 
    99         self.assertFalse(self.widget.calculateAllButton.isEnabled()) 
    100         self.assertEqual(len(self.widget.batchResults), 0) 
    101         self.assertEqual(len(self.widget.batchComplete), 0) 
    102         self.widget.closeBatchResults() 
    103         self.assertIsNone(self.widget.batchResultsWindow) 
     58    def testSetData(self): 
     59        ''' Check if sending data works as expected''' 
     60        # Create dummy data 
     61        item1 = GuiUtils.HashableStandardItem("A") 
     62        item2 = GuiUtils.HashableStandardItem("B") 
     63        reference_data = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
     64        GuiUtils.updateModelItem(item1, [reference_data]) 
     65        GuiUtils.updateModelItem(item2, [reference_data]) 
     66        self.widget.performEstimate = MagicMock() 
     67        self.widget.setData([item1, item2]) 
    10468 
    105     def zeroDataSetState(self): 
    106         """ Testing the base data state of the GUI """ 
    107         # data variables 
    108         self.assertIsNone(self.widget._data) 
    109         self.assertEqual(len(self.widget._dataList), 0) 
    110         self.assertEqual(self.widget.nTermsSuggested, 10) 
    111         # inputs 
    112         self.assertEqual(len(self.widget.dataList), 0) 
    113         self.assertEqual(self.widget.backgroundInput.text(), "0.0") 
    114         self.assertEqual(self.widget.minQInput.text(), "") 
    115         self.assertEqual(self.widget.maxQInput.text(), "") 
    116         self.assertEqual(self.widget.regularizationConstantInput.text(), "0.0001") 
    117         self.assertEqual(self.widget.noOfTermsInput.text(), "10") 
    118         self.assertEqual(self.widget.maxDistanceInput.text(), "140.0") 
     69        # Test the globals 
     70        self.assertEqual(len(self.widget._data_list), 2) 
     71        self.assertEqual(len(self.widget.data_plot_list), 2) 
     72        self.assertEqual(len(self.widget.pr_plot_list), 2) 
     73        self.assertEqual(self.widget.dataList.count(), 2) 
    11974 
    120     def oneDataSetState(self): 
    121         """ Testing the base data state of the GUI """ 
    122         # Test the globals after first sent 
    123         self.assertEqual(len(self.widget._dataList), 1) 
    124         self.assertEqual(self.widget.dataList.count(), 1) 
    125         # See that the buttons are now enabled properly 
    126         self.widget.enableButtons() 
    127         self.assertFalse(self.widget.calculateAllButton.isEnabled()) 
     75        # See that the buttons are now enabled 
     76        self.assertTrue(self.widget.calculateAllButton.isEnabled()) 
    12877        self.assertTrue(self.widget.calculateThisButton.isEnabled()) 
    12978        self.assertTrue(self.widget.removeButton.isEnabled()) 
    13079        self.assertTrue(self.widget.explorerButton.isEnabled()) 
    13180 
    132     def twoDataSetState(self): 
    133         """ Testing the base data state of the GUI """ 
    134         # Test the globals after first sent 
    135         self.assertEqual(len(self.widget._dataList), 2) 
    136         self.assertEqual(self.widget.dataList.count(), 2) 
    137         # See that the buttons are now enabled properly 
    138         self.widget.enableButtons() 
    139         self.assertTrue(self.widget.calculateThisButton.isEnabled()) 
    140         self.assertTrue(self.widget.calculateAllButton.isEnabled()) 
    141         self.assertTrue(self.widget.removeButton.isEnabled()) 
    142         self.assertTrue(self.widget.explorerButton.isEnabled()) 
     81    def notestRemoveData(self): 
     82        ''' Test data removal from widget ''' 
     83        # Create dummy data 
     84        item1 = GuiUtils.HashableStandardItem("A") 
     85        item2 = GuiUtils.HashableStandardItem("B") 
     86        reference_data1 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
     87        reference_data2 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
     88        GuiUtils.updateModelItem(item1, [reference_data1]) 
     89        GuiUtils.updateModelItem(item2, [reference_data2]) 
     90        self.widget.performEstimate = MagicMock() 
     91        self.widget.setData([item1, item2]) 
    14392 
    144     def testDefaults(self): 
    145         """ Test the GUI in its default state """ 
    146         self.baseGUIState() 
    147         self.zeroDataSetState() 
    148         self.baseBatchState() 
    149         self.removeAllData() 
     93        # Remove data 0 
     94        self.widget.removeData() 
     95 
     96        # Test the globals 
     97        self.assertEqual(len(self.widget._data_list), 1) 
     98        self.assertEqual(len(self.widget.data_plot_list), 1) 
     99        self.assertEqual(len(self.widget.pr_plot_list), 1) 
     100        self.assertEqual(self.widget.dataList.count(), 1) 
     101 
    150102 
    151103    def testAllowBatch(self): 
    152         """ Batch P(r) Tests """ 
    153         self.baseBatchState() 
    154         self.widget.setData([self.fakeData1]) 
    155         self.oneDataSetState() 
    156         self.widget.setData([self.fakeData2]) 
    157         self.twoDataSetState() 
    158         self.widget.calculateAllButton.click() 
    159         self.assertTrue(self.widget.isCalculating) 
    160         self.assertTrue(self.widget.isBatch) 
    161         self.assertTrue(self.widget.stopButton.isVisible()) 
    162         self.assertTrue(self.widget.stopButton.isEnabled()) 
    163         self.assertIsNotNone(self.widget.batchResultsWindow) 
    164         self.assertTrue(self.widget.batchResultsWindow.cmdHelp.isEnabled()) 
    165         self.assertEqual(self.widget.batchResultsWindow.tblParams.columnCount(), 9) 
    166         self.assertEqual(self.widget.batchResultsWindow.tblParams.rowCount(), 2) 
    167         # Test stop button 
    168         self.widget.stopButton.click() 
    169         self.assertTrue(self.widget.batchResultsWindow.isVisible()) 
    170         self.assertFalse(self.widget.stopButton.isVisible()) 
    171         self.assertTrue(self.widget.stopButton.isEnabled()) 
    172         self.assertFalse(self.widget.isBatch) 
    173         self.assertFalse(self.widget.isCalculating) 
    174         self.widget.batchResultsWindow.close() 
    175         self.assertIsNone(self.widget.batchResultsWindow) 
    176         # Last test 
    177         self.removeAllData() 
    178         self.baseBatchState() 
     104        ''' Batch is allowed for this perspective''' 
     105        self.assertTrue(self.widget.allowBatch()) 
    179106 
    180     def testSetData(self): 
    181         """ Check if sending data works as expected """ 
    182         self.zeroDataSetState() 
    183         self.widget.setData([self.fakeData1]) 
    184         self.oneDataSetState() 
    185         self.widget.setData([self.fakeData1]) 
    186         self.oneDataSetState() 
    187         self.widget.setData([self.fakeData2]) 
    188         self.twoDataSetState() 
    189         self.removeAllData() 
    190         self.zeroDataSetState() 
    191         self.removeAllData() 
     107    def notestModelChanged(self): 
     108        ''' test the model update ''' 
     109        # unfinished functionality 
     110        pass 
    192111 
    193     def testRemoveData(self): 
    194         """ Test data removal from widget """ 
    195         self.widget.setData([self.fakeData1, self.fakeData2]) 
    196         self.twoDataSetState() 
    197         # Remove data 0 
    198         self.widget.removeData() 
    199         self.oneDataSetState() 
    200         self.removeAllData() 
     112    def notestHelp(self): 
     113        ''' test help widget show ''' 
     114        # unfinished functionality 
     115        pass 
    201116 
    202     def testClose(self): 
    203         """ Test methods related to closing the window """ 
    204         self.assertFalse(self.widget.isClosable()) 
    205         self.widget.close() 
    206         self.assertTrue(self.widget.isMinimized()) 
    207         self.assertIsNone(self.widget.dmaxWindow) 
    208         self.assertIsNone(self.widget.batchResultsWindow) 
    209         self.widget.setClosable(False) 
    210         self.assertFalse(self.widget.isClosable()) 
    211         self.widget.close() 
    212         self.assertTrue(self.widget.isMinimized()) 
    213         self.widget.setClosable(True) 
    214         self.assertTrue(self.widget.isClosable()) 
    215         self.widget.setClosable() 
    216         self.assertTrue(self.widget.isClosable()) 
    217         self.removeAllData() 
     117    def testOpenExplorerWindow(self): 
     118        ''' open Dx window ''' 
     119        self.widget.openExplorerWindow() 
     120        self.assertTrue(self.widget.dmaxWindow.isVisible()) 
    218121 
    219122    def testGetNFunc(self): 
    220         """ test nfunc getter """ 
     123        ''' test nfunc getter ''' 
    221124        # Float 
    222125        self.widget.noOfTermsInput.setText("10.0") 
     
    229132            self.widget.noOfTermsInput.setText("") 
    230133            n = self.widget.getNFunc() 
    231             self.assertEqual(cm.output, ['ERROR:sas.qtgui.Perspectives.Inversion.InversionPerspective:Incorrect number of terms specified: ']) 
     134            self.assertEqual(cm.output, ['ERROR:root:Incorrect number of terms specified: ']) 
    232135        self.assertEqual(self.widget.getNFunc(), 10) 
    233136        # string 
     
    235138            self.widget.noOfTermsInput.setText("Nordvest Pizza") 
    236139            n = self.widget.getNFunc() 
    237             self.assertEqual(cm.output, ['ERROR:sas.qtgui.Perspectives.Inversion.InversionPerspective:Incorrect number of terms specified: Nordvest Pizza']) 
     140            self.assertEqual(cm.output, ['ERROR:root:Incorrect number of terms specified: Nordvest Pizza']) 
    238141        self.assertEqual(self.widget.getNFunc(), 10) 
    239         self.removeAllData() 
    240142 
    241143    def testSetCurrentData(self): 
    242         """ test current data setter """ 
    243         self.widget.setData([self.fakeData1, self.fakeData2]) 
     144        ''' test current data setter ''' 
     145        # Create dummy data 
     146        item1 = GuiUtils.HashableStandardItem("A") 
     147        item2 = GuiUtils.HashableStandardItem("B") 
     148        reference_data1 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
     149        reference_data2 = Data1D(x=[0.1, 0.2], y=[0.0, 0.0], dy=[0.0, 0.0]) 
     150        GuiUtils.updateModelItem(item1, [reference_data1]) 
     151        GuiUtils.updateModelItem(item2, [reference_data2]) 
     152        self.widget.performEstimate = MagicMock() 
     153        self.widget.setData([item1, item2]) 
    244154 
    245155        # Check that the current data is reference2 
    246         self.assertEqual(self.widget._data, self.fakeData2) 
     156        self.assertEqual(self.widget._data, item2) 
     157 
    247158        # Set the ref to none 
    248159        self.widget.setCurrentData(None) 
    249         self.assertEqual(self.widget._data, self.fakeData2) 
     160        self.assertEqual(self.widget._data, item2) 
     161 
    250162        # Set the ref to wrong type 
    251163        with self.assertRaises(AttributeError): 
    252164            self.widget.setCurrentData("Afandi Kebab") 
    253         # Set the reference to ref1 
    254         self.widget.setCurrentData(self.fakeData1) 
    255         self.assertEqual(self.widget._data, self.fakeData1) 
    256         self.removeAllData() 
    257165 
    258     def testModelChanged(self): 
    259         """ Test setting the input and the model and vice-versa """ 
    260         # Initial values 
    261         self.assertEqual(self.widget._calculator.get_dmax(), 140.0) 
    262         self.assertEqual(self.widget._calculator.get_qmax(), -1.0) 
    263         self.assertEqual(self.widget._calculator.get_qmin(), -1.0) 
    264         self.assertEqual(self.widget._calculator.slit_height, 0.0) 
    265         self.assertEqual(self.widget._calculator.slit_width, 0.0) 
    266         self.assertEqual(self.widget._calculator.alpha, 0.0001) 
    267         # Set new values 
    268         self.widget.maxDistanceInput.setText("1.0") 
    269         self.widget.maxQInput.setText("3.0") 
    270         self.widget.minQInput.setText("5.0") 
    271         self.widget.slitHeightInput.setText("7.0") 
    272         self.widget.slitWidthInput.setText("9.0") 
    273         self.widget.regularizationConstantInput.setText("11.0") 
    274         # Check new values 
    275         self.assertEqual(self.widget._calculator.get_dmax(), 1.0) 
    276         self.assertEqual(self.widget._calculator.get_qmax(), 3.0) 
    277         self.assertEqual(self.widget._calculator.get_qmin(), 5.0) 
    278         self.assertEqual(self.widget._calculator.slit_height, 7.0) 
    279         self.assertEqual(self.widget._calculator.slit_width, 9.0) 
    280         self.assertEqual(self.widget._calculator.alpha, 11.0) 
    281         # Change model directly 
    282         self.widget.model.setItem(WIDGETS.W_MAX_DIST, QtGui.QStandardItem("2.0")) 
    283         self.widget.model.setItem(WIDGETS.W_QMIN, QtGui.QStandardItem("4.0")) 
    284         self.widget.model.setItem(WIDGETS.W_QMAX, QtGui.QStandardItem("6.0")) 
    285         self.widget.model.setItem(WIDGETS.W_SLIT_HEIGHT, QtGui.QStandardItem("8.0")) 
    286         self.widget.model.setItem(WIDGETS.W_SLIT_WIDTH, QtGui.QStandardItem("10.0")) 
    287         self.widget.model.setItem(WIDGETS.W_REGULARIZATION, QtGui.QStandardItem("12.0")) 
    288         # Check values 
    289         self.assertEqual(self.widget._calculator.get_dmax(), 2.0) 
    290         self.assertEqual(self.widget._calculator.get_qmin(), 4.0) 
    291         self.assertEqual(self.widget._calculator.get_qmax(), 6.0) 
    292         self.assertEqual(self.widget._calculator.slit_height, 8.0) 
    293         self.assertEqual(self.widget._calculator.slit_width, 10.0) 
    294         self.assertEqual(self.widget._calculator.alpha, 12.0) 
    295         self.removeAllData() 
    296  
    297     def testOpenExplorerWindow(self): 
    298         """ open Dx window """ 
    299         self.assertIsNone(self.widget.dmaxWindow) 
    300         self.assertFalse(self.widget.explorerButton.isEnabled()) 
    301         self.widget.openExplorerWindow() 
    302         self.assertIsNotNone(self.widget.dmaxWindow) 
    303         self.assertTrue(self.widget.dmaxWindow.isVisible()) 
    304         self.assertTrue(self.widget.dmaxWindow.windowTitle() == "Dₐₓ Explorer") 
    305  
     166        # Set the reference to ref2 
     167        self.widget.setCurrentData(item1) 
     168        self.assertEqual(self.widget._data, item1) 
    306169 
    307170if __name__ == "__main__": 
  • src/sas/qtgui/Perspectives/Inversion/__init__.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Perspectives/Inversion/media/pr_help.rst

    r417c03f r417c03f  
    6868.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    6969 
    70 .. _Batch_Pr_Mode: 
    71  
    72 Batch P(r) inversion 
    73 -------------------- 
    74  
    75 The p(r) calculator accepts any number of data sets, and supports batch fitting 
    76 for all data sets in the p(r) data set combo box. Switching between data sets in 
    77 the combo box allows for individual fits and review of fit parameters. The 
    78 displayed plots will also update to include the latest fit results for the 
    79 selected data set. 
    80  
    81 The 'Calculate All' button will run the p(r) calculation for each file, 
    82 sequentially. The calculator will estimate the number of terms, background, and 
    83 regularization constant for each file prior to running the p(r) calculation. 
    84 The final results for all data sets are then presented in a savable data table. 
    85  
    86 .. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    87  
    8870Reference 
    8971--------- 
     
    9476.. ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
    9577 
    96 .. note::  This help document was last modified by Jeff Krzywon, 18 April 2018 
     78.. note::  This help document was last modified by Paul Butler, 05 September, 2016 
  • src/sas/qtgui/Perspectives/__init__.py

    • Property mode changed from 100644 to 100755
  • src/sas/qtgui/Plotting/ConvertUnits.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Plotting/DataTransform.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Plotting/Slicers/Arc.py

    • Property mode changed from 100755 to 100644
  • src/sas/qtgui/Utilities/GridPanel.py

    raed0532 raed0532  
    410410            index += 1 
    411411 
    412  
    413 class BatchInversionOutputPanel(BatchOutputPanel): 
    414     """ 
    415         Class for stateless grid-like printout of P(r) parameters for any number 
    416         of data sets 
    417     """ 
    418     def __init__(self, parent = None, output_data=None): 
    419  
    420         super(BatchInversionOutputPanel, self).__init__(parent, output_data) 
    421         _translate = QtCore.QCoreApplication.translate 
    422         self.setWindowTitle(_translate("GridPanelUI", "Batch P(r) Results")) 
    423  
    424     def setupTable(self, data): 
    425         """ 
    426         Create tablewidget items and show them, based on params 
    427         """ 
    428         # headers 
    429         param_list = ['Filename', 'Rg [à
    430 ]', 'Chi^2/dof', 'I(Q=0)', 'Oscillations', 
    431                       'Background [à
    432 ^-1]', 'P+ Fraction', 'P+1-theta Fraction', 
    433                       'Calc. Time [sec]'] 
    434  
    435         keys = data.keys() 
    436         rows = len(keys) 
    437         columns = len(param_list) 
    438         self.tblParams.setColumnCount(columns) 
    439         self.tblParams.setRowCount(rows) 
    440  
    441         for i, param in enumerate(param_list): 
    442             self.tblParams.setHorizontalHeaderItem(i, QtWidgets.QTableWidgetItem(param)) 
    443  
    444         # first - Chi2 and data filename 
    445         for i_row, (filename, pr) in enumerate(data.items()): 
    446             out = pr.out 
    447             cov = pr.cov 
    448             if out is None: 
    449                 logging.warning("P(r) for {} did not converge.".format(filename)) 
    450                 continue 
    451             self.tblParams.setItem(i_row, 0, QtWidgets.QTableWidgetItem( 
    452                 "{}".format(filename))) 
    453             self.tblParams.setItem(i_row, 1, QtWidgets.QTableWidgetItem( 
    454                 "{:.3g}".format(pr.rg(out)))) 
    455             self.tblParams.setItem(i_row, 2, QtWidgets.QTableWidgetItem( 
    456                 "{:.3g}".format(pr.chi2[0]))) 
    457             self.tblParams.setItem(i_row, 3, QtWidgets.QTableWidgetItem( 
    458                 "{:.3g}".format(pr.iq0(out)))) 
    459             self.tblParams.setItem(i_row, 4, QtWidgets.QTableWidgetItem( 
    460                 "{:.3g}".format(pr.oscillations(out)))) 
    461             self.tblParams.setItem(i_row, 5, QtWidgets.QTableWidgetItem( 
    462                 "{:.3g}".format(pr.background))) 
    463             self.tblParams.setItem(i_row, 6, QtWidgets.QTableWidgetItem( 
    464                 "{:.3g}".format(pr.get_positive(out)))) 
    465             self.tblParams.setItem(i_row, 7, QtWidgets.QTableWidgetItem( 
    466                 "{:.3g}".format(pr.get_pos_err(out, cov)))) 
    467             self.tblParams.setItem(i_row, 8, QtWidgets.QTableWidgetItem( 
    468                 "{:.2g}".format(pr.elapsed))) 
    469  
    470         self.tblParams.resizeColumnsToContents() 
    471  
    472     @classmethod 
    473     def onHelp(cls): 
    474         """ 
    475         Open a local url in the default browser 
    476         """ 
    477         location = GuiUtils.HELP_DIRECTORY_LOCATION 
    478         url = "/user/sasgui/perspectives/pr/pr_help.html#batch-pr-mode" 
    479         try: 
    480             webbrowser.open('file://' + os.path.realpath(location + url)) 
    481         except webbrowser.Error as ex: 
    482             logging.warning("Cannot display help. %s" % ex) 
    483  
    484     def closeEvent(self, event): 
    485         """Tell the parent window the window closed""" 
    486         self.parent.batchResultsWindow = None 
    487         event.accept() 
  • src/sas/sascalc/pr/invertor.py

    r6da860a r8f83719f  
    481481            float(chi2) 
    482482        except: 
    483             chi2 = -1.0 
     483            chi2 = [-1.0] 
    484484        self.chi2 = chi2 
    485485 
Note: See TracChangeset for help on using the changeset viewer.