Plots

scatter

vtkplotlib.scatter(points, color=None, opacity=None, radius=1.0, use_cursors=False, fig='gcf', label=None)

Scatter plot using little spheres or cursor objects.

Parameters:
  • points (np.array with points.shape[-1] == 3) – The point(s) to place the marker(s) at.
  • color (str, 3-tuple, 4-tuple, np.array with same shape as points, optional) – The color of the markers, can be singular or per marker, defaults to white.
  • opacity (float, np.array, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • radius (float, np.array, optional) – The radius of each marker, defaults to 1.0.
  • use_cursors (bool, optional) – If false use spheres, if true use cursors, defaults to False.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

The marker or an array of markers.

Return type:

vtkplotlib.plots.Scatter.Sphere or vtkplotlib.plots.Scatter.Cursor or np.ndarray or spheres or cursors.

Coloring by directly with scalars is not supported for scatter but you can do it using:

from matplotlib.cm import get_cmap
vpl.scatter(points, color=get_cmap("rainbow")(scalars))

plot

vtkplotlib.plot(vertices, color=None, opacity=None, line_width=1.0, join_ends=False, cmap=None, fig='gcf', label=None)

Plots a line passing through an array of points.

Parameters:
  • vertices (np.ndarray of shape (n, 3)) – The points to plot through.
  • color (str, 3-tuple, 4-tuple, np.ndarray optional) – The color(s) of the lines, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • line_width (float, optional) – The thickness of the lines, defaults to 1.0.
  • join_ends (bool, optional) – If true, join the 1st and last points to form a closed loop, defaults to False.
  • cmap (matplotlib cmap, vtkLookupTable, or similar see vtkplotlib.colors.as_vtk_cmap(), optional) – Colormap to use for scalars, defaults to rainbow.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

A lines object. Always a single object - even when plotting multiple lines.

Return type:

vtkplotlib.plots.Lines.Lines

If vertices is 3D then multiple seperate lines are plotted. This can be used to plot meshes as wireframes.

import vtkplotlib as vpl
from stl.mesh import Mesh

mesh = Mesh.from_file(vpl.data.get_rabbit_stl())
vertices = mesh.vectors

vpl.plot(vertices, join_ends=True, color="dark red")
vpl.show()

If color is an np.ndarray then a color per vertex is implied. The shape of color relative to the shape of vertices determines whether the colors should be interpreted as scalars, texture coordinates or RGB values. If color is either a list, tuple, or str then it is one color for the whole plot.

import vtkplotlib as vpl
import numpy as np

# Create an octagon, using `t` as scalar values.

t = np.arange(0, 1, .125) * 2 * np.pi
vertices = vpl.zip_axes(np.cos(t),
                        np.sin(t),
                        0)

# Plot the octagon.
vpl.plot(vertices,
         line_width=6,   # use a chunky (6pt) line
         join_ends=True, # join the first and last points
         color=t,        # use `t` as scalar values to color it
         )

# use a dark background for contrast
fig = vpl.gcf()
fig.background_color = "grey"

vpl.show()

mesh_plot

vtkplotlib.mesh_plot(mesh_data, tri_scalars=None, scalars=None, color=None, opacity=None, cmap=None, fig='gcf', label=None)

To plot STL files you will need some kind of STL reader library. If you don’t have one then get numpy-stl. Their Mesh class can be passed directly to mesh_plot().

Parameters:
  • mesh_data (An STL (like) object (see below)) – The mesh to plot.
  • tri_scalars (np.ndarray, optional) – Per-triangle scalar, texture-coordinates or RGB values, defaults to None.
  • scalars (np.ndarray, optional) – Per-vertex scalar, texture-coordinates or RGB values, defaults to None.
  • color (str, 3-tuple, 4-tuple, optional) – The color of the whole plot, ignored if scalars are used, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • cmap (matplotlib cmap, vtkLookupTable, or similar see vtkplotlib.colors.as_vtk_cmap(), optional) – Colormap to use for scalars, defaults to rainbow.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

A meshplot object.

Return type:

vtkplotlib.plots.MeshPlot.MeshPlot

The following example assumes you have installed numpy-stl.

import vtkplotlib as vpl
from stl.mesh import Mesh

# path = "if you have an STL file then put it's path here."
# Otherwise vtkplotlib comes with a small STL file for demos/testing.
path = vpl.data.get_rabbit_stl()

# Read the STL using numpy-stl
mesh = Mesh.from_file(path)

# Plot the mesh
vpl.mesh_plot(mesh)

# Show the figure
vpl.show()

Unfortunately there are far too many mesh/STL libraries/classes out there to support them all. To overcome this as best we can, mesh_plot has a flexible constructor which accepts any of the following.

  1. A filename.
  2. Some kind of mesh class that has form 3 stored in mesh.vectors. For example numpy-stl’s stl.mesh.Mesh or pymesh’s pymesh.stl.Stl
  3. An np.array with shape (n, 3, 3) in the form:
np.array([[[x, y, z],  # corner 0  \
           [x, y, z],  # corner 1  | triangle 0
           [x, y, z]], # corner 2  /
          ...
          [[x, y, z],  # corner 0  \
           [x, y, z],  # corner 1  | triangle n-1
           [x, y, z]], # corner 2  /
         ])

Note it’s not uncommon to have arrays of shape (n, 3, 4) or (n, 4, 3) where the additional entries’ meanings are usually irrelevant (often to represent scalars but as STL has no color this is always uniform). Hence to support mesh classes that have these, these arrays are allowed and the extra entries are ignored.

  1. An np.array with shape (k, 3) of (usually unique) vertices in the form:

    np.array([[x, y, z],
              [x, y, z],
              ...
              [x, y, z],
              [x, y, z],
              ])
    

    And a second argument of an np.array of integers with shape (n, 3) of point args in the form

    np.array([[i, j, k],  # triangle 0
              ...
              [i, j, k],  # triangle n-1
              ])
    

    where i, j, k are the indices of the points (in the vertices array) representing each corner of a triangle.

    Note that this form can be (and is) easily converted to form 2) using

    vertices = unique_vertices[point_args]
    

