def get_dimensions(self): dic = self.original_metadata reciprocal_name = 'u' spatial_name = 'x' if 'dimensional_calibrations' in dic: dimension_list = dic['dimensional_calibrations'] elif 'spatial_calibrations' in dic: dimension_list = dic['spatial_calibrations'] else: return for dim in range(len(dimension_list)): dimension_tags = dimension_list[dim] units = dimension_tags['units'] values = (np.arange(self.data_cube.shape[int(dim)]) - dimension_tags['offset']) * dimension_tags['scale'] if 'eV' == units: self.dimensions.append( sidpy.Dimension(values, name='energy_loss', units=units, quantity='energy-loss', dimension_type='spectral')) elif 'eV' in units: self.dimensions.append( sidpy.Dimension(values, name='energy', units=units, quantity='energy', dimension_type='spectral')) elif '1/' in units or units in ['mrad', 'rad']: self.dimensions.append( sidpy.Dimension(values, name=reciprocal_name, units=units, quantity='reciprocal distance', dimension_type='reciprocal')) reciprocal_name = chr(ord(reciprocal_name) + 1) elif 'nm' in units: self.dimensions.append( sidpy.Dimension(values, name=spatial_name, units=units, quantity='distance', dimension_type='spatial')) spatial_name = chr(ord(spatial_name) + 1) else: self.dimensions.append( sidpy.Dimension(values, name='generic_{}'.format(dim), units='generic', quantity='generic', dimension_type='UNKNOWN'))
def get_image(self): scale_x = float( self.metadata['BinaryResult']['PixelSize']['width']) * 1e9 scale_y = float( self.metadata['BinaryResult']['PixelSize']['height']) * 1e9 if self.data_array.shape[2] == 1: self.datasets.append( sidpy.Dataset.from_array(self.data_array[:, :, 0])) self.datasets[-1].data_type = 'image' self.datasets[-1].set_dimension( 0, sidpy.Dimension(np.arange(self.data_array.shape[0]) * scale_x, name='x', units='nm', quantity='distance', dimension_type='spatial')) self.datasets[-1].set_dimension( 1, sidpy.Dimension(np.arange(self.data_array.shape[1]) * scale_y, name='y', units='nm', quantity='distance', dimension_type='spatial')) else: self.data_array = np.moveaxis(self.data_array, source=[0, 1, 2], destination=[1, 2, 0]) self.datasets.append(sidpy.Dataset.from_array(self.data_array)) self.datasets[-1].data_type = 'image_stack' self.datasets[-1].set_dimension( 0, sidpy.Dimension(np.arange(self.data_array.shape[0]), name='frame', units='frame', quantity='time', dimension_type='temporal')) self.datasets[-1].set_dimension( 1, sidpy.Dimension(np.arange(self.data_array.shape[1]) * scale_x, name='x', units='nm', quantity='distance', dimension_type='spatial')) self.datasets[-1].set_dimension( 2, sidpy.Dimension(np.arange(self.data_array.shape[2]) * scale_y, name='y', units='nm', quantity='distance', dimension_type='spatial')) self.datasets[-1].original_metadata = self.metadata self.datasets[-1].units = 'counts' self.datasets[-1].quantity = 'intensity'
def _translate_image_stack(self, gwy_data, obj): """ Use this function to write data corresponding to a stack of scan images (most common) Returns ------- """ if obj.endswith('data'): data = gwy_data[obj].data title = gwy_data[obj + '/title'] keys = gwy_data[obj].keys() meta_data = {} for key in keys: if 'data' not in key: meta_data[key] = gwy_data[obj][key] x_range = gwy_data[obj].get('xreal') x_vals = np.linspace(0, x_range, gwy_data[obj]['xres']) y_range = gwy_data[obj].get('yreal') y_vals = np.linspace(0, y_range, gwy_data[obj]['yres']) data_set = sid.Dataset.from_array(data, title=title) data_set.data_type = 'Image' #Add quantity and units data_set.units = gwy_data[obj]['si_unit_z']['unitstr'] data_set.quantity = title #Add dimension info data_set.set_dimension( 0, sid.Dimension(x_vals, name='x', units=gwy_data[obj]['si_unit_xy']['unitstr'], quantity='x', dimension_type='spatial')) data_set.set_dimension( 1, sid.Dimension(y_vals, name='y', units=gwy_data[obj]['si_unit_xy']['unitstr'], quantity='y', dimension_type='spatial')) # append metadata data_set.original_metadata = meta_data data_set.data_type = 'image' return data_set
def set_data_type(self, dataset): spectral_dim = False for axis in dataset._axes.values(): if axis.dimension_type == sidpy.DimensionType.SPECTRAL: spectral_dim = True if len(dataset.shape) > 3: raise NotImplementedError('Data_type not implemented yet') elif len(dataset.shape) == 3: if spectral_dim: dataset.data_type = 'spectral_image' else: dataset.data_type = 'IMAGE_STACK' for dim, axis in dataset._axes.items(): if axis.dimension_type != sidpy.DimensionType.SPATIAL: dataset.set_dimension(dim, sidpy.Dimension(axis.values, name='frame', units='frame', quantity='stack', dimension_type=sidpy.DimensionType.TEMPORAL)) break elif len(dataset.shape) == 2: if spectral_dim: dataset.data_type = sidpy.DataType.SPECTRAL_IMAGE else: dataset.data_type = sidpy.DataType.IMAGE elif len(dataset.shape) == 1: if spectral_dim: dataset.data_type = sidpy.DataType.SPECTRUM else: dataset.data_type = sidpy.DataType.LINE_PLOT
def test_complex_valued_dimension(self): data_set = sidpy.Dataset.from_array(np.zeros([5, 6], dtype=complex), title='Image') h5_file = h5py.File('test.h5', 'w') h5_group = h5_file.create_group('MyGroup') data_set.set_dimension(0, sidpy.Dimension(np.arange(5, dtype=complex))) # with self.assertWarns('ComplexWarning'): pyNSID.hdf_io.write_nsid_dataset(data_set, h5_group)
def base_test(self, dims=3, dim_types=['spatial', 'spatial', 'spectral'], data_type='complex', verbose=True): h5_f = h5py.File('test.h5', 'w') h5_group = h5_f.create_group('MyGroup') shape = tuple([np.random.randint(low=2, high=10) for _ in range(dims)]) data = np.random.normal(size=shape) if data_type == 'complex': data = np.random.normal(size=tuple(shape)) + 1j * np.random.normal(size=tuple(shape)) elif data_type == 'int': np.random.randint(low=0, high=1000, size=shape, dtype=np.int) elif data_type == 'float32': data = np.random.normal(size=shape) data = np.squeeze(np.array(data, dtype=np.float32)) else: data = np.random.normal(size=shape) data = np.squeeze(np.array(data, dtype=np.float64)) data_set = sidpy.Dataset.from_array(data[:], title='Image') for ind in range(dims): data_set.set_dimension(ind, sidpy.Dimension(np.linspace(-2, 2, num=data_set.shape[ind], endpoint=True), title='x'+str(ind), units='um', quantity='Length', dimension_type=dim_types[ind])) data_set.units = 'nm' data_set.source = 'CypherEast2' data_set.quantity = 'Excaliburs' h5_dset = hdf_io.write_nsid_dataset(data_set, h5_group, main_data_name='test2', verbose=verbose) assert type(h5_dset) == h5py._hl.dataset.Dataset, "Output is not a h5py dataset" assert h5_dset.shape == shape, "Output shape is {} but should be {}".format(h5_dset.shape, shape) for ind in range(len(sidpy.hdf_utils.get_attr(h5_dset, 'DIMENSION_LABELS'))): assert sidpy.hdf_utils.get_attr(h5_dset, 'DIMENSION_LABELS')[ind] == data_set._axes[ind].name, \ "Dimension name not correctly written, should be {} but is {} in file"\ .format(data_set._axes[ind].name, sidpy.hdf_utils.get_attr(h5_dset, 'DIMENSION_LABELS')[ind]) assert sidpy.hdf_utils.get_attr(h5_dset, 'quantity') == data_set.quantity, \ "Quantity attribute not correctly written, should be {} but is {} in file"\ .format(data_set.quantity, sidpy.hdf_utils.get_attr(h5_dset, 'quantity')) assert sidpy.hdf_utils.get_attr(h5_dset, 'source') == data_set.source, \ "Source attribute not correctly written, should be {} but is {} in file"\ .format(data_set.source, sidpy.hdf_utils.get_attr(h5_dset, 'source')) assert sidpy.hdf_utils.get_attr(h5_dset, 'units') == data_set.units, \ "Source attribute not correctly written, should be {} but is {} in file"\ .format(data_set.units, sidpy.hdf_utils.get_attr(h5_dset, 'units')) h5_f.close() remove('test.h5')
def _translate_spectra(self, gwy_data, obj): """ Use this to translate simple 1D data like force curves Returns ------- """ keys = gwy_data[obj].keys() meta_data = {} for key in keys: if 'data' not in key: meta_data[key] = gwy_data[obj][key] title = obj['title'] unitstr = obj['unitstr'] coords = obj['coords'] res = obj['data']['res'] real = obj['data']['real'] offset = obj['data']['off'] x_units = obj['data']['si_unit_x']['unitstr'] y_units = obj['data']['si_unit_y']['unitstr'] data = obj['data']['data'] indices = obj['selected'] x_vals = np.linspace(offset, real, res) data_set = sid.Dataset.from_array(data, title=title) data_set.data_type = 'line_plot' #Add quantity and units data_set.units = y_units data_set.quantity = title #Add dimension info data_set.set_dimension( 0, sid.Dimension(x_vals, name='x', units=x_units, quantity='x', dimension_type='spectral')) # append metadata data_set.original_metadata = meta_data return data_set
def make_dummy_dataset(value_type): """Make a dummy sidpy.Dataset """ assert isinstance(value_type, sidpy.DataType) if type == sidpy.DataType.SPECTRUM: dataset = sidpy.Dataset.from_array(np.arange(100)) dataset.data_type = 'spectrum' dataset.units = 'counts' dataset.quantity = 'intensity' dataset.set_dimension( 0, sidpy.Dimension(np.arange(dataset.shape[0]) + 70, name='energy_scale')) dataset.dim_0.dimension_type = 'spectral' dataset.dim_0.units = 'eV' dataset.dim_0.quantity = 'energy loss' else: raise NotImplementedError('not implemented') return dataset
def gsf_read(self): """ Read a Gwyddion Simple Field 1.0 file format http://gwyddion.net/documentation/user-guide-en/gsf.html Parameters ---------- file_name : string path to the file Returns ------- metadata : dict) Additional metadata to be included in the file data : numpy.ndarray An arbitrarily sized 2D array of arbitrary numeric type """ gsf_file = open(self._input_file_path, 'rb') metadata = {} # check if header is OK if not (gsf_file.readline().decode('UTF-8') == 'Gwyddion Simple Field 1.0\n'): gsf_file.close() raise ValueError('File has wrong header') term = b'00' # read metadata header while term != b'\x00': line_string = gsf_file.readline().decode('UTF-8') metadata[line_string.rpartition(' = ') [0]] = line_string.rpartition('=')[2] term = gsf_file.read(1) gsf_file.seek(-1, 1) gsf_file.read(4 - gsf_file.tell() % 4) # fix known metadata types from .gsf file specs # first the mandatory ones... metadata['XRes'] = np.int(metadata['XRes']) metadata['YRes'] = np.int(metadata['YRes']) # now check for the optional ones if 'XReal' in metadata: metadata['XReal'] = np.float(metadata['XReal']) if 'YReal' in metadata: metadata['YReal'] = np.float(metadata['YReal']) if 'XOffset' in metadata: metadata['XOffset'] = np.float(metadata['XOffset']) if 'YOffset' in metadata: metadata['YOffset'] = np.float(metadata['YOffset']) datasets = [] data = np.frombuffer(gsf_file.read(), dtype='float32').reshape(metadata['YRes'], metadata['XRes']) gsf_file.close() num_cols, num_rows = data.shape data_set = sid.Dataset.from_array(data, title=metadata['Title']) data_set.data_type = 'Image' #Add quantity and units data_set.units = metadata['ZUnits'] data_set.quantity = metadata['Title'] #Add dimension info data_set.set_dimension( 0, sid.Dimension(np.linspace(0, metadata['XReal'], num_cols), name='x', units=metadata['XYUnits'], quantity='x', dimension_type='spatial')) data_set.set_dimension( 1, sid.Dimension(np.linspace(0, metadata['YReal'], num_rows), name='y', units=metadata['XYUnits'], quantity='y', dimension_type='spatial')) # append metadata data_set.original_metadata = metadata data_set.data_type = 'image' #Finally, append it datasets.append(data_set) return datasets
def read(self, verbose=False, parm_encoding='utf-8'): """ Reads the file given in file_path into a sidpy dataset Parameters ---------- verbose : Boolean (Optional) Whether or not to show print statements for debugging parm_encoding : str, optional Codec to be used to decode the bytestrings into Python strings if needed. Default 'utf-8' Returns ------- sidpy.Dataset : List of sidpy.Dataset objects. Multi-channel inputs are separated into individual dataset objects """ file_path = self._input_file_path folder_path, file_name = path.split(file_path) file_name = file_name[:-4] # Extracting the raw data into memory file_handle = open(file_path, 'r') string_lines = file_handle.readlines() file_handle.close() # Extract parameters from the first few header lines parm_dict, num_headers = self._read_parms(string_lines) num_rows = int(parm_dict['Main-y_pixels']) num_cols = int(parm_dict['Main-x_pixels']) num_pos = num_rows * num_cols spectra_length = int(parm_dict['Main-z_points']) # Extract the STS data from subsequent lines raw_data_2d = self._read_data(string_lines, num_pos, spectra_length, num_headers) raw_data = np.reshape(raw_data_2d, (num_rows, num_cols, spectra_length)) # Generate the x / voltage / spectroscopic axis: volt_vec = np.linspace(parm_dict['Spectroscopy-Device_1_Start [Volt]'], parm_dict['Spectroscopy-Device_1_End [Volt]'], spectra_length) # Build row, column vectors xvec = np.linspace(0, parm_dict['Main-x_length'], num_cols) yvec = np.linspace(0, parm_dict['Main-y_length'], num_rows) # now write it to the sidpy dataset object data_set = sid.Dataset.from_array(raw_data, name='Omicron_STS') data_set.data_type = 'spectral_image' # Add quantity and units data_set.units = parm_dict['Main-value_unit'] data_set.quantity = 'Current' # Add dimension info data_set.set_dimension( 0, sid.Dimension(xvec, name='x', units='nm', quantity='position', dimension_type=sid.DimensionType.SPATIAL)) data_set.set_dimension( 1, sid.Dimension(yvec, name='y', units='nm', quantity='position', dimension_type=sid.DimensionType.SPATIAL)) data_set.set_dimension( 2, sid.Dimension(volt_vec, name='I', units=parm_dict['Main-value_unit'], quantity='Current', dimension_type=sid.DimensionType.SPECTRAL)) # append metadata data_set.metadata = parm_dict # Return the sidy dataset return data_set
def read(self): if 'ndata' in self.extension: try: self.__f = open(self.__filename, "rb") except FileNotFoundError: raise FileNotFoundError('File not found') local_files, dir_files, eocd = parse_zip(self.__f) contains_data = b"data.npy" in dir_files contains_metadata = b"metadata.json" in dir_files file_count = contains_data + contains_metadata # use fact that True is 1, False is 0 self.__f.seek(local_files[dir_files[b"data.npy"][1]][1]) self.data_cube = np.load(self.__f) json_pos = local_files[dir_files[b"metadata.json"][1]][1] json_len = local_files[dir_files[b"metadata.json"][1]][2] self.__f.seek(json_pos) json_properties = self.__f.read(json_len) self.original_metadata = json.loads( json_properties.decode("utf-8")) self.__f.close() elif self.extension == '.h5': # TODO: use lazy load for large datasets self.__f = h5py.File(self.__filename, 'a') if 'data' in self.__f: json_properties = self.__f['data'].attrs.get("properties", "") self.data_cube = self.__f['data'][:] self.original_metadata = json.loads(json_properties) self.__f.close() self.get_dimensions() # Need to switch image dimensions in Nion format image_dims = [] spectral_dims = [] for dim, axis in enumerate(self.dimensions): # print(dim, axis) if axis.dimension_type == sidpy.DimensionType.SPATIAL: image_dims.append(dim) if axis.dimension_type == sidpy.DimensionType.SPECTRAL: spectral_dims.append(dim) # convert line-scan nxN to spectral_image 1xnxN if len(image_dims) == 1: if self.data_cube.ndim > 1: self.data_cube = self.data_cube.reshape( 1, self.data_cube.shape[0], self.data_cube.shape[1]) new_dims = [ sidpy.Dimension([1], name='x', units='pixels', quantity='distance', dimension_type='spatial'), sidpy.Dimension(np.arange(self.data_cube.shape[0]), name='y', units='pixels', quantity='distance', dimension_type='spatial'), self.dimensions[spectral_dims[0]] ] self.dimensions = new_dims if len(image_dims) == 2: self.data_cube = np.swapaxes(self.data_cube, image_dims[0], image_dims[1]) temp = self.dimensions[image_dims[0]].copy() self.dimensions[image_dims[0]] = self.dimensions[ image_dims[1]].copy() self.dimensions[image_dims[1]] = temp dataset = sidpy.Dataset.from_array(self.data_cube) dim_names = [] for dim, axis in enumerate(self.dimensions): dataset.set_dimension(dim, axis) dataset.original_metadata = self.original_metadata if 'dimensional_calibrations' in dataset.original_metadata: for dim in dataset.original_metadata['dimensional_calibrations']: if dim['units'] == '': dim['units'] = 'pixels' dataset.quantity = 'intensity' dataset.units = 'counts' if 'description' in dataset.original_metadata: dataset.title = dataset.original_metadata['description']['title'] else: if 'title' in dataset.original_metadata: dataset.title = dataset.original_metadata['title'] else: path, file_name = os.path.split(self.__filename) basename, extension = os.path.splitext(file_name) dataset.title = basename if 'data_source' in dataset.original_metadata: dataset.source = dataset.original_metadata['data_source'] else: dataset.source = 'NionReader' self.set_data_type(dataset) dataset.modality = 'STEM data' dataset.h5_dataset = None return dataset
def set_dimensions(dset, current_channel): """Attaches correct dimension from old pyTEMlib style. Parameters ---------- dset: sidpy.Dataset current_channel: hdf5.Group """ dim = 0 if dset.data_type == sidpy.DataType.IMAGE_STACK: dset.set_dimension( dim, sidpy.Dimension(np.arange(dset.shape[dim]), name='frame', units='frame', quantity='stack', dimension_type='TEMPORAL')) dim += 1 if 'IMAGE' in dset.data_type: if 'spatial_scale_x' in current_channel: scale_x = current_channel['spatial_scale_x'][()] else: scale_x = 1 if 'spatial_units' in current_channel: units_x = current_channel['spatial_units'][()] if len(units_x) < 2: units_x = 'pixel' else: units_x = 'generic' if 'spatial_scale_y' in current_channel: scale_y = current_channel['spatial_scale_y'][()] else: scale_y = 0 dset.set_dimension( dim, sidpy.Dimension('x', np.arange(dset.shape[dim]) * scale_x, units=units_x, quantity='Length', dimension_type='SPATIAL')) dim += 1 dset.set_dimension( dim, sidpy.Dimension('y', np.arange(dset.shape[dim]) * scale_y, units=units_x, quantity='Length', dimension_type='SPATIAL')) dim += 1 if dset.data_type in [ sidpy.DataType.SPECTRUM, sidpy.DataType.SPECTRAL_IMAGE ]: if 'spectral_scale_x' in current_channel: scale_s = current_channel['spectral_scale_x'][()] else: scale_s = 1.0 if 'spectral_units_x' in current_channel: units_s = current_channel['spectral_units_x'] else: units_s = 'eV' if 'spectral_offset_x' in current_channel: offset = current_channel['spectral_offset_x'] else: offset = 0.0 dset.set_dimension( dim, sidpy.Dimension(np.arange(dset.shape[dim]) * scale_s + offset, name='energy', units=units_s, quantity='energy_loss', dimension_type='SPECTRAL'))
def fourier_transform(dset): """ Reads information into dictionary 'tags', performs 'FFT', and provides a smoothed FT and reciprocal and intensity limits for visualization. Parameters ---------- dset: sidpy.Dataset image Returns ------- fft_dset: sidpy.Dataset Fourier transform with correct dimensions Example ------- >>> fft_dataset = fourier_transform(sidpy_dataset) >>> fft_dataset.plot() """ assert isinstance(dset, sidpy.Dataset), 'Expected a sidpy Dataset' selection = [] image_dim = [] # image_dim = get_image_dims(sidpy.DimensionTypes.SPATIAL) if dset.data_type == sidpy.DataType.IMAGE_STACK: for dim, axis in dset._axes.items(): if axis.dimension_type == sidpy.DimensionType.SPATIAL: selection.append(slice(None)) image_dim.append(dim) elif axis.dimension_type == sidpy.DimensionType.TEMPORAL or len(dset) == 3: selection.append(slice(None)) stack_dim = dim else: selection.append(slice(0, 1)) if len(image_dim) != 2: raise ValueError('need at least two SPATIAL dimension for an image stack') image_stack = np.squeeze(np.array(dset)[selection]) new_image = np.sum(np.array(image_stack), axis=stack_dim) elif dset.data_type == sidpy.DataType.IMAGE: new_image = np.array(dset) else: return new_image = new_image - new_image.min() fft_transform = (np.fft.fftshift(np.fft.fft2(new_image))) image_dims = get_image_dims(dset) units_x = '1/' + dset._axes[image_dims[0]].units units_y = '1/' + dset._axes[image_dims[1]].units fft_dset = sidpy.Dataset.from_array(fft_transform) fft_dset.quantity = dset.quantity fft_dset.units = 'a.u.' fft_dset.data_type = 'IMAGE' fft_dset.source = dset.title fft_dset.modality = 'fft' fft_dset.set_dimension(0, sidpy.Dimension(np.fft.fftshift(np.fft.fftfreq(new_image.shape[0], d=get_slope(dset.x.values))), name='u', units=units_x, dimension_type='RECIPROCAL', quantity='reciprocal_length')) fft_dset.set_dimension(1, sidpy.Dimension(np.fft.fftshift(np.fft.fftfreq(new_image.shape[1], d=get_slope(dset.y.values))), name='v', units=units_y, dimension_type='RECIPROCAL', quantity='reciprocal_length')) return fft_dset
def get_eds(self, eds_stream=False): if 'AcquisitionSettings' not in self.metadata: eds_stream = True if eds_stream: self.datasets.append(sidpy.Dataset.from_array(self.data_array)) else: data_array = self.get_eds_spectrum() if data_array.shape[0] == 1 and data_array.shape[1] == 1: data_array = np.array(data_array).flatten() self.datasets.append(sidpy.Dataset.from_array(data_array)) # print(self.datasets[-1]) self.datasets[-1].original_metadata = self.metadata detectors = self.datasets[-1].original_metadata['Detectors'] if eds_stream: pass else: offset = 0. dispersion = 1. for detector in detectors.values(): if self.metadata['BinaryResult']['Detector'] in detector[ 'DetectorName']: if 'OffsetEnergy' in detector: offset = float(detector['OffsetEnergy']) if 'Dispersion' in detector: dispersion = float(detector['Dispersion']) self.datasets[-1].units = 'counts' self.datasets[-1].quantity = 'intensity' energy_scale = np.arange( self.datasets[-1].shape[-1]) * dispersion + offset if self.datasets[-1].ndim == 1: self.datasets[-1].data_type = 'spectrum' self.datasets[-1].set_dimension( 0, sidpy.Dimension(energy_scale, name='energy_scale', units='eV', quantity='energy', dimension_type='spectral')) else: self.datasets[-1].data_type = 'spectral_image' self.datasets[-1].set_dimension( 2, sidpy.Dimension(energy_scale, name='energy_scale', units='eV', quantity='energy', dimension_type='spectral')) scale_x = float( self.metadata['BinaryResult']['PixelSize']['width']) * 1e9 scale_y = float( self.metadata['BinaryResult']['PixelSize']['height']) * 1e9 self.datasets[-1].set_dimension( 0, sidpy.Dimension(np.arange(self.datasets[-1].shape[0]) * scale_x, name='x', units='nm', quantity='distance', dimension_type='spatial')) self.datasets[-1].set_dimension( 1, sidpy.Dimension(np.arange(self.datasets[-1].shape[1]) * scale_y, name='y', units='nm', quantity='distance', dimension_type='spatial'))
def read(self, verbose=False): """ Reads the file given in file_path into a sidpy dataset Parameters ---------- verbose : Boolean (Optional) Whether or not to show print statements for debugging debug : Boolean (Optional) Whether or not to print log statements Returns ------- sidpy.Dataset : List of sidpy.Dataset objects. Multi-channel inputs are separated into individual dataset objects """ file_path = self._input_file_path self.notes = None self.segments = None self.segments_name = [] self.map_size = {'X': 0, 'Y': 0} self.channels_name = [] self.points_per_sec = None self.verbose = verbose # Open the datafile try: data_filepath = os.path.abspath(file_path) ARh5_file = h5py.File(data_filepath, 'r') except: print('Unable to open the file', data_filepath) raise # Get info from the origin file like Notes and Segments self.notes = ARh5_file.attrs['Note'].decode('utf-8') self.segments = ARh5_file['ForceMap']['0']['Segments'] segments_name = list(ARh5_file['ForceMap']['0'].attrs['Segments']) self.segments_name = [name.decode('utf-8') for name in segments_name] self.map_size['X'] = ARh5_file['ForceMap']['0']['Segments'].shape[0] self.map_size['Y'] = ARh5_file['ForceMap']['0']['Segments'].shape[1] channels_name = list(ARh5_file['ForceMap']['0'].attrs['Channels']) self.channels_name = [name.decode('utf-8') for name in channels_name] try: self.points_per_sec = np.float( self.note_value('ARDoIVPointsPerSec')) except NameError: self.points_per_sec = np.float(self.note_value('NumPtsPerSec')) if self.verbose: print('Map size [X, Y]: ', self.map_size) print('Channels names: ', self.channels_name) print('Name of Segments:', self.segments_name) # Only the extension 'Ext' segment can change size # so we get the shortest one and we trim all the others extension_idx = self.segments_name.index('Ext') short_ext = np.amin(np.array(self.segments[:, :, extension_idx])) longest_ext = np.amax(np.array(self.segments[:, :, extension_idx])) difference = longest_ext - short_ext # this is a difference between integers tot_length = (np.amax(self.segments) - difference) + 1 # +1 otherwise array(tot_length) will be of 1 position shorter points_trimmed = np.array(self.segments[:, :, extension_idx]) - short_ext # Open the output hdf5 file x_dim = np.linspace(0, np.float(self.note_value('FastScanSize')), self.map_size['X']) y_dim = np.linspace(0, np.float(self.note_value('FastScanSize')), self.map_size['Y']) z_dim = np.arange(tot_length) / np.float(self.points_per_sec) datasets = [] #list of sidpy datasets #Let's get all the metadata # Create the new segments that will be stored as attribute new_segments = {} for seg, name in enumerate(self.segments_name): new_segments.update({name: self.segments[0, 0, seg] - short_ext}) seg_metadata = { 'Segments': new_segments, 'Points_trimmed': points_trimmed, 'Notes': self.notes } general_metadata = { 'translator': 'ARhdf5', 'instrument': 'Asylum Research ' + self.note_value('MicroscopeModel'), 'AR sftware version': self.note_value('Version') } combined_metadata = dict({ 'segments': seg_metadata, 'general': general_metadata }) for index, channel in enumerate(self.channels_name): main_dset = np.empty( (self.map_size['X'], self.map_size['Y'], tot_length)) for column in np.arange(self.map_size['X']): for row in np.arange(self.map_size['Y']): AR_pos_string = str(column) + ':' + str(row) seg_start = self.segments[column, row, extension_idx] - short_ext main_dset[column, row, :] = ARh5_file['ForceMap']['0'][ AR_pos_string][index, seg_start:] quant_unit = self.get_def_unit(channel) data_set = sid.Dataset.from_array(main_dset, name='Image') data_set.data_type = sid.DataType.SPECTRAL_IMAGE # Add quantity and units data_set.units = quant_unit data_set.quantity = channel # Add dimension info data_set.set_dimension( 0, sid.Dimension(x_dim, name='x', units='m', quantity='x', dimension_type='spatial')) data_set.set_dimension( 1, sid.Dimension(y_dim, name='y', units='m', quantity='y', dimension_type='spatial')) data_set.set_dimension( 2, sid.Dimension(z_dim, name='Time', units='s', quantity='z', dimension_type='spectral')) # append metadata chan_metadata = dict(ARh5_file['ForceMap']['0'].attrs) new_dict = {**chan_metadata, **combined_metadata} data_set.metadata = new_dict # Finally, append it datasets.append(data_set) for index, image in enumerate(ARh5_file['Image'].keys()): main_dset = np.array(ARh5_file['Image'][image]) quant_unit = self.get_def_unit(image) data_set = sid.Dataset.from_array(main_dset, name='Image') data_set.data_type = sid.DataType.IMAGE # Add quantity and units data_set.units = quant_unit data_set.quantity = channel # Add dimension info data_set.set_dimension( 0, sid.Dimension(x_dim, name='x', units=quant_unit, quantity='x', dimension_type='spatial')) data_set.set_dimension( 1, sid.Dimension(y_dim, name='y', units=quant_unit, quantity='y', dimension_type='spatial')) # append metadata chan_metadata = dict(ARh5_file['Image'].attrs) new_dict = {**chan_metadata, **combined_metadata} data_set.metadata = new_dict # Finally, append it datasets.append(data_set) # Return the dataset return datasets