differt.plotting package#

Module contents#

Plotting utilities for DiffeRT objects.

Warning

Unlike in other modules, plotting utilities work with NumPy arrays (np.ndarray) instead of JAX arrays. Therefore, it is important to first convert any JAX array into its NumPy equivalent with np.asarray before using it as an argument to any of the functions defined here.

Note

Backend names are case-sensitive.

Backend-specific notes#

Each backend comes with its own configuration options and outputs that the user should be aware of.

VisPy#

VisPy uses SceneCanvas objects to display contents, on which a view is attached. The view (ViewBox) is what contains the data to be plotted.

To reuse an existing canvas object, just pass it as a keyword argument to any of the draw_* functions in this module, i.e., with draw_*(..., canvas=canvas). In turn, each of those functions returns a figure on which you can later add data.

It is also possible to pass an existing view on which data will be plotted: draw_*(..., view=view).

If the jupyter_rfb module is installed, VisPy’s canvas integrate nicely within Jupyter notebooks.

Matplotlib#

Matplotlib uses Figure objects to display contents, on which multiple axes can be attached. In turn, each axis can contain data to be plotted.

To reuse an existing figure object, just pass it as a keyword argument to any of the draw_* functions in this module, i.e., with draw_*(..., figure=figure). In turn, each of those functions returns a figure on which you can later add data.

It is also possible to pass an existing axis (Axes) on which data will be plotted: draw_*(..., ax=ax).

Warning

By default, Matplotlib instantiates 2D axes, but this module extensively uses 3D plot methods. If an axis is provided, it is your responsibility to ensure that it can plot 3D data when needed.

By default, Matpotlib displays static images in Jupyter notebooks. To make them interactive, install ipympl and load the corresponding extension with %matplotlib widget.

Plotly#

Plotly is a dictionary-oriented library that produces HTML-based outputs. Hence, Plotly is a very good choice for publishing nice interactive plots on webpages.

Plots are fully contained inside Figure objects, and can be nicely displayed within Jupyter notebooks without further configuration.

To reuse an existing figure object, you can do the same as with the Matplotlib backend.

dispatch(fun)[source]#

Transform a function into a backend dispatcher for plot functions.

Parameters:

fun (Callable[[ParamSpec(P)], TypeVar(T, SceneCanvas, Figure, Figure)]) – The callable that will register future dispatch functions for each backend implementation.

Return type:

Dispatcher[ParamSpec(P), TypeVar(T, SceneCanvas, Figure, Figure)]

Returns:

The same callable, wrapped in a Dispatcher class instance.

Examples

The following example shows how one can implement plotting utilities on different backends for a given plot.

>>> import differt.plotting as dplt
>>>
>>> @dplt.dispatch
... def plot_line(vertices, color):
...     pass
>>>
>>> @plot_line.register("matplotlib")
... def _(vertices, color):
...     print("Using matplotlib backend")
>>>
>>> @plot_line.register("plotly")
... def _(vertices, color):
...     print("Using plotly backend")
>>>
>>> plot_line(
...     _,
...     _,
...     backend="matplotlib",
... )
Using matplotlib backend
>>>
>>> plot_line(
...     _,
...     _,
...     backend="plotly",
... )
Using plotly backend
>>>
>>> plot_line(
...     _,
...     _,
...     backend="vispy",
... )  
Traceback (most recent call last):
NotImplementedError: No backend implementation for 'vispy'
>>>
>>> # The default backend is VisPy so unimplemented too.
>>> plot_line(_, _)  
Traceback (most recent call last):
NotImplementedError: No backend implementation for 'vispy'
>>>
>>> @plot_line.register("numpy")  
... def _(vertices, color):
...     pass
Traceback (most recent call last):
ValueError: Unsupported backend 'numpy', allowed values are: ...
draw_image(data, x=None, y=None, z0=0.0, **kwargs)[source]#

Plot a 2D image on a 3D canvas, at using a fixed z-coordinate.

Parameters:
  • data (Num[ndarray, 'm n'] | Num[ndarray, 'm n 3'] | Num[ndarray, 'm n 4']) – The image data array. Can be grayscale, RGB or RGBA. For more details on how the data is interpreted, please refer to the documentation of the function corresponding to the specified backend (see below).

  • x (Float[ndarray, '*m'] | None) – The x-coordinates corresponding to first dimension of the image. Those coordinates will be used to scale and translate the image.

  • y (Float[ndarray, '*n'] | None) – The y-coordinates corresponding to second dimension of the image. Those coordinates will be used to scale and translate the image.

  • z0 (float) – The z-coordinate at which the image is placed.

  • kwargs (Any) – Keyword arguments passed to Mesh, plot_trisurf, or Mesh3d, depending on the backend.

Return type:

SceneCanvas | Figure | Figure

Returns:

The resulting plot output.

Warning

Matplotlib backend requires data to be either RGB or RGBA array.

Examples

The following example shows how plot a 2-D image, without and with axis scaling.

>>> from differt.plotting import draw_image
>>>
>>> x = np.linspace(-1.0, +1.0, 100)
>>> y = np.linspace(-4.0, +4.0, 200)
>>> X, Y = np.meshgrid(x, y)
>>> Z = np.sin(X) * np.cos(Y)
>>> fig1 = draw_image(Z, backend="plotly")
>>> fig1  
>>>
>>> fig2 = draw_image(Z, x=x, y=y, backend="plotly")
>>> fig2  
draw_markers(markers, labels=None, text_kwargs=None, **kwargs)[source]#

Plot markers and, optionally, their label.

Parameters:
  • markers (Float[ndarray, 'num_markers 3']) – The array of marker vertices.

  • labels (Sequence[str] | None) – The marker labels.

  • text_kwargs (Mapping[str, Any] | None) –

    A mapping of keyword arguments passed to Text if VisPy backend is used.

    By default, font_sise=1000 is used.

  • kwargs (Any) – Keyword arguments passed to Markers, or Scatter3d, depending on the backend.

Return type:

SceneCanvas | Figure | Figure

Returns:

The resulting plot output.

Warning

Unsupported backend(s): Matplotlib.

Examples

The following example shows how to plot several annotated markers.

>>> from differt.plotting import draw_markers
>>>
>>> markers = np.array(
...     [
...         [0.0, 0.0, 0.0],
...         [1.0, 0.0, 0.0],
...         [1.0, 1.0, 0.0],
...         [0.0, 1.0, 0.0],
...     ]
... )
>>> labels = ["A", "B", "C", "D"]
>>> fig = draw_markers(markers, labels, backend="plotly")
>>> fig  
draw_mesh(vertices, triangles, **kwargs)[source]#

Plot a 3D mesh made of triangles.

Parameters:
  • vertices (Float[ndarray, 'num_vertices 3']) – The array of triangle vertices.

  • triangles (UInt[ndarray, 'num_triangles 3']) – The array of triangle indices.

  • kwargs (Any) – Keyword arguments passed to Mesh, plot_trisurf, or Mesh3d, depending on the backend.

Return type:

SceneCanvas | Figure | Figure

Returns:

The resulting plot output.

Examples

The following example shows how to plot a pyramid mesh.

>>> from differt.plotting import draw_mesh
>>>
>>> vertices = np.array(
...     [
...         [0.0, 0.0, 0.0],
...         [1.0, 0.0, 0.0],
...         [1.0, 1.0, 0.0],
...         [0.0, 1.0, 0.0],
...         [0.5, 0.5, 1.0],
...     ]
... )
>>> triangles = np.array(
...     [[0, 1, 2], [0, 2, 3], [0, 1, 4], [1, 2, 4], [2, 3, 4], [3, 0, 4]]
... )
>>> fig = draw_mesh(vertices, triangles, backend="plotly", opacity=0.5)
>>> fig  
draw_paths(paths, **kwargs)[source]#

Plot a batch of paths of the same length.

Parameters:
  • paths (Float[ndarray, '*batch path_length 3']) – The array of path vertices.

  • kwargs (Any) – Keyword arguments passed to LinePlot, plot, or Scatter3d, depending on the backend.

Return type:

SceneCanvas | Figure | Figure

Returns:

The resulting plot output.

Examples

The following example shows how to plot ten line strings.

>>> from differt.plotting import draw_paths
>>>
>>> def rotation(angle: float) -> np.ndarray:
...     c = np.cos(angle)
...     s = np.sin(angle)
...     return np.array(
...         [
...             [+c, -s, 0.0],
...             [+s, +c, 0.0],
...             [0.0, 0.0, 1.0],
...         ]
...     )
>>>
>>> path = np.array(
...     [
...         [0.0, 0.0, 0.0],
...         [1.0, 0.0, 0.0],
...         [1.0, 1.0, 0.0],
...         [0.1, 0.1, 0.0],
...     ],
... )
>>> paths = np.stack(
...     [
...         path @ rotation(angle) + np.array([0.0, 0.0, 0.1 * dz])
...         for dz, angle in enumerate(np.linspace(0, 2 * np.pi, 10))
...     ]
... )
>>> fig = draw_paths(
...     paths,
...     backend="plotly",
...     marker=dict(size=0, color="red"),
...     line=dict(color="black", width=3),
... )
>>> fig  
process_matplotlib_kwargs(kwargs)[source]#

Process keyword arguments passed to some Matplotlib plotting utility.

Parameters:

kwargs (MutableMapping[str, Any]) –

A mutable mapping of keyword arguments passed to Matplotlib plotting.

Warning

The keys specified below will be removed from the mapping.

Keyword Arguments:
  • figure (Figure) – The figure that draws contents of the scene. If not provided, will try to access figure from ax (if supplied).

  • ax (Axes3D) – The view on which contents are displayed. If not provided, will try to get axes from figure (if supplied). The default axes will use a 3D projection.

Warning

When supplying both figure and ax, user must ensure that ax in figure.axes evaluates to True.

Return type:

tuple[Figure, Axes3D]

Returns:

The figure and axes used to display contents.

process_plotly_kwargs(kwargs)[source]#

Process keyword arguments passed to some Plotly plotting utility.

Parameters:

kwargs (MutableMapping[str, Any]) –

A mutable mapping of keyword arguments passed to Plotly plotting.

Warning

The keys specified below will be removed from the mapping.

Keyword Arguments:

figure (Figure) – The figure that draws contents of the scene.

Return type:

Figure

Returns:

The figure used to display contents.

process_vispy_kwargs(kwargs)[source]#

Process keyword arguments passed to some VisPy plotting utility.

Parameters:

kwargs (MutableMapping[str, Any]) –

A mutable mapping of keyword arguments passed to VisPy plotting.

Warning

The keys specified below will be removed from the mapping.

Keyword Arguments:
  • convas (SceneCanvas) – The canvas that draws contents of the scene. If not provided, will try to access canvas from view (if supplied).

  • view (Viewbox) – The view on which contents are displayed. If not provided, will try to get a view from canvas (if supplied and has at least one view in its children).

Warning

When supplying both canvas and view, user must ensure that view in canvas.central_widget.children evaluates to True.

Return type:

tuple[SceneCanvas, ViewBox]

Returns:

The canvas and view used to display contents.

reuse(**kwargs)[source]#

Create a context manager that will automatically reuse the current canvas / figure.

Parameters:
Return type:

Iterator[SceneCanvas | Figure | Figure]

Returns:

The canvas or figure that is reused for this context.

set_defaults(backend=None, **kwargs)[source]#

Set default keyword arguments for future plotting utilities.

Parameters:
  • backend (str | None) – The name of the backend to use, or None to use the current default.

  • kwargs (Any) – Keyword arguments that will be passed to the corresponding process_*_kwargs function, and plot utilities.

Return type:

str

Returns:

The name of the (new) default backend.

Raises:

Examples

The following example shows how to set the default plotting backend.

>>> import differt.plotting as dplt
>>>
>>> @dplt.dispatch
... def my_plot():
...     pass
>>>
>>> @my_plot.register("vispy")
... def _():
...     print("Using vispy backend")
>>>
>>> @my_plot.register("matplotlib")
... def _():
...     print("Using matplotlib backend")
>>>
>>> my_plot()  # When not specified, use default backend
Using vispy backend
>>>
>>> my_plot(backend="matplotlib")  # We can force the backend
Using matplotlib backend
>>>
>>> dplt.set_defaults("matplotlib")  # Or change the default backend...
'matplotlib'
>>> my_plot()  # So that now it defaults to 'matplotlib'
Using matplotlib backend
>>>
>>> my_plot(backend="vispy")  # Of course, the 'vispy' backend is still available
Using vispy backend
use(*args, **kwargs)[source]#

Create a context manager that sets plotting defaults and returns the current default backend.

When exiting the context, the previous default backend and default keyword arguments are set back.

Parameters:
Return type:

Iterator[str]

Returns:

The name of the default backend used in this context.

view_from_canvas(canvas)[source]#

Return the view from the specified canvas.

If the canvas does not have any view, create one and return it.

This utility is used by process_vispy_kwargs.

Parameters:

canvas (SceneCanvas) – The canvas that draws the contents of the scene.

Return type:

ViewBox

Returns:

The view on which contents are displayed.