def save_result(self, name, value, group=None, overwrite=True): """Save a result to h5 file. Defaults are to save to the active group in the 'results' group and overwrite an existing result. Note that the result is saved as an attribute of 'results/group' and overwriting attributes causes h5 file size bloat.""" if self.no_write: raise Exception('This run is read-only. ' 'You can\'t save results to runs through a ' 'Sequence object. Per-run analysis should be done ' 'in single-shot analysis routines, in which a ' 'single Run object is used') with h5py.File(self.h5_path, 'a') as h5_file: if not group: # Save to analysis results group by default group = 'results/' + self.group elif not group in h5_file: # Create the group if it doesn't exist h5_file.create_group(group) if name in h5_file[group].attrs and not overwrite: raise Exception('Attribute %s exists in group %s. ' \ 'Use overwrite=True to overwrite.' % (name, group)) set_attributes(h5_file[group], {name: value}) if spinning_top: if self.h5_path not in _updated_data: _updated_data[self.h5_path] = {} if group.startswith('results'): toplevel = group.replace('results/', '', 1) _updated_data[self.h5_path][toplevel, name] = value
def transition_to_manual(self): if self.h5_filepath is None: print('No camera exposures in this shot.\n') return True assert self.acquisition_thread is not None self.acquisition_thread.join(timeout=self.stop_acquisition_timeout) if self.acquisition_thread.is_alive(): msg = """Acquisition thread did not finish. Likely did not acquire expected number of images. Check triggering is connected/configured correctly""" if self.exception_on_failed_shot: self.abort() raise RuntimeError(dedent(msg)) else: self.camera.abort_acquisition() self.acquisition_thread.join() print(dedent(msg), file=sys.stderr) self.acquisition_thread = None print("Stopping acquisition.") self.camera.stop_acquisition() print(f"Saving {len(self.images)}/{len(self.exposures)} images.") with h5py.File(self.h5_filepath, 'r+') as f: # Use orientation for image path, device_name if orientation unspecified if self.orientation is not None: image_path = 'images/' + self.orientation else: image_path = 'images/' + self.device_name image_group = f.require_group(image_path) image_group.attrs['camera'] = self.device_name # Save camera attributes to the HDF5 file: if self.attributes_to_save is not None: set_attributes(image_group, self.attributes_to_save) # Whether we failed to get all the expected exposures: image_group.attrs['failed_shot'] = len(self.images) != len( self.exposures) # key the images by name and frametype. Allow for the case of there being # multiple images with the same name and frametype. In this case we will # save an array of images in a single dataset. images = {(exposure['name'], exposure['frametype']): [] for exposure in self.exposures} # Iterate over expected exposures, sorted by acquisition time, to match them # up with the acquired images: self.exposures.sort(order='t') for image, exposure in zip(self.images, self.exposures): images[(exposure['name'], exposure['frametype'])].append(image) # Save images to the HDF5 file: for (name, frametype), imagelist in images.items(): data = imagelist[0] if len(imagelist) == 1 else np.array( imagelist) print(f"Saving frame(s) {name}/{frametype}.") group = image_group.require_group(name) dset = group.create_dataset(frametype, data=data, dtype='uint16', compression='gzip') # Specify this dataset should be viewed as an image dset.attrs['CLASS'] = np.string_('IMAGE') dset.attrs['IMAGE_VERSION'] = np.string_('1.2') dset.attrs['IMAGE_SUBCLASS'] = np.string_('IMAGE_GRAYSCALE') dset.attrs['IMAGE_WHITE_IS_ZERO'] = np.uint8(0) # If the images are all the same shape, send them to the GUI for display: try: image_block = np.stack(self.images) except ValueError: print( "Cannot display images in the GUI, they are not all the same shape" ) else: self._send_image_to_parent(image_block) self.images = None self.n_images = None self.attributes_to_save = None self.exposures = None self.h5_filepath = None self.stop_acquisition_timeout = None self.exception_on_failed_shot = None print("Setting manual mode camera attributes.\n") self.set_attributes_smart(self.manual_mode_camera_attributes) if self.continuous_dt is not None: # If continuous manual mode acquisition was in progress before the bufferd # run, resume it: self.start_continuous(self.continuous_dt) return True
def save_result(self, name, value, group=None, overwrite=True): """Save a result to the hdf5 file. With the default argument values this method saves to `self.group` in the `'/results'` group and overwrites any existing value. Note that the result is saved as an attribute and overwriting attributes causes hdf5 file size bloat. Args: name (str): The name of the result. This will be the name of the attribute added to the hdf5 file's group. value (any): The value of the result, which will be saved as the value of the hdf5 group's attribute set by `name`. However note that when saving large arrays, it is better to use the `self.save_result_array()` method which will store the results as a dataset in the hdf5 file. group (str, optional): The group in the hdf5 file to which the result will be saved as an attribute. If set to `None`, then the result will be saved to `self.group` in `'/results'`. Note that if a value is passed for `group` here then it will NOT have `'/result'` prepended to it which allows the caller to save results anywhere in the hdf5 file. This is in contrast to using the default group set with `self.set_group()`; when the default group is set with that method it WILL have `'/results'` prepended to it when saving results. Defaults to `None`. overwrite (bool, optional): Sets whether or not to overwrite the previous value if the attribute already exists. If set to `False` and the attribute already exists, a `PermissionError` is raised. Defaults to `True`. Raises: PermissionError: A `PermissionError` is raised if `self.no_write` is `True` because saving the result would edit the file. ValueError: A `ValueError` is raised if `self.group` is `None` and no value is provided for `group` because the method then doesn't know where to save the result. PermissionError: A `PermissionError` is raised if an attribute with name `name` already exists but `overwrite` is set to `False`. """ if self.no_write: msg = "Cannot save result; this instance is read-only." raise PermissionError(msg) with h5py.File(self.h5_path, 'a') as h5_file: if not group: if self.group is None: msg = """Cannot save result; no default group set. Either specify a value for this method's optional group argument, or set a default value using the set_group() method.""" raise ValueError(dedent(msg)) # Save to analysis results group by default group = 'results/' + self.group elif not group in h5_file: # Create the group if it doesn't exist h5_file.create_group(group) if name in h5_file[group].attrs and not overwrite: msg = """Cannot save result; group '{group}' already has attribute '{name}' and overwrite is set to False. Set overwrite=True to overwrite the existing value.""".format( group=group, name=name, ) raise PermissionError(dedent(msg)) set_attributes(h5_file[group], {name: value}) if spinning_top: if self.h5_path not in _updated_data: _updated_data[self.h5_path] = {} if group.startswith('results'): toplevel = group.replace('results/', '', 1) _updated_data[self.h5_path][toplevel, name] = value