source: sasview/src/sas/perspectives/fitting/pagestate.py @ 74f419d

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 74f419d was 2f4b430, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

Take care of white spaces (pylint)

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