Ignore:
Timestamp:
Aug 22, 2017 2:55:17 PM (7 years ago)
Author:
GitHub <noreply@…>
Branches:
master, ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc, costrafo411, magnetic_scatt, release-4.2.2, ticket-1009, ticket-1094-headless, ticket-1242-2d-resolution, ticket-1243, ticket-1249, ticket885, unittest-saveload
Children:
fca1f50, 17e257b5, f9ba422, 783c1b5
Parents:
a06ee7e (diff), dcb91cf (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Jeff Krzywon <krzywon@…> (08/22/17 14:55:17)
git-committer:
GitHub <noreply@…> (08/22/17 14:55:17)
Message:

Merge pull request #95 from lewisodriscoll/ticket-876

Refactor File Loaders - fixes #889 #950 #849 #876 #922 #983 #970

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/sas/sascalc/dataloader/readers/cansas_reader.py

    r7432acb rdcb91cf  
    1 """ 
    2     CanSAS data reader - new recursive cansas_version. 
    3 """ 
    4 ############################################################################ 
    5 #This software was developed by the University of Tennessee as part of the 
    6 #Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 
    7 #project funded by the US National Science Foundation. 
    8 #If you use DANSE applications to do scientific research that leads to 
    9 #publication, we ask that you acknowledge the use of the software with the 
    10 #following sentence: 
    11 #This work benefited from DANSE software developed under NSF award DMR-0520547. 
    12 #copyright 2008,2009 University of Tennessee 
    13 ############################################################################# 
    14  
    151import logging 
    162import numpy as np 
     
    2915from sas.sascalc.dataloader.readers.xml_reader import XMLreader 
    3016from sas.sascalc.dataloader.readers.cansas_constants import CansasConstants, CurrentLevel 
     17from sas.sascalc.dataloader.loader_exceptions import FileContentsException, \ 
     18    DefaultReaderException, DataReaderException 
    3119 
    3220# The following 2 imports *ARE* used. Do not remove either. 
    3321import xml.dom.minidom 
    3422from xml.dom.minidom import parseString 
     23 
     24from lxml import etree 
    3525 
    3626logger = logging.getLogger(__name__) 
     
    5545 
    5646class Reader(XMLreader): 
    57     """ 
    58     Class to load cansas 1D XML files 
    59  
    60     :Dependencies: 
    61         The CanSAS reader requires PyXML 0.8.4 or later. 
    62     """ 
    63     # CanSAS version - defaults to version 1.0 
    6447    cansas_version = "1.0" 
    6548    base_ns = "{cansas1d/1.0}" 
     
    7558    ns_list = None 
    7659    # Temporary storage location for loading multiple data sets in a single file 
    77     current_datainfo = None 
    78     current_dataset = None 
    7960    current_data1d = None 
    8061    data = None 
    81     # List of data1D objects to be sent back to SasView 
    82     output = None 
    8362    # Wildcards 
    8463    type = ["XML files (*.xml)|*.xml", "SasView Save Files (*.svs)|*.svs"] 
     
    11089 
    11190    def read(self, xml_file, schema_path="", invalid=True): 
    112         """ 
    113         Validate and read in an xml_file file in the canSAS format. 
    114  
    115         :param xml_file: A canSAS file path in proper XML format 
    116         :param schema_path: A file path to an XML schema to validate the xml_file against 
    117         """ 
    118         # For every file loaded, reset everything to a base state 
     91        if schema_path != "" or invalid != True: 
     92            # read has been called from self.get_file_contents because xml file doens't conform to schema 
     93            _, self.extension = os.path.splitext(os.path.basename(xml_file)) 
     94            return self.get_file_contents(xml_file=xml_file, schema_path=schema_path, invalid=invalid) 
     95 
     96        # Otherwise, read has been called by the data loader - file_reader_base_class handles this 
     97        return super(XMLreader, self).read(xml_file) 
     98 
     99    def get_file_contents(self, xml_file=None, schema_path="", invalid=True): 
     100        # Reset everything since we're loading a new file 
    119101        self.reset_state() 
    120102        self.invalid = invalid 
    121         # Check that the file exists 
    122         if os.path.isfile(xml_file): 
    123             basename, extension = os.path.splitext(os.path.basename(xml_file)) 
    124             # If the file type is not allowed, return nothing 
    125             if extension in self.ext or self.allow_all: 
    126                 # Get the file location of 
    127                 self.load_file_and_schema(xml_file, schema_path) 
    128                 self.add_data_set() 
    129                 # Try to load the file, but raise an error if unable to. 
    130                 # Check the file matches the XML schema 
     103        if xml_file is None: 
     104            xml_file = self.f_open.name 
     105        # We don't sure f_open since lxml handles opnening/closing files 
     106        if not self.f_open.closed: 
     107            self.f_open.close() 
     108 
     109        basename, _ = os.path.splitext(os.path.basename(xml_file)) 
     110 
     111        try: 
     112            # Raises FileContentsException 
     113            self.load_file_and_schema(xml_file, schema_path) 
     114            self.current_datainfo = DataInfo() 
     115            # Raises FileContentsException if file doesn't meet CanSAS schema 
     116            self.is_cansas(self.extension) 
     117            self.invalid = False # If we reach this point then file must be valid CanSAS 
     118 
     119            # Parse each SASentry 
     120            entry_list = self.xmlroot.xpath('/ns:SASroot/ns:SASentry', namespaces={ 
     121                'ns': self.cansas_defaults.get("ns") 
     122            }) 
     123            # Look for a SASentry 
     124            self.names.append("SASentry") 
     125            self.set_processing_instructions() 
     126 
     127            for entry in entry_list: 
     128                self.current_datainfo.filename = basename + self.extension 
     129                self.current_datainfo.meta_data["loader"] = "CanSAS XML 1D" 
     130                self.current_datainfo.meta_data[PREPROCESS] = self.processing_instructions 
     131                self._parse_entry(entry) 
     132                has_error_dx = self.current_dataset.dx is not None 
     133                has_error_dy = self.current_dataset.dy is not None 
     134                self.remove_empty_q_values(has_error_dx=has_error_dx, 
     135                    has_error_dy=has_error_dy) 
     136                self.send_to_output() # Combine datasets with DataInfo 
     137                self.current_datainfo = DataInfo() # Reset DataInfo 
     138        except FileContentsException as fc_exc: 
     139            # File doesn't meet schema - try loading with a less strict schema 
     140            base_name = xml_reader.__file__ 
     141            base_name = base_name.replace("\\", "/") 
     142            base = base_name.split("/sas/")[0] 
     143            if self.cansas_version == "1.1": 
     144                invalid_schema = INVALID_SCHEMA_PATH_1_1.format(base, self.cansas_defaults.get("schema")) 
     145            else: 
     146                invalid_schema = INVALID_SCHEMA_PATH_1_0.format(base, self.cansas_defaults.get("schema")) 
     147            self.set_schema(invalid_schema) 
     148            if self.invalid: 
    131149                try: 
    132                     self.is_cansas(extension) 
    133                     self.invalid = False 
    134                     # Get each SASentry from XML file and add it to a list. 
    135                     entry_list = self.xmlroot.xpath( 
    136                             '/ns:SASroot/ns:SASentry', 
    137                             namespaces={'ns': self.cansas_defaults.get("ns")}) 
    138                     self.names.append("SASentry") 
    139  
    140                     # Get all preprocessing events and encoding 
    141                     self.set_processing_instructions() 
    142  
    143                     # Parse each <SASentry> item 
    144                     for entry in entry_list: 
    145                         # Create a new DataInfo object for every <SASentry> 
    146  
    147                         # Set the file name and then parse the entry. 
    148                         self.current_datainfo.filename = basename + extension 
    149                         self.current_datainfo.meta_data["loader"] = "CanSAS XML 1D" 
    150                         self.current_datainfo.meta_data[PREPROCESS] = \ 
    151                             self.processing_instructions 
    152  
    153                         # Parse the XML SASentry 
    154                         self._parse_entry(entry) 
    155                         # Combine datasets with datainfo 
    156                         self.add_data_set() 
    157                 except RuntimeError: 
    158                     # If the file does not match the schema, raise this error 
     150                    # Load data with less strict schema 
     151                    self.read(xml_file, invalid_schema, False) 
     152 
     153                    # File can still be read but doesn't match schema, so raise exception 
     154                    self.load_file_and_schema(xml_file) # Reload strict schema so we can find where error are in file 
    159155                    invalid_xml = self.find_invalid_xml() 
    160                     invalid_xml = INVALID_XML.format(basename + extension) + invalid_xml 
    161                     self.errors.add(invalid_xml) 
    162                     # Try again with an invalid CanSAS schema, that requires only a data set in each 
    163                     base_name = xml_reader.__file__ 
    164                     base_name = base_name.replace("\\", "/") 
    165                     base = base_name.split("/sas/")[0] 
    166                     if self.cansas_version == "1.1": 
    167                         invalid_schema = INVALID_SCHEMA_PATH_1_1.format(base, self.cansas_defaults.get("schema")) 
    168                     else: 
    169                         invalid_schema = INVALID_SCHEMA_PATH_1_0.format(base, self.cansas_defaults.get("schema")) 
    170                     self.set_schema(invalid_schema) 
    171                     try: 
    172                         if self.invalid: 
    173                             if self.is_cansas(): 
    174                                 self.output = self.read(xml_file, invalid_schema, False) 
    175                             else: 
    176                                 raise RuntimeError 
    177                         else: 
    178                             raise RuntimeError 
    179                     except RuntimeError: 
    180                         x = np.zeros(1) 
    181                         y = np.zeros(1) 
    182                         self.current_data1d = Data1D(x,y) 
    183                         self.current_data1d.errors = self.errors 
    184                         return [self.current_data1d] 
    185         else: 
    186             self.output.append("Not a valid file path.") 
    187         # Return a list of parsed entries that dataloader can manage 
    188         return self.output 
     156                    invalid_xml = INVALID_XML.format(basename + self.extension) + invalid_xml 
     157                    raise DataReaderException(invalid_xml) # Handled by base class 
     158                except FileContentsException as fc_exc: 
     159                    msg = "CanSAS Reader could not load the file {}".format(xml_file) 
     160                    if fc_exc.message is not None: # Propagate error messages from earlier 
     161                        msg = fc_exc.message 
     162                    if not self.extension in self.ext: # If the file has no associated loader 
     163                        raise DefaultReaderException(msg) 
     164                    raise FileContentsException(msg) 
     165                    pass 
     166            else: 
     167                raise fc_exc 
     168        except Exception as e: # Convert all other exceptions to FileContentsExceptions 
     169            raise FileContentsException(e.message) 
     170 
     171 
     172    def load_file_and_schema(self, xml_file, schema_path=""): 
     173        base_name = xml_reader.__file__ 
     174        base_name = base_name.replace("\\", "/") 
     175        base = base_name.split("/sas/")[0] 
     176 
     177        # Try and parse the XML file 
     178        try: 
     179            self.set_xml_file(xml_file) 
     180        except etree.XMLSyntaxError: # File isn't valid XML so can't be loaded 
     181            msg = "SasView cannot load {}.\nInvalid XML syntax".format(xml_file) 
     182            raise FileContentsException(msg) 
     183 
     184        self.cansas_version = self.xmlroot.get("version", "1.0") 
     185        self.cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0") 
     186 
     187        if schema_path == "": 
     188            schema_path = "{}/sas/sascalc/dataloader/readers/schema/{}".format( 
     189                base, self.cansas_defaults.get("schema").replace("\\", "/") 
     190            ) 
     191        self.set_schema(schema_path) 
     192 
     193    def is_cansas(self, ext="xml"): 
     194        """ 
     195        Checks to see if the XML file is a CanSAS file 
     196 
     197        :param ext: The file extension of the data file 
     198        :raises FileContentsException: Raised if XML file isn't valid CanSAS 
     199        """ 
     200        if self.validate_xml(): # Check file is valid XML 
     201            name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation" 
     202            value = self.xmlroot.get(name) 
     203            # Check schema CanSAS version matches file CanSAS version 
     204            if CANSAS_NS.get(self.cansas_version).get("ns") == value.rsplit(" ")[0]: 
     205                return True 
     206        if ext == "svs": 
     207            return True # Why is this required? 
     208        # If we get to this point then file isn't valid CanSAS 
     209        logger.warning("File doesn't meet CanSAS schema. Trying to load anyway.") 
     210        raise FileContentsException("The file is not valid CanSAS") 
    189211 
    190212    def _parse_entry(self, dom, recurse=False): 
    191         """ 
    192         Parse a SASEntry - new recursive method for parsing the dom of 
    193             the CanSAS data format. This will allow multiple data files 
    194             and extra nodes to be read in simultaneously. 
    195  
    196         :param dom: dom object with a namespace base of names 
    197         """ 
    198  
    199213        if not self._is_call_local() and not recurse: 
    200214            self.reset_state() 
    201             self.add_data_set() 
     215            self.data = [] 
     216            self.current_datainfo = DataInfo() 
    202217            self.names.append("SASentry") 
    203218            self.parent_class = "SASentry" 
    204         self._check_for_empty_data() 
    205         self.base_ns = "{0}{1}{2}".format("{", \ 
    206                             CANSAS_NS.get(self.cansas_version).get("ns"), "}") 
    207  
    208         # Go through each child in the parent element 
     219        # Create an empty dataset if no data has been passed to the reader 
     220        if self.current_dataset is None: 
     221            self.current_dataset = plottable_1D(np.empty(0), np.empty(0), 
     222                np.empty(0), np.empty(0)) 
     223        self.base_ns = "{" + CANSAS_NS.get(self.cansas_version).get("ns") + "}" 
     224 
     225        # Loop through each child in the parent element 
    209226        for node in dom: 
    210227            attr = node.attrib 
     
    217234            if tagname == "fitting_plug_in" or tagname == "pr_inversion" or tagname == "invariant": 
    218235                continue 
    219  
    220236            # Get where to store content 
    221237            self.names.append(tagname_original) 
     
    233249                        else: 
    234250                            self.current_dataset.shape = () 
    235                 # Recursion step to access data within the group 
    236                 self._parse_entry(node, True) 
     251                # Recurse to access data within the group 
     252                self._parse_entry(node, recurse=True) 
    237253                if tagname == "SASsample": 
    238254                    self.current_datainfo.sample.name = name 
     
    244260                    self.aperture.name = name 
    245261                    self.aperture.type = type 
    246                 self.add_intermediate() 
     262                self._add_intermediate() 
    247263            else: 
    248264                if isinstance(self.current_dataset, plottable_2D): 
     
    261277                    self.current_datainfo.notes.append(data_point) 
    262278 
    263                 # I and Q - 1D data 
     279                # I and Q points 
    264280                elif tagname == 'I' and isinstance(self.current_dataset, plottable_1D): 
    265281                    unit_list = unit.split("|") 
     
    283299                    self.current_dataset.dx = np.append(self.current_dataset.dx, data_point) 
    284300                elif tagname == 'dQw': 
     301                    if self.current_dataset.dqw is None: self.current_dataset.dqw = np.empty(0) 
    285302                    self.current_dataset.dxw = np.append(self.current_dataset.dxw, data_point) 
    286303                elif tagname == 'dQl': 
     304                    if self.current_dataset.dxl is None: self.current_dataset.dxl = np.empty(0) 
    287305                    self.current_dataset.dxl = np.append(self.current_dataset.dxl, data_point) 
    288306                elif tagname == 'Qmean': 
     
    356374                elif tagname == 'name' and self.parent_class == 'SASinstrument': 
    357375                    self.current_datainfo.instrument = data_point 
     376 
    358377                # Detector Information 
    359378                elif tagname == 'name' and self.parent_class == 'SASdetector': 
     
    401420                    self.detector.orientation.z = data_point 
    402421                    self.detector.orientation_unit = unit 
     422 
    403423                # Collimation and Aperture 
    404424                elif tagname == 'length' and self.parent_class == 'SAScollimation': 
     
    434454                elif tagname == 'term' and self.parent_class == 'SASprocess': 
    435455                    unit = attr.get("unit", "") 
    436                     dic = {} 
    437                     dic["name"] = name 
    438                     dic["value"] = data_point 
    439                     dic["unit"] = unit 
     456                    dic = { "name": name, "value": data_point, "unit": unit } 
    440457                    self.process.term.append(dic) 
    441458 
     
    490507        if not self._is_call_local() and not recurse: 
    491508            self.frm = "" 
    492             self.add_data_set() 
     509            self.current_datainfo.errors = set() 
     510            for error in self.errors: 
     511                self.current_datainfo.errors.add(error) 
     512            self.errors.clear() 
     513            self.send_to_output() 
    493514            empty = None 
    494515            return self.output[0], empty 
    495516 
    496  
    497517    def _is_call_local(self): 
    498         """ 
    499  
    500         """ 
    501518        if self.frm == "": 
    502519            inter = inspect.stack() 
     
    510527        return True 
    511528 
    512     def is_cansas(self, ext="xml"): 
    513         """ 
    514         Checks to see if the xml file is a CanSAS file 
    515  
    516         :param ext: The file extension of the data file 
    517         """ 
    518         if self.validate_xml(): 
    519             name = "{http://www.w3.org/2001/XMLSchema-instance}schemaLocation" 
    520             value = self.xmlroot.get(name) 
    521             if CANSAS_NS.get(self.cansas_version).get("ns") == \ 
    522                     value.rsplit(" ")[0]: 
    523                 return True 
    524         if ext == "svs": 
    525             return True 
    526         raise RuntimeError 
    527  
    528     def load_file_and_schema(self, xml_file, schema_path=""): 
    529         """ 
    530         Loads the file and associates a schema, if a schema is passed in or if one already exists 
    531  
    532         :param xml_file: The xml file path sent to Reader.read 
    533         :param schema_path: The path to a schema associated with the xml_file, or find one based on the file 
    534         """ 
    535         base_name = xml_reader.__file__ 
    536         base_name = base_name.replace("\\", "/") 
    537         base = base_name.split("/sas/")[0] 
    538  
    539         # Load in xml file and get the cansas version from the header 
    540         self.set_xml_file(xml_file) 
    541         self.cansas_version = self.xmlroot.get("version", "1.0") 
    542  
    543         # Generic values for the cansas file based on the version 
    544         self.cansas_defaults = CANSAS_NS.get(self.cansas_version, "1.0") 
    545         if schema_path == "": 
    546             schema_path = "{0}/sas/sascalc/dataloader/readers/schema/{1}".format \ 
    547                 (base, self.cansas_defaults.get("schema")).replace("\\", "/") 
    548  
    549         # Link a schema to the XML file. 
    550         self.set_schema(schema_path) 
    551  
    552     def add_data_set(self): 
    553         """ 
    554         Adds the current_dataset to the list of outputs after preforming final processing on the data and then calls a 
    555         private method to generate a new data set. 
    556  
    557         :param key: NeXus group name for current tree level 
    558         """ 
    559  
    560         if self.current_datainfo and self.current_dataset: 
    561             self._final_cleanup() 
    562         self.data = [] 
    563         self.current_datainfo = DataInfo() 
    564  
    565     def _initialize_new_data_set(self, node=None): 
    566         """ 
    567         A private class method to generate a new 1D data object. 
    568         Outside methods should call add_data_set() to be sure any existing data is stored properly. 
    569  
    570         :param node: XML node to determine if 1D or 2D data 
    571         """ 
    572         x = np.array(0) 
    573         y = np.array(0) 
    574         for child in node: 
    575             if child.tag.replace(self.base_ns, "") == "Idata": 
    576                 for i_child in child: 
    577                     if i_child.tag.replace(self.base_ns, "") == "Qx": 
    578                         self.current_dataset = plottable_2D() 
    579                         return 
    580         self.current_dataset = plottable_1D(x, y) 
    581  
    582     def add_intermediate(self): 
     529    def _add_intermediate(self): 
    583530        """ 
    584531        This method stores any intermediate objects within the final data set after fully reading the set. 
    585  
    586         :param parent: The NXclass name for the h5py Group object that just finished being processed 
    587         """ 
    588  
     532        """ 
    589533        if self.parent_class == 'SASprocess': 
    590534            self.current_datainfo.process.append(self.process) 
     
    605549            self._check_for_empty_resolution() 
    606550            self.data.append(self.current_dataset) 
    607  
    608     def _final_cleanup(self): 
    609         """ 
    610         Final cleanup of the Data1D object to be sure it has all the 
    611         appropriate information needed for perspectives 
    612         """ 
    613  
    614         # Append errors to dataset and reset class errors 
    615         self.current_datainfo.errors = set() 
    616         for error in self.errors: 
    617             self.current_datainfo.errors.add(error) 
    618         self.errors.clear() 
    619  
    620         # Combine all plottables with datainfo and append each to output 
    621         # Type cast data arrays to float64 and find min/max as appropriate 
    622         for dataset in self.data: 
    623             if isinstance(dataset, plottable_1D): 
    624                 if dataset.x is not None: 
    625                     dataset.x = np.delete(dataset.x, [0]) 
    626                     dataset.x = dataset.x.astype(np.float64) 
    627                     dataset.xmin = np.min(dataset.x) 
    628                     dataset.xmax = np.max(dataset.x) 
    629                 if dataset.y is not None: 
    630                     dataset.y = np.delete(dataset.y, [0]) 
    631                     dataset.y = dataset.y.astype(np.float64) 
    632                     dataset.ymin = np.min(dataset.y) 
    633                     dataset.ymax = np.max(dataset.y) 
    634                 if dataset.dx is not None: 
    635                     dataset.dx = np.delete(dataset.dx, [0]) 
    636                     dataset.dx = dataset.dx.astype(np.float64) 
    637                 if dataset.dxl is not None: 
    638                     dataset.dxl = np.delete(dataset.dxl, [0]) 
    639                     dataset.dxl = dataset.dxl.astype(np.float64) 
    640                 if dataset.dxw is not None: 
    641                     dataset.dxw = np.delete(dataset.dxw, [0]) 
    642                     dataset.dxw = dataset.dxw.astype(np.float64) 
    643                 if dataset.dy is not None: 
    644                     dataset.dy = np.delete(dataset.dy, [0]) 
    645                     dataset.dy = dataset.dy.astype(np.float64) 
    646                 np.trim_zeros(dataset.x) 
    647                 np.trim_zeros(dataset.y) 
    648                 np.trim_zeros(dataset.dy) 
    649             elif isinstance(dataset, plottable_2D): 
    650                 dataset.data = dataset.data.astype(np.float64) 
    651                 dataset.qx_data = dataset.qx_data.astype(np.float64) 
    652                 dataset.xmin = np.min(dataset.qx_data) 
    653                 dataset.xmax = np.max(dataset.qx_data) 
    654                 dataset.qy_data = dataset.qy_data.astype(np.float64) 
    655                 dataset.ymin = np.min(dataset.qy_data) 
    656                 dataset.ymax = np.max(dataset.qy_data) 
    657                 dataset.q_data = np.sqrt(dataset.qx_data * dataset.qx_data 
    658                                          + dataset.qy_data * dataset.qy_data) 
    659                 if dataset.err_data is not None: 
    660                     dataset.err_data = dataset.err_data.astype(np.float64) 
    661                 if dataset.dqx_data is not None: 
    662                     dataset.dqx_data = dataset.dqx_data.astype(np.float64) 
    663                 if dataset.dqy_data is not None: 
    664                     dataset.dqy_data = dataset.dqy_data.astype(np.float64) 
    665                 if dataset.mask is not None: 
    666                     dataset.mask = dataset.mask.astype(dtype=bool) 
    667  
    668                 if len(dataset.shape) == 2: 
    669                     n_rows, n_cols = dataset.shape 
    670                     dataset.y_bins = dataset.qy_data[0::int(n_cols)] 
    671                     dataset.x_bins = dataset.qx_data[:int(n_cols)] 
    672                     dataset.data = dataset.data.flatten() 
    673                 else: 
    674                     dataset.y_bins = [] 
    675                     dataset.x_bins = [] 
    676                     dataset.data = dataset.data.flatten() 
    677  
    678             final_dataset = combine_data(dataset, self.current_datainfo) 
    679             self.output.append(final_dataset) 
    680  
    681     def _create_unique_key(self, dictionary, name, numb=0): 
    682         """ 
    683         Create a unique key value for any dictionary to prevent overwriting 
    684         Recurse until a unique key value is found. 
    685  
    686         :param dictionary: A dictionary with any number of entries 
    687         :param name: The index of the item to be added to dictionary 
    688         :param numb: The number to be appended to the name, starts at 0 
    689         """ 
    690         if dictionary.get(name) is not None: 
    691             numb += 1 
    692             name = name.split("_")[0] 
    693             name += "_{0}".format(numb) 
    694             name = self._create_unique_key(dictionary, name, numb) 
    695         return name 
    696551 
    697552    def _get_node_value(self, node, tagname): 
     
    801656        return node_value, value_unit 
    802657 
    803     def _check_for_empty_data(self): 
    804         """ 
    805         Creates an empty data set if no data is passed to the reader 
    806  
    807         :param data1d: presumably a Data1D object 
    808         """ 
    809         if self.current_dataset is None: 
    810             x_vals = np.empty(0) 
    811             y_vals = np.empty(0) 
    812             dx_vals = np.empty(0) 
    813             dy_vals = np.empty(0) 
    814             dxl = np.empty(0) 
    815             dxw = np.empty(0) 
    816             self.current_dataset = plottable_1D(x_vals, y_vals, dx_vals, dy_vals) 
    817             self.current_dataset.dxl = dxl 
    818             self.current_dataset.dxw = dxw 
    819  
    820658    def _check_for_empty_resolution(self): 
    821659        """ 
    822         A method to check all resolution data sets are the same size as I and Q 
    823         """ 
    824         if isinstance(self.current_dataset, plottable_1D): 
    825             dql_exists = False 
    826             dqw_exists = False 
    827             dq_exists = False 
    828             di_exists = False 
    829             if self.current_dataset.dxl is not None: 
    830                 dql_exists = True 
    831             if self.current_dataset.dxw is not None: 
    832                 dqw_exists = True 
    833             if self.current_dataset.dx is not None: 
    834                 dq_exists = True 
    835             if self.current_dataset.dy is not None: 
    836                 di_exists = True 
    837             if dqw_exists and not dql_exists: 
    838                 array_size = self.current_dataset.dxw.size - 1 
    839                 self.current_dataset.dxl = np.append(self.current_dataset.dxl, 
    840                                                      np.zeros([array_size])) 
    841             elif dql_exists and not dqw_exists: 
    842                 array_size = self.current_dataset.dxl.size - 1 
    843                 self.current_dataset.dxw = np.append(self.current_dataset.dxw, 
    844                                                      np.zeros([array_size])) 
    845             elif not dql_exists and not dqw_exists and not dq_exists: 
    846                 array_size = self.current_dataset.x.size - 1 
    847                 self.current_dataset.dx = np.append(self.current_dataset.dx, 
    848                                                     np.zeros([array_size])) 
    849             if not di_exists: 
    850                 array_size = self.current_dataset.y.size - 1 
    851                 self.current_dataset.dy = np.append(self.current_dataset.dy, 
    852                                                     np.zeros([array_size])) 
    853         elif isinstance(self.current_dataset, plottable_2D): 
    854             dqx_exists = False 
    855             dqy_exists = False 
    856             di_exists = False 
    857             mask_exists = False 
    858             if self.current_dataset.dqx_data is not None: 
    859                 dqx_exists = True 
    860             if self.current_dataset.dqy_data is not None: 
    861                 dqy_exists = True 
    862             if self.current_dataset.err_data is not None: 
    863                 di_exists = True 
    864             if self.current_dataset.mask is not None: 
    865                 mask_exists = True 
    866             if not dqy_exists: 
    867                 array_size = self.current_dataset.qy_data.size - 1 
    868                 self.current_dataset.dqy_data = np.append( 
    869                     self.current_dataset.dqy_data, np.zeros([array_size])) 
    870             if not dqx_exists: 
    871                 array_size = self.current_dataset.qx_data.size - 1 
    872                 self.current_dataset.dqx_data = np.append( 
    873                     self.current_dataset.dqx_data, np.zeros([array_size])) 
    874             if not di_exists: 
    875                 array_size = self.current_dataset.data.size - 1 
    876                 self.current_dataset.err_data = np.append( 
    877                     self.current_dataset.err_data, np.zeros([array_size])) 
    878             if not mask_exists: 
    879                 array_size = self.current_dataset.data.size - 1 
    880                 self.current_dataset.mask = np.append( 
    881                     self.current_dataset.mask, 
    882                     np.ones([array_size] ,dtype=bool)) 
    883  
    884     ####### All methods below are for writing CanSAS XML files ####### 
    885  
     660        a method to check all resolution data sets are the same size as I and q 
     661        """ 
     662        dql_exists = False 
     663        dqw_exists = False 
     664        dq_exists = False 
     665        di_exists = False 
     666        if self.current_dataset.dxl is not None: 
     667            dql_exists = True 
     668        if self.current_dataset.dxw is not None: 
     669            dqw_exists = True 
     670        if self.current_dataset.dx is not None: 
     671            dq_exists = True 
     672        if self.current_dataset.dy is not None: 
     673            di_exists = True 
     674        if dqw_exists and not dql_exists: 
     675            array_size = self.current_dataset.dxw.size - 1 
     676            self.current_dataset.dxl = np.append(self.current_dataset.dxl, 
     677                                                 np.zeros([array_size])) 
     678        elif dql_exists and not dqw_exists: 
     679            array_size = self.current_dataset.dxl.size - 1 
     680            self.current_dataset.dxw = np.append(self.current_dataset.dxw, 
     681                                                 np.zeros([array_size])) 
     682        elif not dql_exists and not dqw_exists and not dq_exists: 
     683            array_size = self.current_dataset.x.size - 1 
     684            self.current_dataset.dx = np.append(self.current_dataset.dx, 
     685                                                np.zeros([array_size])) 
     686        if not di_exists: 
     687            array_size = self.current_dataset.y.size - 1 
     688            self.current_dataset.dy = np.append(self.current_dataset.dy, 
     689                                                np.zeros([array_size])) 
     690 
     691    def _initialize_new_data_set(self, node=None): 
     692        if node is not None: 
     693            for child in node: 
     694                if child.tag.replace(self.base_ns, "") == "Idata": 
     695                    for i_child in child: 
     696                        if i_child.tag.replace(self.base_ns, "") == "Qx": 
     697                            self.current_dataset = plottable_2D() 
     698                            return 
     699        self.current_dataset = plottable_1D(np.array(0), np.array(0)) 
     700 
     701    ## Writing Methods 
    886702    def write(self, filename, datainfo): 
    887703        """ 
     
    15141330            exec "storage.%s = entry.text.strip()" % variable 
    15151331 
    1516  
    15171332# DO NOT REMOVE Called by outside packages: 
    15181333#    sas.sasgui.perspectives.invariant.invariant_state 
Note: See TracChangeset for help on using the changeset viewer.