source: sasview/src/sas/sasgui/perspectives/fitting/pagestate.py @ 3a22ce7

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 3a22ce7 was 6c382da, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

support alternate distributions in save/load and copy/paste. Closes #669

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