Slider widget to control surface values

Hi,

Are there any way for control surface values with a slicer widget?

Thanks!

1 Like

@scaracciolo Could you elaborate a bit more on what you’re trying to achieve? Do you mean with a Surface layer, or with an image layer with isosurface rendering?

Thanks for response!

Yes, I’m sory. I have 3D mesh data structured with vertices and faces. This mesh has different data values each time. So, I want to use a slider to change the instant time and data values in consecuence.

This old gif could help to understand what I need

I have this code and I need change [0] to [k] with k controlled with slider.

surface = (vertices, faces, mediciones[0])

with napari.gui_qt():
    viewer = napari.Viewer()
    layer = viewer.add_surface(surface)
1 Like

Ah right! Right now it’s a bit clunky, though we discussed precisely this use case when we first implemented surfaces, and would like to make it easier. Essentially, you need to make the vertices 4D, the faces update with the 4th dimension, and the values a long linear array of values. I haven’t tested the code below but it should capture the idea:

n = len(vertices)
vertices_t = np.concatenate(
    [np.concatenate((np.full((i, 1), vertices), axis=1)
     for i in range(k)],
    axis=0,
)
faces_t = np.concatenate(
    [faces + n*i for i in range(k)],
    axis=0,
)
values_t = np.concatenate([values[i] for i in range(k)])

with napari.gui_qt():
    viewer = napari.Viewer()
    layer = viewer.add_surface((vertices_t, faces_t, values_t))

This results in quite a bit of duplicate data, although I think the above would work verbatim if you used dask.array.concatenate in place of np.concatenate, and the arrays would not get created until you moved the slider.

If you had some data that you could share with us, we could try to improve the syntax for this use case…

Let us know if this helps!

2 Likes

Hola Juan,

The shape of my data is:

  • vertices N x 3 (constant: doesn’t change with time)
  • faces M x 3 (constant: doesn’t change with time)
  • values L x N (each time has N values for the vertices )

I ran this code

vertices_t = np.concatenate(tuple([vertices for i in range(values.shape[0])]))
faces_t = np.concatenate(tuple([faces + i*vertices.shape[0] for i in range(values.shape[0])]))
values_t = values.to_numpy().flatten()

The output seems is correct, but I have not the widget, any idea? Thanks!

Can you confirm the shapes of the following:

vertices_t.shape = (N*L, 4)
faces_t.shape = (M*L, 3)
values_t.shape = (N*L)

vertices_t should have the structure of [[(N, 3), 0], [(N, 3), 1], ...., [(N, 3), L]] if that shorthand makes sense. Can you also print the first and last few rows of vertices_t.

All in all looking at this makes me cringe a bit and think we should seriously improve our API so that you can just pass your data as

vertices N x 3 (constant: doesn’t change with time)
faces M x 3 (constant: doesn’t change with time)
values L x N (each time has N values for the vertices )

and it’ll just work!! Potentially you could pass values K x L x N and then you’d get two sliders!!
I have a pretty clear idea how to implement this and can get to it soonish. Would be nice to see your thing work with our current API too though

I have now added an issue on our GitHub, which describes potential API changes that would make this better - https://github.com/napari/napari/issues/829

I’m very greatful for your help!

This is my code

image

And results

The viewer doesnt’ work fine yet, but I have 2 slider

Thanks for open the issue!

1 Like

You’re close (I hope), all you should need to do is click the 3D cube button near the bottom left corner to enter 3D rendering mode - then you should just have 1 slider and see your surface. You can also do viewer=napari.Viewer(ndisplay=3) to start off in 3D rendering mode

If that doesn’t work, then you might need to pad the vertices with the timestamp before the array and not after, i.e. [[0, (N, 3)], [1, (N, 3)], ...., [L, (N, 3)]]

Yes! Now it’s working!

image

The problem was solved changing timestamp order.

Thanks and good job!

1 Like

There is now a PR in progress #831 to add this support in a better fashion. It will have a large performance increase too, not only because you don’t need to duplicate data in that way, but because you also don’t need to constantly re-slice. Feel free to check it out now, or once it finds its way into master / our next release.

Also, thanks for asking the question in the first place, this sort of engagement from the community helps us set priorities and keeps us focused on features people want to use.

Here is a gif of the current behavior:


(links to data set, and steps to reproduce are in the PR)

Thank you very much!

Now it’s very fast!

2 Likes

This functionality has now been merged into master and will be present in our next release.

2 Likes