source: sasview/fittingview/src/sans/perspectives/fitting/pagestate.py @ 2ee5c61

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 2ee5c61 was 14d2daa, checked in by Jae Cho <jhjcho@…>, 12 years ago

set report fonts in one scale larger size(4)

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