Programmatic Workflow
Using workflows in napari-lattice¶
Demo to use workflows in functions for end to end image analysis.
This notebook shows how to create & save a simple workflow
In [2]:
Copied!
import os
import pyclesperanto_prototype as cle
from napari_workflows import Workflow
cle.get_device()
import os
import pyclesperanto_prototype as cle
from napari_workflows import Workflow
cle.get_device()
Out[2]:
<Intel(R) Iris(R) Xe Graphics on Platform: Intel(R) OpenCL Graphics (1 refs)>
In [3]:
Copied!
#download sample data from https://zenodo.org/records/14903188
img_path = "./sample_data/RBC_tiny.czi"
#make dir if not exists
if not os.path.exists("./sample_data"):
os.makedirs("./sample_data")
import urllib.request
url = "https://zenodo.org/records/14903188/files/RBC_tiny.czi?download=1"
if not os.path.exists(img_path):
print("Downloading file")
urllib.request.urlretrieve(url, img_path)
print(f"Downloaded at : {img_path}")
else:
print(f"File already exists at : {img_path}")
#download sample data from https://zenodo.org/records/14903188
img_path = "./sample_data/RBC_tiny.czi"
#make dir if not exists
if not os.path.exists("./sample_data"):
os.makedirs("./sample_data")
import urllib.request
url = "https://zenodo.org/records/14903188/files/RBC_tiny.czi?download=1"
if not os.path.exists(img_path):
print("Downloading file")
urllib.request.urlretrieve(url, img_path)
print(f"Downloaded at : {img_path}")
else:
print(f"File already exists at : {img_path}")
Downloading file Downloaded at : ./sample_data/RBC_tiny.czi
In [4]:
Copied!
#absolute path for saving
save_path = "C:/Users/rajasekhar.p/nap/napari_lattice/notebooks/sample_data"
#make dir if not exists
if not os.path.exists(save_path):
os.makedirs(save_path)
#absolute path for saving
save_path = "C:/Users/rajasekhar.p/nap/napari_lattice/notebooks/sample_data"
#make dir if not exists
if not os.path.exists(save_path):
os.makedirs(save_path)
To design end to end image analysis workflows, we can use napari-workflows
https://github.com/haesleinhuepf/napari-workflows
Lets apply a gaussian blur filter using pyclesperanto library
In [13]:
Copied!
#import gaussian filter from pyclesperanto
#We initialise a workflow
gaussian_workflow = Workflow()
#For napari-lattice, the input image should always be of the name "deskewed_image"
input_arg = "deskewed_image"
#define a simple gaussian filter
task_name = "gaussian"
gaussian_blur_sigma_x = 5
gaussian_blur_sigma_y = 5
gaussian_blur_sigma_z = 2
gaussian_workflow.set(task_name, cle.gaussian_blur,
input_arg, sigma_x = gaussian_blur_sigma_x,
sigma_y = gaussian_blur_sigma_y,
sigma_z = gaussian_blur_sigma_z)
#Printing a workflow will show you the arguments
print(gaussian_workflow)
#import gaussian filter from pyclesperanto
#We initialise a workflow
gaussian_workflow = Workflow()
#For napari-lattice, the input image should always be of the name "deskewed_image"
input_arg = "deskewed_image"
#define a simple gaussian filter
task_name = "gaussian"
gaussian_blur_sigma_x = 5
gaussian_blur_sigma_y = 5
gaussian_blur_sigma_z = 2
gaussian_workflow.set(task_name, cle.gaussian_blur,
input_arg, sigma_x = gaussian_blur_sigma_x,
sigma_y = gaussian_blur_sigma_y,
sigma_z = gaussian_blur_sigma_z)
#Printing a workflow will show you the arguments
print(gaussian_workflow)
Workflow: gaussian <- (<function gaussian_blur at 0x000001D37F6E3AC0>, 'deskewed_image', None, 5, 5, 2)
In [ ]:
Copied!
from lls_core import LatticeData
params = LatticeData(
input_image=img_path,
save_dir=save_path,
workflow=gaussian_workflow,
)
print(params)
from lls_core import LatticeData
params = LatticeData(
input_image=img_path,
save_dir=save_path,
workflow=gaussian_workflow,
)
print(params)
[INFO:2025-08-28 11:41:57,583] Processing File ./sample_data/RBC_tiny.czi
input_image=<xarray.DataArray 'transpose-1921c499e620816830b32ee3034745d3' (T: 1, C: 1, Z: 834, Y: 118, X: 209)> Size: 41MB dask.array<transpose, shape=(1, 1, 834, 118, 209), dtype=uint16, chunksize=(1, 1, 834, 118, 209), chunktype=numpy.ndarray> Coordinates: * C (C) <U17 68B 'LatticeLightsheet' * Z (Z) float64 7kB 0.0 0.3 0.6 0.9 1.2 ... 249.0 249.3 249.6 249.9 * Y (Y) float64 944B 0.0 0.145 0.29 0.435 ... 16.53 16.67 16.82 16.96 * X (X) float64 2kB 0.0 0.145 0.29 0.435 ... 29.72 29.87 30.01 30.16 Dimensions without coordinates: T Attributes: unprocessed: <Element 'ImageDocument' at 0x000001D332A48F40> skew=<DeskewDirection.Y: 2> angle=30.0 physical_pixel_sizes=DefinedPixelSizes(X=0.14499219272808386, Y=0.14499219272808386, Z=0.3) derived=DerivedDeskewFields(deskew_vol_shape=(59, 1828, 209), deskew_affine_transform=<pyclesperanto_prototype._tier8._AffineTransform3D.AffineTransform3D object at 0x000001D3330298D0>, deskew_affine_transform_zyx=array([[ 1.11022302e-16, -5.00000000e-01, 0.00000000e+00, 5.90000000e+01], [ 2.06907692e+00, 8.66025404e-01, 0.00000000e+00, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])) save_dir=WindowsPath('C:/Users/rajasekhar.p/nap/napari_lattice/notebooks/sample_data') save_suffix='_deskewed' save_name='RBC_tiny_deskewed' save_type=<SaveFileType.h5: 'h5'> time_range=range(0, 1) channel_range=range(0, 1) deconvolution=None crop=None workflow=<napari_workflows._workflow.Workflow object at 0x000001D32285B070> progress_bar=True
[INFO:2025-08-28 11:42:00,863] build program: kernel 'affine_transform_deskew_y_3d' was part of a lengthy source build resulting from a binary cache miss (1.36 s) [INFO:2025-08-28 11:42:01,567] build program: kernel 'gaussian_blur_separable_3d' was part of a lengthy source build resulting from a binary cache miss (0.57 s)
In [7]:
Copied!
# when running isave, if params.workflow has a workflow, then it will run the analysis workflow
params.workflow
# when running isave, if params.workflow has a workflow, then it will run the analysis workflow
params.workflow
Out[7]:
<napari_workflows._workflow.Workflow at 0x1d32285b070>
In [8]:
Copied!
params.save()
params.save()
Timepoints: 0%| | 0/1 [00:00<?, ?it/s][INFO:2025-08-28 11:41:59,144] Processing File <xarray.DataArray 'transpose-1921c499e620816830b32ee3034745d3' (Z: 834, Y: 118, X: 209)> Size: 41MB dask.array<getitem, shape=(834, 118, 209), dtype=uint16, chunksize=(834, 118, 209), chunktype=numpy.ndarray> Coordinates: C <U17 68B 'LatticeLightsheet' * Z (Z) float64 7kB 0.0 0.3 0.6 0.9 1.2 ... 249.0 249.3 249.6 249.9 * Y (Y) float64 944B 0.0 0.145 0.29 0.435 ... 16.53 16.67 16.82 16.96 * X (X) float64 2kB 0.0 0.145 0.29 0.435 ... 29.72 29.87 30.01 30.16 Attributes: unprocessed: <Element 'ImageDocument' at 0x000001D332A48F40>
INFO: blockdim levels (1) < subsamp levels (3): First-level block size (4, 256, 256) will be used for all levels
Timepoints: 100%|██████████| 1/1 [00:05<00:00, 5.77s/it]
This should save a deskewed image with gaussian blur applied
You can save the workflow for use in napari or programatically later on
In [14]:
Copied!
from napari_workflows import _io_yaml_v1 as io_yaml
io_yaml.save_workflow("sample_data/gaussian_workflow.yaml", gaussian_workflow)
from napari_workflows import _io_yaml_v1 as io_yaml
io_yaml.save_workflow("sample_data/gaussian_workflow.yaml", gaussian_workflow)