source: sasview/fittingview/src/sans/perspectives/fitting/pagestate.py @ 22ce7e2

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 22ce7e2 was 8e671c39, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixed minor bug in report due to the recent changes in gui

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