brimfile
What is brimfile?
brimfile is a Python library to read from and write to brim (Brillouin imaging) files, which contain both the spectra and analysed data for Brillouin imaging. More information about the brim file format can be found here.
Briefly, a brim file can contain multiple data groups, typically corresponding to imaging of the same sample at different timepoints/conditions. Each data group contains the spectral data as well as the metadata and the results of the analysis on the spectral data (which can be many in case multiple reconstruction pipelines are performed).
The structure of the brimfile library reflects the structure of the brim file and the user can access the data, metadata and analysis results through their corresponding classes.
- File: represents a brim file, which can be opened or created.
- Data: represents a data group in the brim file, which contains the spectral data and metadata.
- Metadata: represents the metadata associated to a data group (or to the whole file).
- AnalysisResults: represents the results of the analysis of the spectral data.
- Calibration: represents the calibration data associated to a data group, which contains the calibration spectra and relevant metadata.
Install brimfile
We recommend installing brimfile in a virtual environment.
After activating the new environment, simply run:
pip install brimfile
If you also need the support for exporting the analyzed data to OME-TIFF files, you can install the optional dependencies with:
pip install "brimfile[export-tiff]"
For accessing remote data (i.e. S3 buckets), you need remote-store:
pip install "brimfile[remote-store]"
Quickstart
The following code shows how to:
- open a .brim file
- get an image for the Brillouin shift
- get the spectrum at a specific pixel
- get the metadata.
from brimfile import File, Data, Metadata, AnalysisResults
Quantity = AnalysisResults.Quantity
PeakType = AnalysisResults.PeakType
filename = 'path/to/your/file.brim.zarr'
f = File(filename)
# get the first data group in the file
d = f.get_data()
# get the first analysis results in the data group
ar = d.get_analysis_results()
# get the image for the shift
img, px_size = ar.get_image(Quantity.Shift, PeakType.average)
# get the spectrum at the pixel (pz,py,px)
(pz,py,px) = (0,0,0)
PSD, frequency, PSD_units, frequency_units = d.get_spectrum_in_image((pz,py,px))
# get the metadata
md = d.get_metadata()
all_metadata = md.all_to_dict()
# close the file
f.close()
Store types
Currently brimfile supports zip, zarr and S3 buckets as a store. When opening or creating a file, the storage be selected by using the brimfile.file_abstraction.StoreType enum; zip and zarr can be used both for reading and writing while S3 only for reading.
Although it is possible to write directly to zip, this will create duplicated entries in the archive (see GitHub issue).
A possible workaround is to create a .zarr store instead and zip the folder afterwards. Importantly the root of the archive should not contain the folder itself, i.e. you should go inside the .zarr folder, select all the elements there, right click on them to create a .zip archive.
Use brimfile
File
The main class is brimfile.file.File, which represents a brim file.
It can be used to create a new brim file (brimfile.file.File.create) or to open an existing one (brimfile.file.File.__init__).
import brimfile as brim
filename = 'path/to/your/file.brim.zarr'
# Open an existing brim file
f = brim.File(filename)
# or create a new one
f = brim.File.create(filename)
Data
You can then get a brimfile.data.Data object representing the data group in the brim file
by opening an existing one (brimfile.file.File.get_data).
# Get the first data group in the file
data = f.get_data()
To add a new data group to the file, you can use the brimfile.file.File.create_data_group method,
which accepts a 4D array for the PSD with dimensions (z, y, x, spectrum),
a frequency array which might have the same size as PSD or be 1D, in case the frequency axis is the same for all the spectra.
# or create a new one
data = f.create_data_group(PSD, freq_GHz, (dz, dy, dx), name='my_data_group')
Alternatively you can use brimfile.file.File.create_data_group_sparse for sparse data, which lets you directly assign the correspondence
between the spatial positions and the spectra through the scanning dictionary.
Once you have an istance of brimfile.data.Data, you can get the spectrum corresponding to a pixel in the image
by calling the brimfile.data.Data.get_spectrum_in_image method:
PSD, frequency, PSD_units, frequency_units = data.get_spectrum_in_image((pz,py,px))
Metadata
You can then get a brimfile.metadata.main.Metadata object by simply calling the brimfile.data.Data.get_metadata method on a previously retrieved Data object.
The returned Metadata object contains all the metadata associated with the file and the specific data group.
metadata = data.get_metadata()
The list of available metadata is defined here and can also be printed in the terminal with the brimfile.metadata.schema.print_schema method, which also allows to print the description of each metadata field:
brim.metadata.print_schema(include_description=True)
For metadata fields which require an enum, it can be imported from brimfile.metadata, e.g. from brimfile.metadata import ImmersionMedium.
New metadata can be added to the current data group (or to the whole file) by calling the brimfile.metadata.main.Metadata.add method.
import datetime
Attr = Metadata.Item
datetime_now = datetime.now().isoformat()
temp = Attr(22.0, 'C')
metadata.add(Metadata.Type.Experiment, {'Datetime':datetime_now, 'Temperature':temp},local=True)
When adding metadata fields which require an enum, the enum value or the string representation of the enum member (case-insensitive and ignoring underscores and spaces) can be used, e.g. brim.metadata.SignalType.spontaneous or 'spontaneous' can be used for the Signal_type field.
A single metadata item can be retrieved by indexing the Metadata object, which takes a string in the format 'group.object', e.g. 'Experiment.Datetime'.
datetime = metadata['Experiment.Datetime']
A dictionary containing all metadata can be retrieved by calling the brimfile.metadata.main.Metadata.all_to_dict method.
metadata.all_to_dict()
AnalysisResults
The results of the analysis can be accessed through the brimfile.analysis_results.AnalysisResults object, obtained by calling the brimfile.data.Data.get_analysis_results method on a previously retrieved Data object:
analysis_results = data.get_analysis_results()
or create a new one by calling the brimfile.data.Data.create_analysis_results_group:
ar = data.create_analysis_results_group({'shift':shift_GHz, 'shift_units': 'GHz',
'width': width_GHz, 'width_units': 'GHz'},
{'shift':shift_GHz, 'shift_units': 'GHz',
'width': width_GHz, 'width_units': 'GHz'},
name = 'my_analysis_results')
AnalysisResults also exposes a method to retrieve the images of the analysis results (brimfile.analysis_results.AnalysisResults.get_image):
ar_cls = AnalysisResults
img, px_size = analysis_results.get_image(ar_cls.Quantity.Shift, ar_cls.PeakType.average)
Calibration
Calibration data can be accessed through the brimfile.calibration.Calibration object, obtained by calling brimfile.data.Data.get_calibration.
You can create a new calibration group with brimfile.data.Data.create_calibration_group by providing one or more calibration materials
(each with spectra, shift, and optional shift_units) and, when needed, an index array mapping image coordinates to calibration spectra.
If another data group should reuse an existing calibration, you can pass same_as=<data_group_index> when creating the calibration group.
# create calibration for data group d0
N = np.prod(PSD.shape[:-1])
index = np.arange(N).reshape(PSD.shape[:-1])
cal_d = {'spectra': np.empty((N, 50)), 'shift': 7.0, 'shift_units': 'GHz'}
d0.create_calibration_group(index=index, calibration_data=[cal_d])
# retrieve calibration and get a spectrum at (z, y, x)
cal = d0.get_calibration()
spectrum, shift = cal.get_spectrum_at_coor((1, 2, 3))
# optionally reuse calibration from data group 0 in another data group
d1.create_calibration_group(same_as=0)
List the contents of a brim file
The brimfile library provides methods to list the contents of a brim file.
To list all the data groups in a brim file, you can use the brimfile.file.File.list_data_groups method.
Once you have a Data object, you can list the analysis results in it by calling the brimfile.data.Data.list_AnalysisResults method.
Once you have an AnalysisResults object, you can determine:
- if the Stokes and/or anti-Stokes peaks are present by calling the
brimfile.analysis_results.AnalysisResults.list_existing_peak_typesmethod; - the available quantities (e.g. shift, linewidth, etc...) in the analysis results by calling the
brimfile.analysis_results.AnalysisResults.list_existing_quantitiesmethod.
Subtypes
For subtype-specific data and utilities (for example SinglePoint_VIPA helpers), see brimfile.subtypes.
Example code
Here is a simple example which creates a brim file with a data group and some metadata and then reads it back.
We first write a function to generate some dummy data:
import numpy as np
def generate_data():
def lorentzian(x, x0, w):
return 1/(1+((x-x0)/(w/2))**2)
Nx, Ny, Nz = (7, 5, 3) # Number of points in x,y,z
dx, dy, dz = (0.4, 0.5, 2) # Stepsizes (in um)
n_points = Nx*Ny*Nz # total number of points
width_GHz = 0.4
width_GHz_arr = np.full((Nz, Ny, Nx), width_GHz)
shift_GHz_arr = np.empty((Nz, Ny, Nx))
freq_GHz = np.linspace(6, 9, 151) # 151 frequency points
PSD = np.empty((Nz, Ny, Nx, len(freq_GHz)))
for i in range(Nz):
for j in range(Ny):
for k in range(Nx):
index = k + Nx*j + Ny*Nx*i
#let's increase the shift linearly to have a readout
shift_GHz = freq_GHz[0] + (freq_GHz[-1]-freq_GHz[0]) * index/n_points
spectrum = lorentzian(freq_GHz, shift_GHz, width_GHz)
shift_GHz_arr[i,j,k] = shift_GHz
PSD[i, j, k,:] = spectrum
return PSD, freq_GHz, (dz,dy,dx), shift_GHz_arr, width_GHz_arr
Now we can use this function to create a brim file with a data group and some metadata:
import brimfile as brim
from brimfile import File, Data, Metadata, StoreType
from datetime import datetime
filename = 'path/to/your/file.brim.zarr'
f = File.create(filename, store_type=StoreType.AUTO)
PSD, freq_GHz, (dz,dy,dx), shift_GHz, width_GHz = generate_data()
d0 = f.create_data_group(PSD, freq_GHz, (dz,dy,dx), name='test1')
# Create the metadata
Attr = Metadata.Item
datetime_now = datetime.now().isoformat()
temp = Attr(22.0, 'C')
md = d0.get_metadata()
md.add(Metadata.Type.Experiment, {'Datetime':datetime_now, 'Temperature':temp})
md.add(Metadata.Type.Optics, {'Wavelength':Attr(660, 'nm')})
# enums can be added using the enum value or the string representation of the enum member (case-insensitive and ignoring underscores and spaces)
md.add(Metadata.Type.Brillouin, {'Signal_type': brim.metadata.SignalType.spontaneous,
'Phonons_measured': 'longitudinal',})
# Add some metadata to the local data group
temp = Attr(37.0, 'C')
md.add(Metadata.Type.Experiment, {'Temperature':temp}, local=True)
# create the analysis results
ar = d0.create_analysis_results_group({'shift':shift_GHz, 'shift_units': 'GHz',
'width': width_GHz, 'width_units': 'GHz'},
{'shift':shift_GHz, 'shift_units': 'GHz',
'width': width_GHz, 'width_units': 'GHz'},
name = 'test1_analysis')
f.close()
and we can read it back:
from brimfile import File, Data, Metadata, AnalysisResults
filename = 'path/to/your/file.brim.zarr'
f = File(filename)
# check if the file is read only
f.is_read_only()
#list all the data groups in the file
data_groups = f.list_data_groups(retrieve_custom_name=True)
# get the first data group in the file
d = f.get_data()
# get the name of the data group
d.get_name()
# get the number of parameters which the spectra depend on
n_pars = d.get_num_parameters()
# get the metadata
md = d.get_metadata()
all_metadata = md.all_to_dict()
# the list of metadata is defined here https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_metadata.md
time = md['Experiment.Datetime']
time.value
time.units
temp = md['Experiment.Temperature']
md_dict = md.to_dict(Metadata.Type.Experiment)
#get the list of analysis results in the data group
ar_list = d.list_AnalysisResults(retrieve_custom_name=True)
# get the first analysis results in the data group
ar = d.get_analysis_results()
# get the name of the analysis results
ar.get_name()
# list the existing peak types and quantities in the analysis results
pt = ar.list_existing_peak_types()
qt = ar.list_existing_quantities()
# get the image of the shift quantity for the average of the Stokes and anti-Stokes peaks
img, px_size = ar.get_image(AnalysisResults.Quantity.Shift, AnalysisResults.PeakType.average)
# get the units of the shift quantity
u = ar.get_units(AnalysisResults.Quantity.Shift)
# get a quantity at a specific pixel (coord) in the image
coord = (1,3,4)
qt_at_px = ar.get_quantity_at_pixel(coord, AnalysisResults.Quantity.Shift, AnalysisResults.PeakType.average)
assert img[coord]==qt_at_px
# get the spectrum in the image at a specific pixel (coord)
PSD, frequency, PSD_units, frequency_units = d.get_spectrum_in_image(coord)
f.close()
Export the data to a different format
OME-TIFF
You can export a specific quantity in the analyzed data to OME-TIFF files using the brimfile.analysis_results.AnalysisResults.save_image_to_OMETiff method on an instance ar of the AnalysisResults class.
ar_cls = AnalysisResults
ar.save_image_to_OMETiff(ar_cls.Quantity.Shift, ar_cls.PeakType.average, filename='path/to/your/exported_tiff' )
1""" 2## What is brimfile? 3 4*brimfile* is a Python library to read from and write to brim (**Br**illouin **im**aging) files, 5which contain both the spectra and analysed data for Brillouin imaging. 6More information about the brim file format can be found [here](https://github.com/brillouin-imaging/Brillouin-standard-file). 7 8Briefly, a brim file can contain multiple data groups, 9typically corresponding to imaging of the same sample at different timepoints/conditions. 10Each data group contains the spectral data as well as the metadata and 11the results of the analysis on the spectral data (which can be many in case multiple reconstruction pipelines are performed). 12 13The structure of the *brimfile* library reflects the structure of the brim file and the user can access the data, 14metadata and analysis results through their corresponding classes. 15 16- [File](#file): represents a brim file, which can be opened or created. 17- [Data](#data): represents a data group in the brim file, which contains the spectral data and metadata. 18- [Metadata](#metadata): represents the metadata associated to a data group (or to the whole file). 19- [AnalysisResults](#analysisresults): represents the results of the analysis of the spectral data. 20- [Calibration](#calibration): represents the calibration data associated to a data group, which contains the calibration spectra and relevant metadata. 21 22 23## Install brimfile 24 25We recommend installing *brimfile* in a [virtual environment](https://docs.python.org/3/library/venv.html). 26 27After activating the new environment, simply run: 28 29```bash 30pip install brimfile 31``` 32 33If you also need the support for exporting the analyzed data to OME-TIFF files, 34you can install the optional dependencies with: 35 36```bash 37pip install "brimfile[export-tiff]" 38``` 39 40For accessing remote data (i.e. S3 buckets), you need `remote-store`: 41 42```bash 43pip install "brimfile[remote-store]" 44``` 45 46## Quickstart 47 48The following code shows how to: 49- open a .brim file 50- get an image for the Brillouin shift 51- get the spectrum at a specific pixel 52- get the metadata. 53 54```Python 55from brimfile import File, Data, Metadata, AnalysisResults 56Quantity = AnalysisResults.Quantity 57PeakType = AnalysisResults.PeakType 58 59filename = 'path/to/your/file.brim.zarr' 60f = File(filename) 61 62# get the first data group in the file 63d = f.get_data() 64 65# get the first analysis results in the data group 66ar = d.get_analysis_results() 67 68# get the image for the shift 69img, px_size = ar.get_image(Quantity.Shift, PeakType.average) 70 71# get the spectrum at the pixel (pz,py,px) 72(pz,py,px) = (0,0,0) 73PSD, frequency, PSD_units, frequency_units = d.get_spectrum_in_image((pz,py,px)) 74 75# get the metadata 76md = d.get_metadata() 77all_metadata = md.all_to_dict() 78 79# close the file 80f.close() 81``` 82 83## Store types 84 85Currently brimfile supports zip, zarr and S3 buckets as a store. 86When opening or creating a file, the storage be selected by using the brimfile.file_abstraction.StoreType enum; zip and zarr can be used both for reading and writing while S3 only for reading. 87 88Although it is possible to write directly to zip, this will create duplicated entries in the archive (see [GitHub issue](https://github.com/zarr-developers/zarr-python/issues/1695)). 89 90A possible workaround is to create a .zarr store instead and zip the folder afterwards. 91Importantly the root of the archive should not contain the folder itself, i.e. you should go inside the .zarr folder, select all the elements there, right click on them to create a .zip archive. 92 93 94## Use brimfile 95 96### File 97 98The main class is `brimfile.file.File`, which represents a brim file. 99It can be used to create a new brim file (`brimfile.file.File.create`) or to open an existing one (`brimfile.file.File.__init__`). 100 101```Python 102import brimfile as brim 103 104filename = 'path/to/your/file.brim.zarr' 105 106# Open an existing brim file 107f = brim.File(filename) 108 109# or create a new one 110f = brim.File.create(filename) 111``` 112 113### Data 114 115You can then get a `brimfile.data.Data` object representing the data group in the brim file 116by opening an existing one (`brimfile.file.File.get_data`). 117 118```Python 119# Get the first data group in the file 120data = f.get_data() 121``` 122 123To add a new data group to the file, you can use the `brimfile.file.File.create_data_group` method, 124which accepts a 4D array for the PSD with dimensions (z, y, x, spectrum), 125a frequency array which might have the same size as PSD or be 1D, in case the frequency axis is the same for all the spectra. 126```Python 127# or create a new one 128data = f.create_data_group(PSD, freq_GHz, (dz, dy, dx), name='my_data_group') 129``` 130Alternatively you can use `brimfile.file.File.create_data_group_sparse` for sparse data, which lets you directly assign the correspondence 131between the spatial positions and the spectra through the `scanning` dictionary. 132 133Once you have an istance of `brimfile.data.Data`, you can get the spectrum corresponding to a pixel in the image 134by calling the `brimfile.data.Data.get_spectrum_in_image` method: 135```Python 136PSD, frequency, PSD_units, frequency_units = data.get_spectrum_in_image((pz,py,px)) 137``` 138 139### Metadata 140 141You can then get a `brimfile.metadata.main.Metadata` object by simply calling the `brimfile.data.Data.get_metadata` method on a previously retrieved `Data` object. 142The returned Metadata object contains all the metadata associated with the file and the specific data group. 143```Python 144metadata = data.get_metadata() 145``` 146The list of available metadata is defined [here](https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_metadata.md) and can also be printed in the terminal with the `brimfile.metadata.schema.print_schema` method, which also allows to print the description of each metadata field: 147```Python 148brim.metadata.print_schema(include_description=True) 149``` 150For metadata fields which require an enum, it can be imported from `brimfile.metadata`, e.g. `from brimfile.metadata import ImmersionMedium`. 151 152New metadata can be added to the current data group (or to the whole file) by calling the `brimfile.metadata.main.Metadata.add` method. 153```Python 154import datetime 155 156Attr = Metadata.Item 157datetime_now = datetime.now().isoformat() 158temp = Attr(22.0, 'C') 159 160metadata.add(Metadata.Type.Experiment, {'Datetime':datetime_now, 'Temperature':temp},local=True) 161``` 162When adding metadata fields which require an enum, the enum value or the string representation of the enum member (case-insensitive and ignoring underscores and spaces) can be used, e.g. `brim.metadata.SignalType.spontaneous` or 'spontaneous' can be used for the `Signal_type` field. 163 164A single metadata item can be retrieved by indexing the `Metadata` object, which takes a string in the format 'group.object', e.g. 'Experiment.Datetime'. 165```Python 166datetime = metadata['Experiment.Datetime'] 167``` 168A dictionary containing all metadata can be retrieved by calling the `brimfile.metadata.main.Metadata.all_to_dict` method. 169```Python 170metadata.all_to_dict() 171``` 172 173### AnalysisResults 174 175The results of the analysis can be accessed through the `brimfile.analysis_results.AnalysisResults` object, obtained by calling the `brimfile.data.Data.get_analysis_results` method on a previously retrieved `Data` object: 176``` Python 177analysis_results = data.get_analysis_results() 178``` 179or create a new one by calling the `brimfile.data.Data.create_analysis_results_group`: 180``` Python 181ar = data.create_analysis_results_group({'shift':shift_GHz, 'shift_units': 'GHz', 182 'width': width_GHz, 'width_units': 'GHz'}, 183 {'shift':shift_GHz, 'shift_units': 'GHz', 184 'width': width_GHz, 'width_units': 'GHz'}, 185 name = 'my_analysis_results') 186``` 187 188`AnalysisResults` also exposes a method to retrieve the images of the analysis results (`brimfile.analysis_results.AnalysisResults.get_image`): 189 190``` Python 191ar_cls = AnalysisResults 192img, px_size = analysis_results.get_image(ar_cls.Quantity.Shift, ar_cls.PeakType.average) 193``` 194 195### Calibration 196 197Calibration data can be accessed through the `brimfile.calibration.Calibration` object, obtained by calling `brimfile.data.Data.get_calibration`. 198You can create a new calibration group with `brimfile.data.Data.create_calibration_group` by providing one or more calibration materials 199(each with `spectra`, `shift`, and optional `shift_units`) and, when needed, an `index` array mapping image coordinates to calibration spectra. 200If another data group should reuse an existing calibration, you can pass `same_as=<data_group_index>` when creating the calibration group. 201 202```Python 203# create calibration for data group d0 204N = np.prod(PSD.shape[:-1]) 205index = np.arange(N).reshape(PSD.shape[:-1]) 206cal_d = {'spectra': np.empty((N, 50)), 'shift': 7.0, 'shift_units': 'GHz'} 207d0.create_calibration_group(index=index, calibration_data=[cal_d]) 208 209# retrieve calibration and get a spectrum at (z, y, x) 210cal = d0.get_calibration() 211spectrum, shift = cal.get_spectrum_at_coor((1, 2, 3)) 212 213# optionally reuse calibration from data group 0 in another data group 214d1.create_calibration_group(same_as=0) 215``` 216 217## List the contents of a brim file 218 219The *brimfile* library provides methods to list the contents of a brim file. 220 221To list all the data groups in a brim file, you can use the `brimfile.file.File.list_data_groups` method. 222 223Once you have a `Data` object, you can list the analysis results in it by calling the `brimfile.data.Data.list_AnalysisResults` method. 224 225Once you have an `AnalysisResults` object, you can determine: 226- if the Stokes and/or anti-Stokes peaks are present by calling the `brimfile.analysis_results.AnalysisResults.list_existing_peak_types` method; 227- the available quantities (e.g. shift, linewidth, etc...) in the analysis results by calling the `brimfile.analysis_results.AnalysisResults.list_existing_quantities` method. 228 229## Subtypes 230 231For subtype-specific data and utilities (for example SinglePoint_VIPA helpers), see ``brimfile.subtypes``. 232 233## Example code 234 235Here is a simple example which creates a brim file with a data group and some metadata and then reads it back. 236 237We first write a function to generate some dummy data: 238 239``` Python 240import numpy as np 241 242def generate_data(): 243 def lorentzian(x, x0, w): 244 return 1/(1+((x-x0)/(w/2))**2) 245 Nx, Ny, Nz = (7, 5, 3) # Number of points in x,y,z 246 dx, dy, dz = (0.4, 0.5, 2) # Stepsizes (in um) 247 n_points = Nx*Ny*Nz # total number of points 248 249 width_GHz = 0.4 250 width_GHz_arr = np.full((Nz, Ny, Nx), width_GHz) 251 shift_GHz_arr = np.empty((Nz, Ny, Nx)) 252 freq_GHz = np.linspace(6, 9, 151) # 151 frequency points 253 PSD = np.empty((Nz, Ny, Nx, len(freq_GHz))) 254 for i in range(Nz): 255 for j in range(Ny): 256 for k in range(Nx): 257 index = k + Nx*j + Ny*Nx*i 258 #let's increase the shift linearly to have a readout 259 shift_GHz = freq_GHz[0] + (freq_GHz[-1]-freq_GHz[0]) * index/n_points 260 spectrum = lorentzian(freq_GHz, shift_GHz, width_GHz) 261 shift_GHz_arr[i,j,k] = shift_GHz 262 PSD[i, j, k,:] = spectrum 263 264 return PSD, freq_GHz, (dz,dy,dx), shift_GHz_arr, width_GHz_arr 265``` 266 267Now we can use this function to create a brim file with a data group and some metadata: 268 269``` Python 270 import brimfile as brim 271 from brimfile import File, Data, Metadata, StoreType 272 from datetime import datetime 273 274 filename = 'path/to/your/file.brim.zarr' 275 276 f = File.create(filename, store_type=StoreType.AUTO) 277 278 PSD, freq_GHz, (dz,dy,dx), shift_GHz, width_GHz = generate_data() 279 280 d0 = f.create_data_group(PSD, freq_GHz, (dz,dy,dx), name='test1') 281 282 # Create the metadata 283 Attr = Metadata.Item 284 datetime_now = datetime.now().isoformat() 285 temp = Attr(22.0, 'C') 286 md = d0.get_metadata() 287 288 md.add(Metadata.Type.Experiment, {'Datetime':datetime_now, 'Temperature':temp}) 289 md.add(Metadata.Type.Optics, {'Wavelength':Attr(660, 'nm')}) 290 # enums can be added using the enum value or the string representation of the enum member (case-insensitive and ignoring underscores and spaces) 291 md.add(Metadata.Type.Brillouin, {'Signal_type': brim.metadata.SignalType.spontaneous, 292 'Phonons_measured': 'longitudinal',}) 293 # Add some metadata to the local data group 294 temp = Attr(37.0, 'C') 295 md.add(Metadata.Type.Experiment, {'Temperature':temp}, local=True) 296 297 # create the analysis results 298 ar = d0.create_analysis_results_group({'shift':shift_GHz, 'shift_units': 'GHz', 299 'width': width_GHz, 'width_units': 'GHz'}, 300 {'shift':shift_GHz, 'shift_units': 'GHz', 301 'width': width_GHz, 'width_units': 'GHz'}, 302 name = 'test1_analysis') 303 f.close() 304``` 305and we can read it back: 306``` Python 307 from brimfile import File, Data, Metadata, AnalysisResults 308 309 filename = 'path/to/your/file.brim.zarr' 310 311 f = File(filename) 312 313 # check if the file is read only 314 f.is_read_only() 315 316 #list all the data groups in the file 317 data_groups = f.list_data_groups(retrieve_custom_name=True) 318 319 # get the first data group in the file 320 d = f.get_data() 321 # get the name of the data group 322 d.get_name() 323 324 # get the number of parameters which the spectra depend on 325 n_pars = d.get_num_parameters() 326 327 # get the metadata 328 md = d.get_metadata() 329 all_metadata = md.all_to_dict() 330 # the list of metadata is defined here https://github.com/brillouin-imaging/Brillouin-standard-file/blob/main/docs/brim_file_metadata.md 331 time = md['Experiment.Datetime'] 332 time.value 333 time.units 334 temp = md['Experiment.Temperature'] 335 md_dict = md.to_dict(Metadata.Type.Experiment) 336 337 338 #get the list of analysis results in the data group 339 ar_list = d.list_AnalysisResults(retrieve_custom_name=True) 340 # get the first analysis results in the data group 341 ar = d.get_analysis_results() 342 # get the name of the analysis results 343 ar.get_name() 344 # list the existing peak types and quantities in the analysis results 345 pt = ar.list_existing_peak_types() 346 qt = ar.list_existing_quantities() 347 # get the image of the shift quantity for the average of the Stokes and anti-Stokes peaks 348 img, px_size = ar.get_image(AnalysisResults.Quantity.Shift, AnalysisResults.PeakType.average) 349 # get the units of the shift quantity 350 u = ar.get_units(AnalysisResults.Quantity.Shift) 351 352 # get a quantity at a specific pixel (coord) in the image 353 coord = (1,3,4) 354 qt_at_px = ar.get_quantity_at_pixel(coord, AnalysisResults.Quantity.Shift, AnalysisResults.PeakType.average) 355 assert img[coord]==qt_at_px 356 357 # get the spectrum in the image at a specific pixel (coord) 358 PSD, frequency, PSD_units, frequency_units = d.get_spectrum_in_image(coord) 359 360 f.close() 361``` 362 363## Export the data to a different format 364 365### OME-TIFF 366 367You can export a specific quantity in the analyzed data to OME-TIFF files using the `brimfile.analysis_results.AnalysisResults.save_image_to_OMETiff` method on an instance `ar` of the `AnalysisResults` class. 368``` Python 369ar_cls = AnalysisResults 370ar.save_image_to_OMETiff(ar_cls.Quantity.Shift, ar_cls.PeakType.average, filename='path/to/your/exported_tiff' ) 371``` 372""" 373 374try: 375 from ._version import __version__ 376except ImportError: 377 __version__ = "unknown" 378 379import os 380# Default: normal imports enabled. 381# Override with env var: BRIMFILE_IMPORT_VALIDATION_ONLY=1 382_IMPORT_VALIDATION_ONLY = os.getenv("BRIMFILE_IMPORT_VALIDATION_ONLY", "").lower() in { 383 "1", "true", "yes" 384} 385 386if not _IMPORT_VALIDATION_ONLY: 387 from .file import File 388 from .data import Data 389 from .analysis_results import AnalysisResults 390 from .calibration import Calibration 391 from .metadata import Metadata 392 from .file_abstraction import StoreType