import numpy as np import holoviews as hv from holoviews import opts from scipy.spatial import Delaunay hv.extension('matplotlib')
represents a mesh of triangles represented as the simplexes and vertexes. The simplexes represent the indices into the vertex data, made up of three indices per triangle. The mesh therefore follows a datastructure very similar to a graph, with the abstract connectivity between nodes stored on the
element itself, the node or vertex positions stored on a
element and the concrete
making up each triangle generated when required by accessing the edgepaths attribute.
Unlike a Graph each simplex is represented as the node indices of the three corners of each triangle rather than the usual source and target node.
We will begin with a simple random mesh, generated by sampling some random integers and then applying Delaunay triangulation, which is available in SciPy. We can then construct the
by passing it the
n_verts = 100 pts = np.random.randint(1, n_verts, (n_verts, 2)) tris = Delaunay(pts) trimesh = hv.TriMesh((tris.simplices, pts)) trimesh
To make this easier TriMesh also provides a convenient
method, which will apply the Delaunay triangulation and construct the
Just like the
element we can access the
trimesh.nodes + trimesh.edgepaths
Now let's make a slightly more interesting example by generating a more complex geometry. Here we will compute a geometry, then apply Delaunay triangulation again and finally apply a mask to drop nodes in the center.
# First create the x and y coordinates of the points. n_angles = 36 n_radii = 8 min_radius = 0.25 radii = np.linspace(min_radius, 0.95, n_radii) angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False) angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1) angles[:, 1::2] += np.pi/n_angles x = (radii*np.cos(angles)).flatten() y = (radii*np.sin(angles)).flatten() z = (np.cos(radii)*np.cos(angles*3.0)).flatten() nodes = np.column_stack([x, y, z]) # Apply Delaunay triangulation delauney = Delaunay(np.column_stack([x, y])) # Mask off unwanted triangles. xmid = x[delauney.simplices].mean(axis=1) ymid = y[delauney.simplices].mean(axis=1) mask = np.where(xmid*xmid + ymid*ymid < min_radius*min_radius, 1, 0) simplices = delauney.simplices[np.logical_not(mask)]
Once again we can simply supply the simplices and nodes to the
We can also do something more interesting, e.g. by adding a value dimension to the vertices and coloring the edges by the vertex averaged value using the
hv.TriMesh((simplices, hv.Points(nodes, vdims='z'))).opts( opts.TriMesh(cmap='viridis', edge_color='z', filled=True, fig_size=200))
For full documentation and the available style and plot options, use