pyvista / pyvista-support

[moved] Please head over to the Discussions tab of the PyVista repository
https://github.com/pyvista/pyvista/discussions
60 stars 4 forks source link

Spherical Slice? #295

Open lsawade opened 3 years ago

lsawade commented 3 years ago

Description

Asking here because I wasn't able to find it in the documentation or the undocumented functions:

I'm working with Earth model data and was wondering whether there is a way to create depth slices? I.e. create a slice with constant radius R from the origin.

I successfully implemented sliders that define slice with midpoint defined by Latitudes and Longitudes and then a local rotation. And now It would be beneficial for my interpretation to include depth slices to the representation.

Thank you for the help!

Cheers!

Screen Shot 2020-11-19 at 8 43 24 AM

banesullivan commented 3 years ago

Not really. What you can do is create a sphere (you'll need to carefully choose the phi/theta resolutions) and use that sphere to sample your data:

r = depth_slice_radius
shell = pv.Sphere(radius=r, theta_resolution=64, phi_resolution=64)
depth_slice = shell.sample(spherical_data)

See:

This is also a bit similar to https://github.com/pyvista/pyvista-support/issues/154

lsawade commented 3 years ago

Thanks! I understand -- was just hoping for a similar implementation as the paraview spherical slice. I'll have to see how expensive this and whether it makes sense to have in the visualization like this.

One more question, slightly separate from my original question: Is there a way to control the slider values via text input, either through the command line or a possible text box for input. I have a way right now to start my scene with a certain camera angle, slice locations and rotation, but it would be nice to be able to input certain values since the slider often jump more than hoped for. Thoughts?

banesullivan commented 3 years ago

the paraview spherical slice.

oh. huh. I didn't realize that was there. I will look into the internals of how paraview is implementing that and see if we can do the same.


For your other question. You can add a custom callback for key press events and have it handle updating the sliders. this might be worth its own support issue

lsawade commented 3 years ago

I will look into the internals of how Paraview is implementing that and see if we can do the same.

That's awesome! Yeah, when you choose the slicing widget in paraview, you are able to choose the plane type. It's extremely convenient. My plan is to build in a callback button to the export it to a cartopy map.


this might be worth its own support issue

Will submit.

lsawade commented 3 years ago

Fix

As a novice in pyvista, I think a pull request may be a bit too much for me, but I rummaged through the the documentation of the add_plane_widget, and how it is actually implemented. For each movement of the plane or the normal, it creates a plane function/object given a center, and a normal. This plane function is then fed to a cutting algorithm that cuts through a given mesh.

Similarly to the plane function, we can create a vtkSphere function from the vtkmodules.CommonDataModels (should be imported in the pyvista._vtk submodule)

def generate_sphere(radius, origin):
    """Return a vtkSphere."""
    sphere = vtkmodules.vtkCommonDataModel.vtkSphere()
    sphere.SetRadius(radius)
    sphere.SetCenter(origin)
    return sphere

and feed this to the cutting algorithm

The steps are more or less as follows and I have it working in my own plotting tool

# Given an existing plotter 'plotter' and any mesh 'mesh'

if not hasattr(plotter, "plane_sliced_meshes"):
            plotter.plane_sliced_meshes = []

# Construct the cutter object
alg = _vtk.vtkCutter() 

# Use the grid as the data we desire to cut
alg.SetInputDataObject(mesh)
alg.GenerateTrianglesOff()
r_slice = pv.wrap(alg.GetOutput())

# Add slice to plane_sliced_meshes
plotter.plane_sliced_meshes.append(r_slice)

# Then, to actually cut, (important for a slider callback function)
radius = 1.0
center = [0,0,0]

# create the plane for clipping
sphere = generate_sphere(radius, center)

# The cutter to use the sphere we made
alg.SetCutFunction(sphere)
alg.Update()  # Perform the Cut
r_slice.shallow_copy(alg.GetOutput())

# After computing the first spherical slice add the actor to the plotter
r_slice_actor = plotter.add_mesh(r_slice)

Opacity problem

I couldn't find where I'm going wrong, but given opacity scalars in my mesh this seems to fail completely, I get and black and white slices of my non-opacity scalars. It would be nice to get some feedback on what could be wrong here/ what's missing.