Visualizing derotation line-by-line with custom hooks#

This example demonstrates how to use a custom plotting hook to visualize how each image frame is reconstructed during derotation, line by line.

The derotation process works by rotating each horizontal line of an image by a given angle and placing it into a new derotated frame. Understanding this process is useful both for debugging and for developing intuition about how motion correction works.

In this example, we define a custom hook called after each line is processed during derotation. The hook visualizes the following:

  • The original image, with the current line highlighted

  • The partially built derotated image

  • The currently rotated line, overlaid on the right-hand image (if visible)

The hook is triggered only for frame 135 and every 20 lines, to keep the output readable.

This can be particularly helpful when:
  • You want to verify that the rotation mapping is working as expected

  • You want to debug center of rotation or interpolation artifacts

  • You are developing your own hooks or modifying the pipeline internals

Imports#

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np

from derotation.analysis.full_derotation_pipeline import FullPipeline
from derotation.config.load_config import load_config, update_config_paths
from derotation.sample_data import fetch_data

Load and configure paths#

We’ll use a small example dataset and write output to the current folder.

output_folder = Path.cwd()

config = load_config()
config = update_config_paths(
    config=config,
    tif_path=str(fetch_data("rotation_sample.tif")),
    aux_path=str(fetch_data("analog_signals.npy")),
    stim_randperm_path=str(fetch_data("stimulus_randperm.csv")),
    output_folder=str(output_folder),
)

Define a custom hook function#

This hook is called after every line is derotated and placed into the new frame. We’ll use it to inspect how frame 135 is constructed over time. This is a simplified version of the hook derotation.plotting_hooks.for_derotation.line_addition().

def inspect_frame_135_and_line_180(
    derotated_filled_image: np.ndarray,
    rotated_line: np.ndarray,
    image_counter: int,
    line_counter: int,
    angle: float,
    original_image: np.ndarray,
):
    if image_counter == 135 and line_counter == 180:
        fig, ax = plt.subplots(1, 2, figsize=(10, 5))
        #  background fig color: black
        fig.patch.set_facecolor("black")

        ax[0].imshow(original_image, cmap="turbo")
        #  highlight the line in the original image
        ax[0].plot(
            [0, original_image.shape[1] - 1],
            [line_counter, line_counter],
            color="red",
            linewidth=2,
        )
        ax[0].set_title(
            f"Take line {line_counter}\nfrom original image,\n then rotate it"
            f"of {angle:.2f} degrees"
        )
        ax[0].title.set_color("white")
        ax[0].axis("off")

        ax[1].imshow(derotated_filled_image, cmap="turbo")
        ax[1].set_title(
            f"Place the line in a new image\nto build frame {image_counter}"
        )
        ax[1].title.set_color("white")
        ax[1].axis("off")

        #  plot on top axis 1 the rotated_line with a red colormap
        ax[1].imshow(rotated_line, cmap="hsv", alpha=0.5)

        plt.show()

Register the hook#

hooks = {
    "plotting_hook_line_addition": inspect_frame_135_and_line_180,
}

Run the derotation pipeline with the custom hook#

Our hook will be called during processing of each line.

pipeline = FullPipeline(config)
pipeline.hooks = hooks
pipeline()
Take line 180 from original image,  then rotate itof 85.18 degrees, Place the line in a new image to build frame 135
2025-07-24 15:36:18 PM INFO     2025-07-24 15:36:18 PM - INFO -  fancylog.py:451
                                MainProcess fancylog.py:451 -
                                Starting logging
                       INFO     2025-07-24 15:36:18 PM - INFO -  fancylog.py:452
                                MainProcess fancylog.py:452 -
                                Not logging multiple processes
                       INFO     2025-07-24       full_derotation_pipeline.py:164
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:164
                                - Loading
                                data...
                       INFO     2025-07-24       full_derotation_pipeline.py:165
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:165
                                - Loading
                                /home/runner/.de
                                rotation/data/ro
                                tation_sample.ti
                                f
                       INFO     2025-07-24       full_derotation_pipeline.py:186
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:186
                                - Number of
                                rotations: 2
                       INFO     2025-07-24       full_derotation_pipeline.py:194
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:194
                                - Rotation
                                direction:
                                speed      200
                                direction
                                -1           1
                                 1           1
                       INFO     2025-07-24       full_derotation_pipeline.py:253
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:253
                                - Deleting
                                previous debug
                                plots...
                       INFO     2025-07-24       full_derotation_pipeline.py:263
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:263
                                - Dataset
                                rotation_sample
                                loaded
                       INFO     2025-07-24       full_derotation_pipeline.py:264
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:264
                                - Filename:
                                derotated
                       INFO     2025-07-24       full_derotation_pipeline.py:361
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:361
                                - Finding
                                rotation ticks
                                peaks...
                       INFO     2025-07-24       full_derotation_pipeline.py:436
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:436
                                - Cleaning start
                                and end rotation
                                signal...
                       INFO     2025-07-24       full_derotation_pipeline.py:461
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:461
                                - Creating
                                signed rotation
                                array...
                       INFO     2025-07-24       full_derotation_pipeline.py:483
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:483
                                - Dropping ticks
                                outside of the
                                rotation
                                period...
                       INFO     2025-07-24       full_derotation_pipeline.py:519
                                15:36:18 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:519
                                - Ticks dropped:
                                1.
                                Ticks remaining:
                                3451
