Esempio n. 1
0
 def __init__(self):
     self.wall = vplt.load(
         absfilepath("data/walls.stl")).c("green").alpha(0.2).addShadow(
             z=-0.5)
     self.obs = vplt.load(
         absfilepath("data/obs.stl")).c("red").addShadow(z=-0.5)
     self.lexus = vplt.load(absfilepath("data/lexus_hs.obj")).scale([
         0.01, 0.01, 0.01
     ]).texture(absfilepath("data/lexus_hs_diffuse.jpg")).rotateZ(180)
     self.plotter = vplt.Plotter(bg='white',
                                 axes={
                                     'xyGrid': True,
                                     'zxGrid2': True,
                                     'showTicks': True
                                 })
Esempio n. 2
0
def load_volume_file(filepath, **kwargs):
    """
	Load a volume file (e.g., .nii) and return vtk actor

	:param filepath: path to file
	:param **kwargs: 

	"""
    from vtkplotter import Volume, load
    if not os.path.isfile(filepath): raise FileNotFoundError(filepath)

    if ".x3d" in filepath.lower():
        raise ValueError(
            "brainrender cannot use .x3d data as they are not supported by vtkplotter"
        )

    elif "nii" in filepath.lower() or ".label" in filepath.lower():
        import nibabel as nb
        data = nb.load(filepath)
        d = data.get_fdata()

        act = Volume(d, **kwargs)

    else:
        act = load(filepath, **kwargs)
        if act is None:
            raise ValueError("Could not load {}".format(filepath))

    return act
Esempio n. 3
0
    def _load_cached_neuron(self, neuron_name, params):
        """
		Load a cached neuron's VTK actors

		:param neuron_name: str with neuron name

		"""
        if not neuron_name or neuron_name is None:
            return None

        # Load the yaml file with metadata about previously rendered neurons
        if not neuron_name in self.cache_metadata.keys(
        ):  # the neuron was cached before the metadata was in place
            return None

        # Check if the params match those of the cached neuron
        cached_params = self.cache_metadata[neuron_name]
        diff_params = [v1 for v1,v2 in zip(cached_params.values(), params.values())\
             if v1 != v2]
        if diff_params:
            return None

        # All is good with the params, load cached actors
        if self.render_neurites:
            if self.render_dendrites and self.render_axons:
                allowed_components = ['soma', 'axon', 'dendrites']
                skipped_components = []
            elif not self.render_dendrites and not self.render_axons:
                allowed_components = ['soma']
                skipped_components = ['axon', 'dendrites']
            elif not self.render_dendrites:
                allowed_components = ['soma', 'axon']
                skipped_components = ['dendrites']
            else:
                allowed_components = ['soma', 'dendrites']
                skipped_components = ['axon']
        else:
            allowed_components = ['soma']
            skipped_components = ['axon', 'dendrites']

        neuron_files = [
            f for f in listdir(self.morphology_cache) if neuron_name in f
        ]
        if not neuron_files: return None
        else:
            neuron_actors = {}
            for f in neuron_files:
                component = os.path.split(f)[-1].split(".")[0].split("_")[-1]
                if component not in allowed_components and component not in skipped_components:
                    raise ValueError(
                        "Weird file name, unsure what to do: {}".format(f))
                elif component not in allowed_components and component in skipped_components:
                    continue
                neuron_actors[component] = load(f)
            return neuron_actors
Esempio n. 4
0
    def load_save_neuron(self, neuron_file, neuron=None):
        neuron_name = os.path.split(neuron_file)[-1].split('.swc')[0]

        savepath = os.path.join(self.morphology_cache, neuron_name + '.vtk')

        if neuron is None and os.path.isfile(savepath):
            return load(savepath)
        elif neuron is None:
            return None
        elif neuron is not None:
            neuron.write(savepath)
Esempio n. 5
0
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.setupUi(self)

        self.vtkWidget = QVTKRenderWindowInteractor(self)
        self.vtkLayout.addWidget(self.vtkWidget)

        self.plt = Plotter(qtWidget=self.vtkWidget, axes=1, bg='white')

        self.plt += load(datadir + 'shark.ply').c('cyan')

        self.plt.show()
