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

Represents a brim file with Brillouin data, extending h5py.File.

File( filename: str, mode: str = 'r', store_type: brimfile.file_abstraction.StoreType = <StoreType.AUTO: 'auto'>, *, validate: bool = False)
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}")

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 mode in brimfile.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.
def validate(self) -> list[brimfile.validation.main.ValidationError]:
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

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.

def close(self) -> None:
80    def close(self) -> None:
81        self._file.close()
def is_read_only(self) -> bool:
83    def is_read_only(self) -> bool:
84        return sync(self._file.is_read_only())
def is_valid(self) -> bool:
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

Check if the file is a valid brim file.

Returns:

bool: True if the file is valid, False otherwise.

@classmethod
def create( cls, filename: str, store_type: brimfile.file_abstraction.StoreType = <StoreType.AUTO: 'auto'>, brim_version: str = '0.1') -> File:
 96    @classmethod
 97    def create(cls, filename: str, store_type: StoreType = StoreType.AUTO, brim_version: str = '0.1') -> 'File':
 98        """
 99        Create a new brim file with the specified filename. If the file exists already it will generate an error.
100
101        Args:
102            filename (str): Path to the brim file to be created.
103            store_type (StoreType): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'.
104            brim_version (str): Version of the brim file format to use. Default is '0.1'.
105
106        Returns:
107            File: An instance of the File class representing the newly created brim file.
108            store_type (str): Type of the store to use, as defined in `brimfile.file_abstraction.StoreType`. Default is 'AUTO'.
109        """
110        f = cls(filename, mode='w-', store_type=store_type)
111
112        # File version
113        sync(f._file.create_attr('/', 'brim_version', brim_version))
114
115        # Root Brillouin_data group
116        sync(f._file.create_group(brim_obj_names.Brillouin_base_path))
117
118        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'.

def create_data_group( self, PSD: numpy.ndarray, frequency: numpy.ndarray, px_size_um: tuple, *, index: int = None, name: str = None, compression: brimfile.file_abstraction.FileAbstraction.Compression = <brimfile.file_abstraction.FileAbstraction.Compression object>) -> brimfile.data.Data:
120    def create_data_group(self, PSD: np.ndarray, frequency: np.ndarray, px_size_um: tuple, *, index: int = None,
121                          name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data':
122        """
123        Adds a new data entry to the file.
124        Parameters:
125            PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. It must be 4D with dimensions z, y, x, spectrum
126            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)
127            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.
128            index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None.
129            name (str, optional): The name for the new data group. Defaults to None.
130            compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT.
131        Returns:
132            Data: The newly created Data object.
133        Raises:
134            IndexError: If the specified index already exists in the dataset.
135            ValueError: If any of the data provided is not valid or consistent
136        """
137        if PSD.ndim != 4:
138            raise ValueError(
139                "'PSD' must have 4 dimensions (z, y, x, spectrum)")
140        try:
141            np.broadcast_shapes(tuple(frequency.shape), tuple(PSD.shape))
142        except ValueError as e:
143            raise ValueError(f"frequency (shape: {frequency.shape}) is not broadcastable to PSD (shape: {PSD.shape}): {e}")
144        if len(px_size_um) != 3:
145            raise ValueError("'px_size_um' must have 3 elements (z,y,x); unused dimensions can be set to None")
146
147        return self._create_data_group_raw(PSD, frequency, scanning = None, sparse = False, px_size_um=px_size_um, 
148                                             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
def create_data_group_sparse( self, PSD: numpy.ndarray, frequency: numpy.ndarray, scanning: dict, *, timestamp: numpy.ndarray = None, index: int = None, name: str = None, compression: brimfile.file_abstraction.FileAbstraction.Compression = <brimfile.file_abstraction.FileAbstraction.Compression object>) -> brimfile.data.Data:
150    def create_data_group_sparse(self, PSD: np.ndarray, frequency: np.ndarray, scanning: dict, *, timestamp: np.ndarray = None,
151                                index: int = None, name: str = None, compression: FileAbstraction.Compression = FileAbstraction.Compression()) -> 'Data':
152        """
153        Adds a new [sparse data entry](https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_specs.md) to the file.
154        
155        Sparse data allows storage of spectra in a flattened format (first dimension is the spectrum index),
156        with spatial mapping provided separately. This is efficient for data with irregular sampling or missing pixels.
157        
158        Parameters:
159            PSD (np.ndarray): The Power Spectral Density (PSD) data to be added. First dimension is spectrum index,
160                last dimension contains the spectral data. Shape: (n_spectra, ..., n_freq_points).
161            frequency (np.ndarray): The frequency data corresponding to the PSD. Must be broadcastable to the PSD array.
162            scanning (dict): Dictionary defining the spatial mapping. Must include at least 'Spatial_map' or 'Cartesian_visualisation'.
163                See `brimfile.data.Data._add_data` docstring for detailed structure of the scanning dictionary.
164            timestamp (np.ndarray, optional): Timestamps in milliseconds for the data. Defaults to None.
165            index (int, optional): The index for the new data group. If None, the next available index is used. Defaults to None.
166            name (str, optional): The name for the new data group. Defaults to None.
167            compression (FileAbstraction.Compression, optional): The compression method to use for the data. Defaults to FileAbstraction.Compression.DEFAULT.
168        Returns:
169            Data: The newly created Data object.
170        Raises:
171            IndexError: If the specified index already exists in the dataset.
172            ValueError: If any of the data provided is not valid or consistent
173        """
174        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_data docstring 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
def list_data_groups(self, retrieve_custom_name=False) -> list:
220    def list_data_groups(self, retrieve_custom_name=False) -> list:
221        """
222        List all data groups in the brim file.
223
224        Returns:
225            See documentation of brimfile.data.Data.list_data_groups
226        """
227        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

def get_data(self, index: int = 0) -> brimfile.data.Data:
229    def get_data(self, index: int = 0) -> 'Data':
230        """
231        Retrieve a Data object for the specified index.
232
233        Args:
234            index (int): The index of the data group to retrieve.
235
236        Returns:
237            Data: The Data object corresponding to the specified index.
238        """
239        group_name: str = Data._get_existing_group_name(self._file, index)
240        if group_name is None:
241            raise IndexError(f"Data {index} not found")
242        data = Data(self._file, concatenate_paths(
243            brim_obj_names.Brillouin_base_path, group_name))
244        return data

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.

filename: str
246    @property
247    def filename(self) -> str:
248        """
249        Get the filename of the brim file.
250
251        Returns:
252            str: The filename of the brim file.
253        """
254        return self._file.filename

Get the filename of the brim file.

Returns:

str: The filename of the brim file.