Figures¶
Figures, typically abbreviated to fig
, 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 PyQt6.
Overview¶
Some of this is handled automatically. There is a global current working figure.
This can be get and set using gcf()
and 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
vtkplotlib.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')[source]¶
Shows a figure. This is analogous to matplotlib’s show function. After your plot commands call this to open the interactive 3D viewer.
- Parameters
block (bool) – Enter interactive mode, otherwise just open the window, defaults to True.
fig (
figure
orQtFigure
) – The figure to show, defaults tovtkplotlib.gcf()
.
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(name='')¶
Create a new figure. This will automatically be set as the current working figure (returned by
vtkplotlib.gcf()
).- Parameters
name (str) – The window title, defaults to
'vtk figure'
.
gcf¶
- vtkplotlib.gcf(create_new=True)[source]¶
Gets the current working figure.
- Parameters
create_new (bool) – Allow a new one to be created if none exist, defaults to True.
- Returns
The current figure or None.
- Return type
If none exists then a new one gets created by
vtkplotlib.figure()
unlesscreate_new=False
in which caseNone
is returned. This function will always returnNone
ifauto_figure(False)
has been called.
scf¶
screenshot_fig¶
- vtkplotlib.screenshot_fig(magnification=1, pixels=None, trim_pad_width=None, off_screen=False, fig='gcf')[source]¶
Take a screenshot of a figure. The image is returned as an array. To save a screenshot directly to a file, use
save_fig()
.- Parameters
magnification (int or tuple) – Image dimensions relative to the size of the render window.
pixels (int or tuple) – Image
(width, height)
or justheight
in pixels.trim_pad_width (int or float) – Optionally auto crop to contents, this specifies how much space to give it, defaults to no cropping. A positive int for padding in pixels, float from 0.0 - 1.0 for pad width relative to original size
off_screen (bool) – If true, attempt to take the screenshot without opening the figure’s window.
fig (
figure
orQtFigure
) – The figure to screenshot, defaults tovtkplotlib.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.
Changed in version v2.0.0: The shape of the returned array went from
(m, n, 3)
to(m, n, 4)
so as to respect opacity.
save_fig¶
- vtkplotlib.save_fig(path, magnification=1, pixels=None, trim_pad_width=None, off_screen=False, fig='gcf', **imsave_plotargs)[source]¶
Take a screenshot and saves it to a file.
- Parameters
path (str or os.PathLike) – The path, including extension, to save to.
magnification (int or tuple) – Image dimensions relative to the size of the render (window), defaults to 1.
pixels (int or tuple) – Image
(width, height)
or justheight
in pixels.trim_pad_width (int or float) – Padding to leave when cropping to contents, see
screenshot_fig()
.off_screen (bool) – If true, attempt to take the screenshot without opening the figure’s window.
fig (
figure
orQtFigure
) – The figure to save, defaults tovtkplotlib.gcf()
.
This just calls
screenshot_fig()
then passes it tomatplotlib.image.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.
Changed in version v2.0.0: If saving to a format which supports opacity and
fig.background_opacity
has been set to a value less than one, then the saved image will respect the opacity of the background and any translucent plots.
view¶
- vtkplotlib.view(focal_point=None, camera_position=None, camera_direction=None, up_view=None, fig='gcf')[source]¶
Set/get the camera position/orientation.
- Parameters
focal_point (list or tuple or numpy.ndarray) – A point the camera should point directly to.
camera_position (list or tuple or numpy.ndarray) – The point at which the camera is situated.
camera_direction (list or tuple or numpy.ndarray) – The direction in which the camera is pointing.
up_view (list or tuple or numpy.ndarray) – Roll the camera so that the up_view vector is pointing towards the top of the screen.
fig (
figure
orQtFigure
) – The figure to modify, defaults tovtkplotlib.gcf()
.
- Returns
A dictionary containing the new configuration.
- Return type
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 callingprint(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.
If forwards is used then focal_point and camera_position are ignored.
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')[source]¶
Reset the position and zoom of the camera so that all plots are visible.
- Parameters
fig (
figure
orQtFigure
) – The figure to modify, defaults tovtkplotlib.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')[source]¶
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 – Plots that are unimportant and can be cropped out, defaults to
()
.padding (int or float) – Amount of space to leave around the contents, in pixels if integer or relative to
min(fig.render_size)
if float defaults to0.05
.fig (
figure
orQtFigure
) – The figure zoom, defaults tovtkplotlib.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 (usingplot.visible = False
) then restored. 2D plots such as alegend()
orscalar_bar()
which have a fixed position on the render are always excluded.Note
New in v1.3.0.
close¶
- vtkplotlib.close(fig='gcf')[source]¶
Close a figure.
- Parameters
fig (
figure
orQtFigure
) – The figure to close, defaults tovtkplotlib.gcf()
.
If the figure is the current figure then the current figure is reset.
auto_figure¶
- vtkplotlib.auto_figure(auto=None)[source]¶
Enables/disables automatic figure management. If no parameters are provided then it returns the current state.
- Parameters
auto (bool) – Defaults to None.
On by default. Disabling causes
vtkplotlib.gcf()
to always returnNone
. Hence all plot commands will not add to a figure unless told to explicitly using thefig=a_figure
argument. This can be useful for complex scenarios involving multiple figures.
QtFigure¶
- class vtkplotlib.QtFigure(name='qt vtk figure', parent=None)[source]¶
The VTK render window in a
QWidget
. This can be embedded into a GUI the same way all otherQWidget
s are used.- Parameters
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
QWidget
and a vtkplotlib base figure class. Therefore it can be used exactly the same as you would normally use either aQWidget
or avtkplotlib.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 aif 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 aQWidget
from being created without a qapp (which also causes a crash).On
show()
,qapp.exec()
is called automatically iffigure.parent() is None
(unless specified otherwise).If the figure is part of a larger window then
larger_window.show()
must also explicitly show the figure. It won’t begin interactive mode untilexec
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 sys import numpy as np from PyQt6 import QtWidgets import vtkplotlib as vpl 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
QtFigure
s are not reshow-able if the figure has a parent.Note
VTK automatically selects the Qt variant (
PyQt6
,PyQt5
,PySide6
orPySide2
) based on what has already been imported. To use a different Qt variant, import it before importingvtkplotlib
.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)[source]¶
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:
A screenshot button.
A panel for preset camera views.
An actor table to show / hide / color plots interactively (although it needs some way to group them).
A cursor tracker displaying 3D coordinates of the mouse.
I hope/intend to add:
Suggestions welcome here…
Use this class the same way you would use
QtFigure
(see there first.) Each feature is added with afig.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()