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

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 1420066 was 1420066, checked in by celinedurniak <celine.durniak@…>, 6 years ago

Corrected problem with update of loaded files in Data Operation Panel (ESS-GUI-SasView245)

  • Property mode set to 100755
File size: 15.4 KB
Line 
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    def get_by_name(self, name_list=None):
278        """
279        return a list of data given a list of data names
280        """
281        _selected_data = {}
282        for selected_name in name_list:
283            for id, data_state in self.stored_data.iteritems():
284                if data_state.data.name == selected_name:
285                    _selected_data[id] = data_state.data
286        return _selected_data
287
288    def delete_by_name(self, name_list=None):
289        """
290        save data and path
291        """
292        for selected_name in name_list:
293            for id, data_state in self.stored_data.iteritems():
294                if data_state.data.name == selected_name:
295                    del self.stored_data[id]
296
297    def update_stored_data(self, name_list=None):
298        """ update stored data after deleting files in Data Explorer """
299        for selected_name in name_list:
300            for idx in self.stored_data.keys():
301                if str(selected_name) in str(idx):
302                    print selected_name, idx
303                    del self.stored_data[idx]
304
305    def get_data_state(self, data_id):
306        """
307        Send list of selected data
308        """
309        _selected_data_state = {}
310        for id in data_id:
311            if id in self.stored_data.keys():
312                _selected_data_state[id] = self.stored_data[id]
313        return _selected_data_state
314
315    def get_all_data(self):
316        """
317        return list of all available data
318        """
319        return self.stored_data
320
321    def assign(self, other):
322        self.stored_data = other.stored_data
323        self.message = other.message
324        self.data_name_dict = other.data_name_dict
325        self.count = other.count
326        self.list_of_id = other.list_of_id
327        self.time_stamp = other.time_stamp
328
329    def save_to_writable(self, fp):
330        """
331        save content of stored_data to fp (a .write()-supporting file-like object)
332        """
333
334        def add_type(dict, type):
335            dict['__type__'] = type.__name__
336            return dict
337
338        def jdefault(o):
339            """
340            objects that can't otherwise be serialized need to be converted
341            """
342            # tuples and sets (TODO: default JSONEncoder converts tuples to lists, create custom Encoder that preserves tuples)
343            if isinstance(o, (tuple, set)):
344                content = { 'data': list(o) }
345                return add_type(content, type(o))
346
347            # "simple" types
348            if isinstance(o, (Sample, Source, Vector)):
349                return add_type(o.__dict__, type(o))
350            if isinstance(o, (Plottable, View)):
351                return add_type(o.__dict__, type(o))
352
353            # DataState
354            if isinstance(o, DataState):
355                # don't store parent
356                content = o.__dict__.copy()
357                content.pop('parent')
358                return add_type(content, type(o))
359
360            # ndarray
361            if isinstance(o, np.ndarray):
362                buffer = StringIO()
363                np.save(buffer, o)
364                buffer.seek(0)
365                content = { 'data': buffer.read().decode('latin-1') }
366                return add_type(content, type(o))
367
368            # not supported
369            logging.info("data cannot be serialized to json: %s" % type(o))
370            return None
371
372        json.dump(self.stored_data, fp, indent=2, sort_keys=True, default=jdefault)
373
374
375    def load_from_readable(self, fp):
376        """
377        load content from tp to stored_data (a .read()-supporting file-like object)
378        """
379
380        supported = [
381            tuple, set,
382            Sample, Source, Vector,
383            Plottable, Data1D, Data2D, PlottableTheory1D, PlottableFit1D, Text, Chisq, View,
384            DataState, np.ndarray]
385
386        lookup = dict((cls.__name__, cls) for cls in supported)
387
388        class TooComplexException(Exception):
389            pass
390
391        def simple_type(cls, data, level):
392            class Empty(object):
393                def __init__(self):
394                    for key, value in data.iteritems():
395                        setattr(self, key, generate(value, level))
396
397            # create target object
398            o = Empty()
399            o.__class__ = cls
400
401            return o
402
403        def construct(type, data, level):
404            try:
405                cls = lookup[type]
406            except KeyError:
407                logging.info('unknown type: %s' % type)
408                return None
409
410            # tuples and sets
411            if cls in (tuple, set):
412                # convert list to tuple/set
413                return cls(generate(data['data'], level))
414
415            # "simple" types
416            if cls in (Sample, Source, Vector):
417                return simple_type(cls, data, level)
418            if issubclass(cls, Plottable) or (cls == View):
419                return simple_type(cls, data, level)
420
421            # DataState
422            if cls == DataState:
423                o = simple_type(cls, data, level)
424                o.parent = None # TODO: set to ???
425                return o
426
427            # ndarray
428            if cls == np.ndarray:
429                buffer = StringIO()
430                buffer.write(data['data'].encode('latin-1'))
431                buffer.seek(0)
432                return np.load(buffer)
433
434            logging.info('not implemented: %s, %s' % (type, cls))
435            return None
436
437        def generate(data, level):
438            if level > 16: # recursion limit (arbitrary number)
439                raise TooComplexException()
440            else:
441                level += 1
442
443            if isinstance(data, dict):
444                try:
445                    type = data['__type__']
446                except KeyError:
447                    # if dictionary doesn't have __type__ then it is assumed to be just an ordinary dictionary
448                    o = {}
449                    for key, value in data.iteritems():
450                        o[key] = generate(value, level)
451                    return o
452
453                return construct(type, data, level)
454
455            if isinstance(data, list):
456                return [generate(item, level) for item in data]
457
458            return data
459
460        new_stored_data = {}
461        for id, data in json.load(fp).iteritems():
462            try:
463                new_stored_data[id] = generate(data, 0)
464            except TooComplexException:
465                logging.info('unable to load %s' % id)
466
467        self.stored_data = new_stored_data
468
Note: See TracBrowser for help on using the repository browser.