Hopefully this will cover most of the cases. If you are using or have written an STL library (or any other format) that you want supported then let me know. If it’s numpy based then it’s probably only a few extra lines to support. Or you can have a go at writing it yourself, either with mesh_plot() or with the vtkplotlib.PolyData class.

Mesh plotting with scalars:

To create a heat map like image use the scalars or tri_scalars options.

Use the scalars option to assign a scalar value to each point/corner:

import vtkplotlib as vpl
from stl.mesh import Mesh

# Open an STL as before
path = vpl.data.get_rabbit_stl()
mesh = Mesh.from_file(path)

# Plot it with the z values as the scalars. scalars is 'per vertex' or 1
# value for each corner of each triangle and should have shape (n, 3).
plot = vpl.mesh_plot(mesh, scalars=mesh.z)

# Optionally the plot created by mesh_plot can be passed to color_bar
vpl.color_bar(plot, "Heights")

vpl.show()

Use the tri_scalars option to assign a scalar value to each triangle:

import vtkplotlib as vpl
from stl.mesh import Mesh
import numpy as np

# Open an STL as before
path = vpl.data.get_rabbit_stl()
mesh = Mesh.from_file(path)

# `tri_scalars` must have one value per triangle and have shape (n,) or (n, 1).
# Create some scalars showing "how upwards facing" each triangle is.
tri_scalars = np.inner(mesh.units, np.array([0, 0, 1]))

vpl.mesh_plot(mesh, tri_scalars=tri_scalars)

vpl.show()

Note

scalars and tri_scalars overwrite each other and can’t be used simultaneously.

See also

Having per-triangle-edge scalars doesn’t fit well with VTK. So it got its own seperate function mesh_plot_with_edge_scalar().


mesh_plot_with_edge_scalars

vtkplotlib.mesh_plot_with_edge_scalars(mesh_data, edge_scalars, centre_scalar='mean', opacity=None, cmap=None, fig='gcf', label=None)

Like mesh_plot() but able to add scalars per triangle’s edge. By default, the scalar value at centre of each triangle is taken to be the mean of the scalars of its edges, but it can be far more visually effective to use centre_scalar=fixed_value.

