Changeset 345b3b3 in sasview for src/sas


Ignore:
Timestamp:
Oct 9, 2018 2:08:54 PM (5 years ago)
Author:
Piotr Rozyczko <piotr.rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
b95d748
Parents:
f20ea3f
Message:

Save status of data explorer

Location:
src/sas/qtgui
Files:
4 edited

Legend:

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

    r3b95b3b r345b3b3  
    233233        filename = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0] 
    234234        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() 
     235            self.readProject(filename) 
    274236 
    275237    def saveProject(self): 
     
    285247        name_tuple = QtWidgets.QFileDialog.getSaveFileName(**kwargs) 
    286248        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) 
     249        if not filename: 
     250            return 
     251        _, extension = os.path.splitext(filename) 
     252        if not extension: 
     253            filename = '.'.join((filename, 'json')) 
     254        self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
     255 
     256        with open(filename, 'w') as outfile: 
     257            self.saveDataToFile(outfile) 
     258 
     259    def allDataForModel(self, model): 
     260        # data model 
     261        all_data = {} 
     262        for i in range(model.rowCount()): 
     263            properties = {} 
     264            item = model.item(i) 
     265            data = GuiUtils.dataFromItem(item) 
     266            if data is None: continue 
     267            # Now, all plots under this item 
     268            filename = data.filename 
     269            is_checked = item.checkState() 
     270            properties['checked'] = is_checked 
     271            other_datas = GuiUtils.plotsFromFilename(filename, model) 
     272            # skip the main plot 
     273            other_datas = list(other_datas.values())[1:] 
     274            all_data[data.id] = [data, properties, other_datas] 
     275        return all_data 
     276 
     277    def saveDataToFile(self, outfile): 
     278        """ 
     279        Save every dataset to a json file 
     280        """ 
     281        data = self.allDataForModel(self.model) 
     282        theory = self.allDataForModel(self.theory_model) 
     283 
     284        all_data = {} 
     285        for key, value in data.items(): 
     286            all_data[key] = value 
     287        for key, value in theory.items(): 
     288            if key in all_data: 
     289                raise ValueError("Inconsistent data in Project file.") 
     290            all_data[key] = value 
     291 
     292        # perspectives 
     293        current_perspective = self._perspective() 
     294        try: 
     295            perspective_dump = current_perspective.getCurrentStateAsXml() 
     296        except Exception: 
     297            ex = "State of " + current_perspective.windowTitle() + \ 
     298                " cannot be saved." 
     299            logging.error(ex) 
     300        if perspective_dump is not None: 
     301            assert(isinstance(perspective_dump, dict)) 
     302            all_data['perspective'] = perspective_dump 
     303        # save datas 
     304        GuiUtils.saveData(outfile, all_data) 
     305        return 
     306 
     307    def readProject(self, filename): 
     308        """ 
     309        Read out datasets and fitpages from file 
     310        """ 
     311        with open(filename, 'r') as infile: 
     312            all_data = GuiUtils.readDataFromFile(infile) 
     313        # clear the model 
     314        self.model.clear() 
     315 
     316        #self.model.beginResetModel() 
     317        for key, value in all_data.items(): 
     318            # key - cardinal number of dataset 
     319            # value - main dataset, [dependant filesets] 
     320            # add the main index 
     321            new_data = value[0] 
     322            assert isinstance(new_data, (Data1D, Data2D)) 
     323            properties = value[1] 
     324            is_checked = properties['checked'] 
     325            new_item = GuiUtils.createModelItemWithPlot(new_data, new_data.filename) 
     326            new_item.setCheckState(is_checked) 
     327            model = self.theory_model 
     328            if new_data.is_data: 
     329                model = self.model 
     330            model.appendRow(new_item) 
     331            self.manager.add_data(data_list={new_data.id:new_data}) 
     332 
     333            # Add the underlying data 
     334            if not value[2]: 
     335                continue 
     336            for plot in value[2]: 
     337                assert isinstance(plot, (Data1D, Data2D)) 
     338                GuiUtils.updateModelItemWithPlot(new_item, plot, plot.name) 
    294339 
    295340    def deleteFile(self, event): 
     
    13941439        checkbox_item.setCheckable(True) 
    13951440        checkbox_item.setCheckState(QtCore.Qt.Checked) 
    1396         checkbox_item.setText(os.path.basename(p_file)) 
     1441        if p_file is not None: 
     1442            checkbox_item.setText(os.path.basename(p_file)) 
    13971443 
    13981444        # 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/Perspectives/Fitting/FittingPerspective.py

    r20f4857 r345b3b3  
    337337        pass 
    338338 
     339    def getCurrentStateAsXml(self): 
     340        """ 
     341        Returns an XML version of the current state 
     342        """ 
     343        state = {} 
     344        for tab in self.tabs: 
     345            pass 
     346        return state 
     347 
    339348    @property 
    340349    def currentTab(self): 
  • src/sas/qtgui/Utilities/GuiUtils.py

    r63467b6 r345b3b3  
    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 
     
    286297    changeDataExplorerTabSignal = QtCore.pyqtSignal(int) 
    287298 
    288 def updateModelItemWithPlot(item, update_data, name=""): 
     299def updateModelItemWithPlot(item, update_data, name="", checkbox_state=None): 
    289300    """ 
    290301    Adds a checkboxed row named "name" to QStandardItem 
     
    311322            # Force redisplay 
    312323            return 
    313  
    314324    # Create the new item 
    315325    checkbox_item = createModelItemWithPlot(update_data, name) 
    316326 
     327    if checkbox_state is not None: 
     328        checkbox_item.setCheckState(checkbox_state) 
    317329    # Append the new row to the main item 
    318330    item.appendRow(checkbox_item) 
     
    11391151    return result 
    11401152 
     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 
    11411290 
    11421291def enum(*sequential, **named): 
Note: See TracChangeset for help on using the changeset viewer.