vedo

license Anaconda-Server Badge Ubuntu 23.10 package DOI

A python module for scientific analysis of 3D objects and point clouds based on VTK and numpy.

Check out the GitHub repository and the vedo main page here.

Find at this link the documentation for the older version v2023.4.7.

Install and Test

pip install vedo

# Or, install the latest development version with:
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:

   i     print info about the last clicked object     
   I     print color of the pixel under the mouse     
   Y     show the pipeline for this object as a graph 
   <- -> use arrows to reduce/increase opacity        
   x     toggle mesh visibility                       
   w     toggle wireframe/surface style               
   l     toggle surface edges visibility              
   p/P   hide surface faces and show only points      
   1-3   cycle surface color (2=light, 3=dark)        
   4     cycle color map (press shift-4 to go back)   
   5-6   cycle point-cell arrays (shift to go back)   
   7-8   cycle background and gradient color          
   09+-  cycle axes styles (on keypad, or press +/-)  
   k     cycle available lighting styles              
   K     toggle shading as flat or phong              
   A     toggle anti-aliasing                         
   D     toggle depth-peeling (for transparencies)    
   U     toggle perspective/parallel projection       
   o/O   toggle extra light to scene and rotate it    
   a     toggle interaction to Actor Mode             
   n     toggle surface normals                       
   r     reset camera position                        
   R     reset camera to the closest orthogonal view  
   .     fly camera to the last clicked point         
   C     print the current camera parameters state    
   X     invoke a cutter widget tool                  
   S     save a screenshot of the current scene       
   E/F   export 3D scene to numpy file or X3D         
   q     return control to python script              
   Esc   abort execution and exit python kernel       

Some useful bash aliases

alias vr='vedo --run '      # to search and run examples by name
alias vs='vedo --search '   # to search for a string in examples
alias ve='vedo --eog '      # to view single and multiple images

Tutorials

You are welcome to ask specific questions on the image.sc forum, post a github issue or search the examples gallery for some relevant example.

You can also find online tutorials at:

Export a 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 the x3d backend. You can also export it programmatically in k3d format 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

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 and xvfb 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 use chmod +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 mode
  • guest 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

  1. $ docker build -t vedo-test-local .
  2. $ docker run --rm -v /some/path/output:/app/data vedo-test-local python test.py (directory /some/path/output needs to exist)
  3. 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='my_program_name',
          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.

  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()
 26
 27from vedo.colors import *
 28from vedo.transformations import *
 29from vedo.utils import *
 30from vedo.core import *
 31from vedo.shapes import *
 32from vedo.file_io import *
 33from vedo.assembly import *
 34from vedo.pointcloud import *
 35from vedo.mesh import *
 36from vedo.image import *
 37from vedo.volume import *
 38from vedo.grids import *
 39from vedo.addons import *
 40from vedo.plotter import *
 41from vedo.visual import *
 42
 43from vedo import applications
 44from vedo import interactor_modes
 45
 46try:
 47    import platform
 48    sys_platform = platform.system()
 49except (ModuleNotFoundError, AttributeError) as e:
 50    sys_platform = ""
 51
 52######################################################################### GLOBALS
 53__author__     = "Marco Musy"
 54__license__    = "MIT"
 55__maintainer__ = "M. Musy"
 56__email__      = "marco.musy@embl.es"
 57__website__    = "https://github.com/marcomusy/vedo"
 58
 59
 60##########################################################################
 61vtk_version = (
 62    int(vtkVersion().GetVTKMajorVersion()),
 63    int(vtkVersion().GetVTKMinorVersion()),
 64    int(vtkVersion().GetVTKBuildVersion()),
 65)
 66
 67installdir = os.path.dirname(__file__)
 68dataurl = "https://vedo.embl.es/examples/data/"
 69
 70plotter_instance = None
 71notebook_plotter = None
 72notebook_backend = None
 73
 74## fonts
 75fonts_path = os.path.join(installdir, "fonts/")
 76
 77# Note:
 78# a fatal error occurs when compiling to exe,
 79# developer needs to copy the fonts folder to the same location as the exe file
 80# to solve this problem
 81if not os.path.exists(fonts_path):
 82    fonts_path = "fonts/"
 83
 84fonts = [_f.split(".")[0] for _f in os.listdir(fonts_path) if '.npz' not in _f]
 85fonts = list(sorted(fonts))
 86
 87# pyplot module to remember last figure format
 88last_figure = None
 89
 90
 91######################################################################### LOGGING
 92class _LoggingCustomFormatter(logging.Formatter):
 93
 94    logformat = "[vedo.%(filename)s:%(lineno)d] %(levelname)s: %(message)s"
 95
 96    white = "\x1b[1m"
 97    grey = "\x1b[2m\x1b[1m\x1b[38;20m"
 98    yellow = "\x1b[1m\x1b[33;20m"
 99    red = "\x1b[1m\x1b[31;20m"
100    inv_red = "\x1b[7m\x1b[1m\x1b[31;1m"
101    reset = "\x1b[0m"
102
103    FORMATS = {
104        logging.DEBUG: grey  + logformat + reset,
105        logging.INFO: white + logformat + reset,
106        logging.WARNING: yellow + logformat + reset,
107        logging.ERROR: red + logformat + reset,
108        logging.CRITICAL: inv_red + logformat + reset,
109    }
110
111    def format(self, record):
112        log_fmt = self.FORMATS.get(record.levelno)
113        formatter = logging.Formatter(log_fmt)
114        return formatter.format(record).replace(".py", "")
115
116logger = logging.getLogger("vedo")
117
118_chsh = logging.StreamHandler()
119if sys.stdout is None:
120    sys.stdout = open(os.devnull, "w")
121if sys.stderr is None:
122    sys.stderr = open(os.devnull, "w")
123_chsh.flush = sys.stdout.flush
124_chsh.setLevel(logging.DEBUG)
125_chsh.setFormatter(_LoggingCustomFormatter())
126logger.addHandler(_chsh)
127logger.setLevel(logging.INFO)