Phasor coordinates from lifetimes#

An introduction to the phasor_from_lifetime function.

The phasorpy.phasor.phasor_from_lifetime() function is used to calculate phasor coordinates as a function of frequency, single or multiple lifetime components, and the pre-exponential amplitudes or fractional intensities of the components.

Import required modules and functions:

import numpy

from phasorpy.phasor import phasor_from_lifetime, phasor_to_polar
from phasorpy.plot import PhasorPlot, plot_phasor, plot_polar_frequency

rng = numpy.random.default_rng(42)

Single-component lifetimes#

The phasor coordinates of single-component lifetimes are located on the universal semicircle. For example, 4.0 ns and 1.0 ns at a frequency of 80 MHz:

frequency = 80.0
lifetimes = [4.0, 1.0]

plot_phasor(
    *phasor_from_lifetime(frequency, lifetimes),
    frequency=frequency,
    title='Single-component lifetimes',
)
Single-component lifetimes

Multi-component lifetimes#

The phasor coordinates of two lifetime components with varying fractional intensities are linear combinations of the coordinates of the pure components:

fractions = numpy.array(
    [[1, 0], [0.25, 0.75], [0.5, 0.5], [0.75, 0.25], [0, 1]]
)

plot_phasor(
    *phasor_from_lifetime(frequency, lifetimes, fractions),
    linestyle='-',
    frequency=frequency,
    title='Multi-component lifetimes',
)
Multi-component lifetimes

Pre-exponential amplitudes#

The phasor coordinates of two lifetime components with varying pre-exponential amplitudes are also located on a line:

plot_phasor(
    *phasor_from_lifetime(
        frequency, lifetimes, fractions, preexponential=True
    ),
    linestyle='-',
    frequency=frequency,
    title='Pre-exponential amplitudes',
)
Pre-exponential amplitudes

Average of lifetime distributions#

The average phasor coordinates for wider distributions of lifetimes lie further inside the universal semicircle compared to the narrower distributions:

frequency = 80.0
lifetime = 4.0
standard_deviations = [0.1, 0.5, 1.0]
samples = 100000

plot = PhasorPlot(
    frequency=frequency, title='Average of lifetime distributions'
)
for sigma in standard_deviations:
    phi = numpy.sqrt(sigma * sigma / lifetime)
    phasor_average = numpy.average(
        phasor_from_lifetime(
            frequency, rng.gamma(lifetime / phi, phi, samples)
        ),
        axis=1,
    )
    plot.plot(*phasor_average, label=f'{sigma=:.1f}')
plot.show()
Average of lifetime distributions

Lifetime distributions at multiple frequencies#

Phasor coordinates can be calculated at once for many frequencies, lifetime components, and their fractions. As an example, random distrinutions of lifetimes and their fractions are plotted at three frequencies. Lifetimes are passed in units of s and frequencies in Hz, requiring to specify a unit_conversion factor:

samples = 100
lifetimes = [4.0, 2.0, 1.0]

lifetime_distributions = (
    numpy.column_stack(
        [rng.gamma(lifetime / 0.01, 0.01, samples) for lifetime in lifetimes]
    )
    * 1e-9
)
fraction_distributions = numpy.column_stack(
    [rng.random(samples) for lifetime in lifetimes]
)

plot_phasor(
    *phasor_from_lifetime(
        frequency=[40e6, 80e6, 160e6],
        lifetime=lifetime_distributions,
        fraction=fraction_distributions,
        unit_conversion=1.0,
    ),
    marker='.',
    label=('40 MHz', '80 MHz', '160 MHz'),
    title='Lifetime distributions at multiple frequencies',
)
Lifetime distributions at multiple frequencies

FRET efficiency#

The phasor coordinates of a fluorescence energy transfer donor with a single lifetime component of 4.0 ns as a function of FRET efficiency at a frequency of 80 MHz, with some background signal and about 90 % of the donors participating in energy transfer, are on a curved trajectory. For comparison, when 100% donors participate in FRET and there is no background signal, the phasor coordinates lie on the universal semicircle:

frequency = 80.0
samples = 25
lifetime = 4.0
efficiency = numpy.linspace(0.0, 1.0, samples)

lifetime_quenched = lifetime * (1.0 - efficiency)

plot = PhasorPlot(frequency=frequency, title='FRET efficiency')
plot.plot(
    *phasor_from_lifetime(frequency, lifetime_quenched),
    color='k',
    marker='.',
    label='100% Donor in FRET',
)
plot.plot(
    *phasor_from_lifetime(
        frequency,
        lifetime=numpy.column_stack(
            (
                numpy.full(samples, lifetime),  # donor-only lifetime
                lifetime_quenched,  # donor lifetime with FRET
                numpy.full(samples, 1e9),  # background with long lifetime
            )
        ),
        fraction=[0.1, 0.9, 0.1 / 1e9],
        preexponential=True,
    ),
    linestyle='-',
    label='90% Donor in FRET',
)
plot.show()
FRET efficiency

Multi-frequency plot#

Phase shift and demodulation of multi-component lifetimes can be calculated as a function of the excitation light frequency and fractional intensities:

frequencies = numpy.logspace(-1, 4, 32)
lifetimes = [4.0, 1.0]
fractions = numpy.array([[1, 0], [0.5, 0.5], [0, 1]])

plot_polar_frequency(
    frequencies,
    *phasor_to_polar(*phasor_from_lifetime(frequencies, lifetimes, fractions)),
    title='Multi-frequency plot',
)
Multi-frequency plot

sphinx_gallery_thumbnail_number = -2 mypy: allow-untyped-defs, allow-untyped-calls mypy: disable-error-code=”arg-type”

Total running time of the script: (0 minutes 0.467 seconds)

Gallery generated by Sphinx-Gallery