source: sasview/src/sas/sascalc/dataloader/readers/cansas_reader_HDF5.py @ de43192

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since de43192 was 61f329f0, checked in by krzywon, 7 years ago

Reset file reader class data state each time a new data file is loaded.

  • Property mode set to 100644
File size: 26.9 KB
RevLine 
[68aa210]1"""
2    CanSAS 2D data reader for reading HDF5 formatted CanSAS files.
3"""
4
5import h5py
6import numpy as np
7import re
8import os
9import sys
10
[7b50f14]11from ..data_info import plottable_1D, plottable_2D,\
[082239e]12    Data1D, Data2D, DataInfo, Process, Aperture, Collimation, \
13    TransmissionSpectrum, Detector
[7b50f14]14from ..data_info import combine_data_info_with_plottable
15from ..loader_exceptions import FileContentsException, DefaultReaderException
16from ..file_reader_base_class import FileReader, decode
[5c5e7fd]17
18def h5attr(node, key, default=None):
19    return decode(node.attrs.get(key, default))
[68aa210]20
[9d786e5]21class Reader(FileReader):
[68aa210]22    """
[082239e]23    A class for reading in CanSAS v2.0 data files. The existing iteration opens
24    Mantid generated HDF5 formatted files with file extension .h5/.H5. Any
25    number of data sets may be present within the file and any dimensionality
26    of data may be used. Currently 1D and 2D SAS data sets are supported, but
27    future implementations will include 1D and 2D SESANS data.
[d72567e]28
[082239e]29    Any number of SASdata sets may be present in a SASentry and the data within
30    can be either 1D I(Q) or 2D I(Qx, Qy).
[68aa210]31
[5e906207]32    Also supports reading NXcanSAS formatted HDF5 files
33
[68aa210]34    :Dependencies:
[d72567e]35        The CanSAS HDF5 reader requires h5py => v2.5.0 or later.
[68aa210]36    """
37
[082239e]38    # CanSAS version
[68aa210]39    cansas_version = 2.0
[082239e]40    # Logged warnings or messages
[68aa210]41    logging = None
[082239e]42    # List of errors for the current data set
[68aa210]43    errors = None
[082239e]44    # Raw file contents to be processed
[68aa210]45    raw_data = None
[082239e]46    # List of plottable1D objects that should be linked to the current_datainfo
[d72567e]47    data1d = None
[082239e]48    # List of plottable2D objects that should be linked to the current_datainfo
[d72567e]49    data2d = None
[082239e]50    # Data type name
[ad52d31]51    type_name = "CanSAS 2.0"
[082239e]52    # Wildcards
[ad52d31]53    type = ["CanSAS 2.0 HDF5 Files (*.h5)|*.h5"]
[082239e]54    # List of allowed extensions
[68aa210]55    ext = ['.h5', '.H5']
[082239e]56    # Flag to bypass extension check
[54544637]57    allow_all = True
[68aa210]58
[9d786e5]59    def get_file_contents(self):
[68aa210]60        """
[ad52d31]61        This is the general read method that all SasView data_loaders must have.
[68aa210]62
63        :param filename: A path for an HDF5 formatted CanSAS 2D data file.
[d72567e]64        :return: List of Data1D/2D objects and/or a list of errors.
[68aa210]65        """
[082239e]66        # Reinitialize when loading a new data file to reset all class variables
[61f329f0]67        self.reset_state()
[9d786e5]68
69        filename = self.f_open.name
70        self.f_open.close() # IO handled by h5py
71
[082239e]72        # Check that the file exists
[68aa210]73        if os.path.isfile(filename):
74            basename = os.path.basename(filename)
75            _, extension = os.path.splitext(basename)
76            # If the file type is not allowed, return empty list
77            if extension in self.ext or self.allow_all:
[082239e]78                # Load the data file
[7f75a3f]79                try:
80                    self.raw_data = h5py.File(filename, 'r')
81                except Exception as e:
[8dec7e7]82                    if extension not in self.ext:
83                        msg = "CanSAS2.0 HDF5 Reader could not load file {}".format(basename + extension)
84                        raise DefaultReaderException(msg)
85                    raise FileContentsException(e.message)
[dcb91cf]86                try:
87                    # Read in all child elements of top level SASroot
88                    self.read_children(self.raw_data, [])
89                    # Add the last data set to the list of outputs
90                    self.add_data_set()
91                except Exception as exc:
92                    raise FileContentsException(exc.message)
93                finally:
94                    # Close the data file
95                    self.raw_data.close()
96
97                for dataset in self.output:
98                    if isinstance(dataset, Data1D):
99                        if dataset.x.size < 5:
100                            self.output = []
101                            raise FileContentsException("Fewer than 5 data points found.")
[68aa210]102
[61f329f0]103    def reset_state(self):
[d72567e]104        """
105        Create the reader object and define initial states for class variables
106        """
[61f329f0]107        super(Reader, self).reset_state()
[d72567e]108        self.data1d = []
109        self.data2d = []
110        self.raw_data = None
111        self.errors = set()
112        self.logging = []
113        self.parent_class = u''
114        self.detector = Detector()
115        self.collimation = Collimation()
116        self.aperture = Aperture()
117        self.process = Process()
118        self.trans_spectrum = TransmissionSpectrum()
119
120    def read_children(self, data, parent_list):
[68aa210]121        """
[ad52d31]122        A recursive method for stepping through the hierarchical data file.
[68aa210]123
124        :param data: h5py Group object of any kind
125        :param parent: h5py Group parent name
126        """
127
[082239e]128        # Loop through each element of the parent and process accordingly
[68aa210]129        for key in data.keys():
[082239e]130            # Get all information for the current key
[68aa210]131            value = data.get(key)
[7b50f14]132            class_name = h5attr(value, u'canSAS_class')
133            if class_name is None:
[5c5e7fd]134                class_name = h5attr(value, u'NX_class')
[68aa210]135            if class_name is not None:
136                class_prog = re.compile(class_name)
137            else:
138                class_prog = re.compile(value.name)
139
140            if isinstance(value, h5py.Group):
[c9ecd1b]141                # Set parent class before recursion
[d72567e]142                self.parent_class = class_name
143                parent_list.append(key)
[082239e]144                # If a new sasentry, store the current data sets and create
145                # a fresh Data1D/2D object
[68aa210]146                if class_prog.match(u'SASentry'):
147                    self.add_data_set(key)
[d72567e]148                elif class_prog.match(u'SASdata'):
149                    self._initialize_new_data_set(parent_list)
[082239e]150                # Recursion step to access data within the group
[d72567e]151                self.read_children(value, parent_list)
[c9ecd1b]152                # Reset parent class when returning from recursive method
153                self.parent_class = class_name
[d72567e]154                self.add_intermediate()
155                parent_list.remove(key)
[68aa210]156
157            elif isinstance(value, h5py.Dataset):
[082239e]158                # If this is a dataset, store the data appropriately
[68aa210]159                data_set = data[key][:]
[7bd6860a]160                unit = self._get_unit(value)
[ac370c5]161
[082239e]162                # I and Q Data
[7bd6860a]163                if key == u'I':
[082239e]164                    if isinstance(self.current_dataset, plottable_2D):
[ac370c5]165                        self.current_dataset.data = data_set
[7bd6860a]166                        self.current_dataset.zaxis("Intensity", unit)
167                    else:
168                        self.current_dataset.y = data_set.flatten()
169                        self.current_dataset.yaxis("Intensity", unit)
170                    continue
171                elif key == u'Idev':
[082239e]172                    if isinstance(self.current_dataset, plottable_2D):
[7bd6860a]173                        self.current_dataset.err_data = data_set.flatten()
174                    else:
175                        self.current_dataset.dy = data_set.flatten()
176                    continue
177                elif key == u'Q':
178                    self.current_dataset.xaxis("Q", unit)
[082239e]179                    if isinstance(self.current_dataset, plottable_2D):
[7bd6860a]180                        self.current_dataset.q = data_set.flatten()
181                    else:
182                        self.current_dataset.x = data_set.flatten()
183                    continue
[bbd0f37]184                elif key == u'Qdev':
185                    self.current_dataset.dx = data_set.flatten()
186                    continue
[082239e]187                elif key == u'dQw':
188                    self.current_dataset.dxw = data_set.flatten()
189                    continue
190                elif key == u'dQl':
191                    self.current_dataset.dxl = data_set.flatten()
192                    continue
[7bd6860a]193                elif key == u'Qy':
194                    self.current_dataset.yaxis("Q_y", unit)
195                    self.current_dataset.qy_data = data_set.flatten()
196                    continue
197                elif key == u'Qydev':
198                    self.current_dataset.dqy_data = data_set.flatten()
199                    continue
200                elif key == u'Qx':
201                    self.current_dataset.xaxis("Q_x", unit)
202                    self.current_dataset.qx_data = data_set.flatten()
203                    continue
204                elif key == u'Qxdev':
205                    self.current_dataset.dqx_data = data_set.flatten()
206                    continue
207                elif key == u'Mask':
208                    self.current_dataset.mask = data_set.flatten()
209                    continue
[082239e]210                # Transmission Spectrum
[c94280c]211                elif (key == u'T'
212                      and self.parent_class == u'SAStransmission_spectrum'):
[082239e]213                    self.trans_spectrum.transmission = data_set.flatten()
214                    continue
[c94280c]215                elif (key == u'Tdev'
216                      and self.parent_class == u'SAStransmission_spectrum'):
[082239e]217                    self.trans_spectrum.transmission_deviation = \
218                        data_set.flatten()
219                    continue
[c94280c]220                elif (key == u'lambda'
221                      and self.parent_class == u'SAStransmission_spectrum'):
[082239e]222                    self.trans_spectrum.wavelength = data_set.flatten()
223                    continue
[68aa210]224
225                for data_point in data_set:
[2b538cd]226                    if isinstance(data_point, np.ndarray):
227                        if data_point.dtype.char == 'S':
228                            data_point = decode(bytes(data_point))
229                    else:
230                        data_point = decode(data_point)
[082239e]231                    # Top Level Meta Data
[68aa210]232                    if key == u'definition':
[d72567e]233                        self.current_datainfo.meta_data['reader'] = data_point
[68aa210]234                    elif key == u'run':
[d72567e]235                        self.current_datainfo.run.append(data_point)
[be88076]236                        try:
[5c5e7fd]237                            run_name = h5attr(value, 'name')
[be88076]238                            run_dict = {data_point: run_name}
239                            self.current_datainfo.run_name = run_dict
[7b50f14]240                        except Exception:
[be88076]241                            pass
[68aa210]242                    elif key == u'title':
[d72567e]243                        self.current_datainfo.title = data_point
[68aa210]244                    elif key == u'SASnote':
[d72567e]245                        self.current_datainfo.notes.append(data_point)
[68aa210]246
[082239e]247                    # Sample Information
248                    # CanSAS 2.0 format
249                    elif key == u'Title' and self.parent_class == u'SASsample':
[d72567e]250                        self.current_datainfo.sample.name = data_point
[082239e]251                    # NXcanSAS format
252                    elif key == u'name' and self.parent_class == u'SASsample':
[88d85c6]253                        self.current_datainfo.sample.name = data_point
[082239e]254                    # NXcanSAS format
255                    elif key == u'ID' and self.parent_class == u'SASsample':
256                        self.current_datainfo.sample.name = data_point
[c94280c]257                    elif (key == u'thickness'
258                          and self.parent_class == u'SASsample'):
[d72567e]259                        self.current_datainfo.sample.thickness = data_point
[c94280c]260                    elif (key == u'temperature'
261                          and self.parent_class == u'SASsample'):
[d72567e]262                        self.current_datainfo.sample.temperature = data_point
[c94280c]263                    elif (key == u'transmission'
264                          and self.parent_class == u'SASsample'):
[5e906207]265                        self.current_datainfo.sample.transmission = data_point
[c94280c]266                    elif (key == u'x_position'
267                          and self.parent_class == u'SASsample'):
[5e906207]268                        self.current_datainfo.sample.position.x = data_point
[c94280c]269                    elif (key == u'y_position'
270                          and self.parent_class == u'SASsample'):
[5e906207]271                        self.current_datainfo.sample.position.y = data_point
[082239e]272                    elif key == u'pitch' and self.parent_class == u'SASsample':
[5e906207]273                        self.current_datainfo.sample.orientation.x = data_point
[082239e]274                    elif key == u'yaw' and self.parent_class == u'SASsample':
275                        self.current_datainfo.sample.orientation.y = data_point
276                    elif key == u'roll' and self.parent_class == u'SASsample':
[5e906207]277                        self.current_datainfo.sample.orientation.z = data_point
[c94280c]278                    elif (key == u'details'
279                          and self.parent_class == u'SASsample'):
[5e906207]280                        self.current_datainfo.sample.details.append(data_point)
[68aa210]281
[082239e]282                    # Instrumental Information
[c94280c]283                    elif (key == u'name'
284                          and self.parent_class == u'SASinstrument'):
[d72567e]285                        self.current_datainfo.instrument = data_point
286                    elif key == u'name' and self.parent_class == u'SASdetector':
[ad52d31]287                        self.detector.name = data_point
[d72567e]288                    elif key == u'SDD' and self.parent_class == u'SASdetector':
289                        self.detector.distance = float(data_point)
[d398285]290                        self.detector.distance_unit = unit
[c94280c]291                    elif (key == u'slit_length'
292                          and self.parent_class == u'SASdetector'):
[5e906207]293                        self.detector.slit_length = float(data_point)
294                        self.detector.slit_length_unit = unit
[c94280c]295                    elif (key == u'x_position'
296                          and self.parent_class == u'SASdetector'):
[5e906207]297                        self.detector.offset.x = float(data_point)
298                        self.detector.offset_unit = unit
[c94280c]299                    elif (key == u'y_position'
300                          and self.parent_class == u'SASdetector'):
[5e906207]301                        self.detector.offset.y = float(data_point)
302                        self.detector.offset_unit = unit
[c94280c]303                    elif (key == u'pitch'
304                          and self.parent_class == u'SASdetector'):
[5e906207]305                        self.detector.orientation.x = float(data_point)
306                        self.detector.orientation_unit = unit
[082239e]307                    elif key == u'roll' and self.parent_class == u'SASdetector':
[5e906207]308                        self.detector.orientation.z = float(data_point)
309                        self.detector.orientation_unit = unit
[082239e]310                    elif key == u'yaw' and self.parent_class == u'SASdetector':
311                        self.detector.orientation.y = float(data_point)
312                        self.detector.orientation_unit = unit
[c94280c]313                    elif (key == u'beam_center_x'
314                          and self.parent_class == u'SASdetector'):
[5e906207]315                        self.detector.beam_center.x = float(data_point)
316                        self.detector.beam_center_unit = unit
[c94280c]317                    elif (key == u'beam_center_y'
318                          and self.parent_class == u'SASdetector'):
[5e906207]319                        self.detector.beam_center.y = float(data_point)
320                        self.detector.beam_center_unit = unit
[c94280c]321                    elif (key == u'x_pixel_size'
322                          and self.parent_class == u'SASdetector'):
[5e906207]323                        self.detector.pixel_size.x = float(data_point)
324                        self.detector.pixel_size_unit = unit
[c94280c]325                    elif (key == u'y_pixel_size'
326                          and self.parent_class == u'SASdetector'):
[5e906207]327                        self.detector.pixel_size.y = float(data_point)
328                        self.detector.pixel_size_unit = unit
[c94280c]329                    elif (key == u'distance'
330                          and self.parent_class == u'SAScollimation'):
[ad52d31]331                        self.collimation.length = data_point
[d398285]332                        self.collimation.length_unit = unit
[c94280c]333                    elif (key == u'name'
334                          and self.parent_class == u'SAScollimation'):
[ad52d31]335                        self.collimation.name = data_point
[c94280c]336                    elif (key == u'shape'
337                          and self.parent_class == u'SASaperture'):
[082239e]338                        self.aperture.shape = data_point
[c94280c]339                    elif (key == u'x_gap'
340                          and self.parent_class == u'SASaperture'):
[082239e]341                        self.aperture.size.x = data_point
[c94280c]342                    elif (key == u'y_gap'
343                          and self.parent_class == u'SASaperture'):
[082239e]344                        self.aperture.size.y = data_point
345
346                    # Process Information
[c94280c]347                    elif (key == u'Title'
348                          and self.parent_class == u'SASprocess'): # CanSAS 2.0
[68aa210]349                        self.process.name = data_point
[c94280c]350                    elif (key == u'name'
351                          and self.parent_class == u'SASprocess'): # NXcanSAS
[68aa210]352                        self.process.name = data_point
[c94280c]353                    elif (key == u'description'
354                          and self.parent_class == u'SASprocess'):
[68aa210]355                        self.process.description = data_point
[d72567e]356                    elif key == u'date' and self.parent_class == u'SASprocess':
[68aa210]357                        self.process.date = data_point
[082239e]358                    elif key == u'term' and self.parent_class == u'SASprocess':
359                        self.process.term = data_point
[d72567e]360                    elif self.parent_class == u'SASprocess':
[ad52d31]361                        self.process.notes.append(data_point)
362
[082239e]363                    # Source
[c94280c]364                    elif (key == u'wavelength'
365                          and self.parent_class == u'SASdata'):
[d72567e]366                        self.current_datainfo.source.wavelength = data_point
[5e906207]367                        self.current_datainfo.source.wavelength_unit = unit
[c94280c]368                    elif (key == u'incident_wavelength'
369                          and self.parent_class == 'SASsource'):
[5e906207]370                        self.current_datainfo.source.wavelength = data_point
371                        self.current_datainfo.source.wavelength_unit = unit
[c94280c]372                    elif (key == u'wavelength_max'
373                          and self.parent_class == u'SASsource'):
[5e906207]374                        self.current_datainfo.source.wavelength_max = data_point
375                        self.current_datainfo.source.wavelength_max_unit = unit
[c94280c]376                    elif (key == u'wavelength_min'
377                          and self.parent_class == u'SASsource'):
[5e906207]378                        self.current_datainfo.source.wavelength_min = data_point
379                        self.current_datainfo.source.wavelength_min_unit = unit
[c94280c]380                    elif (key == u'incident_wavelength_spread'
381                          and self.parent_class == u'SASsource'):
[082239e]382                        self.current_datainfo.source.wavelength_spread = \
383                            data_point
384                        self.current_datainfo.source.wavelength_spread_unit = \
385                            unit
[c94280c]386                    elif (key == u'beam_size_x'
387                          and self.parent_class == u'SASsource'):
[5e906207]388                        self.current_datainfo.source.beam_size.x = data_point
389                        self.current_datainfo.source.beam_size_unit = unit
[c94280c]390                    elif (key == u'beam_size_y'
391                          and self.parent_class == u'SASsource'):
[5e906207]392                        self.current_datainfo.source.beam_size.y = data_point
393                        self.current_datainfo.source.beam_size_unit = unit
[c94280c]394                    elif (key == u'beam_shape'
395                          and self.parent_class == u'SASsource'):
[5e906207]396                        self.current_datainfo.source.beam_shape = data_point
[c94280c]397                    elif (key == u'radiation'
398                          and self.parent_class == u'SASsource'):
[d72567e]399                        self.current_datainfo.source.radiation = data_point
[c94280c]400                    elif (key == u'transmission'
401                          and self.parent_class == u'SASdata'):
[d72567e]402                        self.current_datainfo.sample.transmission = data_point
[68aa210]403
[082239e]404                    # Everything else goes in meta_data
[68aa210]405                    else:
[082239e]406                        new_key = self._create_unique_key(
407                            self.current_datainfo.meta_data, key)
[d72567e]408                        self.current_datainfo.meta_data[new_key] = data_point
[68aa210]409
410            else:
[082239e]411                # I don't know if this reachable code
[68aa210]412                self.errors.add("ShouldNeverHappenException")
413
[d72567e]414    def add_intermediate(self):
[ad52d31]415        """
[082239e]416        This method stores any intermediate objects within the final data set
417        after fully reading the set.
[ad52d31]418
[082239e]419        :param parent: The NXclass name for the h5py Group object that just
420                       finished being processed
[ad52d31]421        """
422
[d72567e]423        if self.parent_class == u'SASprocess':
424            self.current_datainfo.process.append(self.process)
[ad52d31]425            self.process = Process()
[d72567e]426        elif self.parent_class == u'SASdetector':
427            self.current_datainfo.detector.append(self.detector)
[ad52d31]428            self.detector = Detector()
[d72567e]429        elif self.parent_class == u'SAStransmission_spectrum':
430            self.current_datainfo.trans_spectrum.append(self.trans_spectrum)
[ad52d31]431            self.trans_spectrum = TransmissionSpectrum()
[d72567e]432        elif self.parent_class == u'SAScollimation':
433            self.current_datainfo.collimation.append(self.collimation)
[ad52d31]434            self.collimation = Collimation()
[d72567e]435        elif self.parent_class == u'SASaperture':
[ad52d31]436            self.collimation.aperture.append(self.aperture)
437            self.aperture = Aperture()
[d72567e]438        elif self.parent_class == u'SASdata':
[082239e]439            if isinstance(self.current_dataset, plottable_2D):
[d72567e]440                self.data2d.append(self.current_dataset)
[082239e]441            elif isinstance(self.current_dataset, plottable_1D):
[d72567e]442                self.data1d.append(self.current_dataset)
[68aa210]443
444    def final_data_cleanup(self):
445        """
[082239e]446        Does some final cleanup and formatting on self.current_datainfo and
447        all data1D and data2D objects and then combines the data and info into
448        Data1D and Data2D objects
[68aa210]449        """
[082239e]450        # Type cast data arrays to float64
[d72567e]451        if len(self.current_datainfo.trans_spectrum) > 0:
[ad52d31]452            spectrum_list = []
[d72567e]453            for spectrum in self.current_datainfo.trans_spectrum:
[ad52d31]454                spectrum.transmission = np.delete(spectrum.transmission, [0])
455                spectrum.transmission = spectrum.transmission.astype(np.float64)
[082239e]456                spectrum.transmission_deviation = np.delete(
457                    spectrum.transmission_deviation, [0])
458                spectrum.transmission_deviation = \
459                    spectrum.transmission_deviation.astype(np.float64)
[ad52d31]460                spectrum.wavelength = np.delete(spectrum.wavelength, [0])
461                spectrum.wavelength = spectrum.wavelength.astype(np.float64)
[d72567e]462                if len(spectrum.transmission) > 0:
463                    spectrum_list.append(spectrum)
464            self.current_datainfo.trans_spectrum = spectrum_list
[68aa210]465
[082239e]466        # Append errors to dataset and reset class errors
[d72567e]467        self.current_datainfo.errors = self.errors
[68aa210]468        self.errors.clear()
469
[082239e]470        # Combine all plottables with datainfo and append each to output
471        # Type cast data arrays to float64 and find min/max as appropriate
[d72567e]472        for dataset in self.data2d:
473            zeros = np.ones(dataset.data.size, dtype=bool)
474            try:
[082239e]475                for i in range(0, dataset.mask.size - 1):
[d72567e]476                    zeros[i] = dataset.mask[i]
477            except:
478                self.errors.add(sys.exc_value)
479            dataset.mask = zeros
[082239e]480            # Calculate the actual Q matrix
[d72567e]481            try:
482                if dataset.q_data.size <= 1:
[54544637]483                    dataset.q_data = np.sqrt(dataset.qx_data
484                                             * dataset.qx_data
485                                             + dataset.qy_data
486                                             * dataset.qy_data)
[d72567e]487            except:
488                dataset.q_data = None
[ac370c5]489
490            if dataset.data.ndim == 2:
491                (n_rows, n_cols) = dataset.data.shape
[479799c]492                dataset.y_bins = dataset.qy_data[0::n_cols]
[ac370c5]493                dataset.x_bins = dataset.qx_data[:n_cols]
494                dataset.data = dataset.data.flatten()
[9d786e5]495            self.current_dataset = dataset
496            self.send_to_output()
[d72567e]497
498        for dataset in self.data1d:
[9d786e5]499            self.current_dataset = dataset
500            self.send_to_output()
[d72567e]501
[68aa210]502    def add_data_set(self, key=""):
503        """
[082239e]504        Adds the current_dataset to the list of outputs after preforming final
505        processing on the data and then calls a private method to generate a
506        new data set.
[68aa210]507
508        :param key: NeXus group name for current tree level
509        """
[d72567e]510
511        if self.current_datainfo and self.current_dataset:
[68aa210]512            self.final_data_cleanup()
[d72567e]513        self.data1d = []
514        self.data2d = []
515        self.current_datainfo = DataInfo()
[68aa210]516
[54ba66e]517
[082239e]518    def _initialize_new_data_set(self, parent_list=None):
[68aa210]519        """
[082239e]520        A private class method to generate a new 1D or 2D data object based on
521        the type of data within the set. Outside methods should call
522        add_data_set() to be sure any existing data is stored properly.
[68aa210]523
[d72567e]524        :param parent_list: List of names of parent elements
[68aa210]525        """
[d72567e]526
527        if parent_list is None:
528            parent_list = []
529        if self._find_intermediate(parent_list, "Qx"):
530            self.current_dataset = plottable_2D()
[68aa210]531        else:
532            x = np.array(0)
533            y = np.array(0)
[d72567e]534            self.current_dataset = plottable_1D(x, y)
535        self.current_datainfo.filename = self.raw_data.filename
[68aa210]536
[d72567e]537    def _find_intermediate(self, parent_list, basename=""):
[ad52d31]538        """
[082239e]539        A private class used to find an entry by either using a direct key or
540        knowing the approximate basename.
[ad52d31]541
[082239e]542        :param parent_list: List of parents nodes in the HDF5 file
[d72567e]543        :param basename: Approximate name of an entry to search for
[ad52d31]544        :return:
545        """
[d72567e]546
547        entry = False
548        key_prog = re.compile(basename)
549        top = self.raw_data
550        for parent in parent_list:
551            top = top.get(parent)
552        for key in top.keys():
[082239e]553            if key_prog.match(key):
[d72567e]554                entry = True
555                break
[ad52d31]556        return entry
557
[68aa210]558    def _create_unique_key(self, dictionary, name, numb=0):
559        """
560        Create a unique key value for any dictionary to prevent overwriting
561        Recurses until a unique key value is found.
562
563        :param dictionary: A dictionary with any number of entries
564        :param name: The index of the item to be added to dictionary
565        :param numb: The number to be appended to the name, starts at 0
[d72567e]566        :return: The new name for the dictionary entry
[68aa210]567        """
568        if dictionary.get(name) is not None:
569            numb += 1
570            name = name.split("_")[0]
571            name += "_{0}".format(numb)
572            name = self._create_unique_key(dictionary, name, numb)
[d398285]573        return name
574
575    def _get_unit(self, value):
576        """
577        Find the unit for a particular value within the h5py dictionary
578
579        :param value: attribute dictionary for a particular value set
[d72567e]580        :return: unit for the value passed to the method
[d398285]581        """
[5c5e7fd]582        unit = h5attr(value, u'units')
[54544637]583        if unit is None:
[5c5e7fd]584            unit = h5attr(value, u'unit')
[082239e]585        # Convert the unit formats
[d398285]586        if unit == "1/A":
587            unit = "A^{-1}"
588        elif unit == "1/cm":
589            unit = "cm^{-1}"
[54ba66e]590        return unit
Note: See TracBrowser for help on using the repository browser.