Bound NADH fraction#

Determine the bound NADH fraction using phasor component analysis.

NADH (nicotinamide adenine dinucleotide) is an endogenous fluorophore present in cells in two forms, distinguishable by fluorescence lifetime: a short-lived free form (cytoplasmic NADH, lifetime ~0.4 ns) and a long-lived enzyme-bound form whose lifetime is determined from the data.

Two approaches are demonstrated: a single-harmonic phasor component analysis using prior knowledge of the free NADH lifetime, and a two-harmonic lifetime search without much prior assumption on component lifetimes.

The data are from the companion dataset of:

Import required modules, functions, and classes:

import tifffile

from phasorpy.component import phasor_component_fraction
from phasorpy.datasets import fetch
from phasorpy.lifetime import (
    phasor_calibrate,
    phasor_from_lifetime,
    phasor_semicircle_intersect,
    phasor_to_lifetime_search,
    phasor_to_normal_lifetime,
)
from phasorpy.phasor import phasor_center, phasor_from_signal
from phasorpy.plot import PhasorPlot, plot_image, plot_signal_image

Read dataset#

Read the FLIM data of human breast cancer cells and the reference of known lifetime (Fluorescein in EtOH, 3.05 ns) acquired at 80 MHz. The data are in generic TIFF format containing TCSPC histogram images (97 time bins, 512 x 512 pixels) without metadata:

cell_signal = tifffile.imread(fetch('CellsMaskedFilt3_new3.tiff'))
reference_signal = tifffile.imread(fetch('Fluor.tiff'))

frequency = 80.0  # MHz
lifetime_reference = 3.05  # ns, Fluorescein

Preview the TCSPC histogram images of the cell and reference:

plot_signal_image(cell_signal, axis=0, title='Cell FLIM signal')
Cell FLIM signal, axis=0, mean
plot_signal_image(reference_signal, axis=0, title='Fluorescein reference')
Fluorescein reference, axis=0, mean

The cell signal is apparently pre-filtered to exclude background pixels and improve signal quality, while the reference signal has sufficient signal. Hence, no further thresholding or filtering is applied.

Single-harmonic phasor analysis#

Compute phasor coordinates from the TCSPC histograms along axis 0:

cell_mean, cell_real, cell_imag = phasor_from_signal(cell_signal, axis=0)

reference_mean, reference_real, reference_imag = phasor_from_signal(
    reference_signal, axis=0
)

Calibrate the cell phasor coordinates using the Fluorescein reference distribution:

cell_real, cell_imag = phasor_calibrate(
    cell_real,
    cell_imag,
    reference_mean,
    reference_real,
    reference_imag,
    frequency=frequency,
    lifetime=lifetime_reference,
)

Calculate the phasor coordinates of free NADH from its known lifetime (0.4 ns). The bound NADH phasor is determined from the center of the cell distribution: it is the second intersection of the line from the free NADH phasor through the data center with the universal semicircle. Calculate the corresponding single-exponential lifetime of bound NADH from that intersection:

lifetime_free = 0.4  # ns, free cytoplasmic NADH

free_real, free_imag = phasor_from_lifetime(frequency, lifetime_free)

_, center_real, center_imag = phasor_center(cell_mean, cell_real, cell_imag)

_, _, bound_real, bound_imag = phasor_semicircle_intersect(
    free_real, free_imag, center_real, center_imag
)

lifetime_bound = phasor_to_normal_lifetime(
    bound_real, bound_imag, frequency=frequency
)

Plot the phasor distribution of the cell. Pixel phasors cluster along the line connecting the free and bound NADH phasor coordinates:

phasor_plot = PhasorPlot(frequency=frequency, title='NADH phasor distribution')
phasor_plot.hist2d(cell_real, cell_imag)
phasor_plot.line([free_real, bound_real], [free_imag, bound_imag])
for label, (rx, ix, col) in {
    f'Free NADH ({lifetime_free:.2f} ns, fixed)': (
        free_real,
        free_imag,
        'tab:olive',
    ),
    'Distribution center': (center_real, center_imag, 'tab:orange'),
    f'Bound NADH ({lifetime_bound:.2f} ns, intersection)': (
        bound_real,
        bound_imag,
        'tab:purple',
    ),
}.items():
    phasor_plot.plot(
        rx,
        ix,
        color=col,
        markersize=10,
        markeredgecolor='black',
        markeredgewidth=0.5,
        label=label,
    )
phasor_plot.show()
NADH phasor distribution

Compute the fraction of enzyme-bound NADH per pixel. phasor_component_fraction() returns the fraction of the first component; passing bound NADH first yields the bound fraction directly:

bound_fraction = phasor_component_fraction(
    cell_real, cell_imag, [bound_real, free_real], [bound_imag, free_imag]
)

Display the bound NADH fraction image. Pixel values represent the fraction of enzyme-bound NADH. Background pixels with zero signal appear as NaN:

plot_image(
    bound_fraction,
    vmin=0.4,
    vmax=0.8,
    cmap='turbo',
    title='Bound NADH fraction (single harmonic analysis)',
)
Bound NADH fraction (single harmonic analysis)

Compare to Figure 6c of Georgakoudi et al, which shows significantly lower bound NADH fractions.