2025-07-24 15:36:19 PM INFO     2025-07-24       full_derotation_pipeline.py:550
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:550
                                - Number of
                                rotations is as
                                expected
                       WARNING  2025-07-24       full_derotation_pipeline.py:597
                                15:36:19 PM -
                                WARNING -
                                MainProcess
                                full_derotation_
                                pipeline.py:597
                                - Number of
                                ticks is not as
                                expected: 3451.
                                Expected ticks:
                                3600.0
                                Delta: -149.0
                       INFO     2025-07-24       full_derotation_pipeline.py:649
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:649
                                - New increment
                                example: 0.209
                       INFO     2025-07-24       full_derotation_pipeline.py:662
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:662
                                - Interpolating
                                angles...
                       INFO     2025-07-24       full_derotation_pipeline.py:702
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:702
                                - Cleaning
                                interpolated
                                angles...
                       INFO     2025-07-24       full_derotation_pipeline.py:761
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:761
                                - Calculating
                                angles by line
                                and frame...
                       INFO     2025-07-24       full_derotation_pipeline.py:856
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:856
                                - Plotting
                                rotation ticks
                                and rotation on
                                signal...
                       INFO     2025-07-24       full_derotation_pipeline.py:898
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:898
                                - Plotting
                                rotation
                                angles...
                       INFO     2025-07-24       full_derotation_pipeline.py:901
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:901
                                - Speeds:
                                {np.int64(200)}
                       INFO     2025-07-24       full_derotation_pipeline.py:902
                                15:36:19 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:902
                                - len (speeds):
                                1
2025-07-24 15:36:20 PM INFO     2025-07-24       full_derotation_pipeline.py:348
                                15:36:20 PM -
                                INFO -
                                MainProcess
                                full_derotation_
                                pipeline.py:348
                                - ✨ Analog
                                signals
                                processed ✨
                       INFO     2025-07-24      full_derotation_pipeline.py:1121
                                15:36:20 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:11
                                21 - Optimal
                                center of
                                rotation read
                                from file.
                       INFO     2025-07-24      full_derotation_pipeline.py:1167
                                15:36:20 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:11
                                67 - Starting
                                derotation by
                                line...
                       INFO     2025-07-24      full_derotation_pipeline.py:1135
                                15:36:20 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:11
                                35 - Plotting
                                max projection
                                with center...

  0%|          | 0/69120 [00:00<?, ?it/s]
 48%|████▊     | 33046/69120 [00:00<00:00, 329590.43it/s]
 95%|█████████▌| 66006/69120 [00:01<00:00, 55471.39it/s]
100%|██████████| 69120/69120 [00:01<00:00, 65768.32it/s]
2025-07-24 15:36:21 PM INFO     2025-07-24      full_derotation_pipeline.py:1135
                                15:36:21 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:11
                                35 - Plotting
                                max projection
                                with center...
                       INFO     2025-07-24      full_derotation_pipeline.py:1198
                                15:36:21 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:11
                                98 - ✨ Image
                                stack derotated
                                ✨
/opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/numpy/_core/fromnumeric.py:3860: RuntimeWarning: Mean of empty slice.
  return _methods._mean(a, axis=axis, dtype=dtype,
/opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/numpy/_core/_methods.py:136: RuntimeWarning: invalid value encountered in divide
  ret = um.true_divide(
2025-07-24 15:36:25 PM INFO     2025-07-24      full_derotation_pipeline.py:1338
                                15:36:25 PM -
                                INFO -
                                MainProcess
                                full_derotation
                                _pipeline.py:13
                                38 - Saving
                                /home/runner/wo
                                rk/derotation/d
                                erotation/examp
                                les/derotated.t
                                if
                       WARNING  2025-07-24      full_derotation_pipeline.py:1357
                                15:36:25 PM -
                                WARNING -
                                MainProcess
                                full_derotation
                                _pipeline.py:13
                                57 - Number of
                                rotation angles
                                by frame is
                                higher than the
                                number of
                                frames

Total running time of the script: (0 minutes 6.564 seconds)

Gallery generated by Sphinx-Gallery