Esempio n. 6
0
 def __init__(self):
     self.lexus = vplt.load(absfilepath("data/lexus_hs.obj")).scale([
         0.01, 0.01, 0.01
     ]).texture(absfilepath("data/lexus_hs_diffuse.jpg")).rotateZ(180)
     self.plotter = vplt.Plotter(bg='white',
                                 axes={
                                     'xyGrid': True,
                                     'zxGrid2': True,
                                     'showTicks': True
                                 })
     self.goal = vplt.Sphere(pos=(0, 0, 0.2), r=0.2, c="gold", alpha=0.3)
     self.obstacles = []
Esempio n. 7
0
    def download_and_write_mesh(self, acronym, obj_path):
        print(f"Downloading mesh data for {acronym}")
        path = self.structures.loc[self.structures.acronym ==
                                   acronym].obj_path.values[0]
        url = f"{self._url_paths['data']}/{path}"

        # download and write .obj
        mesh_data = request(url).content.decode("utf-8").split("\n")
        with open(obj_path, 'w') as f:
            for md in mesh_data:
                f.write(f"{md}\n")
            f.close()

        # return the vtk actor
        return load(obj_path)
Esempio n. 8
0
def load_mesh_from_file(filepath, *args, **kwargs):
    """	
	Load a a mesh or volume from files like .obj, .stl, ...

	:param filepath: path to file
	:param **kwargs: 

	"""
    if not os.path.isfile(filepath):
        raise FileNotFoundError(filepath)

    try:
        actor = load(filepath, *args, **kwargs)
    except:
        actor = Volume(load_volume_file(filepath, *args, **kwargs))

    return actor
Esempio n. 9
0
    def _get_structure_mesh(self, acronym, **kwargs):
        """
            Get's the mesh for a brainregion, for this atlas it's just for
            getting/making the root mesh

        """
        if acronym != 'root':
            raise ValueError(f'The atlas {self.atlas_name} only has one structure mesh: root. Argument {acronym} is not valid')

        objpath = os.path.join(self.data_folder,'objs_smoothed', 'root2.obj')
        if not os.path.isfile(objpath):
            root = self._make_root(objpath)
        else:
            root = load(objpath)

        root.c(ROOT_COLOR).alpha(ROOT_ALPHA)

        return root
Esempio n. 10
0
def convert(path):
    EXPORT_PATH = os.path.join(os.getcwd(), "output", "stl")

    if not os.path.exists(EXPORT_PATH):
        os.makedirs(EXPORT_PATH)

    start_time = time.time()
    # print("Relative obtained {}".format(path))
    # FILE_NAME = "test.tif"
    # FILE_PATH = os.path.join(INPUT_PATH, FILE_NAME)
    FILE_PATH = os.path.join(os.getcwd(), path)
    # print("Absolute obtained {}".format(FILE_PATH))
    # Set Params
    THRESHOLD = 80

    # Load Data
    # v = load(FILE_PATH) # Volume
    a = load(FILE_PATH, threshold=THRESHOLD)  # isosurfacing on the fly
    print("Loading TIF Stack")
    # vp1 = show(v, a, shape=(1, 2), axes=8, viewup='z')
    # save(a, "output.obj", binary=True)
    full_filename = os.path.split(path)
    only_filename = full_filename[len(full_filename) - 1]

    macro_name = only_filename.split('.')
    output_name = macro_name[0]

    # Save Path
    EXPORT_NAME = output_name + ".stl"
    # macro_name = FILE_NAME.split('.')
    # EXPORT_NAME = macro_name[0] + ".stl"
    EXPORT_FILE = os.path.join(EXPORT_PATH, EXPORT_NAME)
    exp.write(a, EXPORT_FILE, binary=True)
    execution_time = (time.time() - start_time)
    print("Export to .STL completed")
    print("STL Generation Execution time : {0:.2f}s".format(
        round(execution_time, 2)))
    return EXPORT_NAME
'''
Create a set of transparencies which can be passed to method pointColors()
'''
from vtkplotter import load, show, Text

mesh = load('data/beethoven.ply')

# pick y coordinates of vertices and use them as scalars
scals = mesh.coordinates()[:,1]

# define opacities in the range of the scalar,
# at min(scals) alpha is 0.1,
# at max(scals) alpha is 0.9:
alphas = [0.1, 0.1, 0.3, 0.4, 0.9]

