Skip to content

Commit

Permalink
Merge pull request #59 from zoccoler/patch2_0_0_7
Browse files Browse the repository at this point in the history
Patch2 0 0 7
  • Loading branch information
zoccoler authored Jun 28, 2024
2 parents d3f8e0c + 207e207 commit e6cfeab
Show file tree
Hide file tree
Showing 14 changed files with 380 additions and 123 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,7 @@ venv/
**/_version.py

# unzipped data
unzipped_hazelnut_FLIM_z_stack/
unzipped_hazelnut_FLIM_z_stack/

# videos
*.mp4
170 changes: 132 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,93 @@ Napari-flim-phasor-plotter is a [napari](https://napari.org/stable/) plugin to i

----------------------------------

## Usage
## Quick demo

Open a FLIM image to visualize it both as a 'FLIM image series' being a sequence of intensity images each corresponding to an individual time point of the FLIM 'micro-time', plus as a timely summed up image. Scrolling through the FLIM time series provides a first glimpse of lifetimes across image regions.
![](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/napari_FLIM_phasor_calculator_Demo.gif)

Call the plugin from the menu `Plugins > FLIM phasor plotter > Make FLIM Phasor Plot` to generate a phasor plot by pixel-wise Fourier transformation of the decay data. Hereby, select the FLIM image to be used, specify the laser pulse frequency if not read properly from metadata. Define an intensity threshold to exclude pixels of low photon counts, optionally a median filter, and a harmonic for optimal visualization. `Run` creates the phasor plot and an additional labels layer in the layer list. Below is a demonstration:
## Contents

- [Installation](#installation)
- [Usage](#usage)
- [Loading Raw FLIM Data](#loading-raw-flim-data)
1. [Input Data Types](#1-input-data-types)
2. [Opening a Raw FLIM Image](#2-opening-a-raw-flim-image)
3. [Loading Stacks](#3-loading-stacks)
4. [Sample Data](#4-sample-data)
- [Phasor Analysis](#phasor-analysis)
1. [Generating Phasor Plots](#1-generating-phasor-plots)
2. [Phasor Plot Navigation](#2-phasor-plot-navigation)
3. [Phasor Plot Selection](#3-phasor-plot-selection)
4. [Integrating Phasor Analysis into a Workflow](#4-integrating-phasor-analysis-into-a-workflow)
- [Clustering](#clustering)
- [Post-processing](#post-processing)
- [Saving Results](#saving-results)
- [Data Conversion](#data-conversion)
- [Limitations](#limitations)
- [Contributing](#contributing)
- [License](#license)
- [Issues](#issues)

![](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/napari_FLIM_phasor_calculator_Demo.gif)
## Installation

We recommend installing `napari-flim-phasor-plotter` with [mamba](https://mamba.readthedocs.io/en/latest/) after having [Miniforge](https://github.com/conda-forge/miniforge?tab=readme-ov-file#miniforge) installed in your computer. Follow these steps from a terminal.

Click [here](https://github.com/conda-forge/miniforge?tab=readme-ov-file#download) to choose the right download option for your OS.

Create a conda environment:

mamba create -n napari-flim-phasor-env python=3.9

Activate the environment:

mamba activate napari-flim-phasor-env

Then install `napari` and `napari-clusturs-plotter` (plus git if on Windows):

mamba install -c conda-forge napari==0.4.17 napari-clusters-plotter git pyqt

Change the color-code of the phasor plot to a density plot of various ‘Colormaps’ from the pulldown `Expand for advanced options` and select `HISTOGRAM`. Manually encircle a region of interest in the phasor plot to highlight the corresponding pixels in the newly created image layer. Hold ‘Shift’ to select and visualize several clusters to investigate image regions of similar FLIM patterns.
_Optional, but we **strongly** recommend having the `devbio-napari` plugin bundle also installed for post-processing. This can be done with:_

mamba install -c conda-forge devbio-napari

Finally install `napari-flim-phasor-plotter` plugin with:

pip install napari-flim-phasor-plotter

Alternatively, clone this repository and install the latest plugin development version with:

pip install git+https://github.com/zoccoler/napari-flim-phasor-plotter.git

## Usage

### Input Data
### Loading Raw FLIM Data

This plugin integrates with [napari-clusters-plotter plugin](https://github.com/BiAPoL/napari-clusters-plotter).
#### 1. Input Data Types

This plugin can read the following FLIM file types:
- ".ptu"
- ".sdt"
- ".tif"
- ".zarr"
This plugin can read the following FLIM **file types**:
- `.ptu`
- `.sdt`
- `.tif`
- `.zarr`

This plugin works with the following data shapes:
This plugin works with the following **data shapes**:
- 2D FLIM images (actually 3D data where FLIM counts are in the first axis).
- 3D FLIM images (actually 4D data where FLIM counts are in the first axis).
- 3D timelapse FLIM images (actually 5D data where FLIM counts are in the first axis).
- Multichannel '.tif' or '.zarr' data may need to be loaded separately.

The plugin outputs data axes in the following order (data from multiple detectors are displayed as distinct napari layers):
If you read your files using this plugin as a reader, it returns and works with the data axes in the following order (data from multiple detectors are displayed as distinct napari layers):

(`flim_counts`, `time`, `z`, `y`, `x`)

It also outputs the standard intensity image in another layer by summing the `flim_counts` dimension.

### Data Conversion
Even if the data is 2D, the plugin will add a unitary `time` and a `z` axis.
It also provides the standard intensity image in another layer by summing the `flim_counts` dimension.

If a collection of raw (uncompressed) images are larger than 4GB, we recommend converting them to `.zarr`. This can be done via `Plugins > napari-flim-phasor-plotter > Convert to zarr`.
#### 2. Opening a Raw FLIM Image

_Warning: In the current version, lazy loading with `.zarr` is available, but processing may still load all data into memory, so keep track of your memory usage._
Drag and drop a compatible file format (check supported file formats [here below](#input-data)) to open a FLIM image. It gets displayed in two layer: a 'raw FLIM image series' (a sequence of intensity images each corresponding to an individual time point of the FLIM 'micro-time'), and a timely summed up image (usually just known as the 'intensity' image). Scrolling through the FLIM time series provides a first glimpse of lifetimes across image regions.

![](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/convert_to_zarr.png)
#### 3. Loading Stacks

If you have multiple slices or time-points as separated files, you can choose a folder containing the files. In order for the plugin to properly build a stack, the file names must contain some indication about which slice or time-point they represent, i.e., **each file name should contain a `_t` and/or `_z` followed by a number**.

Expand All @@ -66,36 +114,82 @@ Here are a few example templates:
- ...
- `image_t002_z001.tif`

#### 4. Sample Data

## Installation
The plugin comes with a few sample FLIM raw images:

We recommend installing `napari-flim-phasor-plotter` with [mamba](https://mamba.readthedocs.io/en/latest/) after having [Miniforge](https://github.com/conda-forge/miniforge?tab=readme-ov-file#miniforge) installed in your computer. Follow these steps from a terminal.
- '2D' raw FLIM images:
- Hazelnut (originally a '.ptu' file)
- Seminal Receptacle (originally a '.sdt' file)
- '3D' raw FLIM image stack (Hazelnut 3D)
- Hazelnut 3D (originally a series of '.ptu' files)
- '2D' synthetic FLIM image
- Lifetime Cat

Click [here](https://github.com/conda-forge/miniforge?tab=readme-ov-file#download) to choose the right download option for your OS.
To load it, go to `File > Open Sample -> FLIM phasor plotter`.

Create a conda environment:
### Phasor Analysis

mamba create -n napari-flim-phasor-env python=3.9

Activate the environment:
#### 1. Generating Phasor Plots

mamba activate napari-flim-phasor-env

Then install `napari` and `napari-clusturs-plotter` (plus git if on Windows):
Call the plugin from the menu `Plugins > FLIM phasor plotter > Calculate Phasors` to generate a phasor plot by pixel-wise Fourier transformation of the decay data. Hereby, select the FLIM image to be used (it should be the layer with the raw data), specify the laser pulse frequency (if information is present in the file metadata, this field will be updated after phasor calculation). Choose a harmonic for optimal visualization, define an intensity threshold (here in absoluete values) to exclude pixels of low photon counts, and optionally apply a number of iterations `n` of a 3x3 median filter. `Run` creates the phasor plot and an additional labels layer in the layer list.

mamba install -c conda-forge napari==0.4.17 napari-clusters-plotter git pyqt
#### 2. Phasor Plot Navigation

_Optional, but we **strongly** recommend having the `devbio-napari` plugin bundle also installed for post-processing. This can be done with:_
Use the toolbar on top of the plot to navigate through the plot. For example, by activating the zoom tool button (magnifying glass icon), you can zoom in (with left click) or out (with right click), just *remember to disbale the zoom tool after using it by clicking on the icon once again*.

mamba install -c conda-forge devbio-napari
Change the colormap of the phasor plot from various `Colormaps` by clicking on the pulldown `Expand for advanced options`. There, you can also choose to display the color range in log scale by checking the `Log scale` checkbox. Optionally, add tau lines to the plot by specifying a range of lifetimes to be displayed (write them separated by commas) in the field `Tau lines` anc click on `Show/hide` to visualize them on top of the phasor plot.

Finally install `napari-flim-phasor-plotter` plugin with:
#### 3. Phasor Plot Selection

pip install napari-flim-phasor-plotter

Alternatively, clone this repository and install the latest plugin development version with:
Manually encircle a region of interest in the phasor plot to highlight the corresponding pixels in the newly created image layer. Hold ‘Shift’ to select and visualize several clusters as a way to investigate image regions of similar FLIM patterns.

pip install git+https://github.com/zoccoler/napari-flim-phasor-plotter.git
#### 4. Integrating Phasor Analysis into a Workflow

##### Clustering

This plugin integrates with [napari-clusters-plotter plugin](https://github.com/BiAPoL/napari-clusters-plotter). Thus, you can use the [clustering widget](https://github.com/BiAPoL/napari-clusters-plotter?tab=readme-ov-file#clustering) provided by the `napari-clusters-plotter` plugin to segment the phasor plot automatically and then visualize the segmentation results in the original FLIM image. Access it via `Tools -> Measurement post-processing -> Clustering (ncp)`. Below is a demonstration:

![clustering](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/clustering.gif)

##### Post-processing

After cluster selection, it is common to have different labels (colors) for selected clusters. Within each label, it is also common to have disconnected regions and even isolated pixel in the segmentation. To address this, we offer a few basic post-processing functions.

A common step is to select a single cluster of interest for further processing. By selecting the `Labels` layer (usually named `cluster_ids_in_space`) and checking the `show selected` checkbox, we can identify our cluster/label os interest by continuously increasing the label number until we find the desired cluster. After that, we can extract the chosen label as a mask via `Plugins -> FLIM phasor plotter -> Manual Label Extraction`. This will create a new layer with the mask of the selected cluster.

To connect small isolated regions and remove small holes within the mask, we can use the `smooth_cluster_mask` function. This can be accessed via `Plugins -> FLIM phasor plotter -> Smooth Cluster Mask`. This will remove holes with an area smaller than the specified `fill area px` in total number of pixels and connect regions within a given `smooth radius`. Don't forget to select the layer containing the mask before running the function, because this function expects a layer with a single label (like a binary mask).

Beyond this point, we can use other plugins, like the `devbio-napari` plugin bundle, to further process the mask. For example, we can perform instance segmentation on the mask via `Tools -> Segmentation / labeling -> Connectec component labeling (scikit-image, nsbatwm)`. We can also extract features from the objects via `Tools -> Measurement tables -> Objetct Features/Properties (scikit-image, nsr)`.

Below is a demonstration of the post-processing steps:

![post-processing](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/post_processing.gif)

Also, this example workflow can be reproduced by running this jupyter notebook: [Example_workflow.ipynb](./src/napari_flim_phasor_plotter/notebooks/Example_workflow.ipynb).

### Saving Results

Save your segmentation results by selecting (clicking on) the corresponding `Labels` layer (usually named `cluster_ids_in_space`) and then going to `File -> Save Selected Layer`. This can save the layer as a `.tif` file. To save a screenshot of the phasor plot, click on the `Save` button on the toolbar. To save the phasor plot as a `.csv` file, go to `Tools -> Measurement -> Show table (nsr)` and a new widget will show up. From the `labels layer` dropdown, choose the layer that contains the table, whose name starts with `Labelled_pixels_from_`... and then click on the `Run` button. This should bring the table with `G` and `S` values for each pixel. Click on the `Save as csv...` button to save the table as a `.csv` file.

![saving](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/saving_results.gif)

### Data Conversion

If a collection of raw (uncompressed) images are larger than 4GB, we recommend converting them to `.zarr`. This can be done via `Plugins > napari-flim-phasor-plotter > Convert to zarr`.

_Warning: In the current version, lazy loading with `.zarr` is available, but processing may still load all data into memory, so keep track of your memory usage._

![](https://github.com/zoccoler/napari-flim-phasor-plotter/raw/main/images/convert_to_zarr.png)

## Limitations

The plugin does not yet support:
- Phasor calibration
- Round cluster selection or cursor selection (only free-hand selection is available)
- Pseudo-channel generation from selected clusters in the phasor plot
- FRET analysis
- Tile processing

## Contributing

Expand Down
Binary file added images/clustering.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/napari_FLIM_phasor_calculator_Demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/post_processing.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/saving_results.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 6 additions & 4 deletions src/napari_flim_phasor_plotter/_io/convert_to_zarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def convert_folder_to_zarr(folder_path: pathlib.Path, cancel_button: bool = Fals
max_time_point = get_max_time_points(file_paths, file_extension)
# Build stack shape with the fllowing convention: (channel, ut, time, z, y, x)
stack_shape = (
*image_slice_shape[:-2], max_time_point, max_z, *image_slice_shape[-2:])
*image_slice_shape[:-2], max_time_point+1, max_z+1, *image_slice_shape[-2:])
# Get a nested list of time point containing a list of z slices
list_of_time_point_paths = get_structured_list_of_paths(
file_paths, file_extension)
Expand All @@ -90,17 +90,19 @@ def convert_folder_to_zarr(folder_path: pathlib.Path, cancel_button: bool = Fals
da.to_zarr(dask_array, output_path, overwrite=True)
# Read zarr as read/write
zarr_array = zarr.open(output_path, mode='r+')

# Fill zarr array with data
for z_paths, i in zip(tqdm(list_of_time_point_paths, label='time_points'), range(len(list_of_time_point_paths))):
for path, j in zip(tqdm(z_paths, label='z-slices'), range(len(z_paths))):
data, _ = imread(path)
data, metadata_list = imread(path)
# If single channel, add a new axis
if len(data.shape) == 3:
zarr_array[0, :data.shape[0], i,
j, :data.shape[1], :data.shape[2]] = data
else:
zarr_array[:data.shape[0], :data.shape[1], i,
j, :data.shape[2], :data.shape[3]] = data

zarr_metadata = dict()
for i, metadata in enumerate(metadata_list):
zarr_metadata['channel ' + str(i)] = metadata
zarr_array.attrs.update(zarr_metadata)
print('Done')
Loading

0 comments on commit e6cfeab

Please sign in to comment.