Meshplot Tutorials¶
Meshplot is a simple, and fast 2d and 3d mesh and point cloud viewer based on pythreejs
.
Installing Meshplot¶
Meshplot can be installed from Conda forge with conda install -c conda-forge meshplot
and imported as follows:
import numpy as np import meshplot as mp
Mesh Representation¶
Meshplot uses numpy
to encode vectors and matrices. A triangular mesh is encoded as a pair of matrices:
v: np.array f: np.array data = np.load('data.npz') v, f, n, fs = data["v"], data["f"], data["n"], data["fs"] v1, f1, v2, f2 = data["v1"], data["f1"], data["v2"], data["f2"]
Visualizing Surfaces¶
We can visualize surfaces, their properties and additional debugging information through the plot
function. Let’s visualize the previously loaded triangle mesh:
mp.plot(v, f)
Scalar field visualization¶
Colors and normals can be associated to faces or vertices using the same plot
function with three parameters.
The key parameter c
represents the vertex or face colors and can be one of the following:
- A #v by 1 vector with one function value per vertex, which gets normalized and converted into vertex color values using the viridis colormap.
- A #v by 3 vector with RGB color values per vertex. The color values should be in the range 0.0-1.0.
- A single color value for all vertices in the form of a numpy array [R, G, B] in the range 0.0-1.0.
- A #f by 1 vector with one function value per face, which gets normalized and converted into face color values using the viridis colormap.
- A #f by 3 vector with RGB color values per face. The color values should be in the range 0.0-1.0.
The following four examples show vertex function colors (in this case just the y-coordinate), vertex normals as colors per vertex, random colors per face and face function colors (in this case the size of the faces):
d = mp.subplot(v, f, c=v[:, 1], s=[2, 2, 0]) mp.subplot(v, f, c=n, s=[2, 2, 1], data=d) mp.subplot(v, f, c=np.random.rand(*f.shape), s=[2, 2, 2], data=d) mp.subplot(v, f, c=fs, s=[2, 2, 3], data=d)
Visualizing Point Clouds¶
We can also visualize point clouds, their properties and additional debugging information through the plot
function, by just leaving the faces array empty:
mp.plot(v)
Similar to the surface plot, we can also set color values for all points in the point cloud. This can be done either by passing function values or directly by passing colors:
d = mp.subplot(v, c=v[:, 1], s=[1, 2, 0], shading={"point_size": 0.03}) mp.subplot(v, c=np.random.rand(*v.shape), s=[1, 2, 1], data=d, shading={"point_size": 0.03})
Overlays, Textures and Shading¶
In addition to plotting the surface, the viewer supports the visualization of bounding boxes, points and lines. These overlays can be very helpful while developing geometric processing algorithms to plot debug information.
The following example draws a point of a given color for each row of v_box
. The point is placed at the coordinates specified in each row of v_box
, which is a #v_box by 3 matrix.
In addition, edges of a given color are drawn for the vertices v_box
with the indices f_box
:
m = np.min(v, axis=0) ma = np.max(v, axis=0) # Corners of the bounding box v_box = np.array([[m[0], m[1], m[2]], [ma[0], m[1], m[2]], [ma[0], ma[1], m[2]], [m[0], ma[1], m[2]], [m[0], m[1], ma[2]], [ma[0], m[1], ma[2]], [ma[0], ma[1], ma[2]], [m[0], ma[1], ma[2]]]) # Edges of the bounding box f_box = np.array([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6, 7], [7, 4], [0, 4], [1, 5], [2, 6], [7, 3]], dtype=np.int) p = mp.plot(v, f, return_plot=True) p.add_edges(v_box, f_box, shading={"line_color": "red"}); p.add_points(v_box, shading={"point_color": "green"})
The viewer allows for many customization options, which are presented below:
mi = np.min(v, axis=0) ma = np.max(v, axis=0) shading = {"flat":True, # Flat or smooth shading of triangles "wireframe":False, "wire_width": 0.03, "wire_color": "black", # Wireframe rendering "width": 600, "height": 600, # Size of the viewer canvas "antialias": True, # Antialising, might not work on all GPUs "scale": 2.0, # Scaling of the model "side": "DoubleSide", # FrontSide, BackSide or DoubleSide rendering of the triangles "colormap": "viridis", "normalize": [None, None], # Colormap and normalization for colors "background": "#ffffff", # Background color of the canvas "line_width": 1.0, "line_color": "black", # Line properties of overlay lines "bbox": False, # Enable plotting of bounding box "point_color": "red", "point_size": 0.01 # Point properties of overlay points } p = mp.plot(v, f, shading=shading, return_plot=True) # Instead of adding edges in the form of (v, f), also lines of the form (start, end) can be added p.add_lines(v[f[:,0]], v[f[:,1]], shading={"line_color": "red"}); # The vertex positions can be updated as well v += 0.003 * np.random.rand(v.shape[0], v.shape[1]) # The plotted objects get increasing ids. In this case the mesh object has id 0, and the lines object id 1. p.update_object(vertices=v)
Events and Widgets¶
The viewer supports to use interactive widgets from the ipywidgets package to manipulate the plot.
v = [v1, v2] f = [f1, f2] p = mp.plot(v1, f1, return_plot=True) @mp.interact(mesh=[('bump', 0), ('fertility', 1)]) def ff(mesh): mp.plot(v[mesh], f[mesh], plot=p) p
Offline Plotting¶
Besides interactive plotting in Jupyter Notebooks, meshplot
supports to plot objects in offline html pages. The offline mode is automatically selected, if meshplot
is run outside of a Jupyter Notebook. Within Jupyter Notebooks, one can manually switch to offline mode as follows:
#mp.offline() mp.plot(v1, f1, c=v1[:, 1])
Without parameters, the plot is stored with the name <UUID>.html
. It is possible to save Jupyter plots after they are generated and to chose the filename as follows:
#mp.jupyter() p = mp.plot(v1, f1, c=np.random.rand(*f1.shape), return_plot=True) p.add_mesh(v1 + 5, f1, c=v1[:,1]); p.add_points(v1 - 5, c=v1[:,2], shading={"point_size": 1.0}) #p.save("test.html") p