mesh.pointColors(scals, alpha=alphas, cmap='copper')
#print(mesh.scalars('pointColors_copper')) # retrieve scalars

show([mesh, Text(__doc__)], axes=9)
A tiff stack is a set of image slices in z. The scalar value
(intensity of white) is used to create an isosurface by fixing a threshold.
In this example the level of white is in the range 0=black -> 150=white
If threshold=None this is set to 1/3 of the scalar range.

- Setting connectivity to True discards the small isolated pieces of
surface and only keeps the largest connected surface.

- Smoothing applies a gaussian smoothing with a standard deviation
which is expressed in units of pixels.

- If the spacing of the tiff stack is uneven in xyz, this can be
fixed by setting scaling factors with scaling=[xfac,yfac,zfac]
'''
print(__doc__)
from vtkplotter import show, load

# Read volume data from a tif file:
f = 'data/embryo.tif'
a0 = load(f, threshold=80, connectivity=1)
a1 = load(f, threshold=80, connectivity=0)
a2 = load(f, smoothing=2)

vp1 = show([a0, a1, a2], shape=(1, 3), axes=0, interactive=1)

# Can also read SLC files
a3 = load('data/embryo.slc', c='g', smoothing=1, connectivity=1)

# newPlotter triggers the instantiation of a new Plotter object
vp2 = show(a3, verbose=0, pos=(300, 300), newPlotter=True)
Esempio n. 13
0
"""
How to share the same color map
across different meshes.
"""
from vtkplotter import load, Text2D, show, datadir


#####################################
man1 = load(datadir+"man.vtk")
scals = man1.points()[:, 2] * 5 + 27  # pick z coordinates [18->34]

man1.pointColors(scals, cmap="jet", vmin=18, vmax=44)

#####################################
man2 = load(datadir+"man.vtk")
scals = man2.points()[:, 2] * 5 + 37  # pick z coordinates [28->44]

man2.pointColors(scals, cmap="jet", vmin=18, vmax=44)

show([[man1, Text2D(__doc__)], man2], N=2, elevation=-40)
Esempio n. 14
0
# surface and only keeps the largest connected surface.
#
# - Smoothing applies a gaussian smoothing with a standard deviation
# which is expressed in units of pixels.
#
# - Backface color is set to violet (bc='v') to spot where the vtk
# reconstruction is (by mistake!) inverting the normals to the surface.
#
# - If the spacing of the tiff stack is uneven in xyz, this can be
# corrected by setting scaling factors with scaling=[xfac,yfac,zfac]

from vtkplotter import Plotter, load

# Read volume data from a tif file:
f = 'data/embryo.tif'

vp = Plotter(shape=(1, 3), axes=0)
a0 = load(f, bc='v', threshold=80, connectivity=1, legend='connectivity=True')
a1 = load(f, bc='v', threshold=80, connectivity=0, legend='connectivity=False')
a2 = load(f, bc='v', smoothing=2, legend='thres=automatic\nsmoothing=2')

vp.show(a0, at=0)
vp.show(a1, at=1)
vp.show(a2, at=2)

# Can also read SLC files
#(NB: vp2.load instead of load. This appends the new actor in vp2.actors):
vp2 = Plotter(pos=(300, 300))
vp2.load('data/embryo.slc', c='g', bc='v', smoothing=1, connectivity=1)
vp2.show()
Esempio n. 15
0
def get_drosophila_mesh_from_region(region, paths,  **kwargs):
    """

    :param region: 
    :param paths: 
    :param **kwargs: 

    """
    if not isinstance(region, (tuple, list)):
        region = [region]
        check = False
    else: check = True

    metadata = get_drosophila_regions_metadata(paths.metadata)

    if "color" in list(kwargs.keys()):
        color = kwargs.pop("color", DEFAULT_STRUCTURE_COLOR)
    elif "c" in list(kwargs.keys()):
        color = kwargs.pop("c", DEFAULT_STRUCTURE_COLOR)

    if "color" in list(kwargs.keys()): del kwargs["color"]
    elif "c" in list(kwargs.keys()): del kwargs["c"]


    meshes = []
    for reg in region:
        if reg.lower() == "root":
            meshname = drosophila_root  ## UNDEFINED!!??
            mesh = load(meshname, c=color, **kwargs) 
            mesh = mesh.smoothLaplacian().subdivide(2)
            meshes.append(mesh)
        else:
            if isinstance(reg, int):
                entry = metadata.loc[metadata.Id == reg]
            elif isinstance(reg, str):
                entry = metadata.loc[metadata['acronym'] == reg]
            else:
                raise ValueError("Unrecognized value for region while trying to get mesh for rat: {}".format(reg))
                
            try:
                eid = entry.Id.values[0]
                if len(eid) == 1:
                    meshname = os.path.join(paths.drosophila_meshes, "domains/AdultBrainDomain000{}.obj".format(eid))
                if len(eid) == 2:
                    meshname = os.path.join(paths.drosophila_meshes, "domains/AdultBrainDomain00{}.obj".format(eid))
                if len(eid) == 3:
                    meshname = os.path.join(paths.drosophila_meshes, "domains/AdultBrainDomain0{}.obj".format(eid))

                if not os.path.isfile(meshname):
                    raise FileExistsError(meshname)

                mesh = load(meshname, c=color, **kwargs) 
                mesh = mesh.smoothLaplacian().subdivide(2)
                meshes.append(mesh)
            except:
                print("Could not load rat region: {}".format(entry["acronym"].values[0]))
                return None
    
    if not check:
        return meshes[0]
    else:
        return meshes
Esempio n. 16
0
"""Identify and fill holes of an input mesh.
Holes are identified by locating boundary edges, linking them
together into loops, and then triangulating the resulting loops.
"""
from vtkplotter import load, show, datadir

a = load(datadir+"bunny.obj").lw(0.1)

# size = approximate limit to the size of the hole to be filled.
b = a.clone().pos(.2,0,0).fillHoles(size=0.1)
b.color("lb").legend("filled mesh")

show(a, b, __doc__, elevation=-70)
Esempio n. 17
0
"""
Split a mesh by connectivity and order the pieces
by increasing area.
"""
print(__doc__)
from vtkplotter import splitByConnectivity, load, show, datadir

em = load(datadir + "embryo.tif", threshold=80)

# return the list of the largest 10 connected meshes:
splitem = splitByConnectivity(em, maxdepth=40)[0:9]

splitem[0].alpha(0.5).phong()  # make the largest part transparent

show([em, splitem], N=2, axes=1)
Esempio n. 18
0
"""
Set a jpeg background image on a vtkRenderingWindow layer,
after the first rendering it can be zoomed to fill the window.
"""
from vtkplotter import Plotter, load, Polygon, Text, datadir

doc = Text(__doc__, c="k", bg="w")

vp = Plotter(N=2,
             size=(400, 800),
             axes=4,
             sharecam=0,
             bg=datadir + "images/tropical.jpg")

a1 = load(datadir + "shapes/flamingo.3ds").rotateX(-90)
a2 = Polygon()

vp.show(a1, doc, at=0)

vp.backgroundRenderer.GetActiveCamera().Zoom(2.5)

vp.show(a2, at=1, interactive=1)
Esempio n. 19
0
"""Insert 2D and 3D scalarbars
in the rendering scene"""
from vtkplotter import load, datadir, show

shape = load(datadir + "lamp.vtk")

ms = []
cmaps = ("jet", "PuOr", "viridis")
for i in range(3):
    s = shape.clone().pos(0, i * 2.2, 0)

    # colorize mesh
    scals = s.points()[:, 2]
    s.pointColors(scals, cmap=cmaps[i])

    ms.append(s)

# add 2D scalar bar to first mesh
ms[0].addScalarBar(title="my scalarbar\nnumber #0")  #2D

# add 3D scalar bars
ms[1].addScalarBar3D(title="scalarbar #1", sy=3)

sc = ms[2].addScalarBar3D(
    pos=(1, 0, -5),
    c="k",
    sy=2.8,  # change y-size
    title="A viridis 3D\nscalarbar to play with",
    titleXOffset=-2,  # offset of labels
    titleSize=1.5)
sc.rotateX(90)  # make it vertical
Esempio n. 20
0
from vtkplotter import load, datadir, show

vol = load(datadir + 'embryo.slc').alpha([0, 0, 1]).c('hot_r')
#vol.addScalarBar(title='Volume', pos=(0.8,0.55))
vol.addScalarBar3D(title='Voxel intensity', c='k')

sl = vol.slicePlane(origin=vol.center(), normal=(0, 1, 1))

sl.pointColors(cmap='viridis') \
  .lighting('ambient') \
  .addScalarBar(title='Slice')

show(
    vol,
    sl,
    "Slice a Volume with an arbitrary plane",
    axes=1,
)
Esempio n. 21
0
"""Set a jpeg background image on a 
vtkRenderingWindow layer, after 
the first rendering it can be 
zoomed to fill the window."""
from vtkplotter import Plotter, load, Polygon, Text, datadir

doc = Text(__doc__, c="k", bg="w")

vp = Plotter(N=2,
             size=(400, 800),
             axes=4,
             sharecam=0,
             bg=datadir + "images/tropical.jpg")

a1 = load(datadir + "flamingo.3ds").rotateX(-90)
a2 = Polygon()

vp.show(a1, doc, at=0)

vp.backgroundRenderer.GetActiveCamera().Zoom(2.5)

vp.show(a2, at=1, interactive=1)
'''
Example on how to specify a color for each 
individual cell or point of an actor's mesh. 
Keyword depthpeeling may improve the rendering of transparent objects.
'''
from vtkplotter import load, Text, show
doc = Text(__doc__, pos=1, c='w')

man = load('data/shapes/man.vtk')

# let the scalar be the z coordinate of the mesh vertices
scals = man.coordinates()[:, 2]

# custom color map with optional opacity (here: 1, 0.2 and 0.8)
mymap = ['darkblue', 'cyan 0.2', (1, 0, 0, 0.8)]

# - or by predefined color numbers:
#mymap = [i for i in range(10)]

# - or by generating a palette betwwen 2 colors:
#from vtkplotter.colors import makePalette
#mymap = makePalette('pink', 'green', N=500, hsv=True)

man.pointColors(scals, cmap=mymap).addScalarBar()

show([man, doc], viewup='z', axes=8, depthpeeling=1)
Esempio n. 23
0
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from vtkplotter import load, Volume, isosurface, show, datadir

maxradius = 0.2
neurons = 30
epochs = 20

image = load(datadir + "embryo.tif").imagedata()

vmin, vmax = image.GetScalarRange()
nx, ny, nz = image.GetDimensions()
print("Scalar Range:", vmin, vmax, "Dimensions", image.GetDimensions())

visdata = np.zeros([nx, ny, nz])
datalist, scalars = [], []
lsx = np.linspace(0, 1, nx, endpoint=False)
lsy = np.linspace(0, 1, ny, endpoint=False)
lsz = np.linspace(0, 1, nz, endpoint=False)
for i, x in enumerate(lsx):
    for j, y in enumerate(lsy):
        for k, z in enumerate(lsz):
            s = image.GetScalarComponentAsDouble(i, j, k, 0)
            s = (s - vmin) / (vmax - vmin)
            visdata[i, j, k] = s
            datalist.append([x, y, z])
            scalars.append(s)
datalist = np.array(datalist)
scalars = np.array(scalars)
Esempio n. 24
0
    fig.suptitle('Array')
    axs[0].imshow(b)
    axs[1].imshow(a)
    axs[2].imshow(c)
    #plt.figure()
    #plt.imshow(b)
    #plt.imshow(a,b,c)
    #imgplot = plt.imshow(c)
    plt.show()

elif "new" in var.lower():
    import vtk
    from PyQt5 import Qt
    import vtkplotter as vtkp
    from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
    vol = vtkp.load(pathout)
    if __name__ == "__main__":
        app = Qt.QApplication(sys.argv)
        window = MainWindow()
        sys.exit(app.exec_())

sys.exit()


class MainWindow(Qt.QMainWindow):
    def __init__(self, parent=None):
        Qt.QMainWindow.__init__(self, parent)

        self.frame = Qt.QFrame()

        self.vl = Qt.QVBoxLayout()
Esempio n. 25
0
# From url: https://github.com/marcomusy/vtkplotter/issues/79

import sys
import vtk
from PyQt5 import Qt
from vtk.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor

from vtkplotter import load, datadir
vol = load(datadir + 'embryo.tif')


class MainWindow(Qt.QMainWindow):
    def __init__(self, parent=None):
        Qt.QMainWindow.__init__(self, parent)

        self.frame = Qt.QFrame()

        self.vl = Qt.QVBoxLayout()
        self.vtkWidget = QVTKRenderWindowInteractor(self.frame)
        self.vl.addWidget(self.vtkWidget)

        self.ren = vtk.vtkRenderer()
        self.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
        self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()

        # Create source
        source = vtk.vtkSphereSource()
        source.SetCenter(0, 0, 0)
        source.SetRadius(1000.0)

        # Create a mapper
Esempio n. 26
0
'''
Identifies and fills holes in input mesh.
Holes are identified by locating boundary edges, linking them
together into loops, and then triangulating the resulting loops.
size: approximate limit to the size of the hole that can be filled.
'''
from vtkplotter import load, show, Text

a = load('data/shapes/bunny.obj')

b = a.clone().fillHoles(size=0.1)
b.color('b').wire(True).legend('filled mesh')

doc = Text(__doc__)

show([a, b, doc], elevation=-70)
Esempio n. 27
0
"""
Extracts the cells where scalar value 
satisfies a threshold criterion.
"""
from vtkplotter import load, Text, show, datadir

doc = Text(__doc__)

man = load(datadir+"shapes/man.vtk")

scals = man.coordinates()[:, 1] + 37  # pick y coords of vertices

man.pointColors(scals, cmap="cool")
man.addScalarBar(title="threshold", horizontal=True)

# make a copy and threshold the mesh
cutman = man.clone().threshold(scals, vmin=36.9, vmax=37.5)

# distribute the actors on 2 renderers
show([[man, doc], cutman], N=2, elevation=-30, axes=0)
Esempio n. 28
0
############################################################
#    Please install pyshtools to run this example
#    Follow instructions at https://shtools.oca.eu/shtools
import pyshtools
from scipy.interpolate import griddata
from vtkplotter import Points, load, mag, Text, show, spher2cart, datadir
print(__doc__)

#############################################################
lmax = 20  # maximum degree of the spherical harm. expansion
N = 30  # number of grid intervals on the unit sphere
rmax = 1.5  # line length
x0 = [0, 0, 0]  # set object at this position
#############################################################

shape = load(datadir + 'pumpkin.vtk').normalize().pos(x0).lineWidth(.1)

show(shape, at=0, N=2, bg='w', axes={'zxGrid': False})

############################################################
# cast rays from the center and find intersections
agrid, pts = [], []
for th in np.linspace(0, np.pi, N, endpoint=False):
    lats = []
    for ph in np.linspace(0, 2 * np.pi, N, endpoint=False):
        p = spher2cart(rmax, th, ph)
        intersections = shape.intersectWithLine([0, 0, 0], p)  #
        if len(intersections):
            value = mag(intersections[0])
            lats.append(value)
            pts.append(intersections[0])
Esempio n. 29
0
'''
Split a mesh by connectivity and order the pieces 
by increasing area.
'''
print(__doc__)
from vtkplotter import splitByConnectivity, load, show

blobs = load('data/embryo.tif')

# search up to the 40th subunit of mesh, return a list
# of length 40, but only keep the largest 10:
sblobs = splitByConnectivity(blobs, maxdepth=40)[0:9]

sblobs[0].alpha(0.05)  # make the largest part transparent

show([blobs, sblobs], N=2, zoom=1.2)
Esempio n. 30
0
"""
Make a icon actor to indicate orientation 
or for comparison and place it in one of 
the 4 corners within the same renderer.
"""
from vtkplotter import Plotter, load, Text, datadir


vp = Plotter(axes=5, bg="white")
# type 5 builds an annotated orientation cube

a270 = load(datadir+"270.vtk", c="blue", bc="v")

vp.show(interactive=0)

vlg = load(datadir+"images/vtk_logo.png", alpha=0.5)
vp.addIcon(vlg, pos=1)

elg = load(datadir+"images/embl_logo.jpg")
vp.addIcon(elg, pos=2, size=0.06)

a1 = load(datadir+"250.vtk", c=2)
a2 = load(datadir+"290.vtk", alpha=0.4)
icon = a1 + a2  # vtkActor + vtkActor = vtkAssembly
vp.addIcon(icon, pos=4)  # 4=bottom-right

vp.add(Text(__doc__, pos=8))

vp.show(a270, interactive=1)