source: sasview/src/sas/sasgui/perspectives/fitting/pagestate.py @ 18b7ca96

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 18b7ca96 was 18b7ca96, checked in by krzywon, 7 years ago

Merge branch 'ticket-795' into ticket-827

  • Property mode set to 100644
File size: 58.0 KB
Line 
1"""
2    Class that holds a fit page state
3"""
4# TODO: Refactor code so we don't need to use getattr/setattr
5################################################################################
6# This software was developed by the University of Tennessee as part of the
7# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
8# project funded by the US National Science Foundation.
9#
10# See the license text in license.txt
11#
12# copyright 2009, University of Tennessee
13################################################################################
14import time
15import os
16import sys
17import wx
18import copy
19import logging
20import numpy
21import traceback
22
23import xml.dom.minidom
24from xml.dom.minidom import parseString
25from lxml import etree
26
27from sasmodels import convert
28import sasmodels.weights
29
30import sas.sascalc.dataloader
31from sas.sascalc.dataloader.readers.cansas_reader import Reader as CansasReader
32from sas.sascalc.dataloader.readers.cansas_reader import get_content, write_node
33from sas.sascalc.dataloader.data_info import Data2D, Collimation, Detector
34from sas.sascalc.dataloader.data_info import Process, Aperture
35# Information to read/write state as xml
36FITTING_NODE_NAME = 'fitting_plug_in'
37CANSAS_NS = "cansas1d/1.0"
38
39LIST_OF_DATA_ATTRIBUTES = [["is_data", "is_data", "bool"],
40                           ["group_id", "data_group_id", "string"],
41                           ["data_name", "data_name", "string"],
42                           ["data_id", "data_id", "string"],
43                           ["name", "name", "string"],
44                           ["data_name", "data_name", "string"]]
45LIST_OF_STATE_ATTRIBUTES = [["qmin", "qmin", "float"],
46                            ["qmax", "qmax", "float"],
47                            ["npts", "npts", "float"],
48                            ["categorycombobox", "categorycombobox", "string"],
49                            ["formfactorcombobox", "formfactorcombobox",
50                             "string"],
51                            ["structurecombobox", "structurecombobox",
52                             "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", "float"],
71                            ["dq_r", "dq_r", "float"],
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"],
78                            ["weights", "weights"]]
79
80DISPERSION_LIST = [["disp_obj_dict", "_disp_obj_dict", "string"]]
81
82LIST_OF_STATE_PARAMETERS = [["parameters", "parameters"],
83                            ["str_parameters", "str_parameters"],
84                            ["orientation_parameters", "orientation_params"],
85                            ["dispersity_parameters",
86                             "orientation_params_disp"],
87                            ["fixed_param", "fixed_param"],
88                            ["fittable_param", "fittable_param"]]
89LIST_OF_DATA_2D_ATTR = [["xmin", "xmin", "float"],
90                        ["xmax", "xmax", "float"],
91                        ["ymin", "ymin", "float"],
92                        ["ymax", "ymax", "float"],
93                        ["_xaxis", "_xaxis", "string"],
94                        ["_xunit", "_xunit", "string"],
95                        ["_yaxis", "_yaxis", "string"],
96                        ["_yunit", "_yunit", "string"],
97                        ["_zaxis", "_zaxis", "string"],
98                        ["_zunit", "_zunit", "string"]]
99LIST_OF_DATA_2D_VALUES = [["qx_data", "qx_data", "float"],
100                          ["qy_data", "qy_data", "float"],
101                          ["dqx_data", "dqx_data", "float"],
102                          ["dqy_data", "dqy_data", "float"],
103                          ["data", "data", "float"],
104                          ["q_data", "q_data", "float"],
105                          ["err_data", "err_data", "float"],
106                          ["mask", "mask", "bool"]]
107
108
109def parse_entry_helper(node, item):
110    """
111    Create a numpy list from value extrated from the node
112
113    :param node: node from each the value is stored
114    :param item: list name of three strings.the two first are name of data
115        attribute and the third one is the type of the value of that
116        attribute. type can be string, float, bool, etc.
117
118    : return: numpy array
119    """
120    if node is not None:
121        if item[2] == "string":
122            return str(node.get(item[0]).strip())
123        elif item[2] == "bool":
124            try:
125                return node.get(item[0]).strip() == "True"
126            except Exception:
127                return None
128        else:
129            try:
130                return float(node.get(item[0]))
131            except Exception:
132                return None
133
134
135class PageState(object):
136    """
137    Contains information to reconstruct a page of the fitpanel.
138    """
139    def __init__(self, parent=None, model=None, data=None):
140        """
141        Initialize the current state
142
143        :param model: a selected model within a page
144        :param data:
145
146        """
147        self.file = None
148        # Time of state creation
149        self.timestamp = time.time()
150        # Data member to store the dispersion object created
151        self._disp_obj_dict = {}
152        # ------------------------
153        # Data used for fitting
154        self.data = data
155        # model data
156        self.theory_data = None
157        # Is 2D
158        self.is_2D = False
159        self.images = None
160
161        # save additional information on data that dataloader.reader
162        # does not read
163        self.is_data = None
164        self.data_name = ""
165
166        if self.data is not None:
167            self.data_name = self.data.name
168        self.data_id = None
169        if self.data is not None and hasattr(self.data, "id"):
170            self.data_id = self.data.id
171        self.data_group_id = None
172        if self.data is not None and hasattr(self.data, "group_id"):
173            self.data_group_id = self.data.group_id
174
175        # reset True change the state of existing button
176        self.reset = False
177
178        # flag to allow data2D plot
179        self.enable2D = False
180        # model on which the fit would be performed
181        self.model = model
182        self.m_name = None
183        # list of process done to model
184        self.process = []
185        # fit page manager
186        self.manager = None
187        # Store the parent of this panel parent
188        # For this application fitpanel is the parent
189        self.parent = parent
190        # Event_owner is the owner of model event
191        self.event_owner = None
192        # page name
193        self.page_name = ""
194        # Contains link between model, its parameters, and panel organization
195        self.parameters = []
196        # String parameter list that can not be fitted
197        self.str_parameters = []
198        # Contains list of parameters that cannot be fitted and reference to
199        # panel objects
200        self.fixed_param = []
201        # Contains list of parameters with dispersity and reference to
202        # panel objects
203        self.fittable_param = []
204        # orientation parameters
205        self.orientation_params = []
206        # orientation parameters for gaussian dispersity
207        self.orientation_params_disp = []
208        # smearer info
209        self.smearer = None
210        self.smear_type = None
211        self.dq_l = None
212        self.dq_r = None
213        self.dx_max = None
214        self.dx_min = None
215        self.dxl = None
216        self.dxw = None
217        # list of dispersion parameters
218        self.disp_list = []
219        if self.model is not None:
220            self.disp_list = self.model.getDispParamList()
221
222        self.disp_cb_dict = {}
223        self.values = {}
224        self.weights = {}
225
226        # contains link between a model and selected parameters to fit
227        self.param_toFit = []
228        # dictionary of model type and model class
229        self.model_list_box = None
230        # save the state of the context menu
231        self.saved_states = {}
232        # save selection of combobox
233        self.formfactorcombobox = None
234        self.categorycombobox = None
235        self.structurecombobox = None
236
237        # radio box to select type of model
238        # self.shape_rbutton = False
239        # self.shape_indep_rbutton = False
240        # self.struct_rbutton = False
241        # self.plugin_rbutton = False
242        # the indice of the current selection
243        self.disp_box = 0
244        # Qrange
245        # Q range
246        self.qmin = 0.001
247        self.qmax = 0.1
248        # reset data range
249        self.qmax_x = None
250        self.qmin_x = None
251
252        self.npts = None
253        self.name = ""
254        self.multi_factor = None
255        self.magnetic_on = False
256        # enable smearering state
257        self.enable_smearer = False
258        self.disable_smearer = True
259        self.pinhole_smearer = False
260        self.slit_smearer = False
261        # weighting options
262        self.dI_noweight = False
263        self.dI_didata = True
264        self.dI_sqrdata = False
265        self.dI_idata = False
266        # disperity selection
267        self.enable_disp = False
268        self.disable_disp = True
269
270        # state of selected all check button
271        self.cb1 = False
272        # store value of chisqr
273        self.tcChi = None
274        self.version = (1,0,0)
275
276    def clone(self):
277        """
278        Create a new copy of the current object
279        """
280        model = None
281        if self.model is not None:
282            model = self.model.clone()
283            model.name = self.model.name
284        obj = PageState(self.parent, model=model)
285        obj.file = copy.deepcopy(self.file)
286        obj.data = copy.deepcopy(self.data)
287        if self.data is not None:
288            self.data_name = self.data.name
289        obj.data_name = self.data_name
290        obj.is_data = self.is_data
291        obj.model_list_box = copy.deepcopy(self.model_list_box)
292
293        obj.categorycombobox = self.categorycombobox
294        obj.formfactorcombobox = self.formfactorcombobox
295        obj.structurecombobox = self.structurecombobox
296
297        # obj.shape_rbutton = self.shape_rbutton
298        # obj.shape_indep_rbutton = self.shape_indep_rbutton
299        # obj.struct_rbutton = self.struct_rbutton
300        # obj.plugin_rbutton = self.plugin_rbutton
301
302        obj.manager = self.manager
303        obj.event_owner = self.event_owner
304        obj.disp_list = copy.deepcopy(self.disp_list)
305
306        obj.enable2D = copy.deepcopy(self.enable2D)
307        obj.parameters = copy.deepcopy(self.parameters)
308        obj.str_parameters = copy.deepcopy(self.str_parameters)
309        obj.fixed_param = copy.deepcopy(self.fixed_param)
310        obj.fittable_param = copy.deepcopy(self.fittable_param)
311        obj.orientation_params = copy.deepcopy(self.orientation_params)
312        obj.orientation_params_disp = \
313            copy.deepcopy(self.orientation_params_disp)
314        obj.enable_disp = copy.deepcopy(self.enable_disp)
315        obj.disable_disp = copy.deepcopy(self.disable_disp)
316        obj.tcChi = self.tcChi
317
318        if len(self._disp_obj_dict) > 0:
319            for k, v in self._disp_obj_dict.iteritems():
320                obj._disp_obj_dict[k] = v
321        if len(self.disp_cb_dict) > 0:
322            for k, v in self.disp_cb_dict.iteritems():
323                obj.disp_cb_dict[k] = v
324        if len(self.values) > 0:
325            for k, v in self.values.iteritems():
326                obj.values[k] = v
327        if len(self.weights) > 0:
328            for k, v in self.weights.iteritems():
329                obj.weights[k] = v
330        obj.enable_smearer = copy.deepcopy(self.enable_smearer)
331        obj.disable_smearer = copy.deepcopy(self.disable_smearer)
332        obj.pinhole_smearer = copy.deepcopy(self.pinhole_smearer)
333        obj.slit_smearer = copy.deepcopy(self.slit_smearer)
334        obj.smear_type = copy.deepcopy(self.smear_type)
335        obj.dI_noweight = copy.deepcopy(self.dI_noweight)
336        obj.dI_didata = copy.deepcopy(self.dI_didata)
337        obj.dI_sqrdata = copy.deepcopy(self.dI_sqrdata)
338        obj.dI_idata = copy.deepcopy(self.dI_idata)
339        obj.dq_l = copy.deepcopy(self.dq_l)
340        obj.dq_r = copy.deepcopy(self.dq_r)
341        obj.dx_max = copy.deepcopy(self.dx_max)
342        obj.dx_min = copy.deepcopy(self.dx_min)
343        obj.dxl = copy.deepcopy(self.dxl)
344        obj.dxw = copy.deepcopy(self.dxw)
345        obj.disp_box = copy.deepcopy(self.disp_box)
346        obj.qmin = copy.deepcopy(self.qmin)
347        obj.qmax = copy.deepcopy(self.qmax)
348        obj.multi_factor = self.multi_factor
349        obj.magnetic_on = self.magnetic_on
350        obj.npts = copy.deepcopy(self.npts)
351        obj.cb1 = copy.deepcopy(self.cb1)
352        obj.smearer = copy.deepcopy(self.smearer)
353        obj.version = copy.deepcopy(self.version)
354
355        for name, state in self.saved_states.iteritems():
356            copy_name = copy.deepcopy(name)
357            copy_state = state.clone()
358            obj.saved_states[copy_name] = copy_state
359        return obj
360
361    def _old_first_model(self):
362        """
363        Handle save states from 4.0.1 and before where the first item in the
364        selection boxes of category, formfactor and structurefactor were not
365        saved.
366        :return: None
367        """
368        if self.formfactorcombobox == '':
369            if self.categorycombobox == '' and len(self.parameters) == 3:
370                self.categorycombobox = "Shape-Independent"
371                self.formfactorcombobox = 'PowerLawAbsModel'
372            elif self.categorycombobox == '' and len(self.parameters) == 9:
373                self.categorycombobox = 'Cylinder'
374                self.formfactorcombobox = 'barbell'
375            elif self.categorycombobox == 'Shapes':
376                self.formfactorcombobox = 'BCCrystalModel'
377            elif self.categorycombobox == 'Uncategorized':
378                self.formfactorcombobox = 'LineModel'
379            elif self.categorycombobox == 'StructureFactor':
380                self.structurecombobox = 'HardsphereStructure'
381            elif self.categorycombobox == 'Customized Models':
382                self.formfactorcombobox = 'MySumFunction'
383            elif self.categorycombobox == 'Ellipsoid':
384                self.formfactorcombobox = 'core_shell_ellipsoid'
385            elif self.categorycombobox == 'Lamellae':
386                self.formfactorcombobox = 'lamellar'
387            elif self.categorycombobox == 'Paracrystal':
388                self.formfactorcombobox = 'bcc_paracrystal'
389            elif self.categorycombobox == 'Parallelepiped':
390                self.formfactorcombobox = 'core_shell_parallelepiped'
391            elif self.categorycombobox == 'Shape Independent':
392                self.formfactorcombobox = 'be_polyelectrolyte'
393            elif self.categorycombobox == 'Sphere':
394                self.formfactorcombobox = 'adsorbed_layer'
395            elif self.categorycombobox == 'Structure Factor':
396                self.formfactorcombobox = 'hardsphere'
397
398    @staticmethod
399    def param_remap_to_sasmodels_convert(params, is_string=False):
400        """
401        Remaps the parameters for sasmodels conversion
402
403        :param params: list of parameters (likely self.parameters)
404        :return: remapped dictionary of parameters
405        """
406        p = dict()
407        for fittable, name, value, _, uncert, lower, upper, units in params:
408            if not value:
409                value = numpy.nan
410            if not uncert or uncert[1] == '' or uncert[1] == 'None':
411                uncert[0] = False
412                uncert[1] = numpy.nan
413            if not upper or upper[1] == '' or upper[1] == 'None':
414                upper[0] = False
415                upper[1] = numpy.nan
416            if not lower or lower[1] == '' or lower[1] == 'None':
417                lower[0] = False
418                lower[1] = numpy.nan
419            if is_string:
420                p[name] = str(value)
421            else:
422                p[name] = float(value)
423            p[name + ".fittable"] = bool(fittable)
424            p[name + ".std"] = float(uncert[1])
425            p[name + ".upper"] = float(upper[1])
426            p[name + ".lower"] = float(lower[1])
427            p[name + ".units"] = units
428        return p
429
430    @staticmethod
431    def param_remap_from_sasmodels_convert(params):
432        """
433        Converts {name : value} map back to [] param list
434        :param params: parameter map returned from sasmodels
435        :return: None
436        """
437        p_map = []
438        for name, info in params.iteritems():
439            if ".fittable" in name or ".std" in name or ".upper" in name or \
440                            ".lower" in name or ".units" in name:
441                pass
442            else:
443                fittable = params.get(name + ".fittable", True)
444                std = params.get(name + ".std", '0.0')
445                upper = params.get(name + ".upper", 'inf')
446                lower = params.get(name + ".lower", '-inf')
447                units = params.get(name + ".units")
448                if std is not None and std is not numpy.nan:
449                    std = [True, str(std)]
450                else:
451                    std = [False, '']
452                if lower is not None and lower is not numpy.nan:
453                    lower = [True, str(lower)]
454                else:
455                    lower = [True, '-inf']
456                if upper is not None and upper is not numpy.nan:
457                    upper = [True, str(upper)]
458                else:
459                    upper = [True, 'inf']
460                param_list = [bool(fittable), str(name), str(info),
461                              "+/-", std, lower, upper, str(units)]
462                p_map.append(param_list)
463        return p_map
464
465    def _convert_to_sasmodels(self):
466        """
467        Convert parameters to a form usable by sasmodels converter
468
469        :return: None
470        """
471        # Create conversion dictionary to send to sasmodels
472        self._old_first_model()
473        p = self.param_remap_to_sasmodels_convert(self.parameters)
474        structurefactor, params = convert.convert_model(self.structurecombobox,
475                                                        p, False, self.version)
476        formfactor, params = convert.convert_model(self.formfactorcombobox,
477                                                   params, False, self.version)
478        if len(self.str_parameters) > 0:
479            str_pars = self.param_remap_to_sasmodels_convert(
480                self.str_parameters, True)
481            formfactor, str_params = convert.convert_model(
482                self.formfactorcombobox, str_pars, False, self.version)
483            for key, value in str_params.iteritems():
484                params[key] = value
485
486        if self.formfactorcombobox == 'SphericalSLDModel':
487            self.multi_factor += 1
488        self.formfactorcombobox = formfactor
489        self.structurecombobox = structurefactor
490        self.parameters = []
491        self.parameters = self.param_remap_from_sasmodels_convert(params)
492
493    def _repr_helper(self, list, rep):
494        """
495        Helper method to print a state
496        """
497        for item in list:
498            rep += "parameter name: %s \n" % str(item[1])
499            rep += "value: %s\n" % str(item[2])
500            rep += "selected: %s\n" % str(item[0])
501            rep += "error displayed : %s \n" % str(item[4][0])
502            rep += "error value:%s \n" % str(item[4][1])
503            rep += "minimum displayed : %s \n" % str(item[5][0])
504            rep += "minimum value : %s \n" % str(item[5][1])
505            rep += "maximum displayed : %s \n" % str(item[6][0])
506            rep += "maximum value : %s \n" % str(item[6][1])
507            rep += "parameter unit: %s\n\n" % str(item[7])
508        return rep
509
510    def __repr__(self):
511        """
512        output string for printing
513        """
514        rep = "\nState name: %s\n" % self.file
515        t = time.localtime(self.timestamp)
516        time_str = time.strftime("%b %d %Y %H;%M;%S ", t)
517
518        rep += "State created: %s\n" % time_str
519        rep += "State form factor combobox selection: %s\n" % \
520               self.formfactorcombobox
521        rep += "State structure factor combobox selection: %s\n" % \
522               self.structurecombobox
523        rep += "is data : %s\n" % self.is_data
524        rep += "data's name : %s\n" % self.data_name
525        rep += "data's id : %s\n" % self.data_id
526        if self.model is not None:
527            m_name = self.model.__class__.__name__
528            if m_name == 'Model':
529                m_name = self.m_name
530            rep += "model name : %s\n" % m_name
531        else:
532            rep += "model name : None\n"
533        rep += "multi_factor : %s\n" % str(self.multi_factor)
534        rep += "magnetic_on : %s\n" % str(self.magnetic_on)
535        rep += "model type (Category) selected: %s\n" % self.categorycombobox
536        rep += "data : %s\n" % str(self.data)
537        rep += "Plotting Range: min: %s, max: %s, steps: %s\n" % \
538               (str(self.qmin), str(self.qmax), str(self.npts))
539        rep += "Dispersion selection : %s\n" % str(self.disp_box)
540        rep += "Smearing enable : %s\n" % str(self.enable_smearer)
541        rep += "Smearing disable : %s\n" % str(self.disable_smearer)
542        rep += "Pinhole smearer enable : %s\n" % str(self.pinhole_smearer)
543        rep += "Slit smearer enable : %s\n" % str(self.slit_smearer)
544        rep += "Dispersity enable : %s\n" % str(self.enable_disp)
545        rep += "Dispersity disable : %s\n" % str(self.disable_disp)
546        rep += "Slit smearer enable: %s\n" % str(self.slit_smearer)
547
548        rep += "dI_noweight : %s\n" % str(self.dI_noweight)
549        rep += "dI_didata : %s\n" % str(self.dI_didata)
550        rep += "dI_sqrdata : %s\n" % str(self.dI_sqrdata)
551        rep += "dI_idata : %s\n" % str(self.dI_idata)
552
553        rep += "2D enable : %s\n" % str(self.enable2D)
554        rep += "All parameters checkbox selected: %s\n" % self.cb1
555        rep += "Value of Chisqr : %s\n" % str(self.tcChi)
556        rep += "Smear object : %s\n" % self.smearer
557        rep += "Smear type : %s\n" % self.smear_type
558        rep += "dq_l  : %s\n" % self.dq_l
559        rep += "dq_r  : %s\n" % self.dq_r
560        rep += "dx_max  : %s\n" % str(self.dx_max)
561        rep += "dx_min : %s\n" % str(self.dx_min)
562        rep += "dxl  : %s\n" % str(self.dxl)
563        rep += "dxw : %s\n" % str(self.dxw)
564        rep += "model  : %s\n\n" % str(self.model)
565        temp_parameters = []
566        temp_fittable_param = []
567        if self.data.__class__.__name__ == "Data2D":
568            self.is_2D = True
569        else:
570            self.is_2D = False
571        if self.data is not None:
572            if not self.is_2D:
573                for item in self.parameters:
574                    if item not in self.orientation_params:
575                        temp_parameters.append(item)
576                for item in self.fittable_param:
577                    if item not in self.orientation_params_disp:
578                        temp_fittable_param.append(item)
579            else:
580                temp_parameters = self.parameters
581                temp_fittable_param = self.fittable_param
582
583            rep += "number parameters(self.parameters): %s\n" % \
584                   len(temp_parameters)
585            rep = self._repr_helper(list=temp_parameters, rep=rep)
586            rep += "number str_parameters(self.str_parameters): %s\n" % \
587                   len(self.str_parameters)
588            rep = self._repr_helper(list=self.str_parameters, rep=rep)
589            rep += "number fittable_param(self.fittable_param): %s\n" % \
590                   len(temp_fittable_param)
591            rep = self._repr_helper(list=temp_fittable_param, rep=rep)
592        return rep
593
594    def set_report_string(self):
595        """
596        Get the values (strings) from __str__ for report
597        """
598        # Dictionary of the report strings
599        repo_time = ""
600        model_name = ""
601        title = ""
602        title_name = ""
603        file_name = ""
604        param_string = ""
605        paramval_string = ""
606        chi2_string = ""
607        q_range = ""
608        strings = self.__repr__()
609        lines = strings.split('\n')
610
611        # get all string values from __str__()
612        for line in lines:
613            value = ""
614            content = line.split(":")
615            name = content[0]
616            try:
617                value = content[1]
618            except Exception:
619                msg = "Report string expected 'name: value' but got %r" % line
620                logging.error(msg)
621            if name.count("State created"):
622                repo_time = "" + value
623            if name.count("parameter name"):
624                val_name = value.split(".")
625                if len(val_name) > 1:
626                    if val_name[1].count("width"):
627                        param_string += value + ','
628                    else:
629                        continue
630                else:
631                    param_string += value + ','
632            if name == "value":
633                param_string += value + ','
634            fixed_parameter = False
635            if name == "selected":
636                if value == u' False':
637                    fixed_parameter = True
638            if name == "error value":
639                if fixed_parameter:
640                    param_string += '(fixed),'
641                else:
642                    param_string += value + ','
643            if name == "parameter unit":
644                param_string += value + ':'
645            if name == "Value of Chisqr ":
646                chi2 = ("Chi2/Npts = " + value)
647                chi2_string = CENTRE % chi2
648            if name == "Title":
649                if len(value.strip()) == 0:
650                    continue
651                title = value + " [" + repo_time + "]"
652                title_name = HEADER % title
653            if name == "data ":
654                try:
655                    file_value = ("File name:" + content[2])
656                    file_name = CENTRE % file_value
657                    if len(title) == 0:
658                        title = content[2] + " [" + repo_time + "]"
659                        title_name = HEADER % title
660                except Exception:
661                    msg = "While parsing 'data: ...'\n"
662                    logging.error(msg + traceback.format_exc())
663            if name == "model name ":
664                try:
665                    modelname = "Model name:" + content[1]
666                except:
667                    modelname = "Model name:" + " NAN"
668                model_name = CENTRE % modelname
669
670            if name == "Plotting Range":
671                try:
672                    q_range = content[1] + " = " + content[2] \
673                            + " = " + content[3].split(",")[0]
674                    q_name = ("Q Range:    " + q_range)
675                    q_range = CENTRE % q_name
676                except Exception:
677                    msg = "While parsing 'Plotting Range: ...'\n"
678                    logging.error(msg + traceback.format_exc())
679        paramval = ""
680        for lines in param_string.split(":"):
681            line = lines.split(",")
682            if len(lines) > 0:
683                param = line[0]
684                param += " = " + line[1]
685                if len(line[2].split()) > 0 and not line[2].count("None"):
686                    param += " +- " + line[2]
687                if len(line[3].split()) > 0 and not line[3].count("None"):
688                    param += " " + line[3]
689                if not paramval.count(param):
690                    paramval += param + "\n"
691                    paramval_string += CENTRE % param + "\n"
692
693        text_string = "\n\n\n%s\n\n%s\n%s\n%s\n\n%s" % \
694                      (title, file, q_name, chi2, paramval)
695
696        title_name = self._check_html_format(title_name)
697        file_name = self._check_html_format(file_name)
698        title = self._check_html_format(title)
699
700        html_string = title_name + "\n" + file_name + \
701                                   "\n" + model_name + \
702                                   "\n" + q_range + \
703                                   "\n" + chi2_string + \
704                                   "\n" + ELINE + \
705                                   "\n" + paramval_string + \
706                                   "\n" + ELINE + \
707                                   "\n" + FEET_1 % title + \
708                                   "\n" + FEET_2
709
710        return html_string, text_string, title
711
712    def _check_html_format(self, name):
713        """
714        Check string '%' for html format
715        """
716        if name.count('%'):
717            name = name.replace('%', '&#37')
718
719        return name
720
721    def report(self, figs=None, canvases=None):
722        """
723        Invoke report dialog panel
724
725        : param figs: list of pylab figures [list]
726        """
727        from sas.sasgui.perspectives.fitting.report_dialog import ReportDialog
728        # get the strings for report
729        html_str, text_str, title = self.set_report_string()
730        # Allow 2 figures to append
731        if len(figs) == 1:
732            add_str = FEET_3
733        elif len(figs) == 2:
734            add_str = ELINE
735            add_str += FEET_2 % ("%s")
736            add_str += ELINE
737            add_str += FEET_3
738        elif len(figs) > 2:
739            add_str = ELINE
740            add_str += FEET_2 % ("%s")
741            add_str += ELINE
742            add_str += FEET_2 % ("%s")
743            add_str += ELINE
744            add_str += FEET_3
745        else:
746            add_str = ""
747
748        # final report html strings
749        report_str = html_str % ("%s") + add_str
750
751        # make plot image
752        images = self.set_plot_state(figs, canvases)
753        report_list = [report_str, text_str, images]
754        dialog = ReportDialog(report_list, None, wx.ID_ANY, "")
755        dialog.Show()
756
757    def _to_xml_helper(self, thelist, element, newdoc):
758        """
759        Helper method to create xml file for saving state
760        """
761        for item in thelist:
762            sub_element = newdoc.createElement('parameter')
763            sub_element.setAttribute('name', str(item[1]))
764            sub_element.setAttribute('value', str(item[2]))
765            sub_element.setAttribute('selected_to_fit', str(item[0]))
766            sub_element.setAttribute('error_displayed', str(item[4][0]))
767            sub_element.setAttribute('error_value', str(item[4][1]))
768            sub_element.setAttribute('minimum_displayed', str(item[5][0]))
769            sub_element.setAttribute('minimum_value', str(item[5][1]))
770            sub_element.setAttribute('maximum_displayed', str(item[6][0]))
771            sub_element.setAttribute('maximum_value', str(item[6][1]))
772            sub_element.setAttribute('unit', str(item[7]))
773            element.appendChild(sub_element)
774
775    def to_xml(self, file="fitting_state.fitv", doc=None,
776               entry_node=None, batch_fit_state=None):
777        """
778        Writes the state of the fit panel to file, as XML.
779
780        Compatible with standalone writing, or appending to an
781        already existing XML document. In that case, the XML document is
782        required. An optional entry node in the XML document may also be given.
783
784        :param file: file to write to
785        :param doc: XML document object [optional]
786        :param entry_node: XML node within the XML document at which we
787                           will append the data [optional]
788        :param batch_fit_state: simultaneous fit state
789        """
790        from xml.dom.minidom import getDOMImplementation
791
792        # Check whether we have to write a standalone XML file
793        if doc is None:
794            impl = getDOMImplementation()
795            doc_type = impl.createDocumentType(FITTING_NODE_NAME, "1.0", "1.0")
796            newdoc = impl.createDocument(None, FITTING_NODE_NAME, doc_type)
797            top_element = newdoc.documentElement
798        else:
799            # We are appending to an existing document
800            newdoc = doc
801            try:
802                top_element = newdoc.createElement(FITTING_NODE_NAME)
803            except:
804                string = etree.tostring(doc, pretty_print=True)
805                newdoc = parseString(string)
806                top_element = newdoc.createElement(FITTING_NODE_NAME)
807            if entry_node is None:
808                newdoc.documentElement.appendChild(top_element)
809            else:
810                try:
811                    entry_node.appendChild(top_element)
812                except:
813                    node_name = entry_node.tag
814                    node_list = newdoc.getElementsByTagName(node_name)
815                    entry_node = node_list.item(0)
816                    entry_node.appendChild(top_element)
817
818        attr = newdoc.createAttribute("version")
819        import sasview
820        attr.nodeValue = sasview.__version__
821        # attr.nodeValue = '1.0'
822        top_element.setAttributeNode(attr)
823
824        # File name
825        element = newdoc.createElement("filename")
826        if self.file is not None:
827            element.appendChild(newdoc.createTextNode(str(self.file)))
828        else:
829            element.appendChild(newdoc.createTextNode(str(file)))
830        top_element.appendChild(element)
831
832        element = newdoc.createElement("timestamp")
833        element.appendChild(newdoc.createTextNode(time.ctime(self.timestamp)))
834        attr = newdoc.createAttribute("epoch")
835        attr.nodeValue = str(self.timestamp)
836        element.setAttributeNode(attr)
837        top_element.appendChild(element)
838
839        # Inputs
840        inputs = newdoc.createElement("Attributes")
841        top_element.appendChild(inputs)
842
843        if self.data is not None and hasattr(self.data, "group_id"):
844            self.data_group_id = self.data.group_id
845        if self.data is not None and hasattr(self.data, "is_data"):
846            self.is_data = self.data.is_data
847        if self.data is not None:
848            self.data_name = self.data.name
849        if self.data is not None and hasattr(self.data, "id"):
850            self.data_id = self.data.id
851
852        for item in LIST_OF_DATA_ATTRIBUTES:
853            element = newdoc.createElement(item[0])
854            element.setAttribute(item[0], str(getattr(self, item[1])))
855            inputs.appendChild(element)
856
857        for item in LIST_OF_STATE_ATTRIBUTES:
858            element = newdoc.createElement(item[0])
859            element.setAttribute(item[0], str(getattr(self, item[1])))
860            inputs.appendChild(element)
861
862        # For self.values ={ disp_param_name: [vals,...],...}
863        # and for self.weights ={ disp_param_name: [weights,...],...}
864        for item in LIST_OF_MODEL_ATTRIBUTES:
865            element = newdoc.createElement(item[0])
866            value_list = getattr(self, item[1])
867            for key, value in value_list.iteritems():
868                sub_element = newdoc.createElement(key)
869                sub_element.setAttribute('name', str(key))
870                for val in value:
871                    sub_element.appendChild(newdoc.createTextNode(str(val)))
872
873                element.appendChild(sub_element)
874            inputs.appendChild(element)
875
876        # Create doc for the dictionary of self._disp_obj_dic
877        for tagname, varname, tagtype in DISPERSION_LIST:
878            element = newdoc.createElement(tagname)
879            value_list = getattr(self, varname)
880            for key, value in value_list.iteritems():
881                sub_element = newdoc.createElement(key)
882                sub_element.setAttribute('name', str(key))
883                sub_element.setAttribute('value', str(value))
884                element.appendChild(sub_element)
885            inputs.appendChild(element)
886
887        for item in LIST_OF_STATE_PARAMETERS:
888            element = newdoc.createElement(item[0])
889            self._to_xml_helper(thelist=getattr(self, item[1]),
890                                element=element, newdoc=newdoc)
891            inputs.appendChild(element)
892
893        # Combined and Simultaneous Fit Parameters
894        if batch_fit_state is not None:
895            batch_combo = newdoc.createElement('simultaneous_fit')
896            top_element.appendChild(batch_combo)
897
898            # Simultaneous Fit Number For Linking Later
899            element = newdoc.createElement('sim_fit_number')
900            element.setAttribute('fit_number', str(batch_fit_state.fit_page_no))
901            batch_combo.appendChild(element)
902
903            # Save constraints
904            constraints = newdoc.createElement('constraints')
905            batch_combo.appendChild(constraints)
906            for constraint in batch_fit_state.constraints_list:
907                if constraint.model_cbox.GetValue() != "":
908                    # model_cbox, param_cbox, egal_txt, constraint,
909                    # btRemove, sizer
910                    doc_cons = newdoc.createElement('constraint')
911                    doc_cons.setAttribute('model_cbox',
912                                          str(constraint.model_cbox.GetValue()))
913                    doc_cons.setAttribute('param_cbox',
914                                          str(constraint.param_cbox.GetValue()))
915                    doc_cons.setAttribute('egal_txt',
916                                          str(constraint.egal_txt.GetLabel()))
917                    doc_cons.setAttribute('constraint',
918                                          str(constraint.constraint.GetValue()))
919                    constraints.appendChild(doc_cons)
920
921            # Save all models
922            models = newdoc.createElement('model_list')
923            batch_combo.appendChild(models)
924            for model in batch_fit_state.model_list:
925                doc_model = newdoc.createElement('model_list_item')
926                doc_model.setAttribute('checked', str(model[0].GetValue()))
927                keys = model[1].keys()
928                doc_model.setAttribute('name', str(keys[0]))
929                values = model[1].get(keys[0])
930                doc_model.setAttribute('fit_number', str(model[2]))
931                doc_model.setAttribute('fit_page_source', str(model[3]))
932                doc_model.setAttribute('model_name', str(values.model.id))
933                models.appendChild(doc_model)
934
935            # Select All Checkbox
936            element = newdoc.createElement('select_all')
937            if batch_fit_state.select_all:
938                element.setAttribute('checked', 'True')
939            else:
940                element.setAttribute('checked', 'False')
941            batch_combo.appendChild(element)
942
943        # Save the file
944        if doc is None:
945            fd = open(file, 'w')
946            fd.write(newdoc.toprettyxml())
947            fd.close()
948            return None
949        else:
950            return newdoc
951
952    def _from_xml_helper(self, node, list):
953        """
954        Helper function to write state to xml
955        """
956        for item in node:
957            try:
958                name = item.get('name')
959            except:
960                name = None
961            try:
962                value = item.get('value')
963            except:
964                value = None
965            try:
966                selected_to_fit = (item.get('selected_to_fit') == "True")
967            except:
968                selected_to_fit = None
969            try:
970                error_displayed = (item.get('error_displayed') == "True")
971            except:
972                error_displayed = None
973            try:
974                error_value = item.get('error_value')
975            except:
976                error_value = None
977            try:
978                minimum_displayed = (item.get('minimum_displayed') == "True")
979            except:
980                minimum_displayed = None
981            try:
982                minimum_value = item.get('minimum_value')
983            except:
984                minimum_value = None
985            try:
986                maximum_displayed = (item.get('maximum_displayed') == "True")
987            except:
988                maximum_displayed = None
989            try:
990                maximum_value = item.get('maximum_value')
991            except:
992                maximum_value = None
993            try:
994                unit = item.get('unit')
995            except:
996                unit = None
997            list.append([selected_to_fit, name, value, "+/-",
998                         [error_displayed, error_value],
999                         [minimum_displayed, minimum_value],
1000                         [maximum_displayed, maximum_value], unit])
1001
1002    def from_xml(self, file=None, node=None):
1003        """
1004        Load fitting state from a file
1005
1006        :param file: .fitv file
1007        :param node: node of a XML document to read from
1008        """
1009        if file is not None:
1010            msg = "PageState no longer supports non-CanSAS"
1011            msg += " format for fitting files"
1012            raise RuntimeError, msg
1013
1014        if node.get('version'):
1015            # Get the version for model conversion purposes
1016            self.version = tuple(int(e) for e in
1017                                 str.split(node.get('version'), "."))
1018            # The tuple must be at least 3 items long
1019            while len(self.version) < 3:
1020                ver_list = list(self.version)
1021                ver_list.append(0)
1022                self.version = tuple(ver_list)
1023
1024            # Get file name
1025            entry = get_content('ns:filename', node)
1026            if entry is not None:
1027                self.file = entry.text.strip()
1028
1029            # Get time stamp
1030            entry = get_content('ns:timestamp', node)
1031            if entry is not None and entry.get('epoch'):
1032                try:
1033                    self.timestamp = float(entry.get('epoch'))
1034                except:
1035                    msg = "PageState.fromXML: Could not"
1036                    msg += " read timestamp\n %s" % sys.exc_value
1037                    logging.error(msg)
1038
1039            if entry is not None:
1040                # Parse fitting attributes
1041                entry = get_content('ns:Attributes', node)
1042                for item in LIST_OF_DATA_ATTRIBUTES:
1043                    node = get_content('ns:%s' % item[0], entry)
1044                    setattr(self, item[0], parse_entry_helper(node, item))
1045
1046                for item in LIST_OF_STATE_ATTRIBUTES:
1047                    node = get_content('ns:%s' % item[0], entry)
1048                    setattr(self, item[0], parse_entry_helper(node, item))
1049
1050                for item in LIST_OF_STATE_PARAMETERS:
1051                    node = get_content("ns:%s" % item[0], entry)
1052                    self._from_xml_helper(node=node,
1053                                          list=getattr(self, item[1]))
1054
1055                # Recover _disp_obj_dict from xml file
1056                self._disp_obj_dict = {}
1057                for tagname, varname, tagtype in DISPERSION_LIST:
1058                    node = get_content("ns:%s" % tagname, entry)
1059                    for attr in node:
1060                        parameter = str(attr.get('name'))
1061                        value = attr.get('value')
1062                        if value.startswith("<"):
1063                            try:
1064                                # <path.to.NamedDistribution object/instance...>
1065                                cls_name = value[1:].split()[0].split('.')[-1]
1066                                cls = getattr(sasmodels.weights, cls_name)
1067                                value = cls.type
1068                            except Exception:
1069                                base = "unable to load distribution %r for %s"
1070                                logging.error(base % (value, parameter))
1071                                continue
1072                        _disp_obj_dict = getattr(self, varname)
1073                        _disp_obj_dict[parameter] = value
1074
1075                # get self.values and self.weights dic. if exists
1076                for tagname, varname in LIST_OF_MODEL_ATTRIBUTES:
1077                    node = get_content("ns:%s" % tagname, entry)
1078                    dic = {}
1079                    value_list = []
1080                    for par in node:
1081                        name = par.get('name')
1082                        values = par.text.split()
1083                        # Get lines only with numbers
1084                        for line in values:
1085                            try:
1086                                val = float(line)
1087                                value_list.append(val)
1088                            except Exception:
1089                                # pass if line is empty (it happens)
1090                                msg = ("Error reading %r from %s %s\n"
1091                                       % (line, tagname, name))
1092                                logging.error(msg + traceback.format_exc())
1093                        dic[name] = numpy.array(value_list)
1094                    setattr(self, varname, dic)
1095
1096    def set_plot_state(self, figs, canvases):
1097        """
1098        Build image state that wx.html understand
1099        by plotting, putting it into wx.FileSystem image object
1100
1101        """
1102        images = []
1103
1104        # Reset memory
1105        self.imgRAM = None
1106        wx.MemoryFSHandler()
1107
1108        # For no figures in the list, prepare empty plot
1109        if figs is None or len(figs) == 0:
1110            figs = [None]
1111
1112        # Loop over the list of figures
1113        # use wx.MemoryFSHandler
1114        self.imgRAM = wx.MemoryFSHandler()
1115        for fig in figs:
1116            if fig is not None:
1117                ind = figs.index(fig)
1118                canvas = canvases[ind]
1119
1120            # store the image in wx.FileSystem Object
1121            wx.FileSystem.AddHandler(wx.MemoryFSHandler())
1122
1123            # index of the fig
1124            ind = figs.index(fig)
1125
1126            # AddFile, image can be retrieved with 'memory:filename'
1127            self.imgRAM.AddFile('img_fit%s.png' % ind,
1128                                canvas.bitmap, wx.BITMAP_TYPE_PNG)
1129
1130            # append figs
1131            images.append(fig)
1132
1133        return images
1134
1135
1136class Reader(CansasReader):
1137    """
1138    Class to load a .fitv fitting file
1139    """
1140    # File type
1141    type_name = "Fitting"
1142
1143    # Wildcards
1144    type = ["Fitting files (*.fitv)|*.fitv"
1145            "SASView file (*.svs)|*.svs"]
1146    # List of allowed extensions
1147    ext = ['.fitv', '.FITV', '.svs', 'SVS']
1148
1149    def __init__(self, call_back=None, cansas=True):
1150        CansasReader.__init__(self)
1151        """
1152        Initialize the call-back method to be called
1153        after we load a file
1154
1155        :param call_back: call-back method
1156        :param cansas:  True = files will be written/read in CanSAS format
1157                        False = write CanSAS format
1158
1159        """
1160        # Call back method to be executed after a file is read
1161        self.call_back = call_back
1162        # CanSAS format flag
1163        self.cansas = cansas
1164        self.state = None
1165        # batch fitting params for saving
1166        self.batchfit_params = []
1167
1168    def get_state(self):
1169        return self.state
1170
1171    def read(self, path):
1172        """
1173        Load a new P(r) inversion state from file
1174
1175        :param path: file path
1176
1177        """
1178        if self.cansas:
1179            return self._read_cansas(path)
1180
1181    def _parse_state(self, entry):
1182        """
1183        Read a fit result from an XML node
1184
1185        :param entry: XML node to read from
1186        :return: PageState object
1187        """
1188        # Create an empty state
1189        state = None
1190        # Locate the P(r) node
1191        try:
1192            nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
1193                                namespaces={'ns': CANSAS_NS})
1194            if nodes:
1195                # Create an empty state
1196                state = PageState()
1197                state.from_xml(node=nodes[0])
1198
1199        except:
1200            logging.info("XML document does not contain fitting information.\n"
1201                         + traceback.format_exc())
1202
1203        return state
1204
1205    def _parse_simfit_state(self, entry):
1206        """
1207        Parses the saved data for a simultaneous fit
1208        :param entry: XML object to read from
1209        :return: XML object for a simultaneous fit or None
1210        """
1211        nodes = entry.xpath('ns:%s' % FITTING_NODE_NAME,
1212                            namespaces={'ns': CANSAS_NS})
1213        if nodes:
1214            simfitstate = nodes[0].xpath('ns:simultaneous_fit',
1215                                         namespaces={'ns': CANSAS_NS})
1216            if simfitstate:
1217                from simfitpage import SimFitPageState
1218                sim_fit_state = SimFitPageState()
1219                simfitstate_0 = simfitstate[0]
1220                all = simfitstate_0.xpath('ns:select_all',
1221                                          namespaces={'ns': CANSAS_NS})
1222                atts = all[0].attrib
1223                checked = atts.get('checked')
1224                sim_fit_state.select_all = bool(checked)
1225                model_list = simfitstate_0.xpath('ns:model_list',
1226                                                 namespaces={'ns': CANSAS_NS})
1227                model_list_items = model_list[0].xpath('ns:model_list_item',
1228                                                       namespaces={'ns':
1229                                                                    CANSAS_NS})
1230                for model in model_list_items:
1231                    attrs = model.attrib
1232                    sim_fit_state.model_list.append(attrs)
1233
1234                constraints = simfitstate_0.xpath('ns:constraints',
1235                                                namespaces={'ns': CANSAS_NS})
1236                constraint_list = constraints[0].xpath('ns:constraint',
1237                                               namespaces={'ns': CANSAS_NS})
1238                for constraint in constraint_list:
1239                    attrs = constraint.attrib
1240                    sim_fit_state.constraints_list.append(attrs)
1241
1242                return sim_fit_state
1243            else:
1244                return None
1245
1246    def _parse_save_state_entry(self, dom):
1247        """
1248        Parse a SASentry
1249
1250        :param node: SASentry node
1251
1252        :return: Data1D/Data2D object
1253
1254        """
1255        node = dom.xpath('ns:data_class', namespaces={'ns': CANSAS_NS})
1256        return_value, _ = self._parse_entry(dom)
1257        return return_value, _
1258
1259    def _read_cansas(self, path):
1260        """
1261        Load data and fitting information from a CanSAS XML file.
1262
1263        :param path: file path
1264        :return: Data1D object if a single SASentry was found,
1265                    or a list of Data1D objects if multiple entries were found,
1266                    or None of nothing was found
1267        :raise RuntimeError: when the file can't be opened
1268        :raise ValueError: when the length of the data vectors are inconsistent
1269        """
1270        output = []
1271        simfitstate = None
1272        basename = os.path.basename(path)
1273        root, extension = os.path.splitext(basename)
1274        ext = extension.lower()
1275        try:
1276            if os.path.isfile(path):
1277                if ext in self.ext or ext == '.xml':
1278                    tree = etree.parse(path, parser=etree.ETCompatXMLParser())
1279                    # Check the format version number
1280                    # Specifying the namespace will take care of the file
1281                    # format version
1282                    root = tree.getroot()
1283                    entry_list = root.xpath('ns:SASentry',
1284                                            namespaces={'ns': CANSAS_NS})
1285                    for entry in entry_list:
1286                        try:
1287                            sas_entry, _ = self._parse_save_state_entry(entry)
1288                        except:
1289                            raise
1290                        fitstate = self._parse_state(entry)
1291
1292                        # state could be None when .svs file is loaded
1293                        # in this case, skip appending to output
1294                        if fitstate is not None:
1295                            sas_entry.meta_data['fitstate'] = fitstate
1296                            sas_entry.filename = fitstate.file
1297                            output.append(sas_entry)
1298
1299            else:
1300                self.call_back(format=ext)
1301                raise RuntimeError, "%s is not a file" % path
1302
1303            # Return output consistent with the loader's api
1304            if len(output) == 0:
1305                self.call_back(state=None, datainfo=None, format=ext)
1306                return None
1307            else:
1308                for ind in range(len(output)):
1309                    # Call back to post the new state
1310                    state = output[ind].meta_data['fitstate']
1311                    t = time.localtime(state.timestamp)
1312                    time_str = time.strftime("%b %d %H:%M", t)
1313                    # Check that no time stamp is already appended
1314                    max_char = state.file.find("[")
1315                    if max_char < 0:
1316                        max_char = len(state.file)
1317                    original_fname = state.file[0:max_char]
1318                    state.file = original_fname + ' [' + time_str + ']'
1319
1320                    if state is not None and state.is_data is not None:
1321                        output[ind].is_data = state.is_data
1322
1323                    output[ind].filename = state.file
1324                    state.data = output[ind]
1325                    state.data.name = output[ind].filename  # state.data_name
1326                    state.data.id = state.data_id
1327                    if state.is_data is not None:
1328                        state.data.is_data = state.is_data
1329                    if output[ind].run_name is not None\
1330                         and len(output[ind].run_name) != 0:
1331                        if isinstance(output[ind].run_name, dict):
1332                            name = output[ind].run_name.keys()[0]
1333                        else:
1334                            name = output[ind].run_name
1335                    else:
1336                        name = original_fname
1337                    state.data.group_id = name
1338                    state.version = fitstate.version
1339                    # store state in fitting
1340                    self.call_back(state=state,
1341                                   datainfo=output[ind], format=ext)
1342                    self.state = state
1343                simfitstate = self._parse_simfit_state(entry)
1344                if simfitstate is not None:
1345                    self.call_back(state=simfitstate)
1346
1347                return output
1348        except:
1349            self.call_back(format=ext)
1350            raise
1351
1352    def write(self, filename, datainfo=None, fitstate=None):
1353        """
1354        Write the content of a Data1D as a CanSAS XML file only for standalone
1355
1356        :param filename: name of the file to write
1357        :param datainfo: Data1D object
1358        :param fitstate: PageState object
1359
1360        """
1361        # Sanity check
1362        if self.cansas:
1363            # Add fitting information to the XML document
1364            doc = self.write_toXML(datainfo, fitstate)
1365            # Write the XML document
1366        else:
1367            doc = fitstate.to_xml(file=filename)
1368
1369        # Save the document no matter the type
1370        fd = open(filename, 'w')
1371        fd.write(doc.toprettyxml())
1372        fd.close()
1373
1374    def write_toXML(self, datainfo=None, state=None, batchfit=None):
1375        """
1376        Write toXML, a helper for write(),
1377        could be used by guimanager._on_save()
1378
1379        : return: xml doc
1380        """
1381
1382        self.batchfit_params = batchfit
1383        if state.data is None or not state.data.is_data:
1384            return None
1385        # make sure title and data run are filled.
1386        if state.data.title is None or state.data.title == '':
1387            state.data.title = state.data.name
1388        if state.data.run_name is None or state.data.run_name == {}:
1389            state.data.run = [str(state.data.name)]
1390            state.data.run_name[0] = state.data.name
1391
1392        data = state.data
1393        doc, sasentry = self._to_xml_doc(data)
1394
1395        if state is not None:
1396            doc = state.to_xml(doc=doc, file=data.filename, entry_node=sasentry,
1397                               batch_fit_state=self.batchfit_params)
1398
1399        return doc
1400
1401# Simple html report templet
1402HEADER = "<html>\n"
1403HEADER += "<head>\n"
1404HEADER += "<meta http-equiv=Content-Type content='text/html; "
1405HEADER += "charset=windows-1252'> \n"
1406HEADER += "<meta name=Generator >\n"
1407HEADER += "</head>\n"
1408HEADER += "<body lang=EN-US>\n"
1409HEADER += "<div class=WordSection1>\n"
1410HEADER += "<p class=MsoNormal><b><span ><center><font size='4' >"
1411HEADER += "%s</font></center></span></center></b></p>"
1412HEADER += "<p class=MsoNormal>&nbsp;</p>"
1413PARA = "<p class=MsoNormal><font size='4' > %s \n"
1414PARA += "</font></p>"
1415CENTRE = "<p class=MsoNormal><center><font size='4' > %s \n"
1416CENTRE += "</font></center></p>"
1417FEET_1 = \
1418"""
1419<p class=MsoNormal>&nbsp;</p>
1420<br>
1421<p class=MsoNormal><b><span ><center> <font size='4' > Graph
1422</font></span></center></b></p>
1423<p class=MsoNormal>&nbsp;</p>
1424<center>
1425<br><font size='4' >Model Computation</font>
1426<br><font size='4' >Data: "%s"</font><br>
1427"""
1428FEET_2 = \
1429"""
1430<img src="%s" >
1431</img>
1432"""
1433FEET_3 = \
1434"""
1435</center>
1436</div>
1437</body>
1438</html>
1439"""
1440ELINE = "<p class=MsoNormal>&nbsp;</p>"
Note: See TracBrowser for help on using the repository browser.