#!/usr/bin/env python # coding: utf-8 # # Reading µs-ALEX data from Photon-HDF5 with h5py # # *In this notebook we show how to read a µs-ALEX smFRET measurement stored in* # *[Photon-HDF5 format](http://photon-hdf5.readthedocs.org/)* # *using python and a few common scientific libraries (numpy, **h5py**, matplotlib).* # *Specifically, we show how to load timestamps, build an alternation histogram* # *and select photons in the donor and acceptor excitation periods.* # # *See also a [similar notebook](Reading µs-ALEX data from Photon-HDF5.ipynb) using* # *[pytables](http://www.pytables.org/) instead of [h5py](http://www.h5py.org/).* # In[1]: from __future__ import division, print_function # only needed on py2 get_ipython().run_line_magic('matplotlib', 'inline') import numpy as np import h5py import matplotlib.pyplot as plt # # 1. Utility functions # # Here we define an utility function to print HDF5 file contents: # In[2]: def print_children(group): """Print all the sub-groups in `group` and leaf-nodes children of `group`. Parameters: data_file (h5py HDF5 file object): the data file to print """ for name, value in group.items(): if isinstance(value, h5py.Group): content = '(Group)' else: content = value[()] print(name) print(' Content: %s' % content) print(' Description: %s\n' % value.attrs['TITLE'].decode()) # # 2. Open the data file # # Let assume we have a Photon-HDF5 file at the following location: # In[3]: filename = '../data/0023uLRpitc_NTP_20dT_0.5GndCl.hdf5' # We can open the file, as a normal HDF5 file # In[4]: h5file = h5py.File(filename) # The object `h5file` is a pytables file reference. The root group is accessed with `h5file.root`. # # 3. Print the content # # Let's start by taking a look at the file content: # In[5]: print_children(h5file) # We see the typical Photon-HDF5 structure. In particular the field `description` provides a short description of the measurement and `acquisition_duration` tells that the acquisition lasted 600 seconds. # # As an example let's take a look at the content of the `sample` group: # In[6]: print_children(h5file['sample']) # Finally, we define a shortcut to the `photon_data` group to save some typing later: # In[7]: photon_data = h5file['photon_data'] # # 4. Reading the data # First, we make sure the file contains the right type of measurement: # In[8]: photon_data['measurement_specs']['measurement_type'][()].decode() # Ok, tha's what we espect. # # Now we can load all the timestamps (including timestamps unit) and detectors arrays: # In[9]: timestamps = photon_data['timestamps'][:] timestamps_unit = photon_data['timestamps_specs']['timestamps_unit'][()] detectors = photon_data['detectors'][:] # In[10]: print('Number of photons: %d' % timestamps.size) print('Timestamps unit: %.2e seconds' % timestamps_unit) print('Detectors: %s' % np.unique(detectors)) # We may want to check the excitation wavelengths used in the measurement. This information is found in the setup group: # In[11]: h5file['setup']['excitation_wavelengths'][:] # Now, let's load the definitions of donor/acceptor channel and excitation periods: # In[12]: donor_ch = photon_data['measurement_specs']['detectors_specs']['spectral_ch1'][()] acceptor_ch = photon_data['measurement_specs']['detectors_specs']['spectral_ch2'][()] print('Donor CH: %d Acceptor CH: %d' % (donor_ch, acceptor_ch)) # In[13]: alex_period = photon_data['measurement_specs']['alex_period'][()] donor_period = photon_data['measurement_specs']['alex_excitation_period1'][()] offset = photon_data['measurement_specs']['alex_offset'][()] acceptor_period = photon_data['measurement_specs']['alex_excitation_period2'][()] print('ALEX period: %d \nOffset: %4d \nDonor period: %s \nAcceptor period: %s' % \ (alex_period, offset, donor_period, acceptor_period)) # These numbers define the donor and acceptor alternation periods as shown below: # # $$2180 < \widetilde{t} < 3900 \qquad \textrm{donor period}$$ # # $$200 < \widetilde{t} < 1800 \qquad \textrm{acceptor period}$$ # # where $\widetilde{t}$ represent the (`timestamps` - `offset`) **MODULO** `alex_period`. # # For more information # please refer to the [measurements_specs section](http://photon-hdf5.readthedocs.org/en/latest/phdata.html#measurement-specs) # of the *Reference Documentation*. # # 5. Plotting the alternation histogram # # Let start by separating timestamps from donor and acceptor channels: # In[14]: timestamps_donor = timestamps[detectors == donor_ch] timestamps_acceptor = timestamps[detectors == acceptor_ch] # Now that the data has been loaded we can plot an alternation histogram using *matplotlib*: # In[15]: fig, ax = plt.subplots() ax.hist((timestamps_acceptor - offset) % alex_period, bins=100, alpha=0.8, color='red', label='donor') ax.hist((timestamps_donor - offset) % alex_period, bins=100, alpha=0.8, color='green', label='acceptor') ax.axvspan(donor_period[0], donor_period[1], alpha=0.3, color='green') ax.axvspan(acceptor_period[0], acceptor_period[1], alpha=0.3, color='red') ax.set_xlabel('(timestamps - offset) MOD alex_period') ax.set_title('ALEX histogram') ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), frameon=False); # # 6. Timestamps in different excitation periods # # We conclude by showing, as an example, how to create arrays of timestamps containing only donor or acceptor exitation photons. # # In[16]: timestamps_mod = (timestamps - offset) % alex_period donor_excitation = (timestamps_mod < donor_period[1])*(timestamps_mod > donor_period[0]) acceptor_excitation = (timestamps_mod < acceptor_period[1])*(timestamps_mod > acceptor_period[0]) timestamps_Dex = timestamps[donor_excitation] timestamps_Aex = timestamps[acceptor_excitation] # In[17]: fig, ax = plt.subplots() ax.hist((timestamps_Dex - offset) % alex_period, bins=np.arange(0, alex_period, 40), alpha=0.8, color='green', label='D_ex') ax.hist((timestamps_Aex - offset) % alex_period, bins=np.arange(0, alex_period, 40), alpha=0.8, color='red', label='A_ex') ax.set_xlabel('(timestamps - offset) MOD alex_period') ax.set_title('ALEX histogram (selected periods only)') ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), frameon=False); # In[18]: #plt.close('all') # In[ ]: