brimfile.file
1import numpy as np 2import warnings 3 4from .data import Data 5 6from .utils import concatenate_paths 7from .constants import brim_obj_names 8from . import units 9from . import subtypes 10 11from .file_abstraction import FileAbstraction, StoreType, sync 12from .validation import validate_json, ValidationError, ValidationLevel 13from .validation.json_descriptor import generate_json_descriptor 14 15# don't import _AbstractFile if running in pyodide (it is defined in js) 16import sys 17if "pyodide" not in sys.modules: 18 from .file_abstraction import _AbstractFile 19 20__docformat__ = "google" 21 22class File: 23 """ 24 Represents a brim file with Brillouin data, extending h5py.File. 25 """ 26 27 if "pyodide" in sys.modules: 28 def __init__(self, file): 29 self._file = file 30 if not self.is_valid(): 31 raise ValueError("The brim file is not valid!") 32 else: 33 def __init__(self, filename: str, mode: str = 'r', 34 store_type: StoreType = StoreType.AUTO, * , 35 validate: bool = False) -> None: 36 """ 37 Initialize the File object. 38 39 Args: 40 filename (str): Path to the brim file. 41 mode: {'r', 'r+', 'a', 'w', 'w-'} the mode for opening the file (default is 'r' for read-only). 42 See the definition of `mode` in `brimfile.file_abstraction._zarrFile.__init__()` for more details. 43 'r' means read only (must exist); 'r+' means read/write (must exist); 44 'a' means read/write (create if doesn't exist); 'w' means create (overwrite if exists); 'w-' means create (fail if exists). 45 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 46 validate (bool): Whether to validate the file upon initialization. Default is False. 47 """ 48 self._file = _AbstractFile( 49 filename, mode=mode, store_type=store_type) 50 if not self.is_valid(): 51 raise ValueError("The brim file is not valid!") 52 if validate: 53 validation_errors: list[ValidationError] = self.validate() 54 for err in validation_errors: 55 if err.level == ValidationLevel.WARNING or err.level == ValidationLevel.ERROR: 56 warnings.warn(f"Validation warning at {err.path}: {err.message}") 57 elif err.level == ValidationLevel.CRITICAL: 58 raise ValueError(f"Validation error at {err.path}: {err.message}") 59 60 def validate(self) -> list[ValidationError]: 61 """ 62 Validate the brim file and return a list of validation errors. 63 64 Returns: 65 list[ValidationError]: A list of validation errors found in the brim file. 66 If the list is empty, the file is valid. 67 """ 68 json_descriptor = generate_json_descriptor(self._file) 69 validation_errors: list[ValidationError] = validate_json(json_descriptor) 70 return validation_errors 71 72 def __del__(self): 73 try: 74 if hasattr(self, '_file'): 75 self.close() 76 except Exception as e: 77 # don't throw an error if the file cannot be closed 78 warnings.warn(f"Cannot close the file: {e}") 79 80 def close(self) -> None: 81 self._file.close() 82 83 def is_read_only(self) -> bool: 84 return sync(self._file.is_read_only()) 85 86 def is_valid(self) -> bool: 87 """ 88 Check if the file is a valid brim file. 89 90 Returns: 91 bool: True if the file is valid, False otherwise. 92 """ 93 # TODO validate file against https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md 94 return True 95 96 @classmethod 97 def create(cls, filename: str, store_type: StoreType = StoreType.AUTO, *, 98 brim_version: str = '0.1') -> 'File': 99 """ 100 Create a new brim file with the specified filename. If the file exists already it will generate an error. 101 102 Args: 103 filename (str): Path to the brim file to be created. 104 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 105 brim_version (str): Version of the brim file format to use. Default is '0.1'. 106 107 Returns: 108 File: An instance of the File class representing the newly created brim file. 109 store_type (str): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 110 """ 111 f = cls(filename, mode='w-', store_type=store_type) 112 113 # File version 114 sync(f._file.create_attr('/', 'brim_version', brim_version)) 115 116 # Root Brillouin_data group 117 sync(f._file.create_group(brim_obj_names.Brillouin_base_path)) 118 119 return f 120 121 def create_data_group(self, PSD: np.ndarray, frequency: np.ndarray, px_size_um: tuple, *, index: int = None, 122 name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 123 """ 124 Adds a new data entry to the file. 125 Parameters: 126 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. It must be 4D with dimensions z, y, x, spectrum 127 frequency (np.ndarray): The frequency data corresponding to the PSD. It must be broadcastable to the PSD shape (the most common case is frequency being 1D, in which case the frequency axis is assumed the same for all the spatial coordinates) 128 px_size_um (tuple): A tuple of 3 elements, in the order z,y,x, corresponding to the pixel size in um. Unused dimensions can be set to None. 129 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 130 name (str, optional): The name for the new data group. Defaults to None. 131 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 132 Returns: 133 Data: The newly created Data object. 134 Raises: 135 IndexError: If the specified index already exists in the dataset. 136 ValueError: If any of the data provided is not valid or consistent 137 """ 138 if PSD.ndim != 4: 139 raise ValueError( 140 "'PSD' must have 4 dimensions (z, y, x, spectrum)") 141 try: 142 np.broadcast_shapes(tuple(frequency.shape), tuple(PSD.shape)) 143 except ValueError as e: 144 raise ValueError(f"frequency (shape: {frequency.shape}) is not broadcastable to PSD (shape: {PSD.shape}): {e}") 145 if len(px_size_um) != 3: 146 raise ValueError("'px_size_um' must have 3 elements (z,y,x); unused dimensions can be set to None") 147 148 return self._create_data_group_raw(PSD, frequency, scanning = None, sparse = False, px_size_um=px_size_um, 149 index=index, name=name, compression=compression) 150 151 def create_data_group_sparse(self, PSD: np.ndarray, frequency: np.ndarray, scanning: dict, *, timestamp: np.ndarray = None, 152 index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 153 """ 154 Adds a new [sparse data entry](https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md) to the file. 155 156 Sparse data allows storage of spectra in a flattened format (first dimension is the spectrum index), 157 with spatial mapping provided separately. This is efficient for data with irregular sampling or missing pixels. 158 159 Parameters: 160 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. First dimension is spectrum index, 161 last dimension contains the spectral data. Shape: (n_spectra, ..., n_freq_points). 162 frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array. 163 scanning (dict): Dictionary defining the spatial mapping. Must include at least 'Spatial_map' or 'Cartesian_visualisation'. 164 See `brimfile.data.Data._add_data` docstring for detailed structure of the scanning dictionary. 165 timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None. 166 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 167 name (str, optional): The name for the new data group. Defaults to None. 168 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 169 Returns: 170 Data: The newly created Data object. 171 Raises: 172 IndexError: If the specified index already exists in the dataset. 173 ValueError: If any of the data provided is not valid or consistent 174 """ 175 return self._create_data_group_raw(PSD, frequency, scanning=scanning, timestamp=timestamp, sparse=True, index=index, name=name, compression=compression) 176 177 def _create_data_group_raw(self, PSD: np.ndarray, frequency: np.ndarray, *, scanning: dict = None, px_size_um = None, timestamp: np.ndarray = None, sparse: bool = False, 178 index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 179 """ 180 Adds a new data entry to the file. Check the documentation for `brimfile.data.Data._add_data` for more details on the parameters. 181 Parameters: 182 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. The last dimension contains the spectra. 183 frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array. 184 scanning (dict, optional): Spatial mapping metadata. Required for sparse=True, optional for sparse=False. 185 See `brimfile.data.Data._add_data` docstring for detailed structure. 186 px_size_um (tuple, optional): A tuple of 3 elements (z, y, x) for pixel size in μm. For non-sparse data only. 187 timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None. 188 sparse (bool): Whether the data is sparse. See https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md for details. Defaults to False. 189 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 190 name (str, optional): The name for the new data group. Defaults to None. 191 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 192 Returns: 193 Data: The newly created Data object. 194 Raises: 195 IndexError: If the specified index already exists in the dataset. 196 ValueError: If any of the data provided is not valid or consistent 197 """ 198 if index is not None: 199 if sync(Data._get_existing_group_name_async(self._file, index)) is not None: 200 raise IndexError( 201 f"Data {index} already exists in {self._file.filename}") 202 else: 203 data_groups = self.list_data_groups() 204 indices = [dg['index'] for dg in data_groups] 205 indices.sort() 206 index = indices[-1] + 1 if indices else 0 # Next available index 207 208 # create the data group 209 d = Data._create_new(self._file, index, sparse, name) 210 # add the pixel size as an attribute of the data group 211 if px_size_um is not None: 212 sync(self._file.create_attr(d._group, 'element_size', tuple(px_size_um))) 213 units.add_to_attribute(self._file, d._group, 'element_size', 'um') 214 elif not sparse: 215 warnings.warn("Pixel size is not provided for non-sparse data. It is recommended to provide it for proper spatial calibration and visualization.") 216 # add the data to the data group 217 d._add_data(PSD, frequency, scanning = scanning, 218 timestamp=timestamp, compression=compression) 219 return d 220 221 def list_data_groups(self, retrieve_custom_name=False) -> list: 222 """ 223 List all data groups in the brim file. 224 225 Returns: 226 See documentation of brimfile.data.Data.list_data_groups 227 """ 228 return Data.list_data_groups(self._file, retrieve_custom_name) 229 230 def get_data(self, index: int = 0) -> 'Data': 231 """ 232 Retrieve a Data object for the specified index. 233 234 Args: 235 index (int): The index of the data group to retrieve. 236 237 Returns: 238 Data: The Data object corresponding to the specified index. 239 Raises: 240 IndexError: If the specified index does not exist in the dataset. 241 """ 242 return sync(Data.from_existing_async(self._file, index)) 243 244 @property 245 def filename(self) -> str: 246 """ 247 Get the filename of the brim file. 248 249 Returns: 250 str: The filename of the brim file. 251 """ 252 return self._file.filename 253 254 @property 255 def subtype(self) -> subtypes.SubType: 256 """ 257 Get the subtype of the brim file. 258 259 Returns: 260 subtypes.SubType: The subtype of the brim file. 261 """ 262 return subtypes.get_subtype(self._file)
23class File: 24 """ 25 Represents a brim file with Brillouin data, extending h5py.File. 26 """ 27 28 if "pyodide" in sys.modules: 29 def __init__(self, file): 30 self._file = file 31 if not self.is_valid(): 32 raise ValueError("The brim file is not valid!") 33 else: 34 def __init__(self, filename: str, mode: str = 'r', 35 store_type: StoreType = StoreType.AUTO, * , 36 validate: bool = False) -> None: 37 """ 38 Initialize the File object. 39 40 Args: 41 filename (str): Path to the brim file. 42 mode: {'r', 'r+', 'a', 'w', 'w-'} the mode for opening the file (default is 'r' for read-only). 43 See the definition of `mode` in `brimfile.file_abstraction._zarrFile.__init__()` for more details. 44 'r' means read only (must exist); 'r+' means read/write (must exist); 45 'a' means read/write (create if doesn't exist); 'w' means create (overwrite if exists); 'w-' means create (fail if exists). 46 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 47 validate (bool): Whether to validate the file upon initialization. Default is False. 48 """ 49 self._file = _AbstractFile( 50 filename, mode=mode, store_type=store_type) 51 if not self.is_valid(): 52 raise ValueError("The brim file is not valid!") 53 if validate: 54 validation_errors: list[ValidationError] = self.validate() 55 for err in validation_errors: 56 if err.level == ValidationLevel.WARNING or err.level == ValidationLevel.ERROR: 57 warnings.warn(f"Validation warning at {err.path}: {err.message}") 58 elif err.level == ValidationLevel.CRITICAL: 59 raise ValueError(f"Validation error at {err.path}: {err.message}") 60 61 def validate(self) -> list[ValidationError]: 62 """ 63 Validate the brim file and return a list of validation errors. 64 65 Returns: 66 list[ValidationError]: A list of validation errors found in the brim file. 67 If the list is empty, the file is valid. 68 """ 69 json_descriptor = generate_json_descriptor(self._file) 70 validation_errors: list[ValidationError] = validate_json(json_descriptor) 71 return validation_errors 72 73 def __del__(self): 74 try: 75 if hasattr(self, '_file'): 76 self.close() 77 except Exception as e: 78 # don't throw an error if the file cannot be closed 79 warnings.warn(f"Cannot close the file: {e}") 80 81 def close(self) -> None: 82 self._file.close() 83 84 def is_read_only(self) -> bool: 85 return sync(self._file.is_read_only()) 86 87 def is_valid(self) -> bool: 88 """ 89 Check if the file is a valid brim file. 90 91 Returns: 92 bool: True if the file is valid, False otherwise. 93 """ 94 # TODO validate file against https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md 95 return True 96 97 @classmethod 98 def create(cls, filename: str, store_type: StoreType = StoreType.AUTO, *, 99 brim_version: str = '0.1') -> 'File': 100 """ 101 Create a new brim file with the specified filename. If the file exists already it will generate an error. 102 103 Args: 104 filename (str): Path to the brim file to be created. 105 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 106 brim_version (str): Version of the brim file format to use. Default is '0.1'. 107 108 Returns: 109 File: An instance of the File class representing the newly created brim file. 110 store_type (str): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 111 """ 112 f = cls(filename, mode='w-', store_type=store_type) 113 114 # File version 115 sync(f._file.create_attr('/', 'brim_version', brim_version)) 116 117 # Root Brillouin_data group 118 sync(f._file.create_group(brim_obj_names.Brillouin_base_path)) 119 120 return f 121 122 def create_data_group(self, PSD: np.ndarray, frequency: np.ndarray, px_size_um: tuple, *, index: int = None, 123 name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 124 """ 125 Adds a new data entry to the file. 126 Parameters: 127 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. It must be 4D with dimensions z, y, x, spectrum 128 frequency (np.ndarray): The frequency data corresponding to the PSD. It must be broadcastable to the PSD shape (the most common case is frequency being 1D, in which case the frequency axis is assumed the same for all the spatial coordinates) 129 px_size_um (tuple): A tuple of 3 elements, in the order z,y,x, corresponding to the pixel size in um. Unused dimensions can be set to None. 130 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 131 name (str, optional): The name for the new data group. Defaults to None. 132 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 133 Returns: 134 Data: The newly created Data object. 135 Raises: 136 IndexError: If the specified index already exists in the dataset. 137 ValueError: If any of the data provided is not valid or consistent 138 """ 139 if PSD.ndim != 4: 140 raise ValueError( 141 "'PSD' must have 4 dimensions (z, y, x, spectrum)") 142 try: 143 np.broadcast_shapes(tuple(frequency.shape), tuple(PSD.shape)) 144 except ValueError as e: 145 raise ValueError(f"frequency (shape: {frequency.shape}) is not broadcastable to PSD (shape: {PSD.shape}): {e}") 146 if len(px_size_um) != 3: 147 raise ValueError("'px_size_um' must have 3 elements (z,y,x); unused dimensions can be set to None") 148 149 return self._create_data_group_raw(PSD, frequency, scanning = None, sparse = False, px_size_um=px_size_um, 150 index=index, name=name, compression=compression) 151 152 def create_data_group_sparse(self, PSD: np.ndarray, frequency: np.ndarray, scanning: dict, *, timestamp: np.ndarray = None, 153 index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 154 """ 155 Adds a new [sparse data entry](https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md) to the file. 156 157 Sparse data allows storage of spectra in a flattened format (first dimension is the spectrum index), 158 with spatial mapping provided separately. This is efficient for data with irregular sampling or missing pixels. 159 160 Parameters: 161 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. First dimension is spectrum index, 162 last dimension contains the spectral data. Shape: (n_spectra, ..., n_freq_points). 163 frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array. 164 scanning (dict): Dictionary defining the spatial mapping. Must include at least 'Spatial_map' or 'Cartesian_visualisation'. 165 See `brimfile.data.Data._add_data` docstring for detailed structure of the scanning dictionary. 166 timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None. 167 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 168 name (str, optional): The name for the new data group. Defaults to None. 169 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 170 Returns: 171 Data: The newly created Data object. 172 Raises: 173 IndexError: If the specified index already exists in the dataset. 174 ValueError: If any of the data provided is not valid or consistent 175 """ 176 return self._create_data_group_raw(PSD, frequency, scanning=scanning, timestamp=timestamp, sparse=True, index=index, name=name, compression=compression) 177 178 def _create_data_group_raw(self, PSD: np.ndarray, frequency: np.ndarray, *, scanning: dict = None, px_size_um = None, timestamp: np.ndarray = None, sparse: bool = False, 179 index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 180 """ 181 Adds a new data entry to the file. Check the documentation for `brimfile.data.Data._add_data` for more details on the parameters. 182 Parameters: 183 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. The last dimension contains the spectra. 184 frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array. 185 scanning (dict, optional): Spatial mapping metadata. Required for sparse=True, optional for sparse=False. 186 See `brimfile.data.Data._add_data` docstring for detailed structure. 187 px_size_um (tuple, optional): A tuple of 3 elements (z, y, x) for pixel size in μm. For non-sparse data only. 188 timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None. 189 sparse (bool): Whether the data is sparse. See https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md for details. Defaults to False. 190 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 191 name (str, optional): The name for the new data group. Defaults to None. 192 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 193 Returns: 194 Data: The newly created Data object. 195 Raises: 196 IndexError: If the specified index already exists in the dataset. 197 ValueError: If any of the data provided is not valid or consistent 198 """ 199 if index is not None: 200 if sync(Data._get_existing_group_name_async(self._file, index)) is not None: 201 raise IndexError( 202 f"Data {index} already exists in {self._file.filename}") 203 else: 204 data_groups = self.list_data_groups() 205 indices = [dg['index'] for dg in data_groups] 206 indices.sort() 207 index = indices[-1] + 1 if indices else 0 # Next available index 208 209 # create the data group 210 d = Data._create_new(self._file, index, sparse, name) 211 # add the pixel size as an attribute of the data group 212 if px_size_um is not None: 213 sync(self._file.create_attr(d._group, 'element_size', tuple(px_size_um))) 214 units.add_to_attribute(self._file, d._group, 'element_size', 'um') 215 elif not sparse: 216 warnings.warn("Pixel size is not provided for non-sparse data. It is recommended to provide it for proper spatial calibration and visualization.") 217 # add the data to the data group 218 d._add_data(PSD, frequency, scanning = scanning, 219 timestamp=timestamp, compression=compression) 220 return d 221 222 def list_data_groups(self, retrieve_custom_name=False) -> list: 223 """ 224 List all data groups in the brim file. 225 226 Returns: 227 See documentation of brimfile.data.Data.list_data_groups 228 """ 229 return Data.list_data_groups(self._file, retrieve_custom_name) 230 231 def get_data(self, index: int = 0) -> 'Data': 232 """ 233 Retrieve a Data object for the specified index. 234 235 Args: 236 index (int): The index of the data group to retrieve. 237 238 Returns: 239 Data: The Data object corresponding to the specified index. 240 Raises: 241 IndexError: If the specified index does not exist in the dataset. 242 """ 243 return sync(Data.from_existing_async(self._file, index)) 244 245 @property 246 def filename(self) -> str: 247 """ 248 Get the filename of the brim file. 249 250 Returns: 251 str: The filename of the brim file. 252 """ 253 return self._file.filename 254 255 @property 256 def subtype(self) -> subtypes.SubType: 257 """ 258 Get the subtype of the brim file. 259 260 Returns: 261 subtypes.SubType: The subtype of the brim file. 262 """ 263 return subtypes.get_subtype(self._file)
Represents a brim file with Brillouin data, extending h5py.File.
34 def __init__(self, filename: str, mode: str = 'r', 35 store_type: StoreType = StoreType.AUTO, * , 36 validate: bool = False) -> None: 37 """ 38 Initialize the File object. 39 40 Args: 41 filename (str): Path to the brim file. 42 mode: {'r', 'r+', 'a', 'w', 'w-'} the mode for opening the file (default is 'r' for read-only). 43 See the definition of `mode` in `brimfile.file_abstraction._zarrFile.__init__()` for more details. 44 'r' means read only (must exist); 'r+' means read/write (must exist); 45 'a' means read/write (create if doesn't exist); 'w' means create (overwrite if exists); 'w-' means create (fail if exists). 46 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 47 validate (bool): Whether to validate the file upon initialization. Default is False. 48 """ 49 self._file = _AbstractFile( 50 filename, mode=mode, store_type=store_type) 51 if not self.is_valid(): 52 raise ValueError("The brim file is not valid!") 53 if validate: 54 validation_errors: list[ValidationError] = self.validate() 55 for err in validation_errors: 56 if err.level == ValidationLevel.WARNING or err.level == ValidationLevel.ERROR: 57 warnings.warn(f"Validation warning at {err.path}: {err.message}") 58 elif err.level == ValidationLevel.CRITICAL: 59 raise ValueError(f"Validation error at {err.path}: {err.message}")
Initialize the File object.
Arguments:
- filename (str): Path to the brim file.
- mode: {'r', 'r+', 'a', 'w', 'w-'} the mode for opening the file (default is 'r' for read-only).
See the definition of
modeinbrimfile.file_abstraction._zarrFile.__init__()for more details. 'r' means read only (must exist); 'r+' means read/write (must exist); 'a' means read/write (create if doesn't exist); 'w' means create (overwrite if exists); 'w-' means create (fail if exists). - store_type (StoreType): Type of the store to use, as defined in
brimfile.file_abstraction.StoreType. Default is 'AUTO'. - validate (bool): Whether to validate the file upon initialization. Default is False.
61 def validate(self) -> list[ValidationError]: 62 """ 63 Validate the brim file and return a list of validation errors. 64 65 Returns: 66 list[ValidationError]: A list of validation errors found in the brim file. 67 If the list is empty, the file is valid. 68 """ 69 json_descriptor = generate_json_descriptor(self._file) 70 validation_errors: list[ValidationError] = validate_json(json_descriptor) 71 return validation_errors
Validate the brim file and return a list of validation errors.
Returns:
list[ValidationError]: A list of validation errors found in the brim file. If the list is empty, the file is valid.
87 def is_valid(self) -> bool: 88 """ 89 Check if the file is a valid brim file. 90 91 Returns: 92 bool: True if the file is valid, False otherwise. 93 """ 94 # TODO validate file against https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md 95 return True
Check if the file is a valid brim file.
Returns:
bool: True if the file is valid, False otherwise.
97 @classmethod 98 def create(cls, filename: str, store_type: StoreType = StoreType.AUTO, *, 99 brim_version: str = '0.1') -> 'File': 100 """ 101 Create a new brim file with the specified filename. If the file exists already it will generate an error. 102 103 Args: 104 filename (str): Path to the brim file to be created. 105 store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 106 brim_version (str): Version of the brim file format to use. Default is '0.1'. 107 108 Returns: 109 File: An instance of the File class representing the newly created brim file. 110 store_type (str): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'. 111 """ 112 f = cls(filename, mode='w-', store_type=store_type) 113 114 # File version 115 sync(f._file.create_attr('/', 'brim_version', brim_version)) 116 117 # Root Brillouin_data group 118 sync(f._file.create_group(brim_obj_names.Brillouin_base_path)) 119 120 return f
Create a new brim file with the specified filename. If the file exists already it will generate an error.
Arguments:
- filename (str): Path to the brim file to be created.
- store_type (StoreType): Type of the store to use, as defined in
brimfile.file_abstraction.StoreType. Default is 'AUTO'. - brim_version (str): Version of the brim file format to use. Default is '0.1'.
Returns:
File: An instance of the File class representing the newly created brim file. store_type (str): Type of the store to use, as defined in
brimfile.file_abstraction.StoreType. Default is 'AUTO'.
122 def create_data_group(self, PSD: np.ndarray, frequency: np.ndarray, px_size_um: tuple, *, index: int = None, 123 name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 124 """ 125 Adds a new data entry to the file. 126 Parameters: 127 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. It must be 4D with dimensions z, y, x, spectrum 128 frequency (np.ndarray): The frequency data corresponding to the PSD. It must be broadcastable to the PSD shape (the most common case is frequency being 1D, in which case the frequency axis is assumed the same for all the spatial coordinates) 129 px_size_um (tuple): A tuple of 3 elements, in the order z,y,x, corresponding to the pixel size in um. Unused dimensions can be set to None. 130 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 131 name (str, optional): The name for the new data group. Defaults to None. 132 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 133 Returns: 134 Data: The newly created Data object. 135 Raises: 136 IndexError: If the specified index already exists in the dataset. 137 ValueError: If any of the data provided is not valid or consistent 138 """ 139 if PSD.ndim != 4: 140 raise ValueError( 141 "'PSD' must have 4 dimensions (z, y, x, spectrum)") 142 try: 143 np.broadcast_shapes(tuple(frequency.shape), tuple(PSD.shape)) 144 except ValueError as e: 145 raise ValueError(f"frequency (shape: {frequency.shape}) is not broadcastable to PSD (shape: {PSD.shape}): {e}") 146 if len(px_size_um) != 3: 147 raise ValueError("'px_size_um' must have 3 elements (z,y,x); unused dimensions can be set to None") 148 149 return self._create_data_group_raw(PSD, frequency, scanning = None, sparse = False, px_size_um=px_size_um, 150 index=index, name=name, compression=compression)
Adds a new data entry to the file.
Arguments:
- PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. It must be 4D with dimensions z, y, x, spectrum
- frequency (np.ndarray): The frequency data corresponding to the PSD. It must be broadcastable to the PSD shape (the most common case is frequency being 1D, in which case the frequency axis is assumed the same for all the spatial coordinates)
- px_size_um (tuple): A tuple of 3 elements, in the order z,y,x, corresponding to the pixel size in um. Unused dimensions can be set to None.
- index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None.
- name (str, optional): The name for the new data group. Defaults to None.
- compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT.
Returns:
Data: The newly created Data object.
Raises:
- IndexError: If the specified index already exists in the dataset.
- ValueError: If any of the data provided is not valid or consistent
152 def create_data_group_sparse(self, PSD: np.ndarray, frequency: np.ndarray, scanning: dict, *, timestamp: np.ndarray = None, 153 index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data': 154 """ 155 Adds a new [sparse data entry](https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md) to the file. 156 157 Sparse data allows storage of spectra in a flattened format (first dimension is the spectrum index), 158 with spatial mapping provided separately. This is efficient for data with irregular sampling or missing pixels. 159 160 Parameters: 161 PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. First dimension is spectrum index, 162 last dimension contains the spectral data. Shape: (n_spectra, ..., n_freq_points). 163 frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array. 164 scanning (dict): Dictionary defining the spatial mapping. Must include at least 'Spatial_map' or 'Cartesian_visualisation'. 165 See `brimfile.data.Data._add_data` docstring for detailed structure of the scanning dictionary. 166 timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None. 167 index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None. 168 name (str, optional): The name for the new data group. Defaults to None. 169 compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT. 170 Returns: 171 Data: The newly created Data object. 172 Raises: 173 IndexError: If the specified index already exists in the dataset. 174 ValueError: If any of the data provided is not valid or consistent 175 """ 176 return self._create_data_group_raw(PSD, frequency, scanning=scanning, timestamp=timestamp, sparse=True, index=index, name=name, compression=compression)
Adds a new sparse data entry to the file.
Sparse data allows storage of spectra in a flattened format (first dimension is the spectrum index), with spatial mapping provided separately. This is efficient for data with irregular sampling or missing pixels.
Arguments:
- PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. First dimension is spectrum index, last dimension contains the spectral data. Shape: (n_spectra, ..., n_freq_points).
- frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array.
- scanning (dict): Dictionary defining the spatial mapping. Must include at least 'Spatial_map' or 'Cartesian_visualisation'.
See
brimfile.data.Data._add_datadocstring for detailed structure of the scanning dictionary. - timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None.
- index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None.
- name (str, optional): The name for the new data group. Defaults to None.
- compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT.
Returns:
Data: The newly created Data object.
Raises:
- IndexError: If the specified index already exists in the dataset.
- ValueError: If any of the data provided is not valid or consistent
222 def list_data_groups(self, retrieve_custom_name=False) -> list: 223 """ 224 List all data groups in the brim file. 225 226 Returns: 227 See documentation of brimfile.data.Data.list_data_groups 228 """ 229 return Data.list_data_groups(self._file, retrieve_custom_name)
List all data groups in the brim file.
Returns:
See documentation of brimfile.data.Data.list_data_groups
231 def get_data(self, index: int = 0) -> 'Data': 232 """ 233 Retrieve a Data object for the specified index. 234 235 Args: 236 index (int): The index of the data group to retrieve. 237 238 Returns: 239 Data: The Data object corresponding to the specified index. 240 Raises: 241 IndexError: If the specified index does not exist in the dataset. 242 """ 243 return sync(Data.from_existing_async(self._file, index))
Retrieve a Data object for the specified index.
Arguments:
- index (int): The index of the data group to retrieve.
Returns:
Data: The Data object corresponding to the specified index.
Raises:
- IndexError: If the specified index does not exist in the dataset.
245 @property 246 def filename(self) -> str: 247 """ 248 Get the filename of the brim file. 249 250 Returns: 251 str: The filename of the brim file. 252 """ 253 return self._file.filename
Get the filename of the brim file.
Returns:
str: The filename of the brim file.
255 @property 256 def subtype(self) -> subtypes.SubType: 257 """ 258 Get the subtype of the brim file. 259 260 Returns: 261 subtypes.SubType: The subtype of the brim file. 262 """ 263 return subtypes.get_subtype(self._file)
Get the subtype of the brim file.
Returns:
subtypes.SubType: The subtype of the brim file.