Skip to content

Adds nd vector graphic#1034

Open
apasarkar wants to merge 5 commits intondwidgetfrom
add_ndvector
Open

Adds nd vector graphic#1034
apasarkar wants to merge 5 commits intondwidgetfrom
add_ndvector

Conversation

@apasarkar
Copy link
Copy Markdown
Collaborator

ND Vector graphic, useful for displaying slider-dimension varying vector fields. for my use case i'm primarily interested in showing piecewise rigid shifts. see below video for an example of what i'm doing. also see code snippet below for example of how to reproduce the video outputs.


height, width = 200, 200
start, stop, step = 0, 200, 10

# get uniform x, y positions
x, y = np.meshgrid(np.arange(start, stop, step), np.arange(start, stop, step))

x = x.ravel()
y = y.ravel()

num_pts = x.shape[0]
num_frames = 500

# positions of each vector as [n_points, 2] array
positions = np.column_stack([x, y])
positions = np.broadcast_to(positions[None, :, :], (num_frames, num_pts, positions.shape[1]))
# directions of each vector as a [n_points, 2] array
directions = np.random.rand(*positions.shape) 

data = np.stack([positions, directions], axis = -1)

img_data = np.random.rand(num_frames, height, width)



ref_range = {"time": (0, num_frames, 1)}
extents = {"raw data": (0, 1, 0, 1)}

np.random.rand
ndw = fpl.NDWidget(
    ref_range,
    extents=extents,
    names=[
        "raw data",
    ],
    controller_ids=[
        ["raw data"],
    ],
    size=(1200, 1200),
)

frame_timings = np.arange(num_frames)
movie_dims = ["time", "m", "n"]
movie_spatial_dims = ["m", "n"]
movie_index_mapping = {"time": frame_timings}
img_graphic = ndw["raw data"].add_nd_image(
    img_data,
    movie_dims,
    movie_spatial_dims,
    slider_dim_transforms=movie_index_mapping.copy(),
    name="raw img data",
)


vector_dims = ["time", "num vecs", "vec dim", "stack dim"]
spatial_dims = ["num vecs", "vec dim", "stack dim"]
vec_graphic = ndw['raw data'].add_nd_vector(data=data,
                                    dims=vector_dims,
                                    spatial_dims = spatial_dims,
                                    name='vec img data')


ndw.show()

Screen.Recording.2026-04-14.at.11.21.13.PM.mov

Copy link
Copy Markdown
Member

@kushalkolar kushalkolar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, main comment is I think [n_vecs, pos/dir, xyz] is more intuitive and more similar to NDPositions

Comment on lines +113 to +116
if data.ndim < 3 or data.shape[-1] != 2 or data.shape[-2] not in (2, 3):
raise ValueError(
f"Final dimension must be , indicating spatial dimensions and magnitude of vector, you passed an array of shape {data.shape}"
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be based on the set spatial dims? dims are named so order in the actual array is arbitrary


if len(sdims) != 3:
raise ValueError(
f"There must be exactly 3 spatial dims for vectors indicating [num_vectors, 2, 2] or [num_vectors, 3, 2] "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah it's [n_vecs, xyz, position & direction] ?

I would suggest [n_vecs, pos & dir, xyz], more intuitive and more similar to NDPositions


old_graphic = self._graphic
# check if we are replacing a graphic
# ex: swapping from 2D <-> 3D representation after ``spatial_dims`` was changed
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# ex: swapping from 2D <-> 3D representation after ``spatial_dims`` was changed

Comment on lines +307 to +311
def spatial_dims(self) -> tuple[str, str] | tuple[str, str, str]:
"""
get or set the spatial dims **in order**

[row_dim, col_dim] or [row_dim, col_dim, rgb(a) dim]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update type annots and docstring

return self.processor.spatial_dims

@spatial_dims.setter
def spatial_dims(self, dims: tuple[str, str] | tuple[str, str, str]):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update type annots

magnitudes = np.linalg.norm(self._directions, axis=1, ord=2)

for i in range(self._directions.shape[0]):
# for i in range(self._directions.shape[0]):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove stale code

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.

2 participants