PyVista Integration¶
This tutorial covers the integration between mmgpy and PyVista for visualization and mesh interoperability.
Overview¶
PyVista is a powerful 3D visualization library for Python. mmgpy provides seamless conversion to and from PyVista meshes, enabling:
- Interactive visualization of meshes
- Loading meshes from PyVista geometric primitives
- Quality inspection and comparison
- Integration with PyVista workflows
Quick Visualization¶
The simplest way to visualize a mesh is using the built-in plot() method:
import mmgpy
mesh = mmgpy.read("input.mesh")
mesh.remesh(hmax=0.1)
# One-liner visualization with edges shown by default
mesh.plot()
# Customize with any PyVista plot options
mesh.plot(color="lightblue", opacity=0.8, show_edges=False)
Custom Plotter Integration¶
For more complex visualizations, use the vtk property to access the PyVista mesh:
import mmgpy
import pyvista as pv
mesh = mmgpy.read("input.mesh")
mesh.remesh(hmax=0.1)
# Use mesh.vtk with any PyVista plotter
plotter = pv.Plotter()
plotter.add_mesh(mesh.vtk, show_edges=True, color="lightblue")
plotter.add_mesh(other_mesh.vtk, color="red", opacity=0.5)
plotter.show()
Converting to PyVista¶
For full control, convert to a PyVista object with to_pyvista():
import mmgpy
import pyvista as pv
# Load and remesh
mesh = mmgpy.read("input.mesh")
mesh.remesh(hmax=0.1)
# Convert to PyVista (same as mesh.vtk)
pv_mesh = mesh.to_pyvista()
# Visualize
pv_mesh.plot(show_edges=True)
Converting from PyVista¶
Create mmgpy meshes from PyVista geometry:
import mmgpy
import pyvista as pv
# Create PyVista geometry
sphere = pv.Sphere(radius=1.0)
# Convert to surface mesh
mesh = mmgpy.from_pyvista(sphere, mesh_type="surface")
# Or for volumetric meshes (requires tetrahedral cells)
cube = pv.Box().triangulate().delaunay_3d()
mesh_3d = mmgpy.from_pyvista(cube, mesh_type="3d")
Mesh type options:
mesh_type |
Description |
|---|---|
"surface" |
Surface triangular mesh |
"3d" |
Volumetric tetrahedral mesh |
"2d" |
2D triangular mesh |
Visualization Examples¶
Basic Visualization¶
Side-by-Side Comparison¶
Compare before and after remeshing:
import mmgpy
import pyvista as pv
mesh = mmgpy.read("input.mesh")
before = mesh.to_pyvista()
mesh.remesh(hmax=0.1)
after = mesh.to_pyvista()
pl = pv.Plotter(shape=(1, 2))
pl.subplot(0, 0)
pl.add_mesh(before, show_edges=True, color="lightblue")
pl.add_text("Before", font_size=12)
pl.subplot(0, 1)
pl.add_mesh(after, show_edges=True, color="lightgreen")
pl.add_text("After", font_size=12)
pl.link_views()
pl.show()
Quality Visualization¶
Visualize element quality:
import mmgpy
import pyvista as pv
import numpy as np
mesh = mmgpy.read("input.mesh")
mesh.remesh(hmax=0.1)
pv_mesh = mesh.to_pyvista()
# Compute quality (PyVista has built-in quality metrics)
quality = pv_mesh.compute_cell_quality(quality_measure="scaled_jacobian")
# Plot with quality colormap
quality.plot(
scalars="CellQuality",
cmap="RdYlGn",
show_edges=True,
scalar_bar_args={"title": "Quality"},
)
Animation¶
Animate a remeshing sequence:
import mmgpy
import pyvista as pv
mesh = mmgpy.read("input.mesh")
pl = pv.Plotter()
actor = pl.add_mesh(mesh.to_pyvista(), show_edges=True)
pl.show(interactive_update=True, auto_close=False)
for hmax in [0.5, 0.3, 0.2, 0.15, 0.1]:
mesh.remesh(hmax=hmax, verbose=-1)
actor.mapper.SetInputData(mesh.to_pyvista())
pl.update()
pl.close()
Working with Mesh Data¶
Transferring Scalar Fields¶
import mmgpy
import pyvista as pv
import numpy as np
mesh = mmgpy.read("input.mesh")
# Add a scalar field to the mesh
vertices = mesh.get_vertices()
scalar_field = np.sin(vertices[:, 0] * 2 * np.pi)
mesh["temperature"] = scalar_field
# Convert to PyVista - fields are preserved
pv_mesh = mesh.to_pyvista()
# Plot with scalar field
pv_mesh.plot(scalars="temperature", show_edges=True, cmap="coolwarm")
From PyVista with Data¶
import mmgpy
import pyvista as pv
import numpy as np
# Create PyVista mesh with data
sphere = pv.Sphere()
sphere["elevation"] = sphere.points[:, 2]
# Convert to mmgpy
mesh = mmgpy.from_pyvista(sphere, mesh_type="surface")
# Access the field
elevation = mesh["elevation"]
print(f"Elevation range: {elevation.min():.2f} to {elevation.max():.2f}")
Interactive Workflows¶
Interactive Refinement¶
import mmgpy
import pyvista as pv
from pyvista import examples
# Load example mesh
bunny = examples.download_bunny()
# Convert to mmgpy surface mesh
mesh = mmgpy.from_pyvista(bunny, mesh_type="surface")
def remesh_callback(value):
mesh.remesh(hmax=value, verbose=-1)
pl.update()
pl = pv.Plotter()
actor = pl.add_mesh(mesh.to_pyvista(), show_edges=True)
pl.add_slider_widget(
remesh_callback,
rng=[0.01, 0.1],
value=0.05,
title="hmax",
)
pl.show()
Picking Points for Refinement¶
import mmgpy
import pyvista as pv
mesh = mmgpy.read("input.mesh")
pv_mesh = mesh.to_pyvista()
def add_refinement(point):
mesh.set_size_sphere(center=point, radius=0.1, size=0.01)
mesh.remesh(hmax=0.1, verbose=-1)
actor.mapper.SetInputData(mesh.to_pyvista())
pl.update()
pl = pv.Plotter()
actor = pl.add_mesh(pv_mesh, show_edges=True, pickable=True)
pl.enable_point_picking(callback=add_refinement, show_message="Click to add refinement")
pl.show()
Complete Example¶
Full workflow from PyVista primitive to remeshed output:
import mmgpy
import pyvista as pv
import numpy as np
# Create a complex geometry in PyVista
torus = pv.ParametricTorus(ringradius=1.0, crosssectionradius=0.3)
# Convert to mmgpy surface mesh
mesh = mmgpy.from_pyvista(torus, mesh_type="surface")
print(f"Original: {mesh.get_mesh_size()['triangles']} triangles")
# Remesh with adaptive sizing
mesh.set_size_sphere(center=[1.0, 0, 0], radius=0.3, size=0.02)
result = mesh.remesh(hmax=0.1, hausd=0.001, verbose=1)
print(f"Remeshed: {result.triangles_after} triangles")
print(f"Quality: {result.quality_mean_after:.3f}")
# Visualize result
pv_result = mesh.to_pyvista()
pl = pv.Plotter()
pl.add_mesh(pv_result, show_edges=True, edge_color="gray")
pl.add_text(f"Quality: {result.quality_mean_after:.3f}", font_size=10)
pl.show()
Tips¶
-
Memory: Large meshes may use significant memory when converted. Consider saving to file for very large meshes.
-
Cell types: PyVista supports many cell types, but mmgpy requires triangles (surface/2D) or tetrahedra (3D). Use
triangulate()if needed. -
Coordinates: mmgpy uses 0-indexed arrays. PyVista point/cell IDs match directly.
-
Performance: For real-time visualization, use
interactive_update=Trueand batch updates.
Next Steps¶
- Level-Set Extraction - Extract isosurfaces
- API Reference - Detailed API documentation