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

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

Py3 compatibility and code cleanup.

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