vedo
A python module for scientific analysis of 3D objects and point clouds based on VTK and numpy.
Check out the GitHub repository here.
Install and Test
pip install vedo
# Or, install the latest development version:
pip install -U git+https://github.com/marcomusy/vedo.git
Then
import vedo
vedo.Cone().show(axes=1).close()
Command Line Interface
The library includes a Command Line Interface. Type for example in your terminal:
vedo --help
vedo https://vedo.embl.es/examples/data/panther.stl.gz
Pressing h
will then show a number of options to interact with your 3D scene:
============================================================
| Press: i print info about selected object |
| I print the RGB color under the mouse |
| y show the pipeline for this object as a graph |
| <--> use arrows to reduce/increase opacity |
| w/s toggle wireframe/surface style |
| p/P change point size of vertices |
| l toggle edges visibility |
| x toggle mesh visibility |
| X invoke a cutter widget tool |
| 1-3 change mesh color |
| 4 use data array as colors, if present |
| 5-6 change background color(s) |
| 09+- (on keypad) or +/- to cycle axes style |
| k cycle available lighting styles |
| K cycle available shading styles |
| A toggle anti-aliasing |
| D toggle depth-peeling (for transparencies) |
| o/O add/remove light to scene and rotate it |
| n show surface mesh normals |
| a toggle interaction to Actor Mode |
| j toggle interaction to Joystick Mode |
| U toggle perspective/parallel projection |
| r reset camera position |
| R reset camera orientation to orthogonal view |
| . fly camera towards last clicked point |
| C print current camera settings |
| S save a screenshot |
| E/F export 3D scene to numpy file or X3D |
| q return control to python script |
| Esc abort execution and exit python kernel |
|------------------------------------------------------------|
| Mouse: Left-click rotate scene / pick actors |
| Middle-click pan scene |
| Right-click zoom scene in or out |
| Cntrl-click rotate scene |
|------------------------------------------------------------|
| Check out the documentation at: https://vedo.embl.es |
============================================================
Export your 3D scene to file
You can export it to a vedo file, which is actually a normal numpy
file by pressing E
in your 3D scene, the you can interact with it normally using for example the key bindings shown above.
Another way is to export to a template html web page by pressing F
using x3d
backend.
You can also export it programmatically in k3d
from a jupyter notebook.
File format conversion
You can convert on the fly a file (or multiple files) to a different format with
vedo --convert bunny.obj --to ply
Some useful bash aliases
alias vr='vedo --run ' # to search and run examples by name
alias vs='vedo -i --search ' # to search for a string in examples
alias ve='vedo --eog ' # to view single and multiple images
Running in a Jupyter Notebook
To use in jupyter notebooks use the syntax vedo.settings.default_backend= '...'
the supported backend for visualization are:
2d
, the default a static image is generated.vtk
, in this case a normal graphics rendering window will pop up.- k3d use with
pip install k3d
- ipyvtklink (allows interaction with the scene).
- trame
Check for more examples in repository.
Running on Google Colab
Start your notebook with:
import vedo
vedo.settings.init_colab()
Then test it with:
import vedo
print("vedo", vedo.__version__)
sphere = vedo.Sphere().linewidth(1)
plt = vedo.Plotter()
plt += sphere
plt.show(axes=1, viewup='z', zoom=1.5)
Running on a Server
- Install
libgl1-mesa
andxvfb
on your server:
sudo apt install libgl1-mesa-glx libgl1-mesa-dev xvfb
pip install vedo
- Execute on startup:
set -x
export DISPLAY=:99.0
which Xvfb
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
sleep 3
set +x
exec "$@"
- You can save the above code above as
/etc/rc.local
and usechmod +x
to make it executable. It may throw an error during startup. Then test it with, e.g.:
import vedo
plt = vedo.Plotter(offscreen=True, size=(500,500))
plt.show(vedo.Cube()).screenshot('mycube.png').close()
Running in a Docker container
You need to set everything up for offscreen rendering: there are two main ingredients
vedo
should be set to render in offscreen modeguest OS in the docker container needs the relevant libraries installed (in this example we need the Mesa openGL and GLX extensions, and Xvfb to act as a virtual screen. It's maybe also possible to use OSMesa offscreen driver directly, but that requires a custom build of VTK).
Create a
Dockerfile
:
FROM python:3.8-slim-bullseye
RUN apt-get update -y \
&& apt-get install libgl1-mesa-dev libgl1-mesa-glx xvfb -y --no-install-recommends \
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& rm -rf /var/lib/apt/lists/*
RUN pip install vedo && rm -rf $(pip cache dir)
RUN mkdir -p /app/data
WORKDIR /app/
COPY test.py set_xvfb.sh /app/
ENTRYPOINT ["/app/set_xvfb.sh"]
set_xvfb.sh
:
#!/bin/bash
set -x
export DISPLAY=:99.0
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
#sleep 3
set +x
exec "$@"
test.py
:
from vedo import Sphere, Plotter, settings
sph = Sphere(pos=[-5, 0, 0], c="r")
plt = Plotter(interactive=False, offscreen=True)
plt.show(sph)
plt.screenshot("./data/out.png", scale=2).close()
Then you can
$ docker build -t vedo-test-local .
$ docker run --rm -v /some/path/output:/app/data vedo-test-local python test.py
(directory/some/path/output
needs to exist)- There should be an
out.png
file in the output directory.
Generate a single executable file
You can use pyinstaller to generate a single, portable, executable file for different platforms.
Write a file myscript.spec
as:
# -*- mode: python ; coding: utf-8 -*-
#
import os
import sys
sys.setrecursionlimit(sys.getrecursionlimit() * 5)
from vedo import installdir as vedo_installdir
vedo_fontsdir = os.path.join(vedo_installdir, 'fonts')
print('vedo installation is in', vedo_installdir)
print('fonts are in', vedo_fontsdir)
block_cipher = None
added_files = [
(os.path.join('tuning','*'), 'tuning'),
(os.path.join(vedo_fontsdir,'*'), os.path.join('vedo','fonts')),
]
a = Analysis(['myscript.py'],
pathex=[],
binaries=[],
hiddenimports=[
'vtkmodules',
'vtkmodules.all',
'vtkmodules.util',
'vtkmodules.util.numpy_support',
'vtkmodules.qt.QVTKRenderWindowInteractor',
],
datas = added_files,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='myprogramname',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None)
then run it with
pyinstaller myscript.spec
See also an example here.
If you get an error message related to a font which is not shipped with the vedo library you will need to copy the .npz
and .ttf
files to vedo/fonts
(where all the other fonts are) and reinstall vedo.
Then add in your script settings.font_parameters["FONTNAME"]["islocal"] = True
.
Getting help
Check out the Github repository for more information, where you can ask questions and report issues. You are also welcome to post specific questions on the image.sc forum, or simply browse the examples gallery.
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4##### To generate documentation 5# cd ~/Projects/vedo/docs/pdoc 6# ./build_html.py 7############################### 8""" 9.. include:: ../docs/documentation.md 10""" 11 12######################################################################## imports 13import os 14import sys 15import logging 16import numpy as np 17from numpy import sin, cos, sqrt, exp, log, dot, cross # just because handy 18 19from vtkmodules.vtkCommonCore import vtkVersion 20 21################################################# 22from vedo.version import _version as __version__ 23 24from vedo.settings import Settings 25settings = Settings(level=0) 26 27from vedo.colors import * 28from vedo.utils import * 29from vedo.base import * 30from vedo.shapes import * 31from vedo.file_io import * 32from vedo.ugrid import * 33from vedo.assembly import * 34from vedo.pointcloud import * 35from vedo.mesh import * 36from vedo.picture import * 37from vedo.volume import * 38from vedo.tetmesh import * 39from vedo.addons import * 40from vedo.plotter import * 41 42from vedo import applications 43from vedo import interactor_modes 44 45try: 46 import platform 47 sys_platform = platform.system() 48except (ModuleNotFoundError, AttributeError) as e: 49 sys_platform = "" 50 51######################################################################### GLOBALS 52__author__ = "Marco Musy" 53__license__ = "MIT" 54__maintainer__ = "M. Musy" 55__email__ = "marco.musy@embl.es" 56__website__ = "https://github.com/marcomusy/vedo" 57 58 59########################################################################## 60vtk_version = ( 61 int(vtkVersion().GetVTKMajorVersion()), 62 int(vtkVersion().GetVTKMinorVersion()), 63 int(vtkVersion().GetVTKBuildVersion()), 64) 65 66installdir = os.path.dirname(__file__) 67dataurl = "https://vedo.embl.es/examples/data/" 68 69plotter_instance = None 70notebook_plotter = None 71notebook_backend = None 72 73## fonts 74fonts_path = os.path.join(installdir, "fonts/") 75 76# Note: 77# a fatal error occurs when compiling to exe, 78# developer needs to copy the fonts folder to the same location as the exe file 79# to solve this problem 80if not os.path.exists(fonts_path): 81 fonts_path = "fonts/" 82 83fonts = [_f.split(".")[0] for _f in os.listdir(fonts_path) if '.npz' not in _f] 84fonts = list(sorted(fonts)) 85 86# pyplot module to remember last figure format 87last_figure = None 88 89 90######################################################################### LOGGING 91class _LoggingCustomFormatter(logging.Formatter): 92 93 logformat = "[vedo.%(filename)s] %(levelname)s: %(message)s" 94 95 white = "\x1b[1m" 96 grey = "\x1b[2m\x1b[1m\x1b[38;20m" 97 yellow = "\x1b[1m\x1b[33;20m" 98 red = "\x1b[1m\x1b[31;20m" 99 inv_red = "\x1b[7m\x1b[1m\x1b[31;1m" 100 reset = "\x1b[0m" 101 102 FORMATS = { 103 logging.DEBUG: grey + logformat + reset, 104 logging.INFO: white + logformat + reset, 105 logging.WARNING: yellow + logformat + reset, 106 logging.ERROR: red + logformat + reset, 107 logging.CRITICAL: inv_red + logformat + reset, 108 } 109 110 def format(self, record): 111 log_fmt = self.FORMATS.get(record.levelno) 112 formatter = logging.Formatter(log_fmt) 113 return formatter.format(record).replace(".py", "") 114 115logger = logging.getLogger("vedo") 116 117_chsh = logging.StreamHandler() 118_chsh.flush = sys.stdout.flush 119_chsh.setLevel(logging.DEBUG) 120_chsh.setFormatter(_LoggingCustomFormatter()) 121logger.addHandler(_chsh) 122logger.setLevel(logging.INFO) 123 124################################################# silence annoying messages 125# import warnings 126# warnings.simplefilter(action="ignore", category=FutureWarning) 127# try: 128# np.warnings.filterwarnings('ignore', category=np.VisibleDeprecationWarning) 129# except AttributeError: 130# pass