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

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 f21d496 was 0e33a8d, checked in by Doucet, Mathieu <doucetm@…>, 9 years ago

Minor fixes to state loading

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