Note
Go to the end to download the full example code.
Creating a Spline#
Create a spline/polyline from a numpy array of XYZ vertices using
pyvista.Spline().
from __future__ import annotations
import numpy as np
import pyvista as pv
Create a dataset to plot
def make_points():
    """Make XYZ points."""
    theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
    z = np.linspace(-2, 2, 100)
    r = z**2 + 1
    x = r * np.sin(theta)
    y = r * np.cos(theta)
    return np.column_stack((x, y, z))
points = make_points()
points[0:5, :]
array([[ 2.44929360e-15,  5.00000000e+00, -2.00000000e+00],
       [ 1.21556036e+00,  4.68488752e+00, -1.95959596e+00],
       [ 2.27700402e+00,  4.09249671e+00, -1.91919192e+00],
       [ 3.12595020e+00,  3.27840221e+00, -1.87878788e+00],
       [ 3.72150434e+00,  2.30906573e+00, -1.83838384e+00]])
Now let’s make a function that can create line cells on a
pyvista.PolyData mesh given that the points are in order for the
segments they make.
def lines_from_points(points):
    """Given an array of points, make a line set"""
    poly = pv.PolyData()
    poly.points = points
    cells = np.full((len(points) - 1, 3), 2, dtype=np.int_)
    cells[:, 1] = np.arange(0, len(points) - 1, dtype=np.int_)
    cells[:, 2] = np.arange(1, len(points), dtype=np.int_)
    poly.lines = cells
    return poly
line = lines_from_points(points)
line

That tube has sharp edges at each line segment. This can be mitigated by creating a single PolyLine cell for all of the points
def polyline_from_points(points):
    poly = pv.PolyData()
    poly.points = points
    the_cell = np.arange(0, len(points), dtype=np.int_)
    the_cell = np.insert(the_cell, 0, len(points))
    poly.lines = the_cell
    return poly
polyline = polyline_from_points(points)
polyline['scalars'] = np.arange(polyline.n_points, dtype=float)
tube = polyline.tube(radius=0.1)
tube.plot(smooth_shading=True)

You could also interpolate those points onto a parametric spline
Plot spline as a tube
# add scalars to spline and plot it
spline['scalars'] = np.arange(spline.n_points, dtype=float)
tube = spline.tube(radius=0.1)
tube.plot(smooth_shading=True)

The spline can also be plotted as a plain line
# generate same spline with 400 interpolation points
spline = pv.Spline(points, 400)
# plot without scalars
spline.plot(line_width=4, color='k')

The radius of the tube can be modulated with scalars
spline['theta'] = 0.4 * np.arange(len(spline.points))
spline['radius'] = np.abs(np.sin(spline['theta']))
tube = spline.tube(scalars='radius', absolute=True)
tube.plot(scalars='theta', smooth_shading=True)

Ribbons#
Ayy of the lines from the examples above can be used to create ribbons.
Take a look at the pyvista.PolyDataFilters.ribbon() filter.
ribbon = spline.compute_arc_length().ribbon(width=0.75, scalars='arc_length')
ribbon.plot(color=True)

Total running time of the script: (0 minutes 0.735 seconds)