Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update README and sample contribution #440

Merged
merged 14 commits into from
Oct 6, 2023
35 changes: 25 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,36 @@
[![Python package index](https://img.shields.io/pypi/v/recOrder-napari.svg)](https://pypi.org/project/recOrder-napari)
[![Development Status](https://img.shields.io/pypi/status/napari.svg)](https://en.wikipedia.org/wiki/Software_release_life_cycle#Alpha)

`recOrder` is a napari plugin and command-line tool for quantitative label-free microscopy that depends on a computational optics library, [`waveorder`](https://github.com/mehta-lab/waveorder), and an I/O library, [`iohub`](https://github.com/czbiohub-sf/iohub).
`recOrder` is a collection of computational imaging methods. It currently provides QLIPP (quantitative label-free imaging with phase and polarization), phase from defocus, and fluorescence deconvolution.

In this repository you will find python tools and a napari plugin that allow the user to calibrate microscope hardware, acquire multi-modal data, reconstruct density and anisotropy, and visualize the results.
[![Unveiling the invisible](./docs/images/comms_video_screenshot.png)](https://www.youtube.com/watch?v=JEZAaPeZhck)

The acquisition, calibration, background correction, reconstruction, and applications of QLIPP (quantitative label-free imaging with phase and polarization) are described in the following [E-Life Paper](https://elifesciences.org/articles/55502):
Acquisition, calibration, background correction, reconstruction, and applications of QLIPP are described in the following [E-Life Paper](https://elifesciences.org/articles/55502):

```bibtex
Syuan-Ming Guo, Li-Hao Yeh, Jenny Folkesson, Ivan E Ivanov, Anitha P Krishnan, Matthew G Keefe, Ezzat Hashemi, David Shin, Bryant B Chhun, Nathan H Cho, Manuel D Leonetti, May H Han, Tomasz J Nowakowski, Shalin B Mehta, "Revealing architectural order with quantitative label-free imaging and deep learning," eLife 2020;9:e55502 DOI: 10.7554/eLife.55502 (2020).
```

`recOrder` is to be used alongside a conventional widefield microscope fitted with a universal polarizer (Panel A below). The universal polarizer allows for the collection of label-free information including the intrinsic anisotropy of the sample and its relative phase (density). These measurements are collected by acquiring data under calibrated, polarization-diverse illumination followed by a computational reconstruction. The overall structure of `recOrder` is shown in Panel B, highlighting the structure of the graphical user interface (GUI) through a napari plugin.
These are the kinds of data you can acquire with `recOrder` and QLIPP:

![Flow Chart](https://github.com/mehta-lab/recOrder/blob/main/docs/images/recOrder_Fig1_Overview.png?raw=true)
https://user-images.githubusercontent.com/9554101/271128301-cc71da57-df6f-401b-a955-796750a96d88.mov

## Dataset
https://user-images.githubusercontent.com/9554101/271128510-aa2180af-607f-4c0c-912c-c18dc4f29432.mp4

[Slides](https://doi.org/10.5281/zenodo.5135889) and a [dataset](https://doi.org/10.5281/zenodo.5178487) shared during a workshop on QLIPP and recOrder can be found on Zenodo.
## What do I need to use `recOrder`
`recOrder` is to be used alongside a conventional widefield microscope. For QLIPP, the microscope must be fitted with an analyzer and a universal polarizer:

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5178487.svg)](https://doi.org/10.5281/zenodo.5178487)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5135889.svg)](https://doi.org/10.5281/zenodo.5135889)
https://user-images.githubusercontent.com/9554101/273073475-70afb05a-1eb7-4019-9c42-af3e07bef723.mp4

For phase-from-defocus or fluorescence deconvolution methods, the universal polarizer is optional.

The overall structure of `recOrder` is shown in Panel B, highlighting the structure of the graphical user interface (GUI) through a napari plugin and the command-line interface (CLI) that allows users to perform reconstructions.

![Flow Chart](https://github.com/mehta-lab/recOrder/blob/main/docs/images/recOrder_Fig1_Overview.png?raw=true)

## Quick Start


## Software Quick Start

(Optional but recommended) install [anaconda](https://www.anaconda.com/products/distribution) and create a virtual environment:

Expand All @@ -48,3 +56,10 @@ napari -w recOrder-napari

For more help, see [`recOrder`'s documentation](https://github.com/mehta-lab/recOrder/tree/main/docs). To install `recOrder`
on a microscope, see the [microscope installation guide](https://github.com/mehta-lab/recOrder/blob/main/docs/microscope-installation-guide.md).

## Dataset

[Slides](https://doi.org/10.5281/zenodo.5135889) and a [dataset](https://doi.org/10.5281/zenodo.5178487) shared during a workshop on QLIPP and recOrder can be found on Zenodo, and the napari plugin's sample contributions (`File > Open Sample > recOrder-napari` in napari).

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5178487.svg)](https://doi.org/10.5281/zenodo.5178487)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5135889.svg)](https://doi.org/10.5281/zenodo.5135889)
Binary file added docs/images/comms_video_screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions recOrder/napari.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ contributions:
- id: recOrder-napari.polarization_target_reconstruction
title: Polarization Target Data
python_name: recOrder.scripts.samples:read_polarization_target_reconstruction
- id: recOrder-napari.zebrafish_embryo_reconstruction
title: Zebrafish Embryo Reconstruction
python_name: recOrder.scripts.samples:read_zebrafish_embryo_reconstruction
readers:
- command: recOrder-napari.get_reader
accepts_directories: true
Expand All @@ -24,8 +27,11 @@ contributions:
sample_data:
- command: recOrder-napari.polarization_target_data
key: polarization-target-data
display_name: Polarization Target Data
display_name: Polarization Target Data (10 MB)
- command: recOrder-napari.polarization_target_reconstruction
key: polarization-target-reconstruction
display_name: Polarization Target Reconstruction
display_name: Polarization Target Reconstruction (10 MB)
- command: recOrder-napari.zebrafish_embryo_reconstruction
key: zebrafish-embryo-reconstruction
display_name: Zebrafish Embryo Reconstruction (92 MB)

70 changes: 44 additions & 26 deletions recOrder/scripts/samples.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,59 @@
import shutil
from pathlib import Path

from typing import Literal

Check warning on line 4 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L4

Added line #L4 was not covered by tests
from iohub import open_ome_zarr
from iohub.ngff import Plate

Check warning on line 6 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L6

Added line #L6 was not covered by tests
from napari.utils.notifications import show_warning
from platformdirs import user_data_dir
from wget import download


def download_and_unzip() -> tuple[Path]:
def _build_layer_list(dataset: Plate, layer_names: list[str]):
layer_list = []
ziw-liu marked this conversation as resolved.
Show resolved Hide resolved
for channel_name in layer_names:
channel_index = dataset.channel_names.index(channel_name)
position = dataset["0/0/0"]
data = (position["0"][:, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

Check warning on line 19 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L12-L19

Added lines #L12 - L19 were not covered by tests

return layer_list

Check warning on line 21 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L21

Added line #L21 was not covered by tests


def download_and_unzip(data_type: Literal["target", "embryo"]) -> tuple[Path]:

Check warning on line 24 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L24

Added line #L24 was not covered by tests
"""Downloads sample data .zip from zenodo, unzips, and returns Paths to the .zarr datasets.

Skips the download if the files already exist.

Uses platformdirs.user_data_dir to store data.
"""
temp_dirpath = Path(user_data_dir("recOrder-sample-v1.4"))

# Delete old data
old_data_dirs = ["recOrder-sample-v1.4"]
for old_data_dir in old_data_dirs:
old_data_path = Path(user_data_dir(old_data_dir))
if old_data_path.exists():
shutil.rmtree(str(old_data_path))

Check warning on line 37 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L33-L37

Added lines #L33 - L37 were not covered by tests

temp_dirpath = Path(user_data_dir("recOrder-sample-v1.5"))

Check warning on line 39 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L39

Added line #L39 was not covered by tests
temp_dirpath.mkdir(exist_ok=True, parents=True)
data_dirpath = temp_dirpath / "sample_contribution"

if data_type == "target":
data_dirpath = temp_dirpath / "sample_contribution"
data_size = "10 MB"
data_url = "https://zenodo.org/record/8386856/files/sample_contribution.zip?download=1"
elif data_type == "embryo":
data_dirpath = temp_dirpath / "sample_contribution_embryo"
data_size = "92 MB"
data_url = "https://zenodo.org/record/8386856/files/sample_contribution_embryo.zip?download=1"

Check warning on line 49 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L42-L49

Added lines #L42 - L49 were not covered by tests

if not data_dirpath.with_suffix(".zip").exists():
show_warning(
"Downloading 10 MB sample contribution. This might take a moment..."
f"Downloading {data_size} sample contribution. This might take a moment..."
ziw-liu marked this conversation as resolved.
Show resolved Hide resolved
)
data_url = "https://zenodo.org/record/8280720/files/sample_contribution.zip?download=1"
download(data_url, out=str(temp_dirpath))

if not data_dirpath.exists():
shutil.unpack_archive(
data_dirpath.with_suffix(".zip"), extract_dir=temp_dirpath
Expand All @@ -36,32 +66,20 @@

def read_polarization_target_data():
"""Returns the polarization data sample contribution"""
data_path, _ = download_and_unzip()

data_path, _ = download_and_unzip("target")

Check warning on line 69 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L69

Added line #L69 was not covered by tests
dataset = open_ome_zarr(data_path)
layer_list = []
for channel_index, channel_name in enumerate(dataset.channel_names):
position = dataset["0/0/0"]
data = (position["0"][0, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

return layer_list
return _build_layer_list(dataset, dataset.channel_names)

Check warning on line 71 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L71

Added line #L71 was not covered by tests


def read_polarization_target_reconstruction():
"""Returns the polarization target reconstruction sample contribution"""

_, recon_path = download_and_unzip()
_, recon_path = download_and_unzip("target")

Check warning on line 76 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L76

Added line #L76 was not covered by tests
dataset = open_ome_zarr(recon_path)
return _build_layer_list(dataset, ["Phase3D", "Retardance", "Orientation"])

Check warning on line 78 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L78

Added line #L78 was not covered by tests

layer_list = []
for channel_index, channel_name in enumerate(
["Retardance", "Orientation"]
):
position = dataset["0/0/0"]
data = (position["0"][0, channel_index],)
layer_dict = {"name": channel_name, "scale": position.scale[3:]}
layer_list.append((data, layer_dict))

return layer_list
def read_zebrafish_embryo_reconstruction():

Check warning on line 81 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L81

Added line #L81 was not covered by tests
"""Returns the embryo reconstruction sample contribution"""
_, recon_path = download_and_unzip("embryo")
dataset = open_ome_zarr(recon_path)
return _build_layer_list(dataset, ["Retardance", "Orientation"])

Check warning on line 85 in recOrder/scripts/samples.py

View check run for this annotation

Codecov / codecov/patch

recOrder/scripts/samples.py#L83-L85

Added lines #L83 - L85 were not covered by tests
2 changes: 1 addition & 1 deletion recOrder/tests/widget_tests/test_sample_contributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


def test_download_and_unzip():
p1, p2 = download_and_unzip()
p1, p2 = download_and_unzip("target")

assert p1.exists()
assert p2.exists()