Changeset 630155bd in sasview


Ignore:
Timestamp:
Oct 5, 2016 2:40:30 PM (7 years ago)
Author:
davidm
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
2366fb2, e207c3f
Parents:
d0ccd80f
Message:

implementation of loadProject and saveProject

Location:
src/sas
Files:
3 edited

Legend:

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

    r1af348e r630155bd  
    3030    # for the gui and providing an interface to the data model. 
    3131 
    32     def __init__(self, parent=None, guimanager=None): 
     32    def __init__(self, parent=None, guimanager=None, manager=None): 
    3333        super(DataExplorerWindow, self).__init__(parent, guimanager) 
    3434 
     
    4343        self.parent = guimanager 
    4444        self.loader = Loader() 
    45         self.manager = DataManager() 
     45        self.manager = manager if manager is not None else DataManager() 
    4646        self.txt_widget = QtGui.QTextEdit(None) 
    4747        # self.txt_widget = GuiUtils.DisplayWindow() 
     
    164164 
    165165        self.loadFromURL(path_str) 
     166 
     167    def loadProject(self): 
     168        """ 
     169        Called when the "Open Project" menu item chosen. 
     170        """ 
     171        kwargs = { 
     172            'parent'    : self, 
     173            'caption'   : 'Open Project', 
     174            'filter'    : 'Project (*.json);;All files (*.*)', 
     175            'options'   : QtGui.QFileDialog.DontUseNativeDialog 
     176        } 
     177        filename = str(QtGui.QFileDialog.getOpenFileName(**kwargs)) 
     178        if filename: 
     179            load_thread = threads.deferToThread(self.readProject, filename) 
     180            load_thread.addCallback(self.readProjectComplete) 
     181 
     182    def readProject(self, filename): 
     183        self.communicator.statusBarUpdateSignal.emit("Loading Project... %s" % os.path.basename(filename)) 
     184        try: 
     185            manager = DataManager() 
     186            with open(filename, 'r') as infile: 
     187                manager.load_from_readable(infile) 
     188 
     189            self.communicator.statusBarUpdateSignal.emit("Loaded Project: %s" % os.path.basename(filename)) 
     190            return manager 
     191 
     192        except: 
     193            self.communicator.statusBarUpdateSignal.emit("Failed: %s" % os.path.basename(filename)) 
     194            raise 
     195 
     196    def readProjectComplete(self, manager): 
     197        self.model.clear() 
     198 
     199        self.manager.assign(manager) 
     200        for id, item in self.manager.get_all_data().iteritems(): 
     201            self.updateModel(item.data, item.path) 
     202 
     203        self.model.reset() 
     204 
     205    def saveProject(self): 
     206        """ 
     207        Called when the "Save Project" menu item chosen. 
     208        """ 
     209        kwargs = { 
     210            'parent'    : self, 
     211            'caption'   : 'Save Project', 
     212            'filter'    : 'Project (*.json)', 
     213            'options'   : QtGui.QFileDialog.DontUseNativeDialog 
     214        } 
     215        filename = str(QtGui.QFileDialog.getSaveFileName(**kwargs)) 
     216        if filename: 
     217            self.communicator.statusBarUpdateSignal.emit("Saving Project... %s\n" % os.path.basename(filename)) 
     218            with open(filename, 'w') as outfile: 
     219                self.manager.save_to_writable(outfile) 
    166220 
    167221    def deleteFile(self, event): 
  • src/sas/qtgui/GuiManager.py

    rf51ed67 r630155bd  
    111111        """ 
    112112        # Add FileDialog widget as docked 
    113         self.filesWidget = DataExplorerWindow(self._parent, self) 
     113        self.filesWidget = DataExplorerWindow(self._parent, self, manager=self._data_manager) 
    114114 
    115115        self.dockedFilesWidget = QtGui.QDockWidget("Data Explorer", self._workspace) 
     
    391391    def actionOpen_Project(self): 
    392392        """ 
    393         """ 
    394         print("actionOpen_Project TRIGGERED") 
    395         pass 
     393        Menu Open Project 
     394        """ 
     395        self.filesWidget.loadProject() 
    396396 
    397397    def actionOpen_Analysis(self): 
     
    403403    def actionSave(self): 
    404404        """ 
    405         """ 
    406         print("actionSave TRIGGERED") 
    407         pass 
     405        Menu Save Project 
     406        """ 
     407        self.filesWidget.saveProject() 
    408408 
    409409    def actionSave_Analysis(self): 
  • src/sas/sasgui/guiframe/data_manager.py

    rd85c194 r630155bd  
    22#This software was developed by the University of Tennessee as part of the 
    33#Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 
    4 #project funded by the US National Science Foundation.  
     4#project funded by the US National Science Foundation. 
    55# 
    66#See the license text in license.txt 
     
    99################################################################################ 
    1010""" 
    11 This module manages all data loaded into the application. Data_manager makes  
    12 available all data loaded  for the current perspective.  
    13  
    14 All modules "creating Data" posts their data to data_manager .  
     11This module manages all data loaded into the application. Data_manager makes 
     12available all data loaded  for the current perspective. 
     13 
     14All modules "creating Data" posts their data to data_manager . 
    1515Data_manager  make these new data available for all other perspectives. 
    1616""" 
     17import os 
     18import copy 
    1719import logging 
    18 import os 
    19 import copy  
     20import json 
     21from StringIO import StringIO 
    2022 
    2123from sas.sasgui.guiframe.data_state import DataState 
     
    2628import time 
    2729 
     30# used for import/export 
     31import numpy as np 
     32from sas.sascalc.dataloader.data_info import Sample, Source, Vector 
     33from sas.sasgui.plottools.plottables import Plottable, Theory1D, Fit1D, Text, Chisq, View 
     34 
    2835class DataManager(object): 
    2936    """ 
     
    3340        """ 
    3441        Store opened path and data object created at the loading time 
    35         :param auto_plot: if True the datamanager sends data to plotting  
    36                             plugin.  
     42        :param auto_plot: if True the datamanager sends data to plotting 
     43                            plugin. 
    3744        :param auto_set_data: if True the datamanager sends to the current 
    3845        perspective 
     
    4451        self.list_of_id = [] 
    4552        self.time_stamp = time.time() 
    46        
     53 
    4754    def __str__(self): 
    4855        _str  = "" 
     
    5057        n_count = 0 
    5158        for  value in self.stored_data.values(): 
    52             n_count += 1  
     59            n_count += 1 
    5360            _str += "State No %s \n"  % str(n_count) 
    5461            _str += str(value) + "\n" 
    5562        return _str 
    56          
     63 
    5764    def create_gui_data(self, data, path=None): 
    5865        """ 
    5966        Receive data from loader and create a data to use for guiframe 
    6067        """ 
    61          
     68 
    6269        if issubclass(Data2D, data.__class__): 
    63             new_plot = Data2D(image=None, err_image=None)  
    64         else:  
     70            new_plot = Data2D(image=None, err_image=None) 
     71        else: 
    6572            new_plot = Data1D(x=[], y=[], dx=None, dy=None) 
    66             
     73 
    6774        new_plot.copy_from_datainfo(data) 
    6875        data.clone_without_data(clone=new_plot) 
     
    8289        if title.strip() == "": 
    8390            title = file_name 
    84          
     91 
    8592        if new_plot.filename.strip() == "": 
    8693            new_plot.filename = file_name 
    87          
     94 
    8895        new_plot.name = name 
    8996        new_plot.title = title 
     
    101108        # plot data 
    102109        return new_plot 
    103   
     110 
    104111    def rename(self, name): 
    105112        """ 
     
    108115        ## name of the data allow to differentiate data when plotted 
    109116        name = parse_name(name=name, expression="_") 
    110          
     117 
    111118        max_char = name.find("[") 
    112119        if max_char < 0: 
    113120            max_char = len(name) 
    114121        name = name[0:max_char] 
    115          
     122 
    116123        if name not in self.data_name_dict: 
    117124            self.data_name_dict[name] = 0 
     
    120127            name = name + " [" + str(self.data_name_dict[name]) + "]" 
    121128        return name 
    122      
    123    
     129 
     130 
    124131    def add_data(self, data_list): 
    125132        """ 
    126         receive a list of  
     133        receive a list of 
    127134        """ 
    128135        for id, data in data_list.iteritems(): 
     
    138145                data_state.path = data.path 
    139146                self.stored_data[id] = data_state 
    140      
     147 
    141148    def update_data(self, prev_data, new_data): 
    142149        """ 
     
    144151        if prev_data.id not in self.stored_data.keys(): 
    145152            return None, {} 
    146         data_state = self.stored_data[prev_data.id]  
     153        data_state = self.stored_data[prev_data.id] 
    147154        self.stored_data[new_data.id]  = data_state.clone() 
    148155        self.stored_data[new_data.id].data = new_data 
    149156        if prev_data.id in self.stored_data.keys(): 
    150             del self.stored_data[prev_data.id]  
     157            del self.stored_data[prev_data.id] 
    151158        return prev_data.id, {new_data.id: self.stored_data[new_data.id]} 
    152      
     159 
    153160    def update_theory(self, theory, data_id=None, state=None): 
    154161        """ 
     
    158165            uid = theory.id 
    159166        if uid in self.stored_data.keys(): 
    160              data_state = self.stored_data[uid]  
     167             data_state = self.stored_data[uid] 
    161168        else: 
    162169            data_state = DataState() 
     
    165172        self.stored_data[uid] = data_state 
    166173        return {uid: self.stored_data[uid]} 
    167         
    168      
     174 
     175 
    169176    def get_message(self): 
    170177        """ 
     
    172179        """ 
    173180        return self.message 
    174      
     181 
    175182    def get_by_id(self, id_list=None): 
    176183        """ 
     
    189196                if search_id in theory_list.keys(): 
    190197                     _selected_theory_list[search_id] = theory_list[search_id] 
    191                     
     198 
    192199        return _selected_data, _selected_theory_list 
    193     
    194             
     200 
     201 
    195202    def freeze(self, theory_id): 
    196203        """ 
    197204        """ 
    198205        return self.freeze_theory(self.stored_data.keys(), theory_id) 
    199          
     206 
    200207    def freeze_theory(self, data_id, theory_id): 
    201208        """ 
     
    221228 
    222229        return selected_theory 
    223                      
    224              
     230 
     231 
    225232    def delete_data(self, data_id, theory_id=None, delete_all=False): 
    226233        """ 
     
    232239                    del self.data_name_dict[data_state.data.name] 
    233240                del self.stored_data[d_id] 
    234          
     241 
    235242        self.delete_theory(data_id, theory_id) 
    236243        if delete_all: 
    237244            self.stored_data = {} 
    238245            self.data_name_dict = {} 
    239              
     246 
    240247    def delete_theory(self, data_id, theory_id): 
    241248        """ 
     
    249256        #del pure theory 
    250257        self.delete_by_id(theory_id) 
    251              
     258 
    252259    def delete_by_id(self, id_list=None): 
    253260        """ 
     
    257264            if id in self.stored_data: 
    258265                del self.stored_data[id] 
    259           
    260      
     266 
     267 
    261268    def get_by_name(self, name_list=None): 
    262269        """ 
     
    269276                    _selected_data[id] = data_state.data 
    270277        return _selected_data 
    271      
     278 
    272279    def delete_by_name(self, name_list=None): 
    273280        """ 
     
    288295                _selected_data_state[id] = self.stored_data[id] 
    289296        return _selected_data_state 
    290      
     297 
    291298    def get_all_data(self): 
    292299        """ 
     
    294301        """ 
    295302        return self.stored_data 
    296      
    297  
    298          
     303 
     304    def assign(self, other): 
     305        self.stored_data = other.stored_data 
     306        self.message = other.message 
     307        self.data_name_dict = other.data_name_dict 
     308        self.count = other.count 
     309        self.list_of_id = other.list_of_id 
     310        self.time_stamp = other.time_stamp 
     311 
     312    def save_to_writable(self, fp): 
     313        """ 
     314        save content of stored_data to fp (a .write()-supporting file-like object) 
     315        """ 
     316 
     317        def add_type(dict, type): 
     318            dict['__type__'] = type.__name__ 
     319            return dict 
     320 
     321        def jdefault(o): 
     322            """ 
     323            objects that can't otherwise be serialized need to be converted 
     324            """ 
     325            # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples) 
     326            if isinstance(o, (tuple, set)): 
     327                content = { 'data': list(o) } 
     328                return add_type(content, type(o)) 
     329 
     330            # "simple" types 
     331            if isinstance(o, (Sample, Source, Vector)): 
     332                return add_type(o.__dict__, type(o)) 
     333            if isinstance(o, (Plottable, View)): 
     334                return add_type(o.__dict__, type(o)) 
     335 
     336            # DataState 
     337            if isinstance(o, DataState): 
     338                # don't store parent 
     339                content = o.__dict__.copy() 
     340                content.pop('parent') 
     341                return add_type(content, type(o)) 
     342 
     343            # ndarray 
     344            if isinstance(o, np.ndarray): 
     345                buffer = StringIO() 
     346                np.save(buffer, o) 
     347                buffer.seek(0) 
     348                content = { 'data': buffer.read().decode('latin-1') } 
     349                return add_type(content, type(o)) 
     350 
     351            # not supported 
     352            logging.info("data cannot be serialized to json: %s" % type(o)) 
     353            return None 
     354 
     355        json.dump(self.stored_data, fp, indent=2, sort_keys=True, default=jdefault) 
     356 
     357 
     358    def load_from_readable(self, fp): 
     359        """ 
     360        load content from tp to stored_data (a .read()-supporting file-like object) 
     361        """ 
     362 
     363        supported = [ 
     364            tuple, set, 
     365            Sample, Source, Vector, 
     366            Plottable, Data1D, Data2D, Theory1D, Fit1D, Text, Chisq, View, 
     367            DataState, np.ndarray] 
     368 
     369        lookup = dict((cls.__name__, cls) for cls in supported) 
     370 
     371        class TooComplexException(Exception): 
     372            pass 
     373 
     374        def simple_type(cls, data, level): 
     375            class Empty(object): 
     376                def __init__(self): 
     377                    for key, value in data.iteritems(): 
     378                        setattr(self, key, generate(value, level)) 
     379 
     380            # create target object 
     381            o = Empty() 
     382            o.__class__ = cls 
     383 
     384            return o 
     385 
     386        def construct(type, data, level): 
     387            try: 
     388                cls = lookup[type] 
     389            except KeyError: 
     390                logging.info('unknown type: %s' % type) 
     391                return None 
     392 
     393            # tuples and sets 
     394            if cls in (tuple, set): 
     395                # convert list to tuple/set 
     396                return cls(generate(data['data'], level)) 
     397 
     398            # "simple" types 
     399            if cls in (Sample, Source, Vector): 
     400                return simple_type(cls, data, level) 
     401            if issubclass(cls, Plottable) or (cls == View): 
     402                return simple_type(cls, data, level) 
     403 
     404            # DataState 
     405            if cls == DataState: 
     406                o = simple_type(cls, data, level) 
     407                o.parent = None # TODO: set to ??? 
     408                return o 
     409 
     410            # ndarray 
     411            if cls == np.ndarray: 
     412                buffer = StringIO() 
     413                buffer.write(data['data'].encode('latin-1')) 
     414                buffer.seek(0) 
     415                return np.load(buffer) 
     416 
     417            logging.info('not implemented: %s, %s' % (type, cls)) 
     418            return None 
     419 
     420        def generate(data, level): 
     421            if level > 16: # recursion limit (arbitrary number) 
     422                raise TooComplexException() 
     423            else: 
     424                level += 1 
     425 
     426            if isinstance(data, dict): 
     427                try: 
     428                    type = data['__type__'] 
     429                except KeyError: 
     430                    # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary 
     431                    o = {} 
     432                    for key, value in data.iteritems(): 
     433                        o[key] = generate(value, level) 
     434                    return o 
     435 
     436                return construct(type, data, level) 
     437 
     438            if isinstance(data, list): 
     439                return [generate(item, level) for item in data] 
     440 
     441            return data 
     442 
     443        new_stored_data = {} 
     444        for id, data in json.load(fp).iteritems(): 
     445            try: 
     446                new_stored_data[id] = generate(data, 0) 
     447            except TooComplexException: 
     448                logging.info('unable to load %s' % id) 
     449 
     450        self.stored_data = new_stored_data 
Note: See TracChangeset for help on using the changeset viewer.