Creating an Example PiB Pipeline#
Overview#
This tutorial details the required steps to construct a pipeline for a project using the PiB tracer. As it is unlikely that all the details will fit each neuroimaging project perfectly, this tutorial will explain how to alter the steps to accommodate other project designs.
A broad overview of the steps is given below, followed by a more detailed discussion of each step.
Create an instance of the
BIDS_PipelineClass.Create
StepsContainerobjects for preprocessing and kinetic modeling and add desired steps to those containers.Add containers (created in the previous step) to the pipeline and define their steps’ order using
add_dependency()andupdate_dependencies()(Recommended) Verify pipeline’s construction using its
plot_dependency_graph()method andcan_steps_potentially_run()Run the pipeline.
In-depth Walkthrough#
Note
For the rest of this guide, ‘pipeline’ refers to a BIDS_Pipeline object, and ‘container’ refers to a StepsContainer object.
Step 1. Initialize BIDS_Pipeline#
It is most compact and efficient to define all necessary paths for a pipeline when instantiating it. However, you can always set these path attributes post hoc. An example of this process is shown below for a PiB pipeline which will use T1w (T1-weighted) MRI as the anatomical image, freesurfer outputs (aparc+aseg.nii.gz in this case) as the segmentation image, and a segmentation table stored as ‘dseg.tsv’ (set after initialization).
import petpal
sub_id = '001'
ses_id = '001'
seg_path = f'/example/path/to/Data/PiB_BIDS/derivatives/freesurfer/sub-{sub_id}/ses-{ses_id}/aparc+aseg.nii.gz'
anat_path = f'/example/path/to/Data/PiB_BIDS/sub-{sub_id}/ses-{ses_id}/anat/sub-{sub_id}_ses-{ses_id}_T1w.nii.gz'
bids_dir = '/example/path/to/Data/PiB_BIDS'
PiB_Pipeline = petpal.pipelines.pipelines.BIDS_Pipeline(sub_id=sub_id,
ses_id=ses_id,
pipeline_name='PiB_Pipeline',
raw_anat_img_path=anat_path,
segmentation_img_path=seg_path,
bids_root_dir=bids_dir)
PiB_Pipeline.seg_table = f'/example/path/to/Data/PiB_BIDS/derivatives/freesurfer/dseg.tsv'
Step 2. Construct Containers#
Note
The name of a StepsContainer will determine the name of the folder where the pipeline will store outputs from that container’s steps. For example, a container named ‘preproc’ will store its outputs in a folder titled ‘preproc’.
See the code block below for examples of the two main ways to add steps to containers. The first way is to use
classmethods called ‘default[name-of-function-here]’, which provide a convenient starting point for most use cases. The
second way to add a step to a container is to manually create a step from the classes provided in
kinetic_modeling_steps and preproc_steps. Use this option when there isn’t a ‘default’ function
available or when you want to use different defaults than those provided in the given ‘default’ function. An example of
this is shown below, where the weighted series sum should only be computed from 30-60 minutes (1800-3600 seconds), rather
than the default of the whole scan time.
Important
The order of execution of steps is NOT defined by the order in which they are added to a container (as in the code block below), but rather as shown in Step 3.
preproc_container = petpal.pipelines.steps_containers.StepsContainer(name='preproc')
# Configure steps for preproc container
thresh_crop_step = petpal.pipelines.preproc_steps.ImageToImageStep.default_threshold_cropping(input_image_path=PiB_Pipeline.pet_path)
registration_step = petpal.pipelines.preproc_steps.ImageToImageStep.default_register_pet_to_t1(reference_image_path=PiB_Pipeline.anat_path,
half_life=petpal.utils.constants.HALF_LIVES['c11'])
moco_step = petpal.pipelines.preproc_steps.ImageToImageStep.default_windowed_moco()
write_tacs_step = petpal.pipelines.preproc_steps.TACsFromSegmentationStep.default_write_tacs_from_segmentation_rois(segmentation_image_path=PiB_Pipeline.seg_img,
segmentation_label_map_path=PiB_Pipeline.seg_table)
wss_step = petpal.pipelines.preproc_steps.ImageToImageStep(name='weighted_series_sum',
function=petpal.utils.useful_functions.weighted_series_sum,
input_image_path='',
output_image_path='',
half_life=petpal.utils.constants.HALF_LIVES['c11'],
start_time=1800,
end_time=3600)
# Add steps to preproc container
preproc_container.add_step(step=thresh_crop_step)
preproc_container.add_step(step=registration_step)
preproc_container.add_step(step=moco_step)
preproc_container.add_step(step=write_tacs_step)
preproc_container.add_step(step=wss_step)
kinetic_modeling_container = petpal.pipelines.steps_containers.StepsContainer(name='km')
# Configure steps for kinetic modeling container
suvr_step = petpal.pipelines.preproc_steps.ImageToImageStep(name='suvr',
function=petpal.preproc.image_operations_4d.suvr,
input_image_path='',
output_image_path='',
ref_region=8,
segmentation_image_path=seg_path,
verbose=False)
# Add steps to kinetic modeling container
kinetic_modeling_container.add_step(step=suvr_step)
Step 3. Add Containers to Pipeline and Order Their Steps#
Note
If you’re not sure of the name of a step (i.e. a step generated using a ‘default’ function), there are a number of
functions to help (print_steps_names(), for one). Alternatively,
you can pass a name keyword argument to the ‘default’ function to override the default name.
PiB_Pipeline.add_container(step_container=preproc_container)
PiB_Pipeline.add_container(step_container=kinetic_modeling_container)
PiB_Pipeline.add_dependency(sending='thresh_crop', receiving='windowed_moco')
PiB_Pipeline.add_dependency(sending='windowed_moco', receiving='register_pet_to_t1')
PiB_Pipeline.add_dependency(sending='register_pet_to_t1', receiving='write_roi_tacs')
PiB_Pipeline.add_dependency(sending='register_pet_to_t1', receiving='weighted_series_sum')
PiB_Pipeline.add_dependency(sending='weighted_series_sum', receiving='suvr')
PiB_Pipeline.update_dependencies(verbose=True)
Step 4. (Recommended) Visualize and Verify Pipeline#
At this point, the order of the steps is clear and the pipeline should be ready to run. To verify, use
plot_dependency_graph() to visualize the pipeline in a plot
like the one shown below and can_steps_potentially_run() to
determine if all arguments are prepared as the pipeline expects.
Step 5. Run the Pipeline#
Running a pipeline is as simple as calling the object.
PiB_Pipeline()
Congrats! You’ve now created a functional pipeline to take a participants raw data and outputs TACs and an SUVr parametric image.