source: sasview/sansview/perspectives/fitting/pagestate.py @ ca430a0

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 ca430a0 was f5bdb4a, checked in by Jae Cho <jhjcho@…>, 14 years ago

fixed html string format problem because of '%" symbol

  • Property mode set to 100644
File size: 66.9 KB
Line 
1
2
3################################################################################
4#This software was developed by the University of Tennessee as part of the
5#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
6#project funded by the US National Science Foundation.
7#
8#See the license text in license.txt
9#
10#copyright 2009, University of Tennessee
11################################################################################
12
13import time
14import os
15import sys
16import copy
17import logging
18import numpy
19
20import xml.dom.minidom
21from xml.dom.minidom import parse
22from lxml import etree
23
24import DataLoader
25from DataLoader.readers.cansas_reader import Reader as CansasReader
26from DataLoader.readers.cansas_reader import get_content, write_node
27from DataLoader.data_info import Data2D, Detector
28
29#Information to read/write state as xml
30FITTING_NODE_NAME = 'fitting_plug_in'
31CANSAS_NS = "cansas1d/1.0"
32
33list_of_data_attributes = [["is_data", "is_data", "bool"],
34                      ["group_id", "data_group_id", "string"],
35                      ["data_name", "data_name", "string"],
36                      ["data_id", "data_id", "string"],
37                      ["name", "name", "string"],
38                      ["data_name", "data_name", "string"]]
39list_of_state_attributes = [["engine_type", "engine_type", "string"],
40                       ["qmin", "qmin", "float"],
41                      ["qmax", "qmax", "float"],
42                      ["npts", "npts", "float"],
43                      ["shape_rbutton", "shape_rbutton", "bool"],
44                      ["shape_indep_rbutton", "shape_indep_rbutton", "bool"],
45                      ["plugin_rbutton", "plugin_rbutton","bool"],
46                      ["struct_rbutton", "struct_rbutton", "bool"],
47                      ["formfactorcombobox", "formfactorcombobox", "float"],
48                      ["structurecombobox", "structurecombobox", "float"],
49                      ["multi_factor","multi_factor","float"],
50                      ["enable_smearer","enable_smearer","bool"],
51                      ["disable_smearer","disable_smearer","bool"],
52                      ["pinhole_smearer","pinhole_smearer","bool"],
53                      ["slit_smearer","slit_smearer","bool"],
54                      ["enable_disp","enable_disp","bool"],
55                      ["disable_disp","disable_disp","bool"],
56                      ["slit_smearer","slit_smearer","bool"],
57                      ["enable2D","enable2D","bool"],
58                      ["cb1","cb1","bool"],
59                      ["tcChi","tcChi","float"],
60                     ["smearer", "smearer", "float"],
61                     ["smear_type","smear_type", "string"],
62                     ["dq_l", "dq_l", "string"],
63                     ["dq_r","dq_r", "string"]]
64
65list_of_model_attributes = [["values", "values"],
66                            ["weights", "weights"]]
67
68list_of_obj_dic =  [["disp_obj_dict", "_disp_obj_dict", "string"]]
69
70list_of_state_parameters = [["parameters", "parameters"] , 
71                            ["str_parameters", "str_parameters"] ,                     
72                            ["orientation_parameters", "orientation_params"],
73                            ["dispersity_parameters", "orientation_params_disp"],
74                            ["fixed_param", "fixed_param"],                     
75                            ["fittable_param","fittable_param"]]
76list_of_data_2d_attr = [["xmin", "xmin","float"],
77                        ["xmax","xmax","float"],
78                        ["ymin","ymin","float"],
79                        ["ymax","ymax","float"],
80                        ["_xaxis","_xaxis", "string"],
81                        ["_xunit", "_xunit", "string"],
82                        ["_yaxis","_yaxis","string"],
83                        ["_yunit","_yunit","string"],
84                        ["_zaxis","_zaxis","string"],
85                        ["_zunit","_zunit","string"]]
86list_of_data2d_values = [["qx_data","qx_data","float"],
87                         ["qy_data","qy_data","float"],
88                         ["dqx_data","dqx_data","float"],
89                         ["dqy_data","dqy_data","float"],
90                         ["data","data","float"],
91                         ["q_data","q_data","float"],
92                         ["err_data","err_data","float"],
93                         ["mask","mask","bool"]]
94
95def parse_entry_helper( node, item):
96    """
97    Create a numpy list from value extrated from the node
98   
99    :param node: node from each the value is stored
100    :param item: list name of three strings.the two first are name of data
101        attribute and the third one is the type of the value of that
102        attribute. type can be string, float, bool, etc.
103   
104    : return: numpy array
105    """
106    if node is not None:
107        if item[2] == "string":
108            return str(node.get(item[0]).strip())
109        elif item[2] == "bool":
110            try:
111                return node.get(item[0]).strip() == "True"
112               
113            except:
114                return None
115        else:
116            try:
117                return float(node.get(item[0]))
118            except:
119                return None
120           
121           
122class PageState(object):
123    """
124    Contains information to reconstruct a page of the fitpanel.
125    """
126    def __init__(self, parent=None, model=None, data=None):
127       
128        """
129        Initialize the current state
130       
131        :param model: a selected model within a page
132        :param data:
133       
134        """
135        self.file = None
136        #Time of state creation
137        self.timestamp = time.time()
138        ## Data member to store the dispersion object created
139        self._disp_obj_dict = {}
140        #------------------------
141        #Data used for fitting
142        self.data = data
143        # model data
144        self.theory_data = None
145        #Is 2D
146        self.is_2D = False
147        self.images = None
148       
149        #save additional information on data that dataloader.reader does not read
150        self.is_data = None
151        self.data_name = ""
152
153        if self.data is not None:
154            self.data_name = self.data.name
155        self.data_id = None
156        if self.data is not None and hasattr(self.data, "id"):
157            self.data_id = self.data.id
158        self.data_group_id = None
159        if self.data is not None and hasattr(self.data, "group_id"):
160            self.data_group_id = self.data.group_id
161       
162        ## reset True change the state of exsiting button
163        self.reset = False
164       
165        #engine type
166        self.engine_type = None
167        # flag to allow data2D plot
168        self.enable2D = False
169        # model on which the fit would be performed
170        self.model = model
171        #list of process done to model
172        self.process = []
173        #fit page manager
174        self.manager = None
175        #Store the parent of this panel parent
176        # For this application fitpanel is the parent
177        self.parent  = parent
178        # Event_owner is the owner of model event
179        self.event_owner = None
180        ##page name
181        self.page_name = ""
182        # Contains link between  model ,all its parameters, and panel organization
183        self.parameters = []
184        # String parameter list that can not be fitted
185        self.str_parameters = []
186        # Contains list of parameters that cannot be fitted and reference to
187        #panel objects
188        self.fixed_param = []
189        # Contains list of parameters with dispersity and reference to
190        #panel objects
191        self.fittable_param = []
192        ## orientation parameters
193        self.orientation_params = []
194        ## orientation parmaters for gaussian dispersity
195        self.orientation_params_disp = []
196        ## smearer info
197        self.smearer = None
198        self.smear_type = None
199        self.dq_l = None
200        self.dq_r = None
201
202        #list of dispersion paramaters
203        self.disp_list =[]
204        if self.model is not None:
205            self.disp_list = self.model.getDispParamList()
206
207        self.disp_cb_dict = {}
208        self.values = {}
209        self.weights = {}
210                   
211        #contains link between a model and selected parameters to fit
212        self.param_toFit = []
213        ##dictionary of model type and model class
214        self.model_list_box = None
215        ## save the state of the context menu
216        self.saved_states = {}
217        ## save selection of combobox
218        self.formfactorcombobox = None
219        self.structurecombobox  = None
220
221        ## radio box to select type of model
222        self.shape_rbutton = False
223        self.shape_indep_rbutton = False
224        self.struct_rbutton = False
225        self.plugin_rbutton = False
226        ## the indice of the current selection
227        self.disp_box = 0
228        ## Qrange
229        ## Q range
230        self.qmin = 0.001
231        self.qmax = 0.1
232        #reset data range
233        self.qmax_x = None
234        self.qmin_x = None
235       
236        self.npts = None
237        self.name = ""
238        self.multi_factor = None
239        ## enable smearering state
240        self.enable_smearer = False
241        self.disable_smearer = True
242        self.pinhole_smearer = False
243        self.slit_smearer   = False
244        ## disperity selection
245        self.enable_disp = False
246        self.disable_disp = True
247       
248        ## state of selected all check button
249        self.cb1 = False
250        ## store value of chisqr
251        self.tcChi = None
252   
253    def clone(self):
254        """
255        Create a new copy of the current object
256        """
257        model = None
258        if self.model is not None:
259            model = self.model.clone()
260            model.name = self.model.name
261        obj = PageState(self.parent, model=model)
262        obj.file = copy.deepcopy(self.file)
263        obj.data = copy.deepcopy(self.data)
264        if self.data is not None:
265            self.data_name = self.data.name
266        obj.data_name = self.data_name
267        obj.is_data = self.is_data
268        obj.model_list_box = copy.deepcopy(self.model_list_box)
269        obj.engine_type = copy.deepcopy(self.engine_type)
270       
271        obj.formfactorcombobox = self.formfactorcombobox
272        obj.structurecombobox  = self.structurecombobox 
273       
274        obj.shape_rbutton = self.shape_rbutton
275        obj.shape_indep_rbutton = self.shape_indep_rbutton
276        obj.struct_rbutton = self.struct_rbutton
277        obj.plugin_rbutton = self.plugin_rbutton
278       
279        obj.manager = self.manager
280        obj.event_owner = self.event_owner
281        obj.disp_list = copy.deepcopy(self.disp_list)
282       
283        obj.enable2D = copy.deepcopy(self.enable2D)
284        obj.parameters = copy.deepcopy(self.parameters)
285        obj.str_parameters = copy.deepcopy(self.str_parameters)
286        obj.fixed_param = copy.deepcopy(self.fixed_param)
287        obj.fittable_param = copy.deepcopy(self.fittable_param)
288        obj.orientation_params =  copy.deepcopy(self.orientation_params)
289        obj.orientation_params_disp =  copy.deepcopy(self.orientation_params_disp)
290        obj.enable_disp = copy.deepcopy(self.enable_disp)
291        obj.disable_disp = copy.deepcopy(self.disable_disp)
292        obj.tcChi = self.tcChi
293 
294        if len(self._disp_obj_dict)>0:
295            for k , v in self._disp_obj_dict.iteritems():
296                obj._disp_obj_dict[k]= v
297        if len(self.disp_cb_dict)>0:
298            for k , v in self.disp_cb_dict.iteritems():
299                obj.disp_cb_dict[k]= v
300        if len(self.values)>0: 
301            for k , v in self.values.iteritems():       
302                obj.values[k] = v
303        if len(self.weights)>0: 
304            for k , v in self.weights.iteritems():       
305                obj.weights[k] = v
306        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
307        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
308        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
309        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
310        obj.smear_type = copy.deepcopy(self.smear_type)
311        obj.dq_l = copy.deepcopy(self.dq_l)
312        obj.dq_r = copy.deepcopy(self.dq_r)
313
314        obj.disp_box = copy.deepcopy(self.disp_box)
315        obj.qmin = copy.deepcopy(self.qmin)
316        obj.qmax = copy.deepcopy(self.qmax)
317        obj.multi_factor = self.multi_factor
318        obj.npts = copy.deepcopy(self.npts )
319        obj.cb1 = copy.deepcopy(self.cb1)
320        obj.smearer = copy.deepcopy(self.smearer)
321       
322        for name, state in self.saved_states.iteritems():
323            copy_name = copy.deepcopy(name)
324            copy_state = state.clone()
325            obj.saved_states[copy_name]= copy_state
326        return obj
327   
328    def _repr_helper(self, list, rep):
329        """
330        Helper method to print a state
331        """
332        for item in list:
333            rep += "parameter name: %s \n"%str(item[1])
334            rep += "value: %s\n"%str(item[2])
335            rep += "selected: %s\n"%str(item[0])
336            rep += "error displayed : %s \n"%str(item[4][0])
337            rep += "error value:%s \n"%str(item[4][1])
338            rep += "minimum displayed : %s \n"%str(item[5][0])
339            rep += "minimum value : %s \n"%str(item[5][1])
340            rep += "maximum displayed : %s \n"%str(item[6][0])
341            rep += "maximum value : %s \n"%str(item[6][1])
342            rep += "parameter unit: %s\n\n"%str(item[7])
343        return rep
344   
345    def __repr__(self):
346        """
347        output string for printing
348        """
349        rep = "\nState name: %s\n"%self.file
350        t = time.localtime(self.timestamp)
351        time_str = time.strftime("%b %d %H;%M of %Y", t)
352
353        rep += "State created on : %s\n"%time_str
354        rep += "State form factor combobox selection: %s\n"%self.formfactorcombobox
355        rep += "State structure factor combobox selection: %s\n"%self.structurecombobox
356        rep += "is data : %s\n"%self.is_data
357        rep += "data's name : %s\n"%self.data_name
358        rep += "data's id : %s\n"%self.data_id
359        rep += "model type (form factor) selected: %s\n"%self.shape_rbutton
360        rep += "multi_factor : %s\n"% str(self.multi_factor)
361        rep += "model type (shape independent) selected: %s\n"%self.shape_indep_rbutton
362        rep += "model type (structure factor) selected: %s\n"%self.struct_rbutton
363        rep += "model type (plug-in ) selected: %s\n"%self.plugin_rbutton
364        rep += "data : %s\n"% str(self.data)
365        rep += "Plotting Range: min: %s, max: %s, steps: %s\n"%(str(self.qmin),
366                                                str(self.qmax),str(self.npts))
367        rep += "Dispersion selection : %s\n"%str(self.disp_box)
368        rep += "Smearing enable : %s\n"%str(self.enable_smearer)
369        rep += "Smearing disable : %s\n"%str(self.disable_smearer)
370        rep += "Pinhole smearer enable : %s\n"%str(self.pinhole_smearer)
371        rep += "Slit smearer enable : %s\n"%str(self.slit_smearer)
372        rep += "Dispersity enable : %s\n"%str(self.enable_disp)
373        rep += "Dispersity disable : %s\n"%str(self.disable_disp)
374        rep += "Slit smearer enable: %s\n"%str(self.slit_smearer)
375        rep += "2D enable : %s\n"%str(self.enable2D)
376        rep += "All parameters checkbox selected: %s\n"%(self.cb1)
377        rep += "Value of Chisqr : %s\n"%str(self.tcChi)
378        rep += "Smear object : %s\n"%str(self.smearer)
379        rep += "Smear type : %s\n"%(self.smear_type)
380        rep += "dq_l  : %s\n"%self.dq_l
381        rep += "dq_r  : %s\n"%self.dq_r
382       
383        rep += "model  : %s\n\n"% str(self.model)
384        temp_parameters = []
385        temp_fittable_param = []
386        if self.data.__class__.__name__ == "Data2D":
387            self.is_2D = True
388        else:
389            self.is_2D = False
390        if self.data is not None:
391            if not self.is_2D:
392                for item in self.parameters:
393                    if not item in self.orientation_params:
394                        temp_parameters.append(item)
395                for item in self.fittable_param:
396                    if not item in self.orientation_params_disp:
397                        temp_fittable_param.append(item)
398            else:
399                temp_parameters = self.parameters
400                temp_fittable_param = self.fittable_param
401               
402            rep += "number parameters(self.parameters): %s\n"%len(temp_parameters)
403            rep = self._repr_helper( list=temp_parameters, rep=rep)
404            rep += "number str_parameters(self.str_parameters): %s\n"%len(self.str_parameters)
405            rep = self._repr_helper( list=self.str_parameters, rep=rep) 
406            rep += "number fittable_param(self.fittable_param): %s\n"%len(temp_fittable_param)
407            rep = self._repr_helper( list=temp_fittable_param, rep=rep) 
408            """
409            if is_2D:
410                rep += "number orientation parameters"
411                rep += "(self.orientation_params): %s\n"%len(self.orientation_params)
412                rep = self._repr_helper( list=self.orientation_params, rep=rep)
413                rep += "number dispersity parameters"
414                rep += "(self.orientation_params_disp): %s\n"%len(self.orientation_params_disp)
415                rep = self._repr_helper( list=self.orientation_params_disp, rep=rep)
416            """
417        return rep
418
419    def set_report_string(self):
420        """
421        Get the values (strings) from __str__ for report
422        """
423        # Dictionary of teh report strings
424        repo_time = ""
425        model_name = ""
426        title = ""
427        title_name = ""
428        file_name = ""
429        param_string = ""
430        paramval_string = ""
431        chi2_string = ""
432        multi_factor_string = ""
433        q_range = ""
434        strings = self.__repr__()
435        lines = strings.split('\n')
436
437        # get all string values from __str__()
438        for line in lines:
439            value = ""
440            content = line.split(":")
441            name = content[0]
442            try:
443                value = content[1]
444            except:
445                pass
446            if name.count("State created on"):
447                repo_time = "Created on " + value
448            if name.count("parameter name"):
449                val_name = value.split(".")
450                if len(val_name) > 1:
451                    if val_name[1].count("width"):
452                        param_string += value + ','
453                    else:
454                        continue
455                else:
456                    param_string += value + ','
457            if name == "value":
458                param_string += value + ','
459            if name == "error value":
460                param_string += value + ','
461            if name == "parameter unit":
462                param_string += value + ':' 
463            if name == "Value of Chisqr ":
464                chi2 = ("Chi2/Npts = " + value)
465                chi2_string = CENTRE % chi2
466            if name == "multi_factor ":
467                muti_factor = ("muti_factor = " + value)
468                muti_factor_string = CENTRE % muti_factor
469            if name == "Title":
470                if len(value.strip()) == 0:
471                    continue
472                title = value + " [" + repo_time + "]"
473                title_name = HEADER % title
474            if name == "data ":
475                try:
476                    file = ("File name:" + content[2])
477                    file_name = CENTRE % file
478                    if len(title) == 0:
479                        title = content[2] + " [" + repo_time + "]"
480                        title_name = HEADER % title
481                except:
482                    pass
483            if name == "Plotting Range":
484                try:
485                    q_range = content[1] + " = " + content[2] \
486                            + " = " + content[3].split(",")[0]
487                    q_name = ("Q Range:    " + q_range)
488                    q_range = CENTRE % q_name
489                except:
490                    pass
491        paramval = ""
492        for lines in param_string.split(":"): 
493            line = lines.split(",")
494            if len(lines) > 0: 
495                param = line[0] 
496                param += " = " + line[1]
497                if len(line[2].split()) > 0 and not line[2].count("None"):
498                    param += " +- " + line[2]
499                if len(line[3].split()) > 0 and not line[3].count("None"):
500                    param += " " + line[3]
501                if not paramval.count(param):
502                    paramval +=  param + "\n"
503                    paramval_string += CENTRE % param + "\n"
504       
505        text_string = "\n\n\n" + title + "\n\n" + file + \
506                              "\n" + q_name + \
507                              "\n" + chi2 + \
508                              "\n\n" + paramval
509       
510        title_name = self._check_html_format(title_name)
511        file_name = self._check_html_format(file_name)
512        title = self._check_html_format(title)
513                                 
514        html_string = title_name + "\n" + file_name + \
515                                   "\n" + q_range + \
516                                   "\n" + chi2_string + \
517                                   "\n" + ELINE + \
518                                   "\n" + paramval_string + \
519                                   "\n" + ELINE + \
520                                   "\n" + FEET_1 % title + \
521                                   "\n" + FEET_2
522                                                                     
523        return html_string, text_string, title
524   
525    def _check_html_format(self, name):
526        """
527        Check string '%' for html format
528        """
529        if name.count('%'):
530            name = name.replace('%', '&#37')
531       
532        return name
533   
534   
535    def report(self, figs=None, canvases=None):
536        """
537        Invoke report dialog panel
538       
539        : param figs: list of pylab figures [list]
540        """
541        from report_dialog import ReportDialog
542        # get the strings for report
543        html_str, text_str, title = self.set_report_string()
544        # Allow 2 figures to append
545        if len(figs) == 1:
546            add_str = FEET_3
547        elif len(figs) == 2:
548            add_str = ELINE
549            add_str += FEET_2 % ("%s") 
550            add_str += ELINE
551            add_str += FEET_3
552        elif len(figs) > 2:
553            add_str = ELINE
554            add_str += FEET_2 % ("%s") 
555            add_str += ELINE
556            add_str += FEET_2 % ("%s") 
557            add_str += ELINE
558            add_str += FEET_3
559        else:
560            add_str = ""
561
562        # final report html strings
563        report_str = html_str % ("%s") + add_str
564
565        # make plot image
566        images = self.set_plot_state(figs, canvases)
567        report_list = [report_str, text_str, images ]
568        dialog = ReportDialog(report_list, None, -1, "")
569        dialog.ShowModal()
570       
571   
572    def _toXML_helper(self, list, element, newdoc):
573        """
574        Helper method to create xml file for saving state
575        """
576        for item in list:
577            sub_element = newdoc.createElement('parameter')
578            sub_element.setAttribute('name', str(item[1]))
579            sub_element.setAttribute('value', str(item[2]))
580            sub_element.setAttribute('selected_to_fit', str(item[0]))
581            sub_element.setAttribute('error_displayed', str(item[4][0]))
582            sub_element.setAttribute('error_value', str(item[4][1]))
583            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
584            sub_element.setAttribute('minimum_value', str(item[5][1]))
585            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
586            sub_element.setAttribute('maximum_value', str(item[6][1]))
587            sub_element.setAttribute('unit', str(item[7]))
588            element.appendChild(sub_element)
589       
590    def toXML(self, file="fitting_state.fitv", doc=None, entry_node=None):
591        """
592        Writes the state of the InversionControl panel to file, as XML.
593       
594        Compatible with standalone writing, or appending to an
595        already existing XML document. In that case, the XML document
596        is required. An optional entry node in the XML document may also be given.
597       
598        :param file: file to write to
599        :param doc: XML document object [optional]
600        :param entry_node: XML node within the XML document at which we will append the data [optional]
601       
602        """
603        from xml.dom.minidom import getDOMImplementation
604
605        # Check whether we have to write a standalone XML file
606        if doc is None:
607            impl = getDOMImplementation()
608            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")     
609            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
610            top_element = newdoc.documentElement
611        else:
612            # We are appending to an existing document
613            newdoc = doc
614            top_element = newdoc.createElement(FITTING_NODE_NAME)
615            if entry_node is None:
616                newdoc.documentElement.appendChild(top_element)
617            else:
618                entry_node.appendChild(top_element)
619           
620        attr = newdoc.createAttribute("version")
621        attr.nodeValue = '1.0'
622        top_element.setAttributeNode(attr)
623       
624        # File name
625        element = newdoc.createElement("filename")
626        if self.file is not None:
627            element.appendChild(newdoc.createTextNode(str(self.file)))
628        else:
629            element.appendChild(newdoc.createTextNode(str(file)))
630        top_element.appendChild(element)
631       
632        element = newdoc.createElement("timestamp")
633        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
634        attr = newdoc.createAttribute("epoch")
635        attr.nodeValue = str(self.timestamp)
636        element.setAttributeNode(attr)
637        top_element.appendChild(element)
638        # Inputs
639        inputs = newdoc.createElement("Attributes")
640        top_element.appendChild(inputs)
641       
642
643        if self.data is not None and hasattr(self.data, "group_id"):
644            self.data_group_id = self.data.group_id
645        if self.data is not None and hasattr(self.data, "is_data"):
646            self.is_data = self.data.is_data
647        if self.data is not None:
648            self.data_name = self.data.name
649        if self.data is not None and hasattr(self.data, "id"):
650            self.data_id = self.data.id
651       
652        for item in list_of_data_attributes:
653            element = newdoc.createElement(item[0])
654            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
655            inputs.appendChild(element)   
656       
657        for item in list_of_state_attributes:
658            element = newdoc.createElement(item[0])
659            exec "element.setAttribute(item[0], str(self.%s))" % (item[1])
660            inputs.appendChild(element)
661           
662        # For self.values ={ disp_param_name: [vals,...],...}   
663        # and for self.weights ={ disp_param_name: [weights,...],...} 
664        for item in list_of_model_attributes:
665            element = newdoc.createElement(item[0])
666            exec "list = self.%s" % item[1]
667            for key, value in list.iteritems():
668                sub_element = newdoc.createElement(key)
669                sub_element.setAttribute('name', str(key))
670                for val in value:
671                    com = "sub_element.appendChild"
672                    com += "(newdoc.createTextNode(str(%s)))"
673                    exec com % val
674                   
675                element.appendChild(sub_element) 
676            inputs.appendChild(element)
677       
678        # Create doc for the dictionary of self._disp_obj_dic
679        for item in list_of_obj_dic:
680             element = newdoc.createElement(item[0])
681             exec "list = self.%s" % item[1]
682             for key, val in list.iteritems():
683                 value = repr(val)
684                 sub_element = newdoc.createElement(key)
685                 sub_element.setAttribute('name', str(key))
686                 sub_element.setAttribute('value', str(value))
687                 element.appendChild(sub_element) 
688             inputs.appendChild(element)   
689                 
690        for item in list_of_state_parameters:
691            element = newdoc.createElement(item[0])
692            com = "self._toXML_helper(list=self.%s,"
693            com += " element=element, newdoc=newdoc)"
694            exec com % item[1]                       
695            inputs.appendChild(element)
696       
697        # Save the file
698        if doc is None:
699            fd = open(file, 'w')
700            fd.write(newdoc.toprettyxml())
701            fd.close()
702            return None
703        else:
704            return newdoc.toprettyxml()
705       
706    def _fromXML_helper(self, node, list):
707        """
708        Helper function to write state to xml
709        """
710        for item in node:
711            try:
712                name = item.get('name')
713            except:
714                name = None
715            try:
716                value = item.get('value')
717            except:
718                value = None
719            try:
720                selected_to_fit = (item.get('selected_to_fit') == "True")
721            except:
722                selected_to_fit = None
723            try:
724                error_displayed = (item.get('error_displayed') == "True")
725            except:
726                error_displayed = None
727            try: 
728                error_value = item.get('error_value')
729            except:
730                error_value = None
731            try:
732                minimum_displayed = (item.get('minimum_displayed')== "True")
733            except:
734                minimum_displayed = None
735            try:
736                minimum_value = item.get('minimum_value')
737            except:
738                minimum_value = None
739            try:
740                maximum_displayed = (item.get('maximum_displayed') == "True")
741            except:
742                maximum_displayed = None
743            try:
744                maximum_value = item.get('maximum_value')
745            except:
746                maximum_value = None
747            try:
748                unit = item.get('unit')
749            except:
750                unit = None
751            list.append([selected_to_fit, name, value, "+/-",
752                         [error_displayed, error_value],
753                         [minimum_displayed,minimum_value],
754                         [maximum_displayed,maximum_value], unit])
755       
756    def fromXML(self, file=None, node=None):
757        """
758        Load fitting state from a file
759       
760        :param file: .fitv file
761        :param node: node of a XML document to read from
762       
763        """
764        if file is not None:
765            msg = "PageState no longer supports non-CanSAS"
766            msg += " format for fitting files"
767            raise RuntimeError, msg
768           
769        if node.get('version')and node.get('version') == '1.0':
770           
771            # Get file name
772            entry = get_content('ns:filename', node)
773            if entry is not None:
774                self.file = entry.text.strip()
775               
776            # Get time stamp
777            entry = get_content('ns:timestamp', node)
778            if entry is not None and entry.get('epoch'):
779                try:
780                    self.timestamp = float(entry.get('epoch'))
781                except:
782                    msg = "PageState.fromXML: Could not"
783                    msg += " read timestamp\n %s" % sys.exc_value
784                    logging.error(msg)
785           
786            # Parse fitting attributes
787            entry = get_content('ns:Attributes', node)
788            for item in list_of_data_attributes:
789                node = get_content('ns:%s'%item[0], entry)
790                try:
791                    exec "self.%s = parse_entry_helper(node, item)" % item[0]
792                   
793                except:
794                    raise
795
796            if entry is not None:
797               
798                for item in list_of_state_attributes:
799                    node = get_content('ns:%s' % item[0], entry)
800                    try:
801                        exec "self.%s = parse_entry_helper(node, item)" % \
802                                                                str(item[0])
803                    except:
804                        raise
805                   
806                for item in list_of_state_parameters:
807                    node = get_content("ns:%s" % item[0], entry)
808                    exec "self._fromXML_helper(node=node, list=self.%s)" % \
809                                                                    item[1]
810               
811                # Recover _disp_obj_dict from xml file   
812                self._disp_obj_dict = {}   
813                for item in list_of_obj_dic:
814                    # Get node
815                    node = get_content("ns:%s" % item[0], entry)
816                    for attr in node:
817                        name = attr.get('name')
818                        val  = attr.get('value')
819                        value = val.split(" instance")[0]
820                        disp_name = value.split("<")[1]
821                        try:
822                            # Try to recover disp_model object from strings
823                            com  = "from sans.models.dispersion_models "
824                            com += "import %s as disp"
825                            com_name = disp_name.split(".")[3]
826                            exec com % com_name
827                            disp_model = disp()
828                            exec "self.%s['%s'] = com_name" % (item[1], name)
829                        except:
830                            pass
831                       
832                # get self.values and self.weights dic. if exists   
833                for item in list_of_model_attributes:
834                    node = get_content("ns:%s" % item[0], entry)
835                    dic = {}
836                    list = []
837                    for par in node:
838                        name = par.get('name')
839                        values = par.text.split('\n')
840                        # Get lines only with numbers
841                        for line in values:
842                            try:
843                                val= float(line)
844                                list.append(val) 
845                            except:
846                                # pass if line is empty (it happens)
847                                pass
848                    dic[name] = numpy.array(list)
849                    exec "self.%s = dic" % item[1]
850                   
851    def set_plot_state(self, figs, canvases):
852        """
853        Build image state that wx.html understand
854        by plotting, putting it into wx.FileSystem image object
855
856        """
857        images = []
858        # some imports
859        import wx
860
861        # Reset memory
862        self.imgRAM = None
863        wx.MemoryFSHandler()
864       
865        # For no figures in the list, prepare empty plot
866        if figs == None or len(figs) == 0:
867            figs = [None]
868           
869        # Loop over the list of figures   
870        # use wx.MemoryFSHandler
871        self.imgRAM = wx.MemoryFSHandler() 
872        for fig in figs:
873            if figs != None:
874                #fig.set_facecolor('w')
875                ind = figs.index(fig)
876                canvas = canvases[ind]
877               
878            #bmp = wx.BitmapDataObject()
879            #bmp.SetBitmap(canvas.bitmap)
880            #store the image in wx.FileSystem Object
881            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
882           
883            # index of the fig
884            ind = figs.index(fig)
885           
886            #AddFile, image can be retrieved with 'memory:filename'
887            self.imgRAM.AddFile('img_fit%s.png' % ind , 
888                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
889           
890            #append figs
891            images.append(fig)
892           
893        return images
894
895class Reader(CansasReader):
896    """
897    Class to load a .fitv fitting file
898    """
899    ## File type
900    type_name = "Fitting"
901   
902    ## Wildcards
903    type = ["Fitting files (*.fitv)|*.fitv"
904            "SANSView file (*.svs)|*.svs"]
905    ## List of allowed extensions
906    ext=['.fitv', '.FITV', '.svs', 'SVS']   
907   
908    def __init__(self, call_back=None, cansas=True):
909        CansasReader.__init__(self)
910        """
911        Initialize the call-back method to be called
912        after we load a file
913       
914        :param call_back: call-back method
915        :param cansas:  True = files will be written/read in CanSAS format
916                        False = write CanSAS format
917           
918        """
919        ## Call back method to be executed after a file is read
920        self.call_back = call_back
921        ## CanSAS format flag
922        self.cansas = cansas
923        self.state = None
924    def get_state(self):
925        return self.state
926       
927    def read(self, path):
928        """
929        Load a new P(r) inversion state from file
930       
931        :param path: file path
932       
933        """
934        if self.cansas == True:
935            return self._read_cansas(path)
936     
937    def _data2d_to_xml_doc(self, datainfo):
938        """
939        Create an XML document to contain the content of a Data2D
940       
941        :param datainfo: Data2D object
942       
943        """
944        if not issubclass(datainfo.__class__, Data2D):
945            raise RuntimeError, "The cansas writer expects a Data2D instance"
946       
947        doc = xml.dom.minidom.Document()
948        main_node = doc.createElement("SASroot")
949        main_node.setAttribute("version", self.version)
950        main_node.setAttribute("xmlns", "cansas1d/%s" % self.version)
951        main_node.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
952        main_node.setAttribute("xsi:schemaLocation", "cansas1d/%s http://svn.smallangles.net/svn/canSAS/1dwg/trunk/cansas1d.xsd" % self.version)
953       
954        doc.appendChild(main_node)
955       
956        entry_node = doc.createElement("SASentry")
957        main_node.appendChild(entry_node)
958       
959        write_node(doc, entry_node, "Title", datainfo.title)
960        if datainfo is not None:
961            write_node(doc, entry_node, "data_class", datainfo.__class__.__name__)
962        for item in datainfo.run:
963            runname = {}
964            if datainfo.run_name.has_key(item) and len(str(datainfo.run_name[item]))>1:
965                runname = {'name': datainfo.run_name[item] }
966            write_node(doc, entry_node, "Run", item, runname)
967        # Data info
968        new_node = doc.createElement("SASdata")
969        entry_node.appendChild(new_node)
970        for item in list_of_data_2d_attr:
971            element = doc.createElement(item[0])
972            exec "element.setAttribute(item[0], str(datainfo.%s))"%(item[1])
973            new_node.appendChild(element)
974           
975        for item in list_of_data2d_values:
976            root_node = doc.createElement(item[0])
977            new_node.appendChild(root_node)
978           
979            exec "temp_list = datainfo.%s"%item[1]
980
981            if temp_list is None or len(temp_list)== 0:
982                element = doc.createElement(item[0])
983                exec "element.appendChild(doc.createTextNode(str(%s)))"%temp_list
984                root_node.appendChild(element)
985            else:
986                for value in temp_list:
987                    element = doc.createElement(item[0])
988                    exec "element.setAttribute(item[0], str(%s))"%value
989                    root_node.appendChild(element)
990       
991        # Sample info
992        sample = doc.createElement("SASsample")
993        if datainfo.sample.name is not None:
994            sample.setAttribute("name", str(datainfo.sample.name))
995        entry_node.appendChild(sample)
996        write_node(doc, sample, "ID", str(datainfo.sample.ID))
997        write_node(doc, sample, "thickness", datainfo.sample.thickness, {"unit":datainfo.sample.thickness_unit})
998        write_node(doc, sample, "transmission", datainfo.sample.transmission)
999        write_node(doc, sample, "temperature", datainfo.sample.temperature, {"unit":datainfo.sample.temperature_unit})
1000       
1001        for item in datainfo.sample.details:
1002            write_node(doc, sample, "details", item)
1003       
1004        pos = doc.createElement("position")
1005        written = write_node(doc, pos, "x", datainfo.sample.position.x, {"unit":datainfo.sample.position_unit})
1006        written = written | write_node(doc, pos, "y", datainfo.sample.position.y, {"unit":datainfo.sample.position_unit})
1007        written = written | write_node(doc, pos, "z", datainfo.sample.position.z, {"unit":datainfo.sample.position_unit})
1008        if written == True:
1009            sample.appendChild(pos)
1010       
1011        ori = doc.createElement("orientation")
1012        written = write_node(doc, ori, "roll",  datainfo.sample.orientation.x, {"unit":datainfo.sample.orientation_unit})
1013        written = written | write_node(doc, ori, "pitch", datainfo.sample.orientation.y, {"unit":datainfo.sample.orientation_unit})
1014        written = written | write_node(doc, ori, "yaw",   datainfo.sample.orientation.z, {"unit":datainfo.sample.orientation_unit})
1015        if written == True:
1016            sample.appendChild(ori)
1017       
1018        # Instrument info
1019        instr = doc.createElement("SASinstrument")
1020        entry_node.appendChild(instr)
1021       
1022        write_node(doc, instr, "name", datainfo.instrument)
1023       
1024        #   Source
1025        source = doc.createElement("SASsource")
1026        if datainfo.source.name is not None:
1027            source.setAttribute("name", str(datainfo.source.name))
1028        instr.appendChild(source)
1029       
1030        write_node(doc, source, "radiation", datainfo.source.radiation)
1031        write_node(doc, source, "beam_shape", datainfo.source.beam_shape)
1032        size = doc.createElement("beam_size")
1033        if datainfo.source.beam_size_name is not None:
1034            size.setAttribute("name", str(datainfo.source.beam_size_name))
1035        written = write_node(doc, size, "x", datainfo.source.beam_size.x, {"unit":datainfo.source.beam_size_unit})
1036        written = written | write_node(doc, size, "y", datainfo.source.beam_size.y, {"unit":datainfo.source.beam_size_unit})
1037        written = written | write_node(doc, size, "z", datainfo.source.beam_size.z, {"unit":datainfo.source.beam_size_unit})
1038        if written == True:
1039            source.appendChild(size)
1040           
1041        write_node(doc, source, "wavelength", datainfo.source.wavelength, {"unit":datainfo.source.wavelength_unit})
1042        write_node(doc, source, "wavelength_min", datainfo.source.wavelength_min, {"unit":datainfo.source.wavelength_min_unit})
1043        write_node(doc, source, "wavelength_max", datainfo.source.wavelength_max, {"unit":datainfo.source.wavelength_max_unit})
1044        write_node(doc, source, "wavelength_spread", datainfo.source.wavelength_spread, {"unit":datainfo.source.wavelength_spread_unit})
1045       
1046        #   Collimation
1047        for item in datainfo.collimation:
1048            coll = doc.createElement("SAScollimation")
1049            if item.name is not None:
1050                coll.setAttribute("name", str(item.name))
1051            instr.appendChild(coll)
1052           
1053            write_node(doc, coll, "length", item.length, {"unit":item.length_unit})
1054           
1055            for apert in item.aperture:
1056                ap = doc.createElement("aperture")
1057                if apert.name is not None:
1058                    ap.setAttribute("name", str(apert.name))
1059                if apert.type is not None:
1060                    ap.setAttribute("type", str(apert.type))
1061                coll.appendChild(ap)
1062               
1063                write_node(doc, ap, "distance", apert.distance, {"unit":apert.distance_unit})
1064               
1065                size = doc.createElement("size")
1066                if apert.size_name is not None:
1067                    size.setAttribute("name", str(apert.size_name))
1068                written = write_node(doc, size, "x", apert.size.x, {"unit":apert.size_unit})
1069                written = written | write_node(doc, size, "y", apert.size.y, {"unit":apert.size_unit})
1070                written = written | write_node(doc, size, "z", apert.size.z, {"unit":apert.size_unit})
1071                if written == True:
1072                    ap.appendChild(size)
1073
1074        #   Detectors
1075        for item in datainfo.detector:
1076            det = doc.createElement("SASdetector")
1077            written = write_node(doc, det, "name", item.name)
1078            written = written | write_node(doc, det, "SDD", item.distance, {"unit":item.distance_unit})
1079            written = written | write_node(doc, det, "slit_length", item.slit_length, {"unit":item.slit_length_unit})
1080            if written == True:
1081                instr.appendChild(det)
1082           
1083            off = doc.createElement("offset")
1084            written = write_node(doc, off, "x", item.offset.x, {"unit":item.offset_unit})
1085            written = written | write_node(doc, off, "y", item.offset.y, {"unit":item.offset_unit})
1086            written = written | write_node(doc, off, "z", item.offset.z, {"unit":item.offset_unit})
1087            if written == True:
1088                det.appendChild(off)
1089           
1090            center = doc.createElement("beam_center")
1091            written = write_node(doc, center, "x", item.beam_center.x, {"unit":item.beam_center_unit})
1092            written = written | write_node(doc, center, "y", item.beam_center.y, {"unit":item.beam_center_unit})
1093            written = written | write_node(doc, center, "z", item.beam_center.z, {"unit":item.beam_center_unit})
1094            if written == True:
1095                det.appendChild(center)
1096               
1097            pix = doc.createElement("pixel_size")
1098            written = write_node(doc, pix, "x", item.pixel_size.x, {"unit":item.pixel_size_unit})
1099            written = written | write_node(doc, pix, "y", item.pixel_size.y, {"unit":item.pixel_size_unit})
1100            written = written | write_node(doc, pix, "z", item.pixel_size.z, {"unit":item.pixel_size_unit})
1101            if written == True:
1102                det.appendChild(pix)
1103               
1104            ori = doc.createElement("orientation")
1105            written = write_node(doc, ori, "roll",  item.orientation.x, {"unit":item.orientation_unit})
1106            written = written | write_node(doc, ori, "pitch", item.orientation.y, {"unit":item.orientation_unit})
1107            written = written | write_node(doc, ori, "yaw",   item.orientation.z, {"unit":item.orientation_unit})
1108            if written == True:
1109                det.appendChild(ori)
1110               
1111        # Processes info
1112        for item in datainfo.process:
1113            node = doc.createElement("SASprocess")
1114            entry_node.appendChild(node)
1115
1116            write_node(doc, node, "name", item.name)
1117            write_node(doc, node, "date", item.date)
1118            write_node(doc, node, "description", item.description)
1119            for term in item.term:
1120                value = term['value']
1121                del term['value']
1122                write_node(doc, node, "term", value, term)
1123            for note in item.notes:
1124                write_node(doc, node, "SASprocessnote", note)
1125        # Return the document, and the SASentry node associated with
1126        # the data we just wrote
1127        return doc, entry_node
1128   
1129    def _parse_state(self, entry):
1130        """
1131        Read a fit result from an XML node
1132       
1133        :param entry: XML node to read from
1134       
1135        :return: PageState object
1136        """
1137        # Create an empty state
1138        state = None   
1139        # Locate the P(r) node
1140        try:
1141            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME, namespaces={'ns': CANSAS_NS})
1142            if nodes !=[]:
1143                # Create an empty state
1144                state =  PageState()
1145                state.fromXML(node=nodes[0])
1146        except:
1147            logging.info("XML document does not contain fitting information.\n %s" % sys.exc_value)
1148           
1149        return state
1150   
1151   
1152                   
1153    def _parse_entry(self, dom):
1154        """
1155        Parse a SASentry
1156       
1157        :param node: SASentry node
1158       
1159        :return: Data1D/Data2D object
1160       
1161        """
1162        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
1163        if not node or node[0].text.lstrip().rstrip() != "Data2D":
1164            return CansasReader._parse_entry(self, dom)
1165       
1166        #Parse 2D
1167        data_info = Data2D()
1168       
1169        # Look up title     
1170        self._store_content('ns:Title', dom, 'title', data_info)
1171       
1172        # Look up run number   
1173        nodes = dom.xpath('ns:Run', namespaces={'ns': CANSAS_NS})
1174        for item in nodes:   
1175            if item.text is not None:
1176                value = item.text.strip()
1177                if len(value) > 0:
1178                    data_info.run.append(value)
1179                    if item.get('name') is not None:
1180                        data_info.run_name[value] = item.get('name')
1181                           
1182        # Look up instrument name             
1183        self._store_content('ns:SASinstrument/ns:name', dom, 'instrument', data_info)
1184
1185        # Notes
1186        note_list = dom.xpath('ns:SASnote', namespaces={'ns': CANSAS_NS})
1187        for note in note_list:
1188            try:
1189                if note.text is not None:
1190                    note_value = note.text.strip()
1191                    if len(note_value) > 0:
1192                        data_info.notes.append(note_value)
1193            except:
1194                err_mess = "cansas_reader.read: error processing entry notes\n  %s" % sys.exc_value
1195                self.errors.append(err_mess)
1196                logging.error(err_mess)
1197       
1198        # Sample info ###################
1199        entry = get_content('ns:SASsample', dom)
1200        if entry is not None:
1201            data_info.sample.name = entry.get('name')
1202           
1203        self._store_content('ns:SASsample/ns:ID', 
1204                     dom, 'ID', data_info.sample)                   
1205        self._store_float('ns:SASsample/ns:thickness', 
1206                     dom, 'thickness', data_info.sample)
1207        self._store_float('ns:SASsample/ns:transmission', 
1208                     dom, 'transmission', data_info.sample)
1209        self._store_float('ns:SASsample/ns:temperature', 
1210                     dom, 'temperature', data_info.sample)
1211       
1212        nodes = dom.xpath('ns:SASsample/ns:details', namespaces={'ns': CANSAS_NS})
1213        for item in nodes:
1214            try:
1215                if item.text is not None:
1216                    detail_value = item.text.strip()
1217                    if len(detail_value) > 0:
1218                        data_info.sample.details.append(detail_value)
1219            except:
1220                err_mess = "cansas_reader.read: error processing sample details\n  %s" % sys.exc_value
1221                self.errors.append(err_mess)
1222                logging.error(err_mess)
1223       
1224        # Position (as a vector)
1225        self._store_float('ns:SASsample/ns:position/ns:x', 
1226                     dom, 'position.x', data_info.sample)         
1227        self._store_float('ns:SASsample/ns:position/ns:y', 
1228                     dom, 'position.y', data_info.sample)         
1229        self._store_float('ns:SASsample/ns:position/ns:z', 
1230                     dom, 'position.z', data_info.sample)         
1231       
1232        # Orientation (as a vector)
1233        self._store_float('ns:SASsample/ns:orientation/ns:roll', 
1234                     dom, 'orientation.x', data_info.sample)         
1235        self._store_float('ns:SASsample/ns:orientation/ns:pitch', 
1236                     dom, 'orientation.y', data_info.sample)         
1237        self._store_float('ns:SASsample/ns:orientation/ns:yaw', 
1238                     dom, 'orientation.z', data_info.sample)         
1239       
1240        # Source info ###################
1241        entry = get_content('ns:SASinstrument/ns:SASsource', dom)
1242        if entry is not None:
1243            data_info.source.name = entry.get('name')
1244       
1245        self._store_content('ns:SASinstrument/ns:SASsource/ns:radiation', 
1246                     dom, 'radiation', data_info.source)                   
1247        self._store_content('ns:SASinstrument/ns:SASsource/ns:beam_shape', 
1248                     dom, 'beam_shape', data_info.source)                   
1249        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength', 
1250                     dom, 'wavelength', data_info.source)         
1251        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_min', 
1252                     dom, 'wavelength_min', data_info.source)         
1253        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_max', 
1254                     dom, 'wavelength_max', data_info.source)         
1255        self._store_float('ns:SASinstrument/ns:SASsource/ns:wavelength_spread', 
1256                     dom, 'wavelength_spread', data_info.source)   
1257       
1258        # Beam size (as a vector)   
1259        entry = get_content('ns:SASinstrument/ns:SASsource/ns:beam_size', dom)
1260        if entry is not None:
1261            data_info.source.beam_size_name = entry.get('name')
1262           
1263        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:x', 
1264                     dom, 'beam_size.x', data_info.source)   
1265        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:y', 
1266                     dom, 'beam_size.y', data_info.source)   
1267        self._store_float('ns:SASinstrument/ns:SASsource/ns:beam_size/ns:z', 
1268                     dom, 'beam_size.z', data_info.source)   
1269       
1270        # Collimation info ###################
1271        nodes = dom.xpath('ns:SASinstrument/ns:SAScollimation', namespaces={'ns': CANSAS_NS})
1272        for item in nodes:
1273            collim = Collimation()
1274            if item.get('name') is not None:
1275                collim.name = item.get('name')
1276            self._store_float('ns:length', item, 'length', collim) 
1277           
1278            # Look for apertures
1279            apert_list = item.xpath('ns:aperture', namespaces={'ns': CANSAS_NS})
1280            for apert in apert_list:
1281                aperture =  Aperture()
1282               
1283                # Get the name and type of the aperture
1284                aperture.name = apert.get('name')
1285                aperture.type = apert.get('type')
1286                   
1287                self._store_float('ns:distance', apert, 'distance', aperture)   
1288               
1289                entry = get_content('ns:size', apert)
1290                if entry is not None:
1291                    aperture.size_name = entry.get('name')
1292               
1293                self._store_float('ns:size/ns:x', apert, 'size.x', aperture)   
1294                self._store_float('ns:size/ns:y', apert, 'size.y', aperture)   
1295                self._store_float('ns:size/ns:z', apert, 'size.z', aperture)
1296               
1297                collim.aperture.append(aperture)
1298               
1299            data_info.collimation.append(collim)
1300       
1301        # Detector info ######################
1302        nodes = dom.xpath('ns:SASinstrument/ns:SASdetector', namespaces={'ns': CANSAS_NS})
1303        for item in nodes:
1304           
1305            detector = Detector()
1306           
1307            self._store_content('ns:name', item, 'name', detector)
1308            self._store_float('ns:SDD', item, 'distance', detector)   
1309           
1310            # Detector offset (as a vector)
1311            self._store_float('ns:offset/ns:x', item, 'offset.x', detector)   
1312            self._store_float('ns:offset/ns:y', item, 'offset.y', detector)   
1313            self._store_float('ns:offset/ns:z', item, 'offset.z', detector)   
1314           
1315            # Detector orientation (as a vector)
1316            self._store_float('ns:orientation/ns:roll',  item, 'orientation.x', detector)   
1317            self._store_float('ns:orientation/ns:pitch', item, 'orientation.y', detector)   
1318            self._store_float('ns:orientation/ns:yaw',   item, 'orientation.z', detector)   
1319           
1320            # Beam center (as a vector)
1321            self._store_float('ns:beam_center/ns:x', item, 'beam_center.x', detector)   
1322            self._store_float('ns:beam_center/ns:y', item, 'beam_center.y', detector)   
1323            self._store_float('ns:beam_center/ns:z', item, 'beam_center.z', detector)   
1324           
1325            # Pixel size (as a vector)
1326            self._store_float('ns:pixel_size/ns:x', item, 'pixel_size.x', detector)   
1327            self._store_float('ns:pixel_size/ns:y', item, 'pixel_size.y', detector)   
1328            self._store_float('ns:pixel_size/ns:z', item, 'pixel_size.z', detector)   
1329           
1330            self._store_float('ns:slit_length', item, 'slit_length', detector)
1331           
1332            data_info.detector.append(detector)   
1333
1334        # Processes info ######################
1335        nodes = dom.xpath('ns:SASprocess', namespaces={'ns': CANSAS_NS})
1336        for item in nodes:
1337            process = Process()
1338            self._store_content('ns:name', item, 'name', process)
1339            self._store_content('ns:date', item, 'date', process)
1340            self._store_content('ns:description', item, 'description', process)
1341           
1342            term_list = item.xpath('ns:term', namespaces={'ns': CANSAS_NS})
1343            for term in term_list:
1344                try:
1345                    term_attr = {}
1346                    for attr in term.keys():
1347                        term_attr[attr] = term.get(attr).strip()
1348                    if term.text is not None:
1349                        term_attr['value'] = term.text.strip()
1350                        process.term.append(term_attr)
1351                except:
1352                    err_mess = "cansas_reader.read: error processing process term\n  %s" % sys.exc_value
1353                    self.errors.append(err_mess)
1354                    logging.error(err_mess)
1355           
1356            note_list = item.xpath('ns:SASprocessnote', namespaces={'ns': CANSAS_NS})
1357            for note in note_list:
1358                if note.text is not None:
1359                    process.notes.append(note.text.strip())
1360           
1361            data_info.process.append(process)
1362           
1363           
1364        # Data info ######################
1365        nodes = dom.xpath('ns:SASdata', namespaces={'ns': CANSAS_NS})
1366        if len(nodes)>1:
1367            raise RuntimeError, "CanSAS reader is not compatible with multiple SASdata entries"
1368       
1369        for entry in nodes:
1370            for item in list_of_data_2d_attr:
1371                #get node
1372                node = get_content('ns:%s'%item[0], entry)
1373                exec "data_info.%s = parse_entry_helper(node, item)"%(item[1])
1374                   
1375            for item in list_of_data2d_values:
1376                field = get_content('ns:%s'%item[0], entry)
1377                list = []
1378                if field is not None:
1379                    list = [parse_entry_helper(node, item) for node in field]
1380                exec "data_info.%s = numpy.array(list)"%item[0]
1381       
1382        return data_info
1383
1384    def _read_cansas(self, path):
1385        """
1386        Load data and P(r) information from a CanSAS XML file.
1387       
1388        :param path: file path
1389       
1390        :return: Data1D object if a single SASentry was found,
1391                    or a list of Data1D objects if multiple entries were found,
1392                    or None of nothing was found
1393                   
1394        :raise RuntimeError: when the file can't be opened
1395        :raise ValueError: when the length of the data vectors are inconsistent
1396       
1397        """
1398        output = []
1399        basename  = os.path.basename(path)
1400        root, extension = os.path.splitext(basename)
1401        ext = extension.lower()
1402        try:
1403            if os.path.isfile(path):
1404               
1405                #TODO: eventually remove the check for .xml once
1406                # the P(r) writer/reader is truly complete.
1407                if  ext in self.ext or \
1408                    ext == '.xml':
1409                   
1410                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1411                    # Check the format version number
1412                    # Specifying the namespace will take care of the file format version
1413                    root = tree.getroot()
1414                    entry_list = root.xpath('ns:SASentry', namespaces={'ns': CANSAS_NS})
1415                    for entry in entry_list:   
1416                        try:
1417                            sas_entry = self._parse_entry(entry)
1418                        except:
1419                            raise
1420                        fitstate = self._parse_state(entry)
1421                       
1422                        #state could be None when .svs file is loaded
1423                        #in this case, skip appending to output
1424                        if fitstate != None:
1425                            sas_entry.meta_data['fitstate'] = fitstate
1426                            sas_entry.filename = fitstate.file
1427                            output.append(sas_entry)
1428            else:
1429                self.call_back(format=ext)
1430                raise RuntimeError, "%s is not a file" % path
1431
1432            # Return output consistent with the loader's api
1433            if len(output)==0:
1434                self.call_back(state=None, datainfo=None,format=ext)
1435                return None
1436            else:
1437                for ind in range(len(output)):
1438                    # Call back to post the new state
1439                    state = output[ind].meta_data['fitstate']
1440                    t = time.localtime(state.timestamp)
1441                    time_str = time.strftime("%b %d %H:%M", t)
1442                    # Check that no time stamp is already appended
1443                    max_char = state.file.find("[")
1444                    if max_char < 0:
1445                        max_char = len(state.file)
1446                    original_fname = state.file[0:max_char]
1447                    state.file = original_fname +' [' + time_str + ']'
1448                   
1449                       
1450                    if state is not None and state.is_data is not None:
1451                        exec 'output[%d].is_data = state.is_data'% ind
1452                     
1453                    output[ind].filename = state.file
1454                    state.data = output[ind]
1455                    state.data.name = output[ind].filename #state.data_name
1456                    state.data.id = state.data_id
1457                    if state.is_data is not None:
1458                        state.data.is_data = state.is_data
1459                    if output[ind].run_name is not None and len(output[ind].run_name) != 0 :
1460                        name = output[ind].run_name
1461                    else: 
1462                        name=original_fname
1463                    state.data.group_id = name
1464                    #store state in fitting
1465                    self.call_back(state=state, datainfo=output[ind],format=ext)
1466                    self.state= state
1467                return output
1468             
1469        except:
1470            self.call_back(format=ext)
1471            #self.state= state
1472            raise
1473           
1474    def write(self, filename, datainfo=None, fitstate=None):
1475        """
1476        Write the content of a Data1D as a CanSAS XML file only for standalone
1477       
1478        :param filename: name of the file to write
1479        :param datainfo: Data1D object
1480        :param fitstate: PageState object
1481       
1482        """
1483        # Sanity check
1484        if self.cansas == True:
1485           
1486            # Add fitting information to the XML document
1487            doc = self.write_toXML(datainfo, fitstate)
1488            # Write the XML document
1489            fd = open(filename, 'w')
1490            fd.write(doc.toprettyxml())
1491            fd.close()
1492        else:
1493            fitstate.toXML(file=filename)
1494       
1495    def write_toXML(self, datainfo=None, state=None):
1496        """
1497        Write toXML, a helper for write() , could be used by guimanager._on_save()
1498       
1499        : return: xml doc
1500        """
1501
1502        if state.data is None:
1503            data = DataLoader.data_info.Data1D(x=[], y=[]) 
1504        else: 
1505            #make sure title and data run is filled up.
1506            if state.data.title == None or state.data.title=='': state.data.title = state.data.name
1507            if state.data.run_name == None or state.data.run_name=={}: 
1508                state.data.run = [str(state.data.name)]
1509                state.data.run_name[0] = state.data.name
1510   
1511            if issubclass(state.data.__class__, DataLoader.data_info.Data1D):
1512
1513                data = state.data
1514                doc, sasentry = self._to_xml_doc(data)
1515            else:
1516                data = state.data
1517                doc, sasentry = self._data2d_to_xml_doc(data)
1518           
1519
1520        if state is not None:
1521            state.toXML(doc=doc, file=data.name, entry_node=sasentry)
1522           
1523        return doc
1524   
1525# Simple html report templet 
1526HEADER = "<html>\n"
1527HEADER += "<head>\n"
1528HEADER += "<meta http-equiv=Content-Type content='text/html; "
1529HEADER += "charset=windows-1252'> \n"
1530HEADER += "<meta name=Generator >\n"
1531HEADER += "</head>\n"
1532HEADER += "<body lang=EN-US>\n"
1533HEADER += "<div class=WordSection1>\n"
1534HEADER += "<p class=MsoNormal><b><span ><center>"
1535HEADER += "%s</center></span></center></b></p>"
1536HEADER += "<p class=MsoNormal>&nbsp;</p>"
1537PARA = "<p class=MsoNormal> %s \n"
1538PARA += "</p>"
1539CENTRE = "<p class=MsoNormal><center> %s \n"
1540CENTRE += "</center></p>"
1541FEET_1 = \
1542"""
1543<p class=MsoNormal>&nbsp;</p>
1544<p class=MsoNormal><b><span ><center> Graph</span></center></b></p>
1545<p class=MsoNormal>&nbsp;</p> 
1546<center> 
1547<br>Model Computation<br> 
1548<br>Data: "%s"<br> 
1549"""
1550FEET_2 = \
1551"""
1552<img src="%s" > 
1553</img>
1554"""
1555FEET_3 = \
1556"""
1557</center>
1558</div>
1559</body>
1560</html>
1561"""
1562ELINE = "<p class=MsoNormal>&nbsp;</p>"
1563
1564if __name__ == "__main__":
1565    state = PageState(parent=None)
1566    #state.toXML()
1567    """
1568   
1569    file = open("test_state", "w")
1570    pickle.dump(state, file)
1571    print pickle.dumps(state)
1572    state.data_name = "hello---->"
1573    pickle.dump(state, file)
1574    file = open("test_state", "r")
1575    new_state= pickle.load(file)
1576    print "new state", new_state
1577    new_state= pickle.load(file)
1578    print "new state", new_state
1579    #print "state", state
1580    """
1581    import bsddb
1582    import pickle
1583    db= bsddb.btopen('file_state.db', 'c')
1584    val = (pickle.dumps(state), "hello", "hi")
1585    db['state1']= pickle.dumps(val)
1586    print pickle.loads(db['state1'])
1587    state.data_name = "hello---->22"
1588    db['state2']= pickle.dumps(state)
1589    state.data_name = "hello---->2"
1590    db['state3']= pickle.dumps(state)
1591    del db['state3']
1592    state.data_name = "hello---->3"
1593    db['state4']= pickle.dumps(state)
1594    new_state = pickle.loads(db['state1'])
1595    #print db.last()
1596    db.set_location('state2')
1597    state.data_name = "hello---->5"
1598    db['aastate5']= pickle.dumps(state)
1599    db.keys().sort()
1600    print pickle.loads(db['state2'])
1601 
1602    db.close()
Note: See TracBrowser for help on using the repository browser.