Changes in / [04e1c80:186d678] in sasview


Ignore:
Location:
src/sas
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/MainWindow/DataExplorer.py

    r722b7d6 r722b7d6  
    225225        Called when the "Open Project" menu item chosen. 
    226226        """ 
     227        # check if any items loaded and warn about data deletion 
     228        if self.model.rowCount() > 0: 
     229            msg = "This operation will set remove all data, plots and analyses from" 
     230            msg += " SasView before loading the project. Do you wish to continue?" 
     231            msgbox = QtWidgets.QMessageBox(self) 
     232            msgbox.setIcon(QtWidgets.QMessageBox.Warning) 
     233            msgbox.setText(msg) 
     234            msgbox.setWindowTitle("Project Load") 
     235            # custom buttons 
     236            button_yes = QtWidgets.QPushButton("Yes") 
     237            msgbox.addButton(button_yes, QtWidgets.QMessageBox.YesRole) 
     238            button_no = QtWidgets.QPushButton("No") 
     239            msgbox.addButton(button_no, QtWidgets.QMessageBox.RejectRole) 
     240            retval = msgbox.exec_() 
     241            if retval == QtWidgets.QMessageBox.RejectRole: 
     242                # cancel fit 
     243                return 
     244 
    227245        kwargs = { 
    228246            'parent'    : self, 
    229247            'caption'   : 'Open Project', 
    230             'filter'    : 'Project (*.json);;All files (*.*)', 
     248            'filter'    : 'Project Files (*.json);;Old Project Files (*.svs);;All files (*.*)', 
    231249            'options'   : QtWidgets.QFileDialog.DontUseNativeDialog 
    232250        } 
    233251        filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 
    234252        if filename: 
    235             load_thread = threads.deferToThread(self.readProject, filename) 
    236             load_thread.addCallback(self.readProjectComplete) 
    237             load_thread.addErrback(self.readProjectFailed) 
    238  
    239     def loadFailed(self, reason): 
    240         """ 
    241         """ 
    242         print("file load FAILED: ", reason) 
    243         pass 
    244  
    245     def readProjectFailed(self, reason): 
    246         """ 
    247         """ 
    248         print("readProjectFailed FAILED: ", reason) 
    249         pass 
    250  
    251     def readProject(self, filename): 
    252         self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename)) 
    253         try: 
    254             manager = DataManager() 
    255             with open(filename, 'r') as infile: 
    256                 manager.load_from_readable(infile) 
    257  
    258             self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename)) 
    259             return manager 
    260  
    261         except: 
    262             self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename)) 
    263             raise 
    264  
    265     def readProjectComplete(self, manager): 
    266         self.model.clear() 
    267  
    268         self.manager.assign(manager) 
    269         self.model.beginResetModel() 
    270         for id, item in self.manager.get_all_data().items(): 
    271             self.updateModel(item.data, item.path) 
    272  
    273         self.model.endResetModel() 
     253            self.deleteAllItems() 
     254            self.readProject(filename) 
     255 
     256    def loadAnalysis(self): 
     257        """ 
     258        Called when the "Open Analysis" menu item chosen. 
     259        """ 
     260        kwargs = { 
     261            'parent'    : self, 
     262            'caption'   : 'Open Analysis', 
     263            'filter'    : 'Project (*.fitv);;All files (*.*)', 
     264            'options'   : QtWidgets.QFileDialog.DontUseNativeDialog 
     265        } 
     266        filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 
     267        if filename: 
     268            self.readAnalysis(filename) 
    274269 
    275270    def saveProject(self): 
     
    285280        name_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 
    286281        filename = name_tuple[0] 
    287         if filename: 
    288             _, extension = os.path.splitext(filename) 
    289             if not extension: 
    290                 filename = '.'.join((filename, 'json')) 
    291             self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
    292             with open(filename, 'w') as outfile: 
    293                 self.manager.save_to_writable(outfile) 
     282        if not filename: 
     283            return 
     284        _, extension = os.path.splitext(filename) 
     285        if not extension: 
     286            filename = '.'.join((filename, 'json')) 
     287        self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
     288 
     289        return filename 
     290 
     291    def saveAsAnalysisFile(self, tab_id=1): 
     292        """ 
     293        Show the save as... dialog and return the chosen filepath 
     294        """ 
     295        default_name = "FitPage"+str(tab_id)+".fitv" 
     296 
     297        wildcard = "fitv files (*.fitv)" 
     298        kwargs = { 
     299            'caption'   : 'Save As', 
     300            'directory' : default_name, 
     301            'filter'    : wildcard, 
     302            'parent'    : None, 
     303        } 
     304        # Query user for filename. 
     305        filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 
     306        filename = filename_tuple[0] 
     307        return filename 
     308 
     309    def saveAnalysis(self, data, tab_id=1): 
     310        """ 
     311        Called when the "Save Analysis" menu item chosen. 
     312        """ 
     313        filename = self.saveAsAnalysisFile(tab_id) 
     314        if not filename: 
     315            return 
     316        _, extension = os.path.splitext(filename) 
     317        if not extension: 
     318            filename = '.'.join((filename, 'fitv')) 
     319        self.communicator.statusBarUpdateSignal.emit("Saving analysis... %s\n" % os.path.basename(filename)) 
     320 
     321        with open(filename, 'w') as outfile: 
     322            GuiUtils.saveData(outfile, data) 
     323 
     324        self.communicator.statusBarUpdateSignal.emit('Analysis saved.') 
     325 
     326    def allDataForModel(self, model): 
     327        # data model 
     328        all_data = {} 
     329        for i in range(model.rowCount()): 
     330            properties = {} 
     331            item = model.item(i) 
     332            data = GuiUtils.dataFromItem(item) 
     333            if data is None: continue 
     334            # Now, all plots under this item 
     335            filename = data.filename 
     336            is_checked = item.checkState() 
     337            properties['checked'] = is_checked 
     338            other_datas = [] 
     339            # no need to save other_datas - things will be refit on read 
     340            #other_datas = GuiUtils.plotsFromFilename(filename, model) 
     341            # skip the main plot 
     342            #other_datas = list(other_datas.values())[1:] 
     343            all_data[data.id] = [data, properties, other_datas] 
     344        return all_data 
     345 
     346    def getDataForID(self, id): 
     347        # return the dataset with the given ID 
     348        all_data = [] 
     349        for model in (self.model, self.theory_model): 
     350            for i in range(model.rowCount()): 
     351                properties = {} 
     352                item = model.item(i) 
     353                data = GuiUtils.dataFromItem(item) 
     354                if data is None: continue 
     355                if data.id != id: continue 
     356                # We found the dataset - save it. 
     357                filename = data.filename 
     358                is_checked = item.checkState() 
     359                properties['checked'] = is_checked 
     360                other_datas = GuiUtils.plotsFromFilename(filename, model) 
     361                # skip the main plot 
     362                other_datas = list(other_datas.values())[1:] 
     363                all_data = [data, properties, other_datas] 
     364                break 
     365        return all_data 
     366 
     367    def getAllData(self): 
     368        """ 
     369        converts all datasets into serializable dictionary 
     370        """ 
     371        data = self.allDataForModel(self.model) 
     372        theory = self.allDataForModel(self.theory_model) 
     373 
     374        all_data = {} 
     375        for key, value in data.items(): 
     376            all_data[key] = value 
     377        for key, value in theory.items(): 
     378            if key in all_data: 
     379                raise ValueError("Inconsistent data in Project file.") 
     380            all_data[key] = value 
     381        return all_data 
     382 
     383    def saveDataToFile(self, outfile): 
     384        """ 
     385        Save every dataset to a json file 
     386        """ 
     387        all_data = self.getAllData() 
     388        # save datas 
     389        GuiUtils.saveData(outfile, all_data) 
     390 
     391    def readProject(self, filename): 
     392        """ 
     393        Read out datasets and fitpages from file 
     394        """ 
     395        # Find out the filetype based on extension 
     396        ext = os.path.splitext(filename)[1] 
     397        all_data = {} 
     398        if 'svs' in ext.lower(): 
     399            # backward compatibility mode. 
     400            datasets = GuiUtils.readProjectFromSVS(filename) 
     401            #[[item_1, state_1], [item_2, state_2],...] 
     402 
     403            # Convert fitpage properties and update the dict 
     404            all_data = GuiUtils.convertFromSVS(datasets) 
     405        else: 
     406            with open(filename, 'r') as infile: 
     407                all_data = GuiUtils.readDataFromFile(infile) 
     408 
     409        for key, value in all_data.items(): 
     410            data_dict = {key:value['fit_data']} 
     411            items = self.updateModelFromData(data_dict) 
     412            # send newly created item to its perspective 
     413            if 'fit_params' in value: 
     414                self.sendItemToPerspective(items[0]) 
     415                # Make the perspective read the rest of the read data 
     416                self._perspective().updateFromParameters(value['fit_params']) 
     417 
     418        pass # debugger 
     419 
     420    def readAnalysis(self, filename): 
     421        """ 
     422        Read out a single dataset and fitpage from file 
     423        """ 
     424        with open(filename, 'r') as infile: 
     425            all_data = GuiUtils.readDataFromFile(infile) 
     426            # simulate full project structure 
     427            all_data_dict = {1:all_data['fit_data']} 
     428            items = self.updateModelFromData(all_data_dict) 
     429            # TODO: allow other perspectives 
     430            # send newly created item to its perspective 
     431            if len(items) > 0: 
     432                self.sendItemToPerspective(items[0]) 
     433            # Make the perspective read the rest of the read data 
     434            self._perspective().updateFromParameters(all_data['fit_params']) 
     435 
     436            pass 
     437 
     438    def updateModelFromData(self, data): 
     439        """ 
     440        Given data from analysis/project file, 
     441        create indices and populate data/theory models 
     442        """ 
     443        # model items for top level datasets 
     444        items = [] 
     445        #self.model.beginResetModel() 
     446        for key, value in data.items(): 
     447            # key - cardinal number of dataset 
     448            # value - main dataset, [dependant filesets] 
     449            # add the main index 
     450            if not value: continue 
     451            new_data = value[0] 
     452            from sas.sascalc.dataloader.data_info import Data1D as old_data1d 
     453            from sas.sascalc.dataloader.data_info import Data2D as old_data2d 
     454            if isinstance(new_data, (old_data1d, old_data2d)): 
     455                new_data = self.manager.create_gui_data(value[0], new_data.filename) 
     456            assert isinstance(new_data, (Data1D, Data2D)) 
     457            properties = value[1] 
     458            is_checked = properties['checked'] 
     459            new_item = GuiUtils.createModelItemWithPlot(new_data, new_data.filename) 
     460            new_item.setCheckState(is_checked) 
     461            items.append(new_item) 
     462            model = self.theory_model 
     463            if new_data.is_data: 
     464                model = self.model 
     465            model.appendRow(new_item) 
     466            self.manager.add_data(data_list={new_data.id:new_data}) 
     467 
     468            # Add the underlying data 
     469            if not value[2]: 
     470                continue 
     471            for plot in value[2]: 
     472                assert isinstance(plot, (Data1D, Data2D)) 
     473                GuiUtils.updateModelItemWithPlot(new_item, plot, plot.name) 
     474        return items 
    294475 
    295476    def deleteFile(self, event): 
     
    410591            retval = msgbox.exec_() 
    411592 
     593    def sendItemToPerspective(self, item): 
     594        """ 
     595        Send the passed item data to the current perspective and set the relevant notifiers 
     596        """ 
     597        # Set the signal handlers 
     598        self.communicator.updateModelFromPerspectiveSignal.connect(self.updateModelFromPerspective) 
     599        selected_items = [item] 
     600        # Notify the GuiManager about the send request 
     601        try: 
     602            self._perspective().setData(data_item=selected_items, is_batch=False) 
     603        except Exception as ex: 
     604            msg = "%s perspective returned the following message: \n%s\n" %(self._perspective().name, str(ex)) 
     605            logging.error(msg) 
     606            msg = str(ex) 
     607            msgbox = QtWidgets.QMessageBox() 
     608            msgbox.setIcon(QtWidgets.QMessageBox.Critical) 
     609            msgbox.setText(msg) 
     610            msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok) 
     611            retval = msgbox.exec_() 
    412612 
    413613    def freezeCheckedData(self): 
     
    10361236        self.actionQuick3DPlot.triggered.connect(self.quickData3DPlot) 
    10371237        self.actionEditMask.triggered.connect(self.showEditDataMask) 
    1038         self.actionDelete.triggered.connect(self.deleteItem) 
     1238        self.actionDelete.triggered.connect(self.deleteSelectedItem) 
    10391239        self.actionFreezeResults.triggered.connect(self.freezeSelectedItems) 
    10401240 
     
    12481448                self.freezeItem(item_to_copy) 
    12491449 
    1250     def deleteItem(self): 
     1450    def deleteAllItems(self): 
     1451        """ 
     1452        Deletes all datasets from both model and theory_model 
     1453        """ 
     1454        deleted_items = [self.model.item(row) for row in range(self.model.rowCount()) 
     1455                         if self.model.item(row).isCheckable()] 
     1456        deleted_names = [item.text() for item in deleted_items] 
     1457        # Let others know we deleted data 
     1458        self.communicator.dataDeletedSignal.emit(deleted_items) 
     1459        # update stored_data 
     1460        self.manager.update_stored_data(deleted_names) 
     1461 
     1462        # Clear the model 
     1463        self.model.clear() 
     1464 
     1465    def deleteSelectedItem(self): 
    12511466        """ 
    12521467        Delete the current item 
     
    12651480            return 
    12661481 
     1482        indices = self.current_view.selectedIndexes() 
     1483        self.deleteIndices(indices) 
     1484 
     1485    def deleteIndices(self, indices): 
     1486        """ 
     1487        Delete model idices from the current view 
     1488        """ 
     1489        proxy = self.current_view.model() 
     1490        model = proxy.sourceModel() 
     1491 
     1492        deleted_items = [] 
     1493        deleted_names = [] 
     1494 
    12671495        # Every time a row is removed, the indices change, so we'll just remove 
    12681496        # rows and keep calling selectedIndexes until it returns an empty list. 
    1269         indices = self.current_view.selectedIndexes() 
    1270  
    1271         proxy = self.current_view.model() 
    1272         model = proxy.sourceModel() 
    1273  
    1274         deleted_items = [] 
    1275         deleted_names = [] 
    1276  
    12771497        while len(indices) > 0: 
    12781498            index = indices[0] 
    1279             row_index = proxy.mapToSource(index) 
    1280             item_to_delete = model.itemFromIndex(row_index) 
     1499            #row_index = proxy.mapToSource(index) 
     1500            #item_to_delete = model.itemFromIndex(row_index) 
     1501            item_to_delete = model.itemFromIndex(index) 
    12811502            if item_to_delete and item_to_delete.isCheckable(): 
    1282                 row = row_index.row() 
     1503                #row = row_index.row() 
     1504                row = index.row() 
    12831505 
    12841506                # store the deleted item details so we can pass them on later 
     
    14071629        checkbox_item.setCheckable(True) 
    14081630        checkbox_item.setCheckState(QtCore.Qt.Checked) 
    1409         checkbox_item.setText(os.path.basename(p_file)) 
     1631        if p_file is not None: 
     1632            checkbox_item.setText(os.path.basename(p_file)) 
    14101633 
    14111634        # Add the actual Data1D/Data2D object 
  • src/sas/qtgui/MainWindow/DataManager.py

    re2e5f3d r345b3b3  
    2929from sas.qtgui.Plotting.PlotterData import Data1D 
    3030from sas.qtgui.Plotting.PlotterData import Data2D 
    31 from sas.qtgui.Plotting.Plottables import Plottable 
    3231from sas.qtgui.Plotting.Plottables import PlottableTheory1D 
    3332from sas.qtgui.Plotting.Plottables import PlottableFit1D 
  • src/sas/qtgui/MainWindow/GuiManager.py

    r0c83303 r0c83303  
    254254        if self._current_perspective: 
    255255            self._current_perspective.setClosable() 
    256             #self._workspace.workspace.removeSubWindow(self._current_perspective) 
    257256            self._current_perspective.close() 
    258257            self._workspace.workspace.removeSubWindow(self._current_perspective) 
     
    468467        self._workspace.actionOpen_Project.triggered.connect(self.actionOpen_Project) 
    469468        self._workspace.actionOpen_Analysis.triggered.connect(self.actionOpen_Analysis) 
    470         self._workspace.actionSave.triggered.connect(self.actionSave) 
     469        self._workspace.actionSave.triggered.connect(self.actionSave_Project) 
    471470        self._workspace.actionSave_Analysis.triggered.connect(self.actionSave_Analysis) 
    472471        self._workspace.actionQuit.triggered.connect(self.actionQuit) 
     
    558557        """ 
    559558        """ 
    560         print("actionOpen_Analysis TRIGGERED") 
    561         pass 
    562  
    563     def actionSave(self): 
     559        self.filesWidget.loadAnalysis() 
     560        pass 
     561 
     562    def actionSave_Project(self): 
    564563        """ 
    565564        Menu Save Project 
    566565        """ 
    567         self.filesWidget.saveProject() 
     566        filename = self.filesWidget.saveProject() 
     567 
     568        # datasets 
     569        all_data = self.filesWidget.getAllData() 
     570 
     571        # fit tabs 
     572        params = self.perspective().serializeAllFitpage() 
     573 
     574        # project dictionary structure: 
     575        # analysis[data.id] = [{"fit_data":[data, checkbox, child data], 
     576        #                       "fit_params":[fitpage_state]} 
     577        # "fit_params" not present if dataset not sent to fitting 
     578        analysis = {} 
     579 
     580        for id, data in all_data.items(): 
     581            data_content = {"fit_data":data} 
     582            if id in params.keys(): 
     583                # this dataset is represented also by the fit tab. Add to it. 
     584                data_content["fit_params"] = params[id] 
     585            analysis[id] = data_content 
     586 
     587        with open(filename, 'w') as outfile: 
     588            GuiUtils.saveData(outfile, analysis) 
    568589 
    569590    def actionSave_Analysis(self): 
     
    571592        Menu File/Save Analysis 
    572593        """ 
    573         self.communicate.saveAnalysisSignal.emit() 
     594        per = self.perspective() 
     595        if not isinstance(per, FittingWindow): 
     596            return 
     597        # get fit page serialization 
     598        params = per.serializeCurrentFitpage() 
     599        data_id = per.currentTabDataId() 
     600        tab_id = per.currentTab.tab_id 
     601        data = self.filesWidget.getDataForID(data_id) 
     602        analysis = {} 
     603        analysis['fit_data'] = data 
     604        analysis['fit_params'] = params 
     605 
     606        self.filesWidget.saveAnalysis(analysis, tab_id) 
     607 
     608        pass 
    574609 
    575610    def actionQuit(self): 
     
    10471082        """ 
    10481083        self._workspace.actionReport.setEnabled(False) 
     1084        self._workspace.actionOpen_Analysis.setEnabled(False) 
     1085        self._workspace.actionSave_Analysis.setEnabled(False) 
     1086        if hasattr(perspective, 'isSerializable') and perspective.isSerializable(): 
     1087            self._workspace.actionOpen_Analysis.setEnabled(True) 
     1088            self._workspace.actionSave_Analysis.setEnabled(True) 
     1089 
    10491090        if isinstance(perspective, Perspectives.PERSPECTIVES["Fitting"]): 
    10501091            self.checkAnalysisOption(self._workspace.actionFitting) 
  • src/sas/qtgui/MainWindow/UnitTesting/DataExplorerTest.py

    ra24eacf rb1b71ad  
    854854 
    855855        # Attempt at deleting 
    856         self.form.deleteItem() 
     856        self.form.deleteSelectedItem() 
    857857 
    858858        # Test the warning dialog called once 
     
    868868        self.form.current_view.selectionModel().select(select_index, QtCore.QItemSelectionModel.Rows) 
    869869        # delete it. now for good 
    870         self.form.deleteItem() 
     870        self.form.deleteSelectedItem() 
    871871 
    872872        # Test the warning dialog called once 
  • src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py

    rd2007a8 ra3c59503  
    112112    def onLatexCopy(self): 
    113113        self.currentTab.onCopyToClipboard("Latex") 
     114 
     115    def serializeAllFitpage(self): 
     116        # serialize all active fitpages and return 
     117        # a dictionary: {data_id: fitpage_state} 
     118        params = {} 
     119        for i, tab in enumerate(self.tabs): 
     120            tab_data = self.getSerializedFitpage(tab) 
     121            if tab.tab_id is None: continue 
     122            id = tab_data['data_id'][0] 
     123            params[id] = tab_data 
     124        return params 
     125 
     126    def serializeCurrentFitpage(self): 
     127        # serialize current(active) fitpage 
     128        return self.getSerializedFitpage(self.currentTab) 
     129 
     130    def getSerializedFitpage(self, tab): 
     131        """ 
     132        get serialize requested fit tab 
     133        """ 
     134        fitpage_state = tab.getFitPage() 
     135        fitpage_state += tab.getFitModel() 
     136        # put the text into dictionary 
     137        line_dict = {} 
     138        for line in fitpage_state: 
     139            #content = line.split(',') 
     140            if len(line) > 1: 
     141                line_dict[line[0]] = line[1:] 
     142        return line_dict 
     143 
     144    def currentTabDataId(self): 
     145        """ 
     146        Returns the data ID of the current tab 
     147        """ 
     148        tab_id = None 
     149        if self.currentTab.data: 
     150            tab_id = self.currentTab.data.id 
     151        return tab_id 
     152 
     153    def updateFromParameters(self, parameters): 
     154        """ 
     155        Pass the update parameters to the current fit page 
     156        """ 
     157        self.currentTab.createPageForParameters(parameters) 
    114158 
    115159    def closeEvent(self, event): 
     
    258302        return True 
    259303 
     304    def isSerializable(self): 
     305        """ 
     306        Tell the caller that this perspective writes its state 
     307        """ 
     308        return True 
     309 
    260310    def setData(self, data_item=None, is_batch=False): 
    261311        """ 
     
    337387        pass 
    338388 
     389    def getCurrentStateAsXml(self): 
     390        """ 
     391        Returns an XML version of the current state 
     392        """ 
     393        state = {} 
     394        for tab in self.tabs: 
     395            pass 
     396        return state 
     397 
    339398    @property 
    340399    def currentTab(self): 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r0c83303 r0c83303  
    5252TAB_POLY = 3 
    5353CATEGORY_DEFAULT = "Choose category..." 
     54MODEL_DEFAULT = "Choose model..." 
    5455CATEGORY_STRUCTURE = "Structure Factor" 
    5556CATEGORY_CUSTOM = "Plugin Models" 
     
    574575        # Signals from other widgets 
    575576        self.communicate.customModelDirectoryChanged.connect(self.onCustomModelChange) 
    576         self.communicate.saveAnalysisSignal.connect(self.savePageState) 
    577         #self.communicate.loadAnalysisSignal.connect(self.loadPageState) 
    578577        self.smearing_widget.smearingChangedSignal.connect(self.onSmearingOptionsUpdate) 
    579578 
     
    10291028        model = self.cbModel.currentText() 
    10301029 
     1030        if model == MODEL_DEFAULT: 
     1031            # if the previous category was not the default, keep it. 
     1032            # Otherwise, just return 
     1033            if self._previous_model_index != 0: 
     1034                # We need to block signals, or else state changes on perceived unchanged conditions 
     1035                self.cbModel.blockSignals(True) 
     1036                self.cbModel.setCurrentIndex(self._previous_model_index) 
     1037                self.cbModel.blockSignals(False) 
     1038            return 
     1039 
    10311040        # Assure the control is active 
    10321041        if not self.cbModel.isEnabled(): 
     
    10351044        if not model: 
    10361045            return 
     1046 
     1047        self.chkMagnetism.setEnabled(self.canHaveMagnetism()) 
     1048        self.chkMagnetism.setEnabled(self.canHaveMagnetism()) 
     1049        self.tabFitting.setTabEnabled(TAB_MAGNETISM, self.chkMagnetism.isChecked() and self.canHaveMagnetism()) 
     1050        self._previous_model_index = self.cbModel.currentIndex() 
    10371051 
    10381052        # Reset parameters to fit 
     
    12131227            self._model_model.clear() 
    12141228            return 
    1215  
     1229        # Wipe out the parameter model 
     1230        self._model_model.clear() 
    12161231        # Safely clear and enable the model combo 
    12171232        self.cbModel.blockSignals(True) 
     
    12251240        model_list = self.master_category_dict[category] 
    12261241        # Populate the models combobox 
     1242        self.cbModel.blockSignals(True) 
     1243        self.cbModel.addItem(MODEL_DEFAULT) 
    12271244        self.cbModel.addItems(sorted([model for (model, _) in model_list])) 
     1245        self.cbModel.blockSignals(False) 
    12281246 
    12291247    def onPolyModelChange(self, top, bottom): 
     
    34103428        return report_logic.reportList() 
    34113429 
    3412     def savePageState(self): 
    3413         """ 
    3414         Create and serialize local PageState 
    3415         """ 
    3416         filepath = self.saveAsAnalysisFile() 
    3417         if filepath is None or filepath == "": 
    3418             return 
    3419  
    3420         fitpage_state = self.getFitPage() 
    3421         fitpage_state += self.getFitModel() 
    3422  
    3423         with open(filepath, 'w') as statefile: 
    3424             for line in fitpage_state: 
    3425                 statefile.write(str(line)) 
    3426  
    3427         self.communicate.statusBarUpdateSignal.emit('Analysis saved.') 
    3428  
    3429     def saveAsAnalysisFile(self): 
    3430         """ 
    3431         Show the save as... dialog and return the chosen filepath 
    3432         """ 
    3433         default_name = "FitPage"+str(self.tab_id)+".fitv" 
    3434  
    3435         wildcard = "fitv files (*.fitv)" 
    3436         kwargs = { 
    3437             'caption'   : 'Save As', 
    3438             'directory' : default_name, 
    3439             'filter'    : wildcard, 
    3440             'parent'    : None, 
    3441         } 
    3442         # Query user for filename. 
    3443         filename_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 
    3444         filename = filename_tuple[0] 
    3445         return filename 
    3446  
    34473430    def loadPageStateCallback(self,state=None, datainfo=None, format=None): 
    34483431        """ 
     
    35633546        """ 
    35643547        param_list = [] 
     3548        if self.kernel_module is None: 
     3549            return param_list 
     3550 
    35653551        param_list.append(['model_name', str(self.cbModel.currentText())]) 
    35663552 
     
    36673653        cb_text = cb.text() 
    36683654 
    3669         context = {} 
    36703655        lines = cb_text.split(':') 
    36713656        if lines[0] != 'sasview_parameter_values': 
     
    36793664                line_dict[content[0]] = content[1:] 
    36803665 
     3666        self.updatePageWithParameters(line_dict) 
     3667 
     3668    def createPageForParameters(self, line_dict): 
     3669        """ 
     3670        Sets up page with requested model/str factor 
     3671        and fills it up with sent parameters 
     3672        """ 
     3673        if 'fitpage_category' in line_dict: 
     3674            self.cbCategory.setCurrentIndex(self.cbCategory.findText(line_dict['fitpage_category'][0])) 
     3675        if 'fitpage_model' in line_dict: 
     3676            self.cbModel.setCurrentIndex(self.cbModel.findText(line_dict['fitpage_model'][0])) 
     3677        if 'fitpage_structure' in line_dict: 
     3678            self.cbStructureFactor.setCurrentIndex(self.cbStructureFactor.findText(line_dict['fitpage_structure'][0])) 
     3679 
     3680        # Now that the page is ready for parameters, fill it up 
     3681        self.updatePageWithParameters(line_dict) 
     3682 
     3683    def updatePageWithParameters(self, line_dict): 
     3684        """ 
     3685        Update FitPage with parameters in line_dict 
     3686        """ 
     3687        if 'model_name' not in line_dict.keys(): 
     3688            return 
    36813689        model = line_dict['model_name'][0] 
    3682  
    3683         if 'model_name' not in line_dict.keys(): 
    3684             return False 
     3690        context = {} 
    36853691 
    36863692        if 'multiplicity' in line_dict.keys(): 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/ComplexConstraintTest.py

    r725d9c06 r2eeda93  
    3434        category_index = self.tab1.cbCategory.findText("Shape Independent") 
    3535        self.tab1.cbCategory.setCurrentIndex(category_index) 
     36        model_index = self.tab1.cbModel.findText("be_polyelectrolyte") 
     37        self.tab1.cbModel.setCurrentIndex(model_index) 
     38 
    3639        category_index = self.tab2.cbCategory.findText("Cylinder") 
    3740        self.tab2.cbCategory.setCurrentIndex(category_index) 
     41        model_index = self.tab2.cbModel.findText("barbell") 
     42        self.tab2.cbModel.setCurrentIndex(model_index) 
    3843 
    3944        tabs = [self.tab1, self.tab2] 
  • src/sas/qtgui/Perspectives/Fitting/UnitTesting/FittingWidgetTest.py

    rec4a143 rec4a143  
    175175        category_index = self.widget.cbCategory.findText("Shape Independent") 
    176176        self.widget.cbCategory.setCurrentIndex(category_index) 
     177        model_index = self.widget.cbModel.findText("be_polyelectrolyte") 
     178        self.widget.cbModel.setCurrentIndex(model_index) 
    177179 
    178180        # test the model combo content 
    179         self.assertEqual(self.widget.cbModel.count(), 28) 
     181        self.assertEqual(self.widget.cbModel.count(), 30) 
    180182 
    181183        # Try to change back to default 
     
    201203        category_index = self.widget.cbCategory.findText("Shape Independent") 
    202204        self.widget.cbCategory.setCurrentIndex(category_index) 
     205        model_index = self.widget.cbModel.findText("be_polyelectrolyte") 
     206        self.widget.cbModel.setCurrentIndex(model_index) 
    203207 
    204208        # check the enablement of controls 
     
    215219        #  
    216220        # Now change the model 
     221<<<<<<< HEAD 
     222        self.widget.cbModel.setCurrentIndex(4) 
     223======= 
    217224        self.widget.cbModel.setCurrentIndex(2) 
     225>>>>>>> ESS_GUI 
    218226        self.assertEqual(self.widget.cbModel.currentText(),'dab') 
    219227 
     
    226234        self.widget.data_is_loaded = True 
    227235        # Reset the sasmodel index 
    228         self.widget.cbModel.setCurrentIndex(1) 
     236        self.widget.cbModel.setCurrentIndex(2) 
    229237        self.assertEqual(self.widget.cbModel.currentText(),'broad_peak') 
    230238 
     
    377385        category_index = self.widget.cbCategory.findText("Shape Independent") 
    378386        self.widget.cbCategory.setCurrentIndex(category_index) 
     387        model_index = self.widget.cbModel.findText("be_polyelectrolyte") 
     388        self.widget.cbModel.setCurrentIndex(model_index) 
     389 
    379390        # Check the poly model 
    380391        self.assertEqual(self.widget._poly_model.rowCount(), 0) 
     
    383394        # Change the category index so we have a model available 
    384395        self.widget.cbCategory.setCurrentIndex(2) 
     396        self.widget.cbModel.setCurrentIndex(1) 
    385397 
    386398        # Check the poly model 
     
    556568        category_index = self.widget.cbCategory.findText("Sphere") 
    557569        self.widget.cbCategory.setCurrentIndex(category_index) 
     570        model_index = self.widget.cbModel.findText("adsorbed_layer") 
     571        self.widget.cbModel.setCurrentIndex(model_index) 
    558572 
    559573        # Check the magnetic model 
     
    634648        category_index = self.widget.cbCategory.findText("Sphere") 
    635649        self.widget.cbCategory.setCurrentIndex(category_index) 
     650        model_index = self.widget.cbModel.findText("adsorbed_layer") 
     651        self.widget.cbModel.setCurrentIndex(model_index) 
    636652 
    637653        # Check the enablement/text 
     
    973989        category_index = self.widget.cbCategory.findText("Sphere") 
    974990        self.widget.cbCategory.setCurrentIndex(category_index) 
     991        model_index = self.widget.cbModel.findText("adsorbed_layer") 
     992        self.widget.cbModel.setCurrentIndex(model_index) 
    975993        self.widget.main_params_to_fit = ['scale'] 
    976994 
     
    9861004        self.assertListEqual(fp.main_params_to_fit, ['scale']) 
    9871005 
    988     def testPushFitPage(self): 
     1006    def notestPushFitPage(self): 
    9891007        """ 
    9901008        Push current state of fitpage onto stack 
     
    9971015        self.widget.data = item 
    9981016        category_index = self.widget.cbCategory.findText("Sphere") 
     1017        model_index = self.widget.cbModel.findText("adsorbed_layer") 
     1018        self.widget.cbModel.setCurrentIndex(model_index) 
    9991019 
    10001020        # Asses the initial state of stack 
  • src/sas/qtgui/Utilities/GuiUtils.py

    raed159f rb1b71ad  
    1111import webbrowser 
    1212import urllib.parse 
     13import json 
     14from io import BytesIO 
    1315 
    1416import numpy as np 
     
    2628from sas.qtgui.Plotting.PlotterData import Data1D 
    2729from sas.qtgui.Plotting.PlotterData import Data2D 
     30from sas.qtgui.Plotting.Plottables import Plottable 
     31from sas.sascalc.dataloader.data_info import Sample, Source, Vector 
     32from sas.qtgui.Plotting.Plottables import View 
     33from sas.qtgui.Plotting.Plottables import PlottableTheory1D 
     34from sas.qtgui.Plotting.Plottables import PlottableFit1D 
     35from sas.qtgui.Plotting.Plottables import Text 
     36from sas.qtgui.Plotting.Plottables import Chisq 
     37from sas.qtgui.MainWindow.DataState import DataState 
     38 
    2839from sas.sascalc.dataloader.loader import Loader 
    2940from sas.qtgui.Utilities import CustomDir 
     
    257268    sendDataToGridSignal = QtCore.pyqtSignal(list) 
    258269 
    259     # Action Save Analysis triggered 
    260     saveAnalysisSignal = QtCore.pyqtSignal() 
    261  
    262270    # Mask Editor requested 
    263271    maskEditorSignal = QtCore.pyqtSignal(Data2D) 
     
    287295    resultPlotUpdateSignal = QtCore.pyqtSignal(list) 
    288296 
    289 def updateModelItemWithPlot(item, update_data, name=""): 
     297def updateModelItemWithPlot(item, update_data, name="", checkbox_state=None): 
    290298    """ 
    291299    Adds a checkboxed row named "name" to QStandardItem 
     
    312320            # Force redisplay 
    313321            return 
    314  
    315322    # Create the new item 
    316323    checkbox_item = createModelItemWithPlot(update_data, name) 
    317324 
     325    if checkbox_state is not None: 
     326        checkbox_item.setCheckState(checkbox_state) 
    318327    # Append the new row to the main item 
    319328    item.appendRow(checkbox_item) 
     
    566575    if isinstance(data.process, list) and data.process: 
    567576        for process in data.process: 
     577            if process is None: 
     578                continue 
    568579            process_date = process.date 
    569580            process_date_item = QtGui.QStandardItem("Date: " + process_date) 
     
    11401151    return result 
    11411152 
     1153def saveData(fp, data): 
     1154    """ 
     1155    save content of data to fp (a .write()-supporting file-like object) 
     1156    """ 
     1157 
     1158    def add_type(dict, type): 
     1159        dict['__type__'] = type.__name__ 
     1160        return dict 
     1161 
     1162    def jdefault(o): 
     1163        """ 
     1164        objects that can't otherwise be serialized need to be converted 
     1165        """ 
     1166        # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples) 
     1167        if isinstance(o, (tuple, set)): 
     1168            content = { 'data': list(o) } 
     1169            return add_type(content, type(o)) 
     1170 
     1171        # "simple" types 
     1172        if isinstance(o, (Sample, Source, Vector)): 
     1173            return add_type(o.__dict__, type(o)) 
     1174        if isinstance(o, (Plottable, View)): 
     1175            return add_type(o.__dict__, type(o)) 
     1176 
     1177        # DataState 
     1178        if isinstance(o, (Data1D, Data2D)): 
     1179            # don't store parent 
     1180            content = o.__dict__.copy() 
     1181            #content.pop('parent') 
     1182            return add_type(content, type(o)) 
     1183 
     1184        # ndarray 
     1185        if isinstance(o, np.ndarray): 
     1186            buffer = BytesIO() 
     1187            np.save(buffer, o) 
     1188            buffer.seek(0) 
     1189            content = { 'data': buffer.read().decode('latin-1') } 
     1190            return add_type(content, type(o)) 
     1191 
     1192        # not supported 
     1193        logging.info("data cannot be serialized to json: %s" % type(o)) 
     1194        return None 
     1195 
     1196    json.dump(data, fp, indent=2, sort_keys=True, default=jdefault) 
     1197 
     1198def readDataFromFile(fp): 
     1199    ''' 
     1200    ''' 
     1201    supported = [ 
     1202        tuple, set, 
     1203        Sample, Source, Vector, 
     1204        Plottable, Data1D, Data2D, PlottableTheory1D, PlottableFit1D, Text, Chisq, View, 
     1205        DataState, np.ndarray] 
     1206 
     1207    lookup = dict((cls.__name__, cls) for cls in supported) 
     1208 
     1209    class TooComplexException(Exception): 
     1210        pass 
     1211 
     1212    def simple_type(cls, data, level): 
     1213        class Empty(object): 
     1214            def __init__(self): 
     1215                for key, value in data.items(): 
     1216                    setattr(self, key, generate(value, level)) 
     1217 
     1218        # create target object 
     1219        o = Empty() 
     1220        o.__class__ = cls 
     1221 
     1222        return o 
     1223 
     1224    def construct(type, data, level): 
     1225        try: 
     1226            cls = lookup[type] 
     1227        except KeyError: 
     1228            logging.info('unknown type: %s' % type) 
     1229            return None 
     1230 
     1231        # tuples and sets 
     1232        if cls in (tuple, set): 
     1233            # convert list to tuple/set 
     1234            return cls(generate(data['data'], level)) 
     1235 
     1236        # "simple" types 
     1237        if cls in (Sample, Source, Vector): 
     1238            return simple_type(cls, data, level) 
     1239        if issubclass(cls, Plottable) or (cls == View): 
     1240            return simple_type(cls, data, level) 
     1241 
     1242        # DataState 
     1243        if cls == DataState: 
     1244            o = simple_type(cls, data, level) 
     1245            o.parent = None # TODO: set to ??? 
     1246            return o 
     1247 
     1248        # ndarray 
     1249        if cls == np.ndarray: 
     1250            buffer = BytesIO() 
     1251            buffer.write(data['data'].encode('latin-1')) 
     1252            buffer.seek(0) 
     1253            return np.load(buffer) 
     1254 
     1255        logging.info('not implemented: %s, %s' % (type, cls)) 
     1256        return None 
     1257 
     1258    def generate(data, level): 
     1259        if level > 16: # recursion limit (arbitrary number) 
     1260            raise TooComplexException() 
     1261        else: 
     1262            level += 1 
     1263 
     1264        if isinstance(data, dict): 
     1265            try: 
     1266                type = data['__type__'] 
     1267            except KeyError: 
     1268                # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary 
     1269                o = {} 
     1270                for key, value in data.items(): 
     1271                    o[key] = generate(value, level) 
     1272                return o 
     1273 
     1274            return construct(type, data, level) 
     1275 
     1276        if isinstance(data, list): 
     1277            return [generate(item, level) for item in data] 
     1278 
     1279        return data 
     1280 
     1281    new_stored_data = {} 
     1282    for id, data in json.load(fp).items(): 
     1283        try: 
     1284            new_stored_data[id] = generate(data, 0) 
     1285        except TooComplexException: 
     1286            logging.info('unable to load %s' % id) 
     1287 
     1288    return new_stored_data 
     1289 
     1290def readProjectFromSVS(filepath): 
     1291    """ 
     1292    Read old SVS file and convert to the project dictionary 
     1293    """ 
     1294    from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader 
     1295    from sas.sascalc.fit.pagestate import Reader 
     1296 
     1297    loader = Loader() 
     1298    loader.associate_file_reader('.svs', Reader) 
     1299    temp = loader.load(filepath) 
     1300    state_reader = Reader() 
     1301    data_svs, state_svs = state_reader.read(filepath) 
     1302 
     1303    output = [] 
     1304    if isinstance(temp, list) and isinstance(state_svs, list): 
     1305        for item, state in zip(temp, state_svs): 
     1306            output.append([item, state]) 
     1307    else: 
     1308        output[temp, state_svs] 
     1309    return output 
     1310 
     1311def convertFromSVS(datasets): 
     1312    """ 
     1313    Read in properties from SVS and convert into a simple dict 
     1314    """ 
     1315    content = {} 
     1316    for dataset in datasets: 
     1317        # we already have data - interested only in properties 
     1318        #[[item_1, state_1], [item_2, state_2],...] 
     1319        data = dataset[0] 
     1320        params = dataset[1] 
     1321        content[params.data_id] = {} 
     1322        content[params.data_id]['fit_data'] = [data, {'checked': 2}, []] 
     1323        param_dict = {} 
     1324        param_dict['fitpage_category'] = [params.categorycombobox] 
     1325        param_dict['fitpage_model'] = [params.formfactorcombobox] 
     1326        param_dict['fitpage_structure'] = [params.structurecombobox] 
     1327        param_dict['2D_params'] = [str(params.is_2D)] 
     1328        param_dict['chainfit_params'] = ["False"] 
     1329        param_dict['data_id'] = [params.data_id] 
     1330        param_dict['data_name'] = [params.data_name] 
     1331        param_dict['is_data'] = [str(params.is_data)] 
     1332        param_dict['magnetic_params'] = [str(params.magnetic_on)] 
     1333        param_dict['model_name'] = [params.formfactorcombobox] 
     1334        param_dict['polydisperse_params'] = [str(params.enable_disp)] 
     1335        param_dict['q_range_max'] = [str(params.qmax)] 
     1336        param_dict['q_range_min'] = [str(params.qmin)] 
     1337        # Smearing is a bit trickier. 4.x has multiple keywords, 
     1338        # one for each combobox option 
     1339        if params.enable_smearer: 
     1340            if params.slit_smearer: 
     1341                w = 1 
     1342            elif params.pinhole_smearer: 
     1343                w = 2 
     1344            else: 
     1345                w = 0 
     1346            param_dict['smearing'] = [str(w)] 
     1347        # weighting is a bit trickier. 4.x has multiple keywords, 
     1348        # one for each radio box. 
     1349        if params.dI_noweight: 
     1350            w = 2 
     1351        elif params.dI_didata: 
     1352            w = 3 
     1353        elif params.dI_sqrdata: 
     1354            w = 4 
     1355        elif params.dI_idata: 
     1356            w = 5 
     1357        else: 
     1358            w = 2 
     1359        param_dict['weighting'] = [str(w)] 
     1360 
     1361        # 4.x multi_factor is really the multiplicity 
     1362        if params.multi_factor is not None: 
     1363            param_dict['multiplicity'] = [str(int(params.multi_factor))] 
     1364 
     1365        # playing with titles 
     1366        data.filename = params.file 
     1367        data.title = params.data_name 
     1368        data.name = params.data_name 
     1369 
     1370        # main parameters 
     1371        for p in params.parameters: 
     1372            p_name = p[1] 
     1373            param_dict[p_name] = [str(p[0]), str(p[2]), None, str(p[5][1]), str(p[6][1])] 
     1374        # orientation parameters 
     1375        if params.is_2D: 
     1376            for p in params.orientation_params: 
     1377                p_name = p[1] 
     1378                param_dict[p_name] = [str(p[0]), str(p[2]), None, str(p[5][1]), str(p[6][1])] 
     1379 
     1380        # disperse parameters 
     1381        if params.enable_disp: 
     1382            for p in params.fittable_param: 
     1383                p_name = p[1] 
     1384                param_dict[p_name] = [str(p[0]), str(p[2]), None, str(35), str(3)] 
     1385 
     1386        # magnetic parameters 
     1387 
     1388        content[params.data_id]['fit_params'] = param_dict 
     1389    return content 
    11421390 
    11431391def enum(*sequential, **named): 
  • src/sas/sascalc/dataloader/readers/cansas_reader.py

    rb8080e1 rb1b71ad  
    184184            if CANSAS_NS.get(self.cansas_version).get("ns") == value.rsplit(" ")[0]: 
    185185                return True 
    186         if ext == "svs": 
     186        if ext == ".svs": 
    187187            return True # Why is this required? 
    188188        # If we get to this point then file isn't valid CanSAS 
  • src/sas/sascalc/fit/pagestate.py

    rb8080e1 rb1b71ad  
    12491249 
    12501250            else: 
    1251                 self.call_back(format=ext) 
     1251                #self.call_back(format=ext) 
    12521252                raise RuntimeError("%s is not a file" % path) 
    12531253 
    12541254            # Return output consistent with the loader's api 
    12551255            if len(output) == 0: 
    1256                 self.call_back(state=None, datainfo=None, format=ext) 
     1256                #self.call_back(state=None, datainfo=None, format=ext) 
    12571257                return None 
    12581258            else: 
     1259                states=[] 
    12591260                for data in output: 
    12601261                    # Call back to post the new state 
     
    12811282                        if isinstance(data.run_name, dict): 
    12821283                            # Note: key order in dict is not guaranteed, so sort 
    1283                             name = data.run_name.keys()[0] 
     1284                            name = list(data.run_name.keys())[0] 
    12841285                        else: 
    12851286                            name = data.run_name 
     
    12891290                    state.version = fitstate.version 
    12901291                    # store state in fitting 
    1291                     self.call_back(state=state, datainfo=data, format=ext) 
     1292                    #self.call_back(state=state, datainfo=data, format=ext) 
    12921293                    self.state = state 
     1294                    states.append(state) 
    12931295                simfitstate = self._parse_simfit_state(entry) 
    12941296                if simfitstate is not None: 
    1295                     self.call_back(state=simfitstate) 
    1296  
    1297                 return output 
     1297                    #self.call_back(state=simfitstate) 
     1298                    states.append(simfitstate) 
     1299                return (output, states) 
    12981300        except: 
    1299             self.call_back(format=ext) 
     1301            #self.call_back(format=ext) 
    13001302            raise 
    13011303 
Note: See TracChangeset for help on using the changeset viewer.