source: sasview/invariantview/perspectives/invariant/invariant_state.py @ 6450d8c

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 6450d8c was b281210, checked in by Jae Cho <jhjcho@…>, 14 years ago

added save as text and added png saves, improved the behavior

  • Property mode set to 100644
File size: 29.2 KB
RevLine 
[4e1c362]1import time, os, sys
2import logging
3import copy
4import DataLoader
5from xml.dom.minidom import parse
6from lxml import etree
7
8from DataLoader.readers.cansas_reader import Reader as CansasReader
9from DataLoader.readers.cansas_reader import get_content
10from sans.guiframe.utils import format_number
11from sans.guiframe.dataFitting import Theory1D, Data1D
12INVNODE_NAME = 'invariant'
13CANSAS_NS = "cansas1d/1.0"
14# default state
15list = {'file': 'None',
16        'compute_num':0,
17        'state_num':0,
18        'is_time_machine':False,
19        'background_tcl':0.0,
20        'scale_tcl':1.0,
21        'contrast_tcl':1.0,
22        'porod_constant_tcl':'',
23        'npts_low_tcl':10,
24        'npts_high_tcl':10,
25        'power_high_tcl':4.0,
26        'power_low_tcl': 4.0,
27        'enable_high_cbox':False,
28        'enable_low_cbox':False,
29        'guinier': True,
30        'power_law_high': False,
31        'power_law_low': False,
32        'fit_enable_high': False,
33        'fit_enable_low': False,
34        'fix_enable_high':True,
35        'fix_enable_low':True,
36        'volume_tcl':'',
37        'volume_err_tcl':'',
38        'surface_tcl':'',
39        'surface_err_tcl':''}
40# list of states: This list will be filled as panel init and the number of states increases
41state_list = {}
42bookmark_list = {}
43# list of input parameters (will be filled up on panel init) used by __str__
[cb463b4]44input_list = {'background_tcl':0,
45        'scale_tcl':0,
46        'contrast_tcl':0,
47        'porod_constant_tcl':'',
48        'npts_low_tcl':0,
49        'npts_high_tcl':0,
50        'power_high_tcl':0,
51        'power_low_tcl': 0} 
[4e1c362]52# list of output parameters (order sensitive) used by __str__   
53output_list = [["qstar_low",                  "Q* from low Q extrapolation [1/(cm*A)]"],
54               ["qstar_low_err",             "dQ* from low Q extrapolation"],
55               ["qstar_low_percent",  "Q* percent from low Q extrapolation"],
56               ["qstar",                                     "Q* from data [1/(cm*A)]"],
57               ["qstar_err",                                "dQ* from data"],
58               ["qstar_percent",                     "Q* percent from data"],
59               ["qstar_high",                "Q* from high Q extrapolation [1/(cm*A)]"],
60               ["qstar_high_err",           "dQ* from high Q extrapolation"],
61               ["qstar_high_percent", "Q* percent from low Q extrapolation"],
62               ["qstar_total",                                   "total Q* [1/(cm*A)]"],
63               ["qstar_total_err",                              "total dQ*"],
64               ["volume",                                 "volume fraction"],
65               ["volume_err",                       "volume fraction error"],
66               ["surface",                               "specific surface"],
67               ["surface_err",                     "specific surface error"]]
68
69   
70
71class InvariantState(object):
72    """
73    Class to hold the state information of the InversionControl panel.
74    """
75    def __init__(self):
76        """
77        Default values
78        """
79        # Input
80        self.file  = None
81        self.data = Data1D(x=[], y=[], dx=None, dy=None)
82        self.theory_lowQ =  Theory1D(x=[], y=[], dy=None)
83        self.theory_highQ = Theory1D(x=[], y=[], dy=None)
84        #self.is_time_machine = False
85        self.saved_state = list
86        self.state_list = state_list
87        self.bookmark_list = bookmark_list
88        self.input_list = input_list
89        self.output_list = output_list
90       
91        self.compute_num = 0
92        self.state_num = 0
[cb463b4]93        self.timestamp = "('00:00:00', '00/00/0000')"
[4e1c362]94        self.container = None
[a94c4e1]95        #plot image
96        self.wximbmp = None
[cb463b4]97        # report_html strings
98        import sans.perspectives.invariant as invariant
99        path = invariant.get_data_path(media='media')
100        path_report_html= os.path.join(path,"report_template.html")
101        html_template=open(path_report_html,"r")
102        self.template_str = html_template.read()
103        self.report_str = self.template_str
[b281210]104        #self.report_str_save = None
[cb463b4]105        html_template.close()
[4e1c362]106       
[cb463b4]107
[4e1c362]108       
109    def __str__(self):
110        """
111        Pretty print
112           
113        : return: string representing the state
114        """
115        # Input string
116        compute_num = self.saved_state['compute_num']
117        compute_state = self.state_list[str(compute_num)]
118        my_time, date = self.timestamp
119        file_name = self.file
120
121        state_num = int(self.saved_state['state_num'])
122        state = "\n[Invariant computation for %s: "% file_name
123        state += "performed at %s on %s] \n"%(my_time, date)
124        state += "State No.: %d \n"% state_num
125        state += "\n=== Inputs ===\n"
126       
127        # text ctl general inputs ( excluding extrapolation text ctl)
128        for key,value in self.input_list.iteritems(): 
129            if value == '':
130                continue
131            key_split = key.split('_') 
132            max_ind = len(key_split)-1
133            if key_split[max_ind] == 'tcl': 
134                name =""
135                if key_split[1]== 'low' or key_split[1]== 'high':
136                    continue
137                for ind in range(0,max_ind):
138                    name +=" %s"%key_split[ind]
139                state += "%s:   %s\n"% (name.lstrip(" "),value)
140               
141        # other input parameters       
142        extra_lo = compute_state['enable_low_cbox']
143        if compute_state['enable_low_cbox']:
144            if compute_state['guinier']:
145                extra_lo = 'Guinier'
146            else:
147                extra_lo = 'Power law'
148        extra_hi = compute_state['enable_high_cbox']
149        if compute_state['enable_high_cbox']:
150            extra_hi = 'Power law'
151        state += "\nExtrapolation:  High=%s; Low=%s\n" %(extra_hi,extra_lo)   
152        low_off = False
153        high_off = False
154        for key,value in self.input_list.iteritems(): 
155            key_split = key.split('_') 
156            max_ind = len(key_split)-1   
157            if key_split[max_ind] == 'tcl': 
158                name ="" 
159                # check each buttons whether or not ON or OFF
160                if key_split[1]== 'low' or key_split[1]== 'high':
161                    if not compute_state['enable_low_cbox'] and key_split[max_ind-1] == 'low':
162                        low_off = True
163                        continue             
164                    elif not compute_state['enable_high_cbox'] and key_split[max_ind-1]== 'high':
165                        high_off = True
166                        continue
167                    elif extra_lo == 'Guinier' and key_split[0]== 'power' and key_split[max_ind-1]== 'low':
168                        continue
169                    for ind in range(0,max_ind):
170                        name +=" %s"%key_split[ind]
171                    name = name.lstrip(" ")
172                    if name == "power low" :
173                        if compute_state['fix_enable_low']:
174                            name += ' (Fixed)'
175                        else:
176                            name += ' (Fitted)'
177                    if name == "power high" :
178                        if compute_state['fix_enable_high']:
179                            name += ' (Fixed)'
180                        else:
181                            name += ' (Fitted)'
182                    state += "%s:   %s\n"% (name,value)
183        # Outputs
184        state += "\n=== Outputs ==="
185        for item in output_list:
186            item_split = item[0].split('_') 
187            # Exclude the extrapolation that turned off
188            if len(item_split)>1:
189                if low_off and item_split[1] == 'low': continue
190                if high_off and item_split[1] == 'high': continue
191            max_ind = len(item_split)-1
192            value = None
193            try:
194                # Q* outputs
195                exec "value = self.container.%s\n"% item[0]
196            except:
197                # other outputs than Q*
198                name = item[0]+"_tcl"
199                exec "value = self.saved_state['%s']"% name
200               
201            # Exclude the outputs w/''   
202            if value == '': continue   
203           
204            # Error outputs
205            if item_split[max_ind] == 'err':
206                state += "+- %s "%format_number(value)
207               
208            # Percentage outputs
209            elif item_split[max_ind] == 'percent':
210                try:
211                    value = float(value)*100
212                except:
213                    pass
[b281210]214                state += "(%s %s)"%(format_number(value),'o/o')
[4e1c362]215            # Outputs
216            else:
217                state += "\n%s:   %s "%(item[1],format_number(value,high=True))
218        # Include warning msg
219        state += "\n\nNote:\n" + self.container.warning_msg
[cb463b4]220       
[4e1c362]221        return state
222
223   
224    def clone_state(self):
225        """
226        deepcopy the state
227        """
228        return copy.deepcopy(self.saved_state)
229   
230
231    def toXML(self, file="inv_state.inv", doc=None, entry_node=None):
232        """
233        Writes the state of the InversionControl panel to file, as XML.
234       
235        Compatible with standalone writing, or appending to an
236        already existing XML document. In that case, the XML document
237        is required. An optional entry node in the XML document may also be given.
238       
239        : param file: file to write to
240        : param doc: XML document object [optional]
241        : param entry_node: XML node within the XML document at which we will append the data [optional]   
242        """
243        from xml.dom.minidom import getDOMImplementation
244        import time
245        timestamp = time.time()
246        # Check whether we have to write a standalone XML file
247        if doc is None:
248            impl = getDOMImplementation()
249       
250            doc_type = impl.createDocumentType(INVNODE_NAME, "1.0", "1.0")     
251       
252            newdoc = impl.createDocument(None, INVNODE_NAME, doc_type)
253            top_element = newdoc.documentElement
254        else:
255            # We are appending to an existing document
256            newdoc = doc
257            top_element = newdoc.createElement(INVNODE_NAME)
258            if entry_node is None:
259                newdoc.documentElement.appendChild(top_element)
260            else:
261                entry_node.appendChild(top_element)
262           
263        attr = newdoc.createAttribute("version")
264        attr.nodeValue = '1.0'
265        top_element.setAttributeNode(attr)
266       
267        # File name
268        element = newdoc.createElement("filename")
269        if self.file is not None:
270            element.appendChild(newdoc.createTextNode(str(self.file)))
271        else:
272            element.appendChild(newdoc.createTextNode(str(file)))
273        top_element.appendChild(element)
274       
275        element = newdoc.createElement("timestamp")
276        element.appendChild(newdoc.createTextNode(time.ctime(timestamp)))
277        attr = newdoc.createAttribute("epoch")
278        attr.nodeValue = str(timestamp)
279        element.setAttributeNode(attr)
280        top_element.appendChild(element)
281       
282        # Current state
283        state = newdoc.createElement("state")
284        top_element.appendChild(state)
285       
286        for name,value in self.saved_state.iteritems():
287            element = newdoc.createElement(str(name))
288            element.appendChild(newdoc.createTextNode(str(value)))
289            state.appendChild(element)
290             
291        # State history list
292        history = newdoc.createElement("history")
293        top_element.appendChild(history)
294       
295        for name, value in self.state_list.iteritems():
296            history_element = newdoc.createElement('state_'+str(name))
297            for state_name,state_value in value.iteritems():
298                state_element = newdoc.createElement(str(state_name))
299                state_element.appendChild(newdoc.createTextNode(str(state_value)))
300                history_element.appendChild(state_element)
301            #history_element.appendChild(state_list_element)
302            history.appendChild(history_element)
303
304        # Bookmarks  bookmark_list[self.bookmark_num] = [my_time,date,state,comp_state]
305        bookmark = newdoc.createElement("bookmark")
306        top_element.appendChild(bookmark)
307        item_list = ['time','date','state','comp_state']
308        for name, value_list in self.bookmark_list.iteritems():
309            element = newdoc.createElement('mark_'+ str(name))
310            time,date,state,comp_state = value_list
311            time_element = newdoc.createElement('time')
312            time_element.appendChild(newdoc.createTextNode(str(value_list[0])))
313            date_element = newdoc.createElement('date')
314            date_element.appendChild(newdoc.createTextNode(str(value_list[1])))
315            state_list_element = newdoc.createElement('state')
316            comp_state_list_element = newdoc.createElement('comp_state')
317            for state_name,state_value in value_list[2].iteritems():
318                state_element = newdoc.createElement(str(state_name))
319                state_element.appendChild(newdoc.createTextNode(str(state_value)))
320                state_list_element.appendChild(state_element)
321            for comp_name,comp_value in value_list[3].iteritems():
322                comp_element = newdoc.createElement(str(comp_name))
323                comp_element.appendChild(newdoc.createTextNode(str(comp_value)))
324                comp_state_list_element.appendChild(comp_element)
325            element.appendChild(time_element)
326            element.appendChild(date_element)
327            element.appendChild(state_list_element)
328            element.appendChild(comp_state_list_element)
329            bookmark.appendChild(element)
330
331        # Save the file
332        if doc is None:
333            fd = open('test000', 'w')
334            fd.write(newdoc.toprettyxml())
335            fd.close()
336            return None
337        else:
338            return newdoc.toprettyxml()
339       
340    def fromXML(self, file=None, node=None):
341        """
342        Load invariant states from a file
343           
344        : param file: .inv file
345        : param node: node of a XML document to read from       
346        """
347        if file is not None:
348            raise RuntimeError, "InvariantSate no longer supports non-CanSAS format for invariant files"
349       
350        if node.get('version')\
351            and node.get('version') == '1.0':
352
353            # Get file name
354            entry = get_content('ns:filename', node)
355            if entry is not None:
356                self.file = entry.text.strip()
357           
358            # Get time stamp
359            entry = get_content('ns:timestamp', node)
360            if entry is not None and entry.get('epoch'):
361                try:
362                    timestamp = (entry.get('epoch'))
363                except:
364                    logging.error("InvariantSate.fromXML: Could not read timestamp\n %s" % sys.exc_value)
365           
366            # Parse bookmarks
367            entry_bookmark = get_content('ns:bookmark', node)
368
369            for ind in range(1,len(entry_bookmark)+1):
370                temp_state = {}
371                temp_bookmark = {}
372                entry = get_content('ns:mark_%s' % ind, entry_bookmark) 
373                               
374                if entry is not None:
375                    time = get_content('ns:time', entry )
376                    val_time = str(time.text.strip())
377                    date = get_content('ns:date', entry )
378                    val_date = str(date.text.strip())
379                    state_entry = get_content('ns:state', entry )
380                    for item in list:
381
382                        input_field = get_content('ns:%s' % item, state_entry )
383                        val = str(input_field.text.strip())
384
385                        if input_field is not None:
386                            try:
387                                exec "temp_state['%s'] = %s"% (item,val)     
388                            except:
389                                exec "temp_state['%s'] = '%s'"% (item,val)
390                           
391                    comp_entry = get_content('ns:comp_state', entry )
392                   
393                    for item in list:
394                        input_field = get_content('ns:%s' % item, comp_entry )
395                        val = str(input_field.text.strip())
396                        if input_field is not None:
397                            try:
398                                exec "temp_bookmark['%s'] = %s"% (item,val)     
399                            except:
400                                exec "temp_bookmark['%s'] = '%s'"% (item,val)
401                    try:
402                        exec "self.bookmark_list[%s] = [val_time,val_date,temp_state,temp_bookmark]"% ind
403
404                    except:
405                        raise "missing components of bookmarks..."
406   
407            # Parse histories
408            entry_history = get_content('ns:history', node)
409
410            for ind in range(0,len(entry_history)):
411                temp_state = {}
412                entry = get_content('ns:state_%s' % ind, entry_history) 
413
414                if entry is not None:
415                    for item in list:
416                        input_field = get_content('ns:%s' % item, entry )
417                        val = str(input_field.text.strip())
418
419                        if input_field is not None:
420                            try:
421                                exec "temp_state['%s'] = %s"% (item,val)         
422                            except:
423                                exec "temp_state['%s'] = '%s'"% (item,val)
424                            finally:
425                                exec "self.state_list['%s'] = temp_state"% ind
426           
427            # Parse current state (ie, saved_state)
428            entry = get_content('ns:state', node)           
429            if entry is not None:
430                for item in list:
431                    input_field = get_content('ns:%s' % item, entry)
432                    val = str(input_field.text.strip())
433                    if input_field is not None:
434                        self.set_saved_state(name=item, value=val)
435
[cb463b4]436    def set_report_string(self):
437        """
438        Get the values (strings) from __str__ for report
439        """
440        strings = self.__str__()
441   
442        # default string values
443        for num in range (1,19):
444            exec "s_%s = 'NA'"% str(num)
445        lines = strings.split('\n')
446        # get all string values from __str__()
447        for line in range(0,len(lines)):
448            if line == 1:
449                s_1 = lines[1]
450            elif line == 2:
451                s_2 = lines[2]
452            else:
453                item = lines[line].split(':')
454                item[0] = item[0].strip()
455                if item[0]== "scale":
456                    s_3 = item[1]
457                elif item[0] == "porod constant":
458                    s_4 = item[1]
459                elif item[0] == "background":
460                    s_5 = item[1]
461                elif item[0] == "contrast":
462                    s_6 = item[1]
463                elif item[0] == "Extrapolation":
464                    extra = item[1].split(";")
465                    bool_0 = extra[0].split("=")
466                    bool_1 = extra[1].split("=")
[b281210]467                    s_7 = " "+bool_0[0]+"Q region = "+bool_0[1]
468                    s_8 = " "+bool_1[0]+"Q region = "+bool_1[1]
[cb463b4]469                elif item[0]=="npts low":
470                    s_9 = item[1]
471                elif item[0]=="npts high":
472                    s_10 = item[1]
473                elif item[0] == "volume fraction":
474                    s_17 = item[1]
475                elif item[0] == "specific surface":
476                    s_18 = item[1]
477                elif item[0].split("(")[0].strip()=="power high":
478                    s_11 = item[0]+" ="+item[1]
479                elif item[0].split("(")[0].strip()=="power low":
480                    s_12 = item[0]+" ="+item[1]
481                elif item[0].split("[")[0].strip()=="Q* from low Q extrapolation":
482                    s_13 = item[1]
483                elif item[0].split("[")[0].strip()=="Q* from data":
484                    s_14 = item[1]
485                elif item[0].split("[")[0].strip()=="Q* from high Q extrapolation":
486                    s_15 = item[1]
487                elif item[0].split("[")[0].strip()=="total Q*":
488                    s_16 = item[1]
489                else:
490                    continue
491
[a94c4e1]492        # make plot image
493        self.set_plot_state(extra_high=bool_0[1],extra_low=bool_1[1])
494        # get ready for report with setting all the html strings
[b281210]495        self.report_str =  str(self.template_str)% (s_1,s_2,s_3,s_4,s_5,s_6,s_7,s_8,s_9,s_10,s_11,s_12,s_13,s_14,s_15,s_16,s_17,s_18,self.file,"%s")
496
497
[4e1c362]498    def set_saved_state(self, name, value):
499        """
500        Set the state list
501                   
502        : param name: name of the state component
503        : param value: value of the state component
504        """
505        rb_list = [['power_law_low','guinier'],['fit_enable_low','fix_enable_low'],['fit_enable_high','fix_enable_high']]
506
507        try:
508            if value == None or value.lstrip().rstrip() =='':
509                exec "self.%s = '%s'" % (name, value)
510                exec "self.saved_state['%s'] = '%s'" %  (name, value)
511            else:
512                exec 'self.%s = %s' % (name, value)
513                exec "self.saved_state['%s'] = %s" %  (name, value)
514
515           
516            # set the count part of radio button clicked False for the saved_state
517            for title,content in rb_list:
518                if name ==  title:
519                    name = content
520                    value = False     
521                elif name == content:
522                    name = title
523                    value = False 
524            exec "self.saved_state['%s'] = '%s'" %  (name, value)     
525            self.state_num = self.saved_state['state_num']
526        except:           
527            pass
528
[a94c4e1]529    def set_plot_state(self,extra_high=False,extra_low=False):
530        """
531        Build image state that wx.html understand
532        by plotting, putting it into wx.FileSystem image object
533       
534        : extrap_high,extra_low: low/high extrapolations are possible extra-plots
535        """
536        # some imports
537        import cStringIO
538        import matplotlib,wx
539        matplotlib.use('Agg')
540        import matplotlib.pyplot as plt
541        import Image
542       
543        #we use simple plot, not plotpanel
544        #make matlab figure
545        fig = plt.figure()
546        graph = fig.add_subplot(111)
547       
548        #data plot
549        graph.errorbar(self.data.x, self.data.y, yerr=self.data.dy, fmt='o')
550        #low Q extrapolation fit plot
551        if not extra_low == 'False':
552            graph.plot(self.theory_lowQ.x,self.theory_lowQ.y)
553        #high Q extrapolation fit plot
554        if not extra_high == 'False':
555            graph.plot(self.theory_highQ.x,self.theory_highQ.y)
556        graph.set_xscale("log", nonposx='clip')
557        graph.set_yscale("log", nonposy='clip')
558        plt.xlabel('$\\rm{Q}(\\AA^{-1})$', fontsize = 12)
559        plt.ylabel('$\\rm{Intensity}(cm^{-1})$', fontsize = 12)
[4e1c362]560
[a94c4e1]561        #make python.Image object
562        imagedata = cStringIO.StringIO()
563        fig.savefig(imagedata,format='png')
564        imagedata.seek(0)
565        img = Image.open(imagedata) 
566        #convert to wx.Image
567        wxim = wx.EmptyImage(img.size[0],img.size[1])
568        wxim.SetData(img.convert("RGB").tostring()) 
569        #get the dynamic image for the htmlwindow
570        wximbmp = wx.BitmapFromImage(wxim)
571        #store the image in wx.FileSystem Object
572        wx.FileSystem.AddHandler(wx.MemoryFSHandler())
573        # use wx.MemoryFSHandler
574        self.imgRAM = wx.MemoryFSHandler()
575        #AddFile, image can be retrieved with 'memory:filename'
576        self.imgRAM.AddFile('img_inv.png',wximbmp, wx.BITMAP_TYPE_PNG)
577       
578        self.wximbmp = 'memory:img_inv.png'
[b281210]579        self.image = img
[4e1c362]580
581class Reader(CansasReader):
582    """
583    Class to load a .inv invariant file
584    """
585    ## File type
586    type_name = "Invariant"
587   
588    ## Wildcards
589    type = ["Invariant file (*.inv)|*.inv"]
590    ## List of allowed extensions
591    ext=['.inv', '.INV'] 
592   
593    def __init__(self, call_back, cansas=True):
594        """
595        Initialize the call-back method to be called
596        after we load a file
597       
598        : param call_back: call-back method
599        : param cansas:  True = files will be written/read in CanSAS format
600                        False = write CanSAS format 
601        """
602        ## Call back method to be executed after a file is read
603        self.call_back = call_back
604        ## CanSAS format flag
605        self.cansas = cansas
606
607    def read(self, path):
608        """
609        Load a new invariant state from file
610       
611        : param path: file path
612        : return: None
613        """
614        if self.cansas==True:
615            return self._read_cansas(path)
616        else:
617            return self._read_standalone(path)
618       
619    def _read_standalone(self, path):
620        """
621        Load a new invariant state from file.
622        The invariant node is assumed to be the top element.
623       
624        : param path: file path
625        : return: None
626        """
627        # Read the new state from file
628        state = InvariantState()
629
630        state.fromXML(file=path)
631       
632        # Call back to post the new state
633        self.call_back(state)
634        return None
635   
636    def _parse_state(self, entry):
637        """
638        Read an invariant result from an XML node
639       
640        : param entry: XML node to read from
641        : return: InvariantState object
642        """
643        # Create an empty state
644        state = InvariantState()
645
646        # Locate the invariant node
647        try:
648            nodes = entry.xpath('ns:%s' % INVNODE_NAME, namespaces={'ns': CANSAS_NS})
649            state.fromXML(node=nodes[0])
650        except:
651            logging.info("XML document does not contain invariant information.\n %s" % sys.exc_value) 
652        return state
653   
654    def _read_cansas(self, path):
655        """
656        Load data and invariant information from a CanSAS XML file.
657       
658        : param path: file path
659        : return: Data1D object if a single SASentry was found,
660                    or a list of Data1D objects if multiple entries were found,
661                    or None of nothing was found
662        : raise RuntimeError: when the file can't be opened
663        : raise ValueError: when the length of the data vectors are inconsistent
664        """
665        output = []
666       
667        if os.path.isfile(path):
668            basename  = os.path.basename(path)
669            root, extension = os.path.splitext(basename)
670           
671            if  extension.lower() in self.ext or \
672                extension.lower() == '.xml':
673                tree = etree.parse(path, parser=etree.ETCompatXMLParser())
674       
675                # Check the format version number
676                # Specifying the namespace will take care of the file format version
677                root = tree.getroot()
678               
679                entry_list = root.xpath('/ns:SASroot/ns:SASentry', namespaces={'ns': CANSAS_NS})
680               
681                for entry in entry_list:
682                   
683                    sas_entry = self._parse_entry(entry)
684                    invstate = self._parse_state(entry)
685                    sas_entry.meta_data['invstate'] = invstate
686
687                    sas_entry.filename = invstate.file
688                    output.append(sas_entry)
689               
690        else:
691            raise RuntimeError, "%s is not a file" % path
692
693        # Return output consistent with the loader's api
694        if len(output)==0:
695            return None
696        elif len(output)==1:
697            # Call back to post the new state
698
699            self.call_back(state=output[0].meta_data['invstate'], datainfo = output[0])
700            return output[0]
701        else:
702            return output               
703   
704   
705    def write(self, filename, datainfo=None, invstate=None):
706        """
707        Write the content of a Data1D as a CanSAS XML file
708       
709        : param filename: name of the file to write
710        : param datainfo: Data1D object
711        : param invstate: InvariantState object
712        """
713
714        # Sanity check
715        if self.cansas == True:
716            if datainfo is None:
717                datainfo = DataLoader.data_info.Data1D(x=[], y=[])   
718            elif not issubclass(datainfo.__class__, DataLoader.data_info.Data1D):
719                raise RuntimeError, "The cansas writer expects a Data1D instance: %s" % str(datainfo.__class__.__name__)
720       
721            # Create basic XML document
722            doc, sasentry = self._to_xml_doc(datainfo)
723       
724            # Add the invariant information to the XML document
725            if invstate is not None:
726                invstate.toXML(doc=doc, entry_node=sasentry)
727       
728            # Write the XML document
729            fd = open(filename, 'w')
730            fd.write(doc.toprettyxml())
731            fd.close()
732        else:
733            invstate.toXML(file=filename)
734       
735   
736   
Note: See TracBrowser for help on using the repository browser.