source: sasview/src/sas/qtgui/MainWindow/DataManager.py @ dc5ef15

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since dc5ef15 was dc5ef15, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Removed qtgui dependency on sasgui and wx SASVIEW-590

  • Property mode set to 100755
File size: 15.0 KB
RevLine 
[dc5ef15]1################################################################################
2#This software was developed by the University of Tennessee as part of the
3#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4#project funded by the US National Science Foundation.
5#
6#See the license text in license.txt
7#
8#copyright 2010, University of Tennessee
9################################################################################
10"""
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 .
15Data_manager  make these new data available for all other perspectives.
16"""
17#
18# REDUNDANT CLASS!!!
19# ALL THE FUNCTIONALITY IS BEING MOVED TO GuiManager.py
20#
21import os
22import copy
23import logging
24import json
25import time
26from StringIO import StringIO
27import numpy as np
28
29from sas.qtgui.Plotting.PlotterData import Data1D
30from sas.qtgui.Plotting.PlotterData import Data2D
31from sas.qtgui.Plotting.Plottables import Plottable
32from sas.qtgui.Plotting.Plottables import PlottableTheory1D
33from sas.qtgui.Plotting.Plottables import PlottableFit1D
34from sas.qtgui.Plotting.Plottables import Text
35from sas.qtgui.Plotting.Plottables import Chisq
36from sas.qtgui.Plotting.Plottables import View
37
38from sas.qtgui.Utilities import GuiUtils
39from sas.qtgui.MainWindow.DataState import DataState
40import sas.sascalc.dataloader.data_info as DataInfo
41
42# used for import/export
43from sas.sascalc.dataloader.data_info import Sample, Source, Vector
44
45class DataManager(object):
46    """
47    Manage a list of data
48    """
49    def __init__(self):
50        """
51        Store opened path and data object created at the loading time
52        :param auto_plot: if True the datamanager sends data to plotting
53                            plugin.
54        :param auto_set_data: if True the datamanager sends to the current
55        perspective
56        """
57        self.stored_data = {}
58        self.message = ""
59        self.data_name_dict = {}
60        self.count = 0
61        self.list_of_id = []
62        self.time_stamp = time.time()
63
64    def __str__(self):
65        _str  = ""
66        _str += "No of states  is %s \n" % str(len(self.stored_data))
67        n_count = 0
68        for  value in self.stored_data.values():
69            n_count += 1
70            _str += "State No %s \n"  % str(n_count)
71            _str += str(value) + "\n"
72        return _str
73
74    def create_gui_data(self, data, path=None):
75        """
76        Receive data from loader and create a data to use for guiframe
77        """
78
79        if issubclass(Data2D, data.__class__):
80            new_plot = Data2D(image=None, err_image=None)
81        else:
82            new_plot = Data1D(x=[], y=[], dx=None, dy=None)
83
84        new_plot.copy_from_datainfo(data)
85        data.clone_without_data(clone=new_plot)
86        #creating a name for data
87        title = ""
88        file_name = os.path.basename(path) if path is not None else data.filename
89        if file_name:
90            name = file_name
91        elif data.run:
92            name = data.run[0]
93        else:
94            name = "data"
95        name = self.rename(name)
96        #find title
97        if data.title.strip():
98            title = data.title
99        if title.strip() == "":
100            title = file_name
101
102        if new_plot.filename.strip() == "":
103            new_plot.filename = file_name
104
105        new_plot.name = name
106        new_plot.title = title
107        ## allow to highlight data when plotted
108        new_plot.interactive = True
109        ## when 2 data have the same id override the 1 st plotted
110        self.time_stamp += 1
111        new_plot.id = str(name) + str(self.time_stamp)
112        ##group_id specify on which panel to plot this data
113        new_plot.group_id = str(name) + str(self.time_stamp)
114        new_plot.is_data = True
115        new_plot.path = path
116        new_plot.list_group_id = []
117        ##post data to plot
118        # plot data
119        return new_plot
120
121    def rename(self, name):
122        """
123        rename data
124        """
125        ## name of the data allow to differentiate data when plotted
126        name = GuiUtils.parseName(name=name, expression="_")
127
128        max_char = name.find("[")
129        if max_char < 0:
130            max_char = len(name)
131        name = name[0:max_char]
132
133        if name not in self.data_name_dict:
134            self.data_name_dict[name] = 0
135        else:
136            self.data_name_dict[name] += 1
137            name = name + " [" + str(self.data_name_dict[name]) + "]"
138        return name
139
140
141    def add_data(self, data_list):
142        """
143        receive a list of
144        """
145        for id, data in data_list.iteritems():
146            if id  in self.stored_data:
147                msg = "Data manager already stores %s" % str(data.name)
148                msg += ""
149                logging.info(msg)
150                data_state = self.stored_data[id]
151                data_state.data = data
152            else:
153                data_state = DataState(data)
154                data_state.id = id
155                data_state.path = data.path
156                self.stored_data[id] = data_state
157
158    def update_data(self, prev_data, new_data):
159        """
160        """
161        if prev_data.id not in self.stored_data.keys():
162            return None, {}
163        data_state = self.stored_data[prev_data.id]
164        self.stored_data[new_data.id]  = data_state.clone()
165        self.stored_data[new_data.id].data = new_data
166        if prev_data.id in self.stored_data.keys():
167            del self.stored_data[prev_data.id]
168        return prev_data.id, {new_data.id: self.stored_data[new_data.id]}
169
170    def update_theory(self, theory, data_id=None, state=None):
171        """
172        """
173        uid = data_id
174        if data_id is None and theory is not None:
175            uid = theory.id
176        if uid in self.stored_data.keys():
177             data_state = self.stored_data[uid]
178        else:
179            data_state = DataState()
180        data_state.uid = uid
181        data_state.set_theory(theory_data=theory, theory_state=state)
182        self.stored_data[uid] = data_state
183        return {uid: self.stored_data[uid]}
184
185
186    def get_message(self):
187        """
188        return message
189        """
190        return self.message
191
192    def get_by_id(self, id_list=None):
193        """
194        """
195        _selected_data = {}
196        _selected_theory_list = {}
197        if id_list is None:
198            return
199        for d_id in self.stored_data:
200            for search_id in id_list:
201                data_state = self.stored_data[d_id]
202                data = data_state.data
203                theory_list = data_state.get_theory()
204                if search_id == d_id:
205                    _selected_data[search_id] = data
206                if search_id in theory_list.keys():
207                     _selected_theory_list[search_id] = theory_list[search_id]
208
209        return _selected_data, _selected_theory_list
210
211
212    def freeze(self, theory_id):
213        """
214        """
215        return self.freeze_theory(self.stored_data.keys(), theory_id)
216
217    def freeze_theory(self, data_id, theory_id):
218        """
219        """
220        selected_theory = {}
221        for d_id in data_id:
222            if d_id in self.stored_data:
223                data_state = self.stored_data[d_id]
224                theory_list = data_state.get_theory()
225                for t_id in theory_id:
226                    if t_id in theory_list.keys():
227                        theory_data, theory_state = theory_list[t_id]
228                        new_theory = copy.deepcopy(theory_data)
229                        new_theory.id  = time.time()
230                        new_theory.is_data = True
231                        new_theory.name += '_@' + \
232                                    str(new_theory.id)[7:-1].replace('.', '')
233                        new_theory.title = new_theory.name
234                        new_theory.label = new_theory.name
235                        selected_theory[new_theory.id] = DataState(new_theory)
236                        self.stored_data[new_theory.id] = \
237                                    selected_theory[new_theory.id]
238
239        return selected_theory
240
241
242    def delete_data(self, data_id, theory_id=None, delete_all=False):
243        """
244        """
245        for d_id in data_id:
246            if d_id in self.stored_data.keys():
247                data_state = self.stored_data[d_id]
248                if data_state.data.name in self.data_name_dict:
249                    del self.data_name_dict[data_state.data.name]
250                del self.stored_data[d_id]
251
252        self.delete_theory(data_id, theory_id)
253        if delete_all:
254            self.stored_data = {}
255            self.data_name_dict = {}
256
257    def delete_theory(self, data_id, theory_id):
258        """
259        """
260        for d_id in data_id:
261            if d_id in self.stored_data:
262                data_state = self.stored_data[d_id]
263                theory_list = data_state.get_theory()
264                if theory_id in theory_list.keys():
265                    del theory_list[theory_id]
266        #del pure theory
267        self.delete_by_id(theory_id)
268
269    def delete_by_id(self, id_list=None):
270        """
271        save data and path
272        """
273        for id in id_list:
274            if id in self.stored_data:
275                del self.stored_data[id]
276
277
278    def get_by_name(self, name_list=None):
279        """
280        return a list of data given a list of data names
281        """
282        _selected_data = {}
283        for selected_name in name_list:
284            for id, data_state in self.stored_data.iteritems():
285                if data_state.data.name == selected_name:
286                    _selected_data[id] = data_state.data
287        return _selected_data
288
289    def delete_by_name(self, name_list=None):
290        """
291        save data and path
292        """
293        for selected_name in name_list:
294            for id, data_state in self.stored_data.iteritems():
295                if data_state.data.name == selected_name:
296                    del self.stored_data[id]
297
298    def get_data_state(self, data_id):
299        """
300        Send list of selected data
301        """
302        _selected_data_state = {}
303        for id in data_id:
304            if id in self.stored_data.keys():
305                _selected_data_state[id] = self.stored_data[id]
306        return _selected_data_state
307
308    def get_all_data(self):
309        """
310        return list of all available data
311        """
312        return self.stored_data
313
314    def assign(self, other):
315        self.stored_data = other.stored_data
316        self.message = other.message
317        self.data_name_dict = other.data_name_dict
318        self.count = other.count
319        self.list_of_id = other.list_of_id
320        self.time_stamp = other.time_stamp
321
322    def save_to_writable(self, fp):
323        """
324        save content of stored_data to fp (a .write()-supporting file-like object)
325        """
326
327        def add_type(dict, type):
328            dict['__type__'] = type.__name__
329            return dict
330
331        def jdefault(o):
332            """
333            objects that can't otherwise be serialized need to be converted
334            """
335            # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples)
336            if isinstance(o, (tuple, set)):
337                content = { 'data': list(o) }
338                return add_type(content, type(o))
339
340            # "simple" types
341            if isinstance(o, (Sample, Source, Vector)):
342                return add_type(o.__dict__, type(o))
343            if isinstance(o, (Plottable, View)):
344                return add_type(o.__dict__, type(o))
345
346            # DataState
347            if isinstance(o, DataState):
348                # don't store parent
349                content = o.__dict__.copy()
350                content.pop('parent')
351                return add_type(content, type(o))
352
353            # ndarray
354            if isinstance(o, np.ndarray):
355                buffer = StringIO()
356                np.save(buffer, o)
357                buffer.seek(0)
358                content = { 'data': buffer.read().decode('latin-1') }
359                return add_type(content, type(o))
360
361            # not supported
362            logging.info("data cannot be serialized to json: %s" % type(o))
363            return None
364
365        json.dump(self.stored_data, fp, indent=2, sort_keys=True, default=jdefault)
366
367
368    def load_from_readable(self, fp):
369        """
370        load content from tp to stored_data (a .read()-supporting file-like object)
371        """
372
373        supported = [
374            tuple, set,
375            Sample, Source, Vector,
376            Plottable, Data1D, Data2D, PlottableTheory1D, PlottableFit1D, Text, Chisq, View,
377            DataState, np.ndarray]
378
379        lookup = dict((cls.__name__, cls) for cls in supported)
380
381        class TooComplexException(Exception):
382            pass
383
384        def simple_type(cls, data, level):
385            class Empty(object):
386                def __init__(self):
387                    for key, value in data.iteritems():
388                        setattr(self, key, generate(value, level))
389
390            # create target object
391            o = Empty()
392            o.__class__ = cls
393
394            return o
395
396        def construct(type, data, level):
397            try:
398                cls = lookup[type]
399            except KeyError:
400                logging.info('unknown type: %s' % type)
401                return None
402
403            # tuples and sets
404            if cls in (tuple, set):
405                # convert list to tuple/set
406                return cls(generate(data['data'], level))
407
408            # "simple" types
409            if cls in (Sample, Source, Vector):
410                return simple_type(cls, data, level)
411            if issubclass(cls, Plottable) or (cls == View):
412                return simple_type(cls, data, level)
413
414            # DataState
415            if cls == DataState:
416                o = simple_type(cls, data, level)
417                o.parent = None # TODO: set to ???
418                return o
419
420            # ndarray
421            if cls == np.ndarray:
422                buffer = StringIO()
423                buffer.write(data['data'].encode('latin-1'))
424                buffer.seek(0)
425                return np.load(buffer)
426
427            logging.info('not implemented: %s, %s' % (type, cls))
428            return None
429
430        def generate(data, level):
431            if level > 16: # recursion limit (arbitrary number)
432                raise TooComplexException()
433            else:
434                level += 1
435
436            if isinstance(data, dict):
437                try:
438                    type = data['__type__']
439                except KeyError:
440                    # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary
441                    o = {}
442                    for key, value in data.iteritems():
443                        o[key] = generate(value, level)
444                    return o
445
446                return construct(type, data, level)
447
448            if isinstance(data, list):
449                return [generate(item, level) for item in data]
450
451            return data
452
453        new_stored_data = {}
454        for id, data in json.load(fp).iteritems():
455            try:
456                new_stored_data[id] = generate(data, 0)
457            except TooComplexException:
458                logging.info('unable to load %s' % id)
459
460        self.stored_data = new_stored_data
461
Note: See TracBrowser for help on using the repository browser.