Skip to content

Includes option to synchronize reference index objects over a fixed s…#1024

Open
apasarkar wants to merge 1 commit intondwidgetfrom
arbitrary_sync
Open

Includes option to synchronize reference index objects over a fixed s…#1024
apasarkar wants to merge 1 commit intondwidgetfrom
arbitrary_sync

Conversation

@apasarkar
Copy link
Copy Markdown
Collaborator

@apasarkar apasarkar commented Apr 1, 2026

Screen.Recording.2026-04-01.at.12.09.30.AM.mov

Goal of this PR is to provide "first-class" support for synchronizing reference index objects. If done right, this will allow visualization systems build with NDWidget to be easily "extended" and "chained together" in arbitrary ways.

Example problem: you have built/released some visualization code with NDWidget. All widgets so far as synchronized across one scrollable dimension: time. Let's say someone wants to extend this visualization and add a new NDWidget consisting of a single NDImage Graphic. This NDImage graphic has a time dimension (which should be synchronized with the existing NDWidget code). But is also has a "depth" dimension (which was not present in the existing visualization code). Right now, it is nontrivial to link together the old and new code into one coherent system.

It should be possible, without explicitly writing event handlers, to synchronize the time dimensions in this kind of scenario.

This PR adds functionality to ReferenceIndex to synchronize ReferenceIndex objects. Sample usage would look like:

ref_index_first.add_synchronized_index(ref_index_second, "time")

This code synchronizes these two reference index objects across time. An update to the time index of these reference index objects guarantees an equivalent update to the other.

Here is code that can verify that the implementation does what we'd expect.

data_first = np.random.rand(1000, 20, 20)
data_second = np.random.rand(30, 1000, 20, 20)

ref_range = {"time": (0, 3000, 1)}
ndw_fov_first = fpl.NDWidget(
            ref_range,
            extents=None,
            names=["test1"],
            size=(1200, 1200),
        )

movie_dims = ["time", "m", "n"]
movie_spatial_dims = ["m", "n"]
movie_index_mapping = {"time": np.arange(data_first.shape[0])}
ndw_fov_first['test1'].add_nd_image(data_first,
                     movie_dims,
                     movie_spatial_dims,
                     slider_dim_transforms=movie_index_mapping.copy())


ref_range = {"time": (0, 3000, 1),
            "depth": (0, 30, 1)}
ndw_fov_second = fpl.NDWidget(
            ref_range,
            extents=None,
            names=["test2"],
            size=(1200, 1200),
        )

movie_dims = ["depth", "time", "m", "n"]
movie_spatial_dims = ["m", "n"]
movie_index_mapping = {"time": np.arange(data_second.shape[1]), "depth": np.arange(data_second.shape[0])}
ndw_fov_second['test2'].add_nd_image(data_second,
                     movie_dims,
                     movie_spatial_dims,
                     slider_dim_transforms=movie_index_mapping.copy())


ndw_fov_second.indices.add_synchronized_index(ndw_fov_first.indices, "time")

This implementation of ReferenceIndex includes a function, add_synchronized_index which performs symmetric synchronization between self and an input ref_index over a specified dimension.

The "set" implementation now carefully looks at what was implemented and calls "set" on the other synchronized reference index objects. Note this implementation has event handler style logic to prevent infinite recursion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant