Figures

Figures, typically abbreviated to figs, are the window that you plot into. This section outlines:

  • Their creation.
  • General figure management.
  • Functions for controlling the camera position.
  • Screenshotting the figure contents to a frozen image (file).
  • Embedding a figure into PyQt5.

Overview

Some of this is handled automatically. There is a global “current working figure”. This can be get and set using vpl.gcf() and vpl.scf(fig). If it doesn’t exist then it is automatically created. Each plot command will add itself to the current working figure unless explicitly told not by setting fig=None or fig=alternative_fig in the plot command. The figure is shown using vpl.show() or fig.show(). After the shown figure is closed it ceases to be the current working figure but you can use it by referencing it explicitly. Figures can be reshown indefinitely and should be exactly as you left them on close.


show

vtkplotlib.show(block=True, fig='gcf')

Shows a figure. This is analogous to matplotlib’s show function. After your plot commands call this to open the interactive 3D viewer.

Parameters:

If block is True then it enters interactive mode and the program is held until window exit. Otherwise the window is opened but not monitored. i.e an image will appear on the screen but it wont respond to being clicked on. By editing the plot and calling fig.update() you can create an animation but it will be non-interactive. True interactive animation hasn’t been implemented yet - it’s on the TODO list.

Note

You might feel tempted to run show in a background thread. It doesn’t work. If anyone does manage it then please let me know.

Warning

A window can not be closed by the close button until it is in interactive mode. Otherwise it’ll just crash Python. Use vtkplotlib.close() to close a non interactive window.

The current figure is reset on exit from interactive mode.


figure

vtkplotlib.figure

alias of vtkplotlib.figures.figure.Figure


gcf

vtkplotlib.gcf(create_new=True)

Gets the current working figure.

Parameters:create_new (bool, optional) – Allow a new one to be created if none exist, defaults to True.
Returns:The current figure or None.
Return type:vtkplotlib.figure or vtkplotlib.QtFigure

If none exists then a new one gets created by vpl.figure() unless create_new=False in which case None is returned. Will always return None if auto_figure(False) has been called.


scf

vtkplotlib.scf(figure)

Sets the current working figure.

Parameters:figure – A figure or None.

screenshot_fig

vtkplotlib.screenshot_fig(magnification=1, pixels=None, trim_pad_width=None, off_screen=False, fig='gcf')

Take a screenshot of a figure. The image is returned as an array. To save a screenshot directly to a file, see vpl.save_fig.

Parameters:
  • path (str or Pathlike) – The path, including extension, to save to.
  • magnification (int or a (width, height) tuple of ints, optional) – Image dimensions relative to the size of the render (window), defaults to 1.
  • pixels (int or a (width, height) tuple of ints, optional) – Image dimensions in pixels, defaults to None.
  • trim_pad_width (positive int for padding in pixels, float from 0.0 - 1.0 for pad width relative to original size.) – Optionally auto crop to contents, this specifies how much space to give it, defaults to None for no cropping.
  • off_screen (bool, optional) – If true, attempt to take the screenshot without opening the figure’s window, defaults to False.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to screenshot, defaults to vtkplotlib.gcf().

Setting pixels overrides magnification. If only one dimension is given to pixels then it is the height and an aspect ration of 16:9 is used. This is to match with the 1080p/720p/480p/… naming convention.

Note

VTK can only work with integer multiples of the render size (given by figure.render_size). pixels will be therefore be rounded to conform to this.

Note

I have no idea why it spins. But vtk’s example in the docs does it as well so I think it’s safe to say there’s not much we can do about it.

Note

For QtFigures off_screen is ignored.

Warning

There has been a case where the contents of other windows (e.g Firefox) have somehow ended up in the output (see <https://github.com/bwoodsend/vtkplotlib/issues/1>). Which can be resolved by setting off_screen=True. But this option can lead to a bad X server connection error on (I think) Linux machines without built in graphics hardware. This is currently unresolved.


save_fig

vtkplotlib.save_fig(path, magnification=1, pixels=None, trim_pad_width=None, off_screen=False, fig='gcf', **imsave_plotargs)

Take a screenshot and saves it to a file.

Parameters:
  • path (str or Pathlike) – The path, including extension, to save to.
  • magnification (int or a (width, height) tuple of ints, optional) – Image dimensions relative to the size of the render (window), defaults to 1.
  • pixels (int or a (width, height) tuple of ints, optional) – Image dimensions in pixels, defaults to None.
  • off_screen (bool, optional) – If true, attempt to take the screenshot without opening the figure’s window, defaults to False.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to save, defaults to vtkplotlib.gcf().

This just calls vpl.screenshot_fig then passes it to matplotlib’s pylab.imsave function. See those for more information.

The available file formats are determined by matplotlib’s choice of backend. For JPEG, you will likely need to install PILLOW. JPEG has considerably better file size than PNG.


view

vtkplotlib.view(focal_point=None, camera_position=None, camera_direction=None, up_view=None, fig='gcf')

Set/get the camera position/orientation.

Parameters:
  • focal_point (np.array([x, y, z]), optional) – A point the camera should point directly to, defaults to None.
  • camera_position (np.array([x, y, z]), optional) – The point the camera is situated, defaults to None.
  • camera_direction (np.array([eX, eY, eZ]), optional) – The direction the camera is pointing, defaults to None.
  • up_view (np.array([eX, eY, eZ]), optional) – Roll the camera so that the up_view vector is pointing towards the top of the screen, defaults to None.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to modify, defaults to vtkplotlib.gcf().
Returns:

A dictionary containing the new configuration.

Return type:

dict

Note

This function’s not brilliant. You may be better off manipulating the vtk camera directly (stored in fig.camera). If you do choose this route, start experimenting by calling print(fig.camera). If anyone makes a better version of this function then please share.

There is an unfortunate amount of implicit chaos going on here. Here are some hidden implications. I’m not even sure these are all true.

  1. If forwards is used then focal_point and camera_position are ignored.
  2. If camera_position is given but focal_point is not also given then camera_position is relative to where VTK determines is the middle of your plots. This is equivalent to setting camera_direction=-camera_position.

The following is well behaved:

vpl.view(camera_direction=...,
         up_view=...,)        # set orientations first
vpl.reset_camera()            # auto reset the zoom

reset_camera

vtkplotlib.reset_camera(fig='gcf')

Reset the position and zoom of the camera so that all plots are visible.

Parameters:fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to modify, defaults to vtkplotlib.gcf().

This does not touch the orientation. It pushes the camera without rotating it so that, whichever direction it is pointing, it is pointing into the middle of where all the plots are. Then it adjusts the zoom so that everything fits on the screen.


zoom_to_contents

vtkplotlib.zoom_to_contents(plots_to_exclude=(), padding=0.05, fig='gcf')

VTK, by default, leaves the camera zoomed out so that the renders contain a large amount of empty background. zoom_to_contents() zooms in so that the contents fill the render.

Parameters:
  • plots_to_exclude (iterable of plots, optional) – Plots that are unimportant and can be cropped out, defaults to ().
  • padding (int, float, optional) – Amount of space to leave around the contents, in pixels if integer or relative to min(fig.render_size) if float defaults to 0.05.
  • fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure zoom, defaults to :meth:`vtkplotlib.gcf`.

This method only zooms in. If you need to zoom out to fit all your plots in call vtkplotlib.reset_camera() first then this method. Plots in plots_to_exclude are temporarily hidden (using plot.visible = False) then restored. 2D plots such as a legend() or scalar_bar() which have a fixed position on the render are always excluded.

Note

New in v1.3.0.


close

vtkplotlib.close(fig='gcf')

Close a figure.

Parameters:fig (vtkplotlib.figure, vtkplotlib.QtFigure, optional) – The figure to close, defaults to vtkplotlib.gcf().

If the figure is the current figure then the current figure is reset.


figure_history

vtkplotlib.figure_history = <FigureHistory deque([], maxlen=2)>

auto_figure

vtkplotlib.auto_figure(auto=None)

Enables/disables automatic figure management. If no parameters are provided then it returns the current state.

Parameters:auto (bool, optional) – Defaults to None.

On by default. Disabling causes vpl.gcf() to always return None. Meaning that all plot commands will not add to a figure unless told to explicitly using the fig=a_figure argument. This can be useful for complex scenarios involving multiple figures.


QtFigure

class vtkplotlib.QtFigure(name='qt vtk figure', parent=None)

The VTK render window embedded into a PyQt5 QWidget. This can be embedded into a GUI the same way all other QWidgets are used.

Parameters:
  • name (str, optional) – The window title of the figure, only applicable is parent is None, defaults to ‘qt vtk figure’.
  • parent (PyQt5.QtWidgets.QWidget, optional) – Parent window, defaults to None.

Note

If you are new to Qt then this is a rather poor place to start. Whilst many libraries in Python are intuitive enough to be able to just dive straight in, Qt is not one of them. Preferably familiarise yourself with some basic Qt before coming here.

This class inherits both from PyQt5.QtWidgets.QWidget and a vtkplotlib BaseFigure class. Therefore it can be used exactly the same as you would normally use either a QWidget or a vtkplotlib.figure.

Care must be taken when using Qt to ensure you have exactly one QApplication. To make this class quicker to use the qapp is created automatically but is wrapped in a

if QApplication.instance() is None:
    self.qapp = QApplication(sys.argv)
else:
    self.qapp = QApplication.instance()

This prevents multiple QApplication instances from being created (which causes an instant crash) whilst also preventing a QWidget from being created without a qapp (which also causes a crash).

On self.show(), self.qapp.exec_() is called automatically if self.parent() is None (unless specified otherwise). If the QFigure is part of a larger window then larger_window.show() must also explicitly show the figure. It won’t begin interactive mode until qapp.exec_() is called.

If the figure is not to be part of a larger window then it behaves exactly like a regular figure. You just need to explicitly create it first.

import vtkplotlib as vpl

# Create the figure. This automatically sets itself as the current
# working figure. The qapp is created automatically if one doesn't
# already exist.
vpl.QtFigure("Exciting Window Title")

# Everything from here on should be exactly the same as normal.

vpl.quick_test_plot()

# Automatically calls ``qapp.exec_()``. If you don't want it to then
# use ``vpl.show(False)``.
vpl.show()

However this isn’t particularly helpful. A more realistic example would require the figure be part of a larger window. In this case, treat the figure as you would any other QWidget. You must explicitly call figure.show() however. (Not sure why.)

import vtkplotlib as vpl
from PyQt5 import QtWidgets
import numpy as np
import sys

# python 2 compatibility
from builtins import super


class FigureAndButton(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # Go for a vertical stack layout.
        vbox = QtWidgets.QVBoxLayout()
        self.setLayout(vbox)

        # Create the figure
        self.figure = vpl.QtFigure()

        # Create a button and attach a callback.
        self.button = QtWidgets.QPushButton("Make a Ball")
        self.button.released.connect(self.button_pressed_cb)

        # QtFigures are QWidgets and are added to layouts with `addWidget`
        vbox.addWidget(self.figure)
        vbox.addWidget(self.button)


    def button_pressed_cb(self):
        """Plot commands can be called in callbacks. The current working
        figure is still self.figure and will remain so until a new
        figure is created explicitly. So the ``fig=self.figure``
        arguments below aren't necessary but are recommended for
        larger, more complex scenarios.
        """

        # Randomly place a ball.
        vpl.scatter(np.random.uniform(-30, 30, 3),
                    color=np.random.rand(3),
                    fig=self.figure)

        # Reposition the camera to better fit to the balls.
        vpl.reset_camera(self.figure)

        # Without this the figure will not redraw unless you click on it.
        self.figure.update()


    def show(self):
        # The order of these two are interchangeable.
        super().show()
        self.figure.show()


    def closeEvent(self, event):
        """This isn't essential. VTK, OpenGL, Qt and Python's garbage
        collect all get in the way of each other so that VTK can't
        clean up properly which causes an annoying VTK error window to
        pop up. Explicitly calling QtFigure's `closeEvent()` ensures
        everything gets deleted in the right order.
        """
        self.figure.closeEvent(event)




qapp = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)

window = FigureAndButton()
window.show()
qapp.exec_()

Note

QtFigures are not reshowable if the figure has a parent.

See also

vtkplotlib.QtFigure2 is an extension of this to provide some standard GUI elements, ready-made.


QtFigure2

class vtkplotlib.QtFigure2(name='qt vtk figure', parent=None)

This is intended to be used as/for a more sophisticated GUI when one is needed. By providing some common features here, hopefully this can speed up the tedious process of building a GUI. Any contributions here would be very welcome. I want to write this so that each extra feature is optional allowing custom GUIs can be built quickly.

This is still under development. Currently it has:

  1. A screenshot button.
  2. A panel for preset camera views.
  3. An actor table to show / hide / color plots interactively (although it needs some way to group them).

I hope/intend to add:

  1. Suggestions welcome here…

Use this class the same way you would use vpl.QtFigure (see there first.) Each feature is added with a fig.add_***() method.

import vtkplotlib as vpl
import numpy as np

# Create the figure. This as-is looks like just a QtFigure.
fig = vpl.QtFigure2()

# Add each feature you want. Pass arguments to customise each one.
fig.add_screenshot_button(pixels=1080)
fig.add_preset_views()
fig.add_show_plot_table_button()
# Use ``fig.add_all()`` to add all them all.

# You will likely want to dump the above into a function. Or a class
# inheriting from ``vpl.QtFigure2``.

# The usual, plot something super exciting.
vpl.polygon(np.array([[1, 0, 0],
                      [1, 1, 0],
                      [0, 1, 1],
                      [0, 0, 1]]), color="grey")

# Then either ``vpl.show()`` or
fig.show()