Parameters:
  • mesh_data (An STL (like) object (see below)) – The mesh to plot.
  • edge_scalars (np.ndarray) – Per-edge scalar, texture-coordinates or RGB values.
  • centre_scalar (str, optional) – Scalar value(s) for the centre of each triangle, defaults to ‘mean’.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • cmap (matplotlib cmap, vtkLookupTable, or similar see vtkplotlib.colors.as_vtk_cmap(), optional) – Colormap to use for scalars, defaults to rainbow.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

A meshplot object.

Return type:

vtkplotlib.plots.MeshPlot.MeshPlot

Edge scalars are very much not the way VTK likes it. Infact VTK doesn’t allow it. To overcome this, this function triple-ises each triangle. See the diagram below to see how this is done:

(The diagrams's tacky, I know)

           p1

         //|\\         Double lines represent the original triangle.
        // | \\        The single lines represent the division lines that
  l0   //  |  \\  l1   split the triangle into three.
      //  / \  \\      The annotations show the order in which the
     // /     \ \\     scalar for each edge must be provided.
    ///~~~~~~~~~\\\
p0  ~~~~~~~~~~~~~~~  p2
          l2

(reST doesn't like it either)

Here is a usage example:

import vtkplotlib as vpl
from vtkplotlib import geometry
from stl.mesh import Mesh
import numpy as np


path = vpl.data.get_rabbit_stl()
mesh = Mesh.from_file(path)

# This is the length of each side of each triangle.
edge_scalars = geometry.distance(mesh.vectors[:, np.arange(1, 4) % 3] - mesh.vectors)

vpl.mesh_plot_with_edge_scalars(mesh, edge_scalars, centre_scalar=0, cmap="Greens")

vpl.show()

I wrote this orginally to visualise curvature. The calculation is ugly, but on the off chance someone needs it, here it is.

import vtkplotlib as vpl
from vtkplotlib import geometry
from stl.mesh import Mesh
import numpy as np


path = vpl.data.get_rabbit_stl()
mesh = Mesh.from_file(path)

def astype(arr, dtype):
    return np.frombuffer(arr.tobytes(), dtype)

def build_tri2tri_map(mesh):
    """This creates an (n, 3) array that maps each triangle to its 3
    adjacent triangles. It takes advantage of each triangles vertices
    being consistently ordered anti-clockwise. If triangle A shares an
    edge with triangle B then both A and B have the edges ends as
    vertices but in opposite order. Looking for this helps reduce the
    complexity of the problem.
    """

    # The most efficient way to make a pair of points hashable is to
    # take its binary representation.
    dtype = np.array(mesh.vectors[0, :2].tobytes()).dtype

    vectors_rolled = mesh.vectors[:, np.arange(1, 4) % 3]

    # Get all point pairs going one way round.
    pairs = np.concatenate((mesh.vectors, vectors_rolled), -1)

    # Get all point pairs going the other way round.
    pairs_rev = np.concatenate((vectors_rolled, mesh.vectors), -1)

    bin_pairs = astype(pairs, dtype).reshape(-1, 3)
    bin_pairs_rev = astype(pairs_rev, dtype).reshape(-1, 3)

    # Use a dictionary to find all the matching pairs.
    mapp = dict(zip(bin_pairs.ravel(), np.arange(bin_pairs.size) // 3))
    args = np.fromiter(map(mapp.get, bin_pairs_rev.flat), dtype=float, count=bin_pairs.size).reshape(-1, 3)

    # Triangles with a missing adjacent edge come out as nans.
    # Convert mapping to ints and nans to -1s.
    mask = np.isfinite(args)
    tri2tri_map = np.empty(args.shape, int)
    tri2tri_map[mask] = args[mask]
    tri2tri_map[~mask] = -1

    return tri2tri_map


tri2tri_map = build_tri2tri_map(mesh)

tri_centres = np.mean(mesh.vectors, axis=1)
curves = np.cross(mesh.units[tri2tri_map], mesh.units[:, np.newaxis])
displacements = tri_centres[tri2tri_map] - tri_centres[:, np.newaxis]
curvatures = curves / geometry.distance(displacements, keepdims=True)

curvature_signs = np.sign(geometry.inner_product(mesh.units[:, np.newaxis],
                                                 displacements)) * -1

signed_curvatures = geometry.distance(curvatures) * curvature_signs

# And finally, to plot it.
plot = vpl.mesh_plot_with_edge_scalars(mesh, signed_curvatures)

# Curvature must be clipped to prevent anomalies overwidenning the
# scalar range.
plot.scalar_range = -.1, .1

# Red represents an inside corner, blue represents an outside corner.
plot.cmap = "coolwarm_r"

vpl.show()

polygon

vtkplotlib.polygon(vertices, scalars=None, color=None, opacity=None, fig='gcf', label=None)

Creates a filled polygon(s) with vertices as it’s corners. For a 3 dimensional vertices array, each 2d array within vertices is a seperate polygon.

Parameters:
  • vertices (np.ndarray with shape ([number_of_polygons,] points_per_polygon, 3)) – Each corner of each polygon.
  • color (str, 3-tuple, 4-tuple, optional) – The color of whole the plot, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

A polygon object.

Return type:

vtkplotlib.plots.Polygon.Polygon

VTK renders everything as only triangles. Polygons with more than 3 sides are broken down by VTK into multiple triangles. For non-flat polygons with many sides, the fragmentation doesn’t look too great.


scalar_bar

vtkplotlib.scalar_bar(plot, title='', fig='gcf')

Create a scalar bar. Also goes by the alias colorbar.

Parameters:
Returns:

The scalarbar object.

Return type:

vtkplotlib.plots.ScalarBar.ScalarBar

The plot argument can be the output of any vtkplotlib.*** command that takes scalars as an argument.


arrow

vtkplotlib.arrow(start, end, length=None, width_scale=1.0, color=None, opacity=None, fig='gcf', label=None)

Draw (an) arrow(s) from start to end.

Parameters:
  • start (np.ndarray) – The starting point(s) of the arrow(s).
  • end (np.ndarray) – The end point(s) of the arrow(s).
  • length (number, np.ndarray, optional) – The length of the arrow(s), defaults to None.
  • width_scale (number, np.ndarray, optional) – How fat to make each arrow, is relative to its length, defaults to 1.0.
  • color (str, 3-tuple, 4-tuple, np.ndarray of shape (n, 3)) – The color of each arrow, defaults to white.
  • opacity (float) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

arrow or array of arrows

Return type:

vtkplotlib.plots.Arrow.Arrow, np.array of Arrows

The shapes of start and end should match. Arrow lengths are automatically calculated via pythagoras if not provided but can be overwritten by setting length. In this case the arrow(s) will always start at start but may not end at end. length can either be a single value for all arrows or an array of lengths to match the number of arrows.

Note

Arrays are supported only for convenience and just use a python for loop. There is no speed bonus to using numpy or trying to plot in bulk here.

See also

vtkplotlib.quiver() for field plots.


quiver

vtkplotlib.quiver(point, gradient, length=None, length_scale=1.0, width_scale=1.0, color=None, opacity=None, fig='gcf', label=None)

Create arrow(s) from ‘point’ towards a direction given by ‘gradient’ to make field/quiver plots. Arrow lengths by default are the magnitude of ‘gradient but can be scaled with ‘length_scale’ or frozen with ‘length’. See arrow’s docs for more detail.

Parameters:
  • point (np.ndarray) – The starting point of the arrow(s).
  • gradient (np.ndarray) – The displacement / gradient vector.
  • length (NoneType, optional) – A frozen length for each arrow, defaults to None.
  • length_scale (int, optional) – A scaling factor for the length of each arrow, defaults to 1.0.
  • width_scale (int, optional) – How fat to make each arrow, is relative to its length, defaults to 1.0.
  • color (str, 3-tuple, 4-tuple, np.ndarray of shape (n, 3)) – The color of each arrow, defaults to white.
  • opacity (float) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

arrow or array of arrows

Return type:

vtkplotlib.plots.Arrow.Arrow, np.array of Arrows

See also

vpl.arrow to draw arrows from a start point to an end point.


text

vtkplotlib.text(text_str, position=(0, 0), fontsize=18, use_pixels=False, color=(1, 1, 1), opacity=None, fig='gcf')

2D text at a fixed point on the window (independent of camera position / orientation).

Parameters:
  • text_str (str, object) – The text, converts to string if not one already.
  • position (2-tuple of ints, optional) – The (x, y) position in pixels on the screen, defaults to (0, 0) (left, bottom).
  • fontsize (int, optional) – Text height (ignoring tails) in pixels, defaults to 18.
  • color (str, 3-tuple, 4-tuple, optional) – The color of the text, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
Returns:

The text plot object.

Return type:

vtkplotlib.plots.Text.Text

The text doesn’t resize or reposition itself when the window is resized. It’s on the todo list.

See also

vpl.text3D


text3d

vtkplotlib.text3d(text, position=(0, 0, 0), follow_cam=True, scale=1, color=None, opacity=None, fig='gcf', label=None)

Create floating text in 3D space. Optionally can be set to orientate itself to follow the camera (defaults to on) with the follow_cam argument.

Parameters:
  • string – The text to be shown.
  • position (tuple, optional) – The position of the start of the text, defaults to (0, 0, 0).
  • follow_cam (bool, optional) – Automatically rotates to follow the camera, defaults to True.
  • scale (number or 3-tuple of numbers, optional) – The height of one line of text, can have 3 values, defaults to 1.0.
  • color (str, 3-tuple, 4-tuple, optional) – The color of the text, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

text3D plot object

Return type:

vtkplotlib.plots.Text3D.Text3D

Warning

This can’t be passed about between figures if follow_cam=True (the default). The figure who’s camera it follows is frozen to the figure given to it on first construction.

See also

vpl.text for 2D text at a fixed point on the screen.

See also

vpl.annotate for a convenient way to label features with text and an arrow.


annotate

vtkplotlib.annotate(points, text, direction, text_color='w', arrow_color='k', distance=3.0, text_size=1.0, fig='gcf')

Annotate a feature with an arrow pointing at a point and a text label on the reverse end of the arrow. This is just a convenience call to arrow() and text3d(). See there for just one or the other.

Parameters:
  • points (np.ndarray) – The position of the feature where the arrow’s tip should be.
  • text – The text to put in the label.
  • direction (np.ndarray with shape (3,)) – The direction from the feature to the text position as a unit vector.
  • text_color (optional) – The color of the label, defaults to ‘w’.
  • arrow_color (optional) – The color of the arrow, defaults to ‘k’.
  • distance (number, optional) – The distance from the feature to the label, defaults to 3.0.
  • text_size (number or 3-tuple of numbers, optional) – The height of one line of text, can have 3 values, defaults to 1.0.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
Returns:

(arrow, text) 2-tuple

Return type:

(vtkplotlib.plots.Arrow.Arrow, vtkplotlib.plots.Text3D.Text3D)

The arrow points to the highest point and the text is placed at a point distance above (where above also is determined by direction).

If text is not a str then it is automatically converted to one.

import vtkplotlib as vpl
import numpy as np

# Create a ball at a point in space.
point = np.array([1, 2, 3])
vpl.scatter(point)

vpl.annotate(point,
             "This ball is at {}".format(point),
             np.array([0, 0, 1]))
vpl.show()

If multiple points are given the farthest in the direction direction is selected. The idea is to try to prevent the annotations ending up in amongst the plots or, when plotting meshes, inside the mesh.

import vtkplotlib as vpl
import numpy as np

# Create several balls.
points = np.random.uniform(-30, 30, (30, 3))
vpl.scatter(points, color=np.random.random(points.shape))

vpl.annotate(points,
             "This ball is the highest",
             np.array([0, 0, 1]),
             text_color="k",
             arrow_color="orange"
             )

vpl.annotate(points,
             "This ball is the lowest",
             np.array([0, 0, -1]),
             text_color="rust",
             arrow_color="hunter green"
             )

vpl.show()

surface

vtkplotlib.surface(x, y, z, scalars=None, color=None, opacity=None, texture_map=None, cmap=None, fig='gcf', label=None)

Create a parametrically defined surface. This is intended for visualising mathematical functions of the form

\[z = f(x, y)\]

or

\[x = f(\phi, \theta) \quad y = g(\phi, \theta) \quad z = h(\phi, \theta) \quad\]
Parameters:
  • x (2D np.ndarray with shape (m, n)) – x components.
  • y (2D np.ndarray with shape (m, n)) – y components.
  • z (2D np.ndarray with shape (m, n)) – z components.
  • scalars (np.ndarray with shape (m, n [, 1 or 2 or 3]), optional) – per-point scalars / texturemap coordinates / RGB colors, defaults to None.
  • color (str, 3-tuple, 4-tuple, optional) – The color of the plot, defaults to white.
  • opacity (float, optional) – The translucency of the plot, from 0 invisible to 1 solid, defaults to 1.
  • cmap (matplotlib cmap, vtkLookupTable, or similar see vtkplotlib.colors.as_vtk_cmap(), optional) – Colormap to use for scalars, defaults to rainbow.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • label (str, optional) – Give the plot a label to use in legends, defaults to None.
Returns:

The surface object.

Return type:

vtkplotlib.surface

See also

vtkplotlib.mesh_plot() for a surface made out of triangles or vtkplotlib.polygon() for a surface made out of polygons.

This is the only function in vtkplotlib that takes it’s (x, y, z) components as seperate arguments. x, y and z should be 2D arrays with matching shapes. This is typically achieved by using phi, theta = np.meshgrid(phis, thetas) then calculating x, y and z from phi and theta. Here is a rather unexciting example.

import vtkplotlib as vpl
import numpy as np

phi, theta = np.meshgrid(np.linspace(0, 2 * np.pi, 1024),
                     np.linspace(0, np.pi, 1024))


x = np.cos(phi) * np.sin(theta)
y = np.sin(phi) * np.sin(theta)
z = np.cos(theta)

vpl.surface(x, y, z)

vpl.show()

See also

A parametrically constructed object plays well with a vtkplotlib.colors.TextureMap.


legend

vtkplotlib.legend(plots_source='fig', fig='gcf', position=(0.7, 0.7), size=(0.3, 0.3), color='grey', opacity=None, allow_non_polydata_plots=False, allow_no_label=False)

Creates a legend to label plots.

Parameters:
  • plots_source (iterable of plots or None, optional) – Plots to use in the legend, can be None, defaults to fig.plots.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to plot into, can be None, defaults to vtkplotlib.gcf().
  • position (tuple pair of floats, optional) – Position (relative to the size of the figure) of the bottom left corner, defaults to (0.7, 0.7).
  • size (tuple pair of floats, optional) – Size (relative to the size of the figure) of the legend, defaults to (0.3, 0.3).
  • color (str, 3-tuple, 4-tuple, optional) – The background color of the legend, defaults to ‘grey’.
  • allow_no_label (bool, optional) – Allow plots that have no label to have label None, only applicable if entries are added automatically, defaults to False.
  • allow_non_polydata_plots (bool, optional) – Allow plots that have no polydata to represented with a box, only applicable if entries are added automatically, defaults to False.
Returns:

The legend created.

Return type:

vtkplotlib.plots.Legend.Legend

Elements can be added to the legend automatically or explicitly. Most plot commands have an optional label argument. If this is used then they will be added automatically. Multiple plots with the same label will be grouped.

import vtkplotlib as vpl
import numpy as np

# Create some plots with labels
vpl.scatter([0, 0, 0], color="red", label="Red Ball")
vpl.scatter(vpl.zip_axes(5, np.arange(0, 10, 4), 0), color="yellow", label="Yellow Ball")

# A plot without a label will not be included in the legend.
vpl.scatter([10, 0, 0], color="green")

# Create the legend
vpl.legend()
# Unless told otherwise this internally calls
# legend.add_plots(vpl.gcf().plots)

vpl.show()

The legend uses a tabular format.

Symbol Icon Text Label
Symbol Icon Text Label
Symbol Icon Text Label
  • A symbol is a 2D representation of the original plot. VTK can generate these flattened snapshots from a polydata object which most plots either have or can generate. These are accessible via plot.polydata.
  • An icon is just a 2D image. Note that VTK only supports greyscale icons in legends.
  • The text label, as the name suggests, is just a piece of text.

All three columns are optional. If a column is never used throughout the legend then the contents adjusts to close the space. Color can only be applied per-row. i.e the symbol, icon and text of an entry are always the same color.

The following example shows how to set the entries explicitly.

import vtkplotlib as vpl

# Create a legend and don't allow it to fill itself.
legend = vpl.legend(plots_source=None)


# A labelled plot contains all the information it needs to add itself.
sphere = vpl.scatter([0, 5, 10], color="g", label="Green Ball")
# Add it like so.
legend.set_entry(sphere)

# Written explicitly the above is equivalent to:
# legend.set_entry(symbol=sphere.polydata, color=sphere.color, label=sphere.label)


# Not all plots can have a polydata. If one isn't provided then a by
# default a square is used.
legend.set_entry(label="Blue Square", color="blue")

# Alternatively, if explicitly given ``symbol=None``, then the symbol
# space is left blank.
legend.set_entry(symbol=None, label="Just Text")


# Most plots can be used.
legend.set_entry(vpl.mesh_plot(vpl.data.get_rabbit_stl()), label="Rabbit")


# To use an icon, pass a string path, array, PIL image or vtkImageData
# to the **icon** argument. The image is converted to greyscale
# automatically.
legend.set_entry(None, label="Shark", icon=vpl.data.ICONS["Right"])


vpl.show()

legend.set_entry has an optional argument index which can be used to overwrite rows. Otherwise it defaults to appending a row.

Some caveats / potential sources of confusion:

  • Long and thin plots such as arrow() tend to mess up the spacing which is seemingly non configurable.
  • Be careful when using scatter() and quiver() which return an array of plots rather than a single plot.
  • Plots based on lines such as the output of vpl.plot tend not to show well as the lines are less than one pixel wide.
  • Automatic setting of color can only work for uniformly colored plots. any colors derived from scalars are ignored.

To some extent, the text labels can be customised via legend.text_options which holds the vtkTextProperty (bucket class for settings like font). However, a lot of its methods do nothing. Most notably, legend.text_options.SetFontSize(size) has no effect.


custom plots using PolyData

vtkplotlib.PolyData(vtk_polydata=None, mapper=None)

The polydata is a key building block to making customised plot objects. The mesh_plot, plot and surface methods are in fact just a thin wrapping layer around a PolyData. This is a wrapper around VTK’s vtkPolyData object, which is functionally equivalent, but difficult and crash-prone to work with directly.

Parameters:vtk_polydata (vtk.vtkPolyData, optional) – An original vtkPolyData to build on top of, defaults to None.

A polydata consists of the following 2D numpy arrays:

Attribute name dtype shape Meaning
points float (a, 3)
All line start and end points
and all polygon corners.
lines int (b, 3)
Each row of lines corresponds
the point indices a line passes
through.
polygons int (c, 3)
Each row of polygons corresponds
the point indices a the corners of
a polygon.
point_colors float (a,) (a, 1) (a, 2) (a, 3)
Per-point scalars, texture coordinates
or RGB values, depending on the shape.
polygon_colors float (c,) (c, 1) (c, 2) (c, 3)
Per-polygon scalars, texture coordinates
or RGB values, depending on the shape.

The points aren’t visible themselves - to create some kind of points plot use :meth`scatter`.

Lines and polyons can be interchanged to switch from solid surface to wire-frame.

Here is an example to create a single triangle

import vtkplotlib as vpl
import numpy as np


polydata = vpl.PolyData()

polydata.points = np.array([[1, 0, 0],          # vertex 0
                            [0, 1, 0],          # vertex 1
                            [0, 0, 1]], float)  # vertex 2

# Create a wire-frame triangle passing through vertices [0, 1, 2, 0].
polydata.lines = np.array([[0, 1, 2, 0]])

# Create a solid triangle with vertices [0, 1, 2] as it's corners.
polydata.polygons = np.array([[0, 1, 2]])

# The polydata can be quickly inspected using
polydata.quick_show()

# When you are happy with it, it can be turned into a proper plot
# object like those output from other ``vpl.***()`` commands. It will be
# automatically added to ``vpl.gcf()`` unless told otherwise.
plot = polydata.to_plot()
vpl.show()