The Plotter3D is a wrapper around the pyvista.BackgroundPlotter with some added functionality around
convenient simplifications for use in structural dynamics.
Running on Linux
If the viewer does not open, maybe libxcb-cursor0 is missing. Try installing (Ubuntu):
sudo apt install libxcb-cursor0Also, if running wayland, the following should be added at the top of the file:
os.environ['QT_QPA_PLATFORM'] = 'xcb'Running from shell
If not running from jupyter notebook, the viewer might close right away. To keep it interactive, run it with:
python -i file.pyimport sdypy as sd
nodes = ... # Finite element nodes
elements ... # Finite elements
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements)
plotter.show(show_grid=True, show_axes=True)To animate a mode shape:
mode_shape = ... # Shape (n_nodes, 3)
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements, animate=mode_shape)To animate according to a time history:
time_history = ... # Shape (n_nodes, 3, n_timesteps)
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements, animate=time_history)To color the mesh according to a norm of the mode_shape:
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements, animate=mode_shape, field="norm")Here, if field="norm" is passed, the mesh will be colored according to the
norm of the mode_shape (or more generally, according to the norm of the animate argument).
To color the mesh according to an arbitrary field, the field argument must be of shape (n_nodes, n_timesteps).
The Plotter3D class also enables the user to animate the mesh. There are two way to animate the FEM mesh or points:
- By passing a 3D array of shape
(n_nodes, 3, n_timesteps)to theanimateargument. The points/nodes will be animated according to the time history. - By passing a 2D array of shape
(n_nodes, 3)to theanimateargument. Theanimatedefines the maximum displacement of the nodes. The animation is interpolated with a sine function.
The animate argument can also have the following shapes:
(n_nodes*3): ThePlotter3Dwill automatically convert this to(n_nodes, 3).(n_nodes*3, n_timesteps): ThePlotter3Dwill automatically convert this to(n_nodes, 3, n_timesteps).(n_nodes*N): ThePlotter3Dwill automatically convert this to(n_nodes, 3), whereNis an arbitrary number. Only the first 3 columns are used. This is useful when animating e.g. a mode shape of a shell (each node has 6 DOF).(n_nodes*N, n_timesteps): ThePlotter3Dwill automatically convert this to(n_nodes, 3, n_timesteps). Similar to previous point, but with time history.
The n_frames is set to 100 by default, but can be changed to alter the number of frames per one iteration. When providing the time history, the n_frames should match the last dimension of the animate argument.
Here is an example of animating a mode shape:
import sdypy as sd
nodes = ... # Finite element nodes (n_nodes, 3)
elements ... # Finite elements (n_elements, n_nodes_per_element)
mode_shape = ... # Mode shape (n_nodes, 3)
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements, animate=mode_shape, field="norm")
plotter.configure_animation(interval=20) # To adjust the interval and camera position
plotter.start_animation() # Optional. To immediately start the animation. Otherwise, the controls are available in the plotter.
plotter.show()To record a GIF, the configure_gif_recorder method must be called. Example:
import sdypy as sd
nodes = ... # Finite element nodes (n_nodes, 3)
elements ... # Finite elements (n_elements, n_nodes_per_element)
mode_shape = ... # Mode shape (n_nodes, 3)
plotter = sd.view.Plotter3D(nodes, elements)
plotter.gif_recorder("mode_shape.gif") # MUST BE CALLED BEFORE THE ANIMATION STARTS
plotter.add_fem_mesh(nodes, elements, animate=mode_shape, field="norm")
plotter.configure_gif_recorder('mode_shape.gif', fps=30) # Configure the GIF recorder
plotter.show()The recording will start on pressing the "Record" button in the toolbar. Alternatively, the
configure_gif_recorder can be called like this:
plotter.configure_gif_recorder('mode_shape.gif', fps=30, start_on_play=True)This will start the recording when the animation starts. To start the animation, call the start_animation method
or press the "Play" button in the toolbar.
The recording will last for 1 iteration of the animation.
To add custom toolbar commands, use the configure_toolbar method. Example:
import sdypy as sd
nodes = ... # Finite element nodes (n_nodes, 3)
elements ... # Finite elements (n_elements, n_nodes_per_element)
mode_shape = ... # Mode shape (n_nodes, 3)
plotter = sd.view.Plotter3D(nodes, elements)
plotter.add_fem_mesh(nodes, elements, animate=mode_shape, field="norm")
def custom_command():
print("Custom command")
toolbar_actions = {
"Custom command": custom_command
}
plotter.configure_toolbar(toolbar_actions)
plotter.show()