Skip to content

vedo.visual

runtime

CommonVisual

Class to manage the visual aspects common to all objects.

Source code in vedo/visual/runtime.py
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
class CommonVisual:
    """Class to manage the visual aspects common to all objects."""

    def __init__(self):
        # print("init CommonVisual", type(self))

        self.properties = None

        self.scalarbar = None
        self.pipeline = None

        self.trail = None
        self.trail_points = []
        self.trail_segment_size = 0
        self.trail_offset = None

        self.shadows = []

        self.axes = None
        self.picked3d = None

        self.rendered_at = set()

        self._lightingnr = 0  # index of the lighting mode changed from CLI
        self._cmap_name = ""  # remember the cmap name for self._keypress
        self._caption = None

        self.actor = None

    def print(self):
        """Print object info."""
        print(self.__str__())
        return self

    @property
    def LUT(self) -> np.ndarray:
        """Return the lookup table of the object as a numpy object."""
        try:
            _lut = self.mapper.GetLookupTable()
            values = []
            for i in range(_lut.GetTable().GetNumberOfTuples()):
                # print("LUT i =", i, "value =", _lut.GetTableValue(i))
                values.append(_lut.GetTableValue(i))
            return np.array(values)
        except AttributeError:
            return np.array([], dtype=float)

    @LUT.setter
    def LUT(self, arr):
        """
        Set the lookup table of the object from a numpy or `vtkLookupTable` object.
        Consider using `cmap()` or `build_lut()` instead as it allows
        to set the range of the LUT and to use a string name for the color map.
        """
        if isinstance(arr, vtki.vtkLookupTable):
            newlut = arr
            self.mapper.SetScalarRange(newlut.GetRange())
        else:
            newlut = vtki.vtkLookupTable()
            newlut.SetNumberOfTableValues(len(arr))
            if len(arr[0]) == 3:
                arr = np.insert(arr, 3, 1, axis=1)
            for i, v in enumerate(arr):
                newlut.SetTableValue(i, v)
            newlut.SetRange(self.mapper.GetScalarRange())
            # print("newlut.GetRange() =", newlut.GetRange())
            # print("self.mapper.GetScalarRange() =", self.mapper.GetScalarRange())
            newlut.Build()
        self.mapper.SetLookupTable(newlut)
        self.mapper.ScalarVisibilityOn()

    def scalar_range(self, vmin=None, vmax=None):
        """Set the range of the scalar value for visualization."""
        if vmin is None and vmax is None:
            return np.array(self.mapper.GetScalarRange())
        if vmax is None:
            vmin, vmax = vmin  # assume it is a list
        self.mapper.SetScalarRange(float(vmin), float(vmax))
        return self

    def add_observer(self, event_name, func, priority=0) -> int:
        """Add a callback function that will be called when an event occurs."""
        event_name = utils.get_vtk_name_event(event_name)
        idd = self.actor.AddObserver(event_name, func, priority)
        return idd

    def invoke_event(self, event_name) -> Self:
        """Invoke an event."""
        event_name = utils.get_vtk_name_event(event_name)
        self.actor.InvokeEvent(event_name)
        return self

    # def abort_event(self, obs_id):
    #     """Abort an event."""
    #     cmd = self.actor.GetCommand(obs_id) # vtkCommand
    #     if cmd:
    #         cmd.AbortFlagOn()
    #     return self

    def show(self, **options) -> vedo.Plotter | None:
        """
        Create on the fly an instance of class `Plotter` or use the last existing one to
        show one single object.

        This method is meant as a shortcut. If more than one object needs to be visualised
        please use the syntax `show(mesh1, mesh2, volume, ..., options)`.

        Returns the `Plotter` class instance.
        """
        return vedo.plotter.show(self, **options)

    def thumbnail(
        self, zoom=1.25, size=(200, 200), bg="white", azimuth=0, elevation=0, axes=False
    ) -> np.ndarray:
        """Build a thumbnail of the object and return it as an array."""
        # speed is about 20Hz for size=[200,200]
        ren = vtki.vtkRenderer()

        actor = self.actor
        if isinstance(self, vedo.UnstructuredGrid):
            geo = vtki.new("GeometryFilter")
            geo.SetInputData(self.dataset)
            geo.Update()
            actor = vedo.Mesh(geo.GetOutput()).cmap("rainbow").actor

        ren.AddActor(actor)
        if axes:
            axes = vedo.addons.Axes(self)
            ren.AddActor(axes.actor)
        ren.ResetCamera()
        cam = ren.GetActiveCamera()
        cam.Zoom(zoom)
        cam.Elevation(elevation)
        cam.Azimuth(azimuth)

        ren_win = vtki.vtkRenderWindow()
        ren_win.SetOffScreenRendering(True)
        ren_win.SetSize(size)
        ren.SetBackground(colors.get_color(bg))
        ren_win.AddRenderer(ren)
        ren.ResetCameraClippingRange()
        ren_win.Render()

        nx, ny = ren_win.GetSize()
        arr = vtki.vtkUnsignedCharArray()
        ren_win.GetRGBACharPixelData(0, 0, nx - 1, ny - 1, 0, arr)
        narr = utils.vtk2numpy(arr).T[:3].T.reshape([ny, nx, 3])
        narr = np.ascontiguousarray(np.flip(narr, axis=0))

        ren.RemoveActor(actor)
        if axes:
            ren.RemoveActor(axes.actor)
        ren_win.Finalize()
        del ren_win
        return narr

    def pickable(self, value=None) -> Self:
        """Set/get the pickability property of an object."""
        if value is None:
            return self.actor.GetPickable()
        self.actor.SetPickable(value)
        return self

    def use_bounds(self, value=True) -> Self:
        """
        Instruct the current camera to either take into account or ignore
        the object bounds when resetting.
        """
        self.actor.SetUseBounds(value)
        return self

    def draggable(self, value=None) -> Self:  # NOT FUNCTIONAL?
        """Set/get the draggability property of an object."""
        if value is None:
            return self.actor.GetDragable()
        self.actor.SetDragable(value)
        return self

    def on(self) -> Self:
        """Switch on  object visibility. Object is not removed."""
        self.actor.VisibilityOn()
        try:
            self.scalarbar.actor.VisibilityOn()
        except AttributeError:
            pass
        try:
            self.trail.actor.VisibilityOn()
        except AttributeError:
            pass
        try:
            for sh in self.shadows:
                sh.actor.VisibilityOn()
        except AttributeError:
            pass
        return self

    def off(self) -> Self:
        """Switch off object visibility. Object is not removed."""
        self.actor.VisibilityOff()
        try:
            self.scalarbar.actor.VisibilityOff()
        except AttributeError:
            pass
        try:
            self.trail.actor.VisibilityOff()
        except AttributeError:
            pass
        try:
            for sh in self.shadows:
                sh.actor.VisibilityOff()
        except AttributeError:
            pass
        return self

    def toggle(self) -> Self:
        """Toggle object visibility on/off."""
        v = self.actor.GetVisibility()
        if v:
            self.off()
        else:
            self.on()
        return self

    def add_scalarbar(
        self,
        title="",
        pos=(),
        size=(80, 400),
        font_size=14,
        title_yoffset=15,
        nlabels=None,
        c=None,
        horizontal=False,
        use_alpha=True,
        label_format=":6.3g",
    ) -> Self:
        """
        Add a 2D scalar bar for the specified object.

        Args:
            title (str):
                scalar bar title
            pos (list):
                position coordinates of the bottom left corner.
                Can also be a pair of (x,y) values in the range [0,1]
                to indicate the position of the bottom left and top right corners.
            size (float,float):
                size of the scalarbar in number of pixels (width, height)
            font_size (float):
                size of font for title and numeric labels
            title_yoffset (float):
                vertical space offset between title and color scalarbar
            nlabels (int):
                number of numeric labels
            c (list):
                color of the scalar bar text
            horizontal (bool):
                lay the scalarbar horizontally
            use_alpha (bool):
                render transparency in the color bar itself
            label_format (str):
                c-style format string for numeric labels

        Examples:
            - [mesh_coloring.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_coloring.py)
            - [scalarbars.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/scalarbars.py)
        """
        plt = vedo.current_plotter()

        if plt and plt.renderer:
            c = (0.9, 0.9, 0.9)
            if np.sum(plt.renderer.GetBackground()) > 1.5:
                c = (0.1, 0.1, 0.1)
            if isinstance(self.scalarbar, vtki.vtkActor):
                plt.renderer.RemoveActor(self.scalarbar)
            elif isinstance(self.scalarbar, vedo.Assembly):
                for a in self.scalarbar.unpack():
                    plt.renderer.RemoveActor(a)
        if c is None:
            c = "gray"

        sb = vedo.addons.ScalarBar(
            self,
            title,
            pos,
            size,
            font_size,
            title_yoffset,
            nlabels,
            c,
            horizontal,
            use_alpha,
            label_format,
        )
        self.scalarbar = sb
        return self

    def add_scalarbar3d(
        self,
        title="",
        pos=None,
        size=(0, 0),
        title_font="",
        title_xoffset=-1.2,
        title_yoffset=0.0,
        title_size=1.5,
        title_rotation=0.0,
        nlabels=9,
        label_font="",
        label_size=1,
        label_offset=0.375,
        label_rotation=0,
        label_format="",
        italic=0,
        c=None,
        draw_box=True,
        above_text=None,
        below_text=None,
        nan_text="NaN",
        categories=None,
    ) -> Self:
        """
        Associate a 3D scalar bar to the object and add it to the scene.
        The new scalarbar object (Assembly) will be accessible as obj.scalarbar

        Args:
            size (list):
                (thickness, length) of scalarbar
            title (str):
                scalar bar title
            title_xoffset (float):
                horizontal space btw title and color scalarbar
            title_yoffset (float):
                vertical space offset
            title_size (float):
                size of title wrt numeric labels
            title_rotation (float):
                title rotation in degrees
            nlabels (int):
                number of numeric labels
            label_font (str):
                font type for labels
            label_size (float):
                label scale factor
            label_offset (float):
                space btw numeric labels and scale
            label_rotation (float):
                label rotation in degrees
            label_format (str):
                label format for floats and integers (e.g. `':.2f'`)
            draw_box (bool):
                draw a box around the colorbar
            categories (list):
                make a categorical scalarbar,
                the input list will have the format `[value, color, alpha, textlabel]`

        Examples:
            - [scalarbars.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/scalarbars.py)
        """
        plt = vedo.current_plotter()
        if plt and c is None:  # automatic black or white
            c = (0.9, 0.9, 0.9)
            if np.sum(vedo.get_color(plt.backgrcol)) > 1.5:
                c = (0.1, 0.1, 0.1)
        if c is None:
            c = (0, 0, 0)
        c = vedo.get_color(c)

        self.scalarbar = vedo.addons.ScalarBar3D(
            self,
            title,
            pos,
            size,
            title_font,
            title_xoffset,
            title_yoffset,
            title_size,
            title_rotation,
            nlabels,
            label_font,
            label_size,
            label_offset,
            label_rotation,
            label_format,
            italic,
            c,
            draw_box,
            above_text,
            below_text,
            nan_text,
            categories,
        )
        return self

    def color(self, col, alpha=None, vmin=None, vmax=None):
        """
        Assign a color or a set of colors along the range of the scalar value.
        A single constant color can also be assigned.
        Any matplotlib color map name is also accepted, e.g. `volume.color('jet')`.

        E.g.: say that your cells scalar runs from -3 to 6,
        and you want -3 to show red and 1.5 violet and 6 green, then just set:

        `volume.color(['red', 'violet', 'green'])`

        You can also assign a specific color to a aspecific value with eg.:

        `volume.color([(0,'red'), (0.5,'violet'), (1,'green')])`

        Args:
            alpha (list):
                use a list to specify transparencies along the scalar range
            vmin (float):
                force the min of the scalar range to be this value
            vmax (float):
                force the max of the scalar range to be this value
        """
        # supersedes method in Points, Mesh

        if col is None:
            return self

        if vmin is None:
            vmin, _ = self.dataset.GetScalarRange()
        if vmax is None:
            _, vmax = self.dataset.GetScalarRange()
        ctf = self.properties.GetRGBTransferFunction()
        ctf.RemoveAllPoints()

        if utils.is_sequence(col):
            if utils.is_sequence(col[0]) and len(col[0]) == 2:
                # user passing [(value1, color1), ...]
                for x, ci in col:
                    r, g, b = colors.get_color(ci)
                    ctf.AddRGBPoint(x, r, g, b)
                    # colors.printc('color at', round(x, 1),
                    #               'set to', colors.get_color_name((r, g, b)), bold=0)
            else:
                # user passing [color1, color2, ..]
                for i, ci in enumerate(col):
                    r, g, b = colors.get_color(ci)
                    x = vmin + (vmax - vmin) * i / (len(col) - 1)
                    ctf.AddRGBPoint(x, r, g, b)
        elif isinstance(col, str):
            if col in colors.colors.keys() or col in colors.color_nicks.keys():
                r, g, b = colors.get_color(col)
                ctf.AddRGBPoint(vmin, r, g, b)  # constant color
                ctf.AddRGBPoint(vmax, r, g, b)
            else:  # assume it's a colormap
                for x in np.linspace(vmin, vmax, num=64, endpoint=True):
                    r, g, b = colors.color_map(x, name=col, vmin=vmin, vmax=vmax)
                    ctf.AddRGBPoint(x, r, g, b)
        elif isinstance(col, int):
            r, g, b = colors.get_color(col)
            ctf.AddRGBPoint(vmin, r, g, b)  # constant color
            ctf.AddRGBPoint(vmax, r, g, b)
        elif isinstance(col, vtki.vtkLookupTable):
            alpha = []
            nt = col.GetNumberOfTableValues()
            for i in range(nt):
                r, g, b, a = col.GetTableValue(i)
                x = vmin + (vmax - vmin) * i / (nt - 1)
                ctf.AddRGBPoint(x, r, g, b)
                alpha.append(a)
        elif hasattr(col, "resampled"):  # cover the case of LinearSegmentedColormap
            N = col.N
            cs = np.array([col(i / N) for i in range(N)])
            alpha = cs[:, 3].copy()
            for i, v in enumerate(cs):
                r, g, b, _ = v
                x = vmin + (vmax - vmin) * i / (N - 1)
                ctf.AddRGBPoint(x, r, g, b)
        elif hasattr(col, "to_rgba"):  # col is a matplotlib colormap
            alpha = []
            for i in range(256):
                r, g, b, a = col(i / 255)
                x = vmin + (vmax - vmin) * i / 255
                ctf.AddRGBPoint(x, r, g, b)
                alpha.append(a)
        else:
            vedo.logger.warning(f"in color() unknown input type {type(col)}")

        if alpha is not None:
            self.alpha(alpha, vmin=vmin, vmax=vmax)
        return self

    def alpha(self, alpha, vmin=None, vmax=None) -> Self:
        """
        Assign a set of tranparencies along the range of the scalar value.
        A single constant value can also be assigned.

        E.g.: say `alpha=(0.0, 0.3, 0.9, 1)` and the scalar range goes from -10 to 150.
        Then all cells with a value close to -10 will be completely transparent, cells at 1/4
        of the range will get an alpha equal to 0.3 and voxels with value close to 150
        will be completely opaque.

        As a second option one can set explicit (x, alpha_x) pairs to define the transfer function.

        E.g.: say `alpha=[(-5, 0), (35, 0.4) (123,0.9)]` and the scalar range goes from -10 to 150.
        Then all cells below -5 will be completely transparent, cells with a scalar value of 35
        will get an opacity of 40% and above 123 alpha is set to 90%.
        """
        if isinstance(self, (vedo.Assembly, vedo.Group)):
            for actor in self:
                try:
                    actor.alpha(alpha)
                except Exception:
                    continue
            return self

        if vmin is None:
            vmin, _ = self.dataset.GetScalarRange()
        if vmax is None:
            _, vmax = self.dataset.GetScalarRange()
        otf = self.properties.GetScalarOpacity()
        otf.RemoveAllPoints()

        if utils.is_sequence(alpha):
            alpha = np.array(alpha)
            if (
                len(alpha.shape) == 1
            ):  # user passing a flat list e.g. (0.0, 0.3, 0.9, 1)
                for i, al in enumerate(alpha):
                    xalpha = vmin + (vmax - vmin) * i / (len(alpha) - 1)
                    # Create transfer mapping scalar value to opacity
                    otf.AddPoint(xalpha, al)
                    # print("alpha at", round(xalpha, 1), "\tset to", al)
            elif len(alpha.shape) == 2:  # user passing [(x0,alpha0), ...]
                otf.AddPoint(vmin, alpha[0][1])
                for xalpha, al in alpha:
                    # Create transfer mapping scalar value to opacity
                    otf.AddPoint(xalpha, al)
                otf.AddPoint(vmax, alpha[-1][1])

        else:
            otf.AddPoint(vmin, alpha)  # constant alpha
            otf.AddPoint(vmax, alpha)

        return self

LUT property writable

Return the lookup table of the object as a numpy object.

add_observer(event_name, func, priority=0)

Add a callback function that will be called when an event occurs.

Source code in vedo/visual/runtime.py
120
121
122
123
124
def add_observer(self, event_name, func, priority=0) -> int:
    """Add a callback function that will be called when an event occurs."""
    event_name = utils.get_vtk_name_event(event_name)
    idd = self.actor.AddObserver(event_name, func, priority)
    return idd

add_scalarbar(title='', pos=(), size=(80, 400), font_size=14, title_yoffset=15, nlabels=None, c=None, horizontal=False, use_alpha=True, label_format=':6.3g')

Add a 2D scalar bar for the specified object.

Parameters:

Name Type Description Default
title str

scalar bar title

''
pos list

position coordinates of the bottom left corner. Can also be a pair of (x,y) values in the range [0,1] to indicate the position of the bottom left and top right corners.

()
size (float, float)

size of the scalarbar in number of pixels (width, height)

(80, 400)
font_size float

size of font for title and numeric labels

14
title_yoffset float

vertical space offset between title and color scalarbar

15
nlabels int

number of numeric labels

None
c list

color of the scalar bar text

None
horizontal bool

lay the scalarbar horizontally

False
use_alpha bool

render transparency in the color bar itself

True
label_format str

c-style format string for numeric labels

':6.3g'

Examples:

Source code in vedo/visual/runtime.py
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
def add_scalarbar(
    self,
    title="",
    pos=(),
    size=(80, 400),
    font_size=14,
    title_yoffset=15,
    nlabels=None,
    c=None,
    horizontal=False,
    use_alpha=True,
    label_format=":6.3g",
) -> Self:
    """
    Add a 2D scalar bar for the specified object.

    Args:
        title (str):
            scalar bar title
        pos (list):
            position coordinates of the bottom left corner.
            Can also be a pair of (x,y) values in the range [0,1]
            to indicate the position of the bottom left and top right corners.
        size (float,float):
            size of the scalarbar in number of pixels (width, height)
        font_size (float):
            size of font for title and numeric labels
        title_yoffset (float):
            vertical space offset between title and color scalarbar
        nlabels (int):
            number of numeric labels
        c (list):
            color of the scalar bar text
        horizontal (bool):
            lay the scalarbar horizontally
        use_alpha (bool):
            render transparency in the color bar itself
        label_format (str):
            c-style format string for numeric labels

    Examples:
        - [mesh_coloring.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_coloring.py)
        - [scalarbars.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/scalarbars.py)
    """
    plt = vedo.current_plotter()

    if plt and plt.renderer:
        c = (0.9, 0.9, 0.9)
        if np.sum(plt.renderer.GetBackground()) > 1.5:
            c = (0.1, 0.1, 0.1)
        if isinstance(self.scalarbar, vtki.vtkActor):
            plt.renderer.RemoveActor(self.scalarbar)
        elif isinstance(self.scalarbar, vedo.Assembly):
            for a in self.scalarbar.unpack():
                plt.renderer.RemoveActor(a)
    if c is None:
        c = "gray"

    sb = vedo.addons.ScalarBar(
        self,
        title,
        pos,
        size,
        font_size,
        title_yoffset,
        nlabels,
        c,
        horizontal,
        use_alpha,
        label_format,
    )
    self.scalarbar = sb
    return self

add_scalarbar3d(title='', pos=None, size=(0, 0), title_font='', title_xoffset=-1.2, title_yoffset=0.0, title_size=1.5, title_rotation=0.0, nlabels=9, label_font='', label_size=1, label_offset=0.375, label_rotation=0, label_format='', italic=0, c=None, draw_box=True, above_text=None, below_text=None, nan_text='NaN', categories=None)

Associate a 3D scalar bar to the object and add it to the scene. The new scalarbar object (Assembly) will be accessible as obj.scalarbar

Parameters:

Name Type Description Default
size list

(thickness, length) of scalarbar

(0, 0)
title str

scalar bar title

''
title_xoffset float

horizontal space btw title and color scalarbar

-1.2
title_yoffset float

vertical space offset

0.0
title_size float

size of title wrt numeric labels

1.5
title_rotation float

title rotation in degrees

0.0
nlabels int

number of numeric labels

9
label_font str

font type for labels

''
label_size float

label scale factor

1
label_offset float

space btw numeric labels and scale

0.375
label_rotation float

label rotation in degrees

0
label_format str

label format for floats and integers (e.g. ':.2f')

''
draw_box bool

draw a box around the colorbar

True
categories list

make a categorical scalarbar, the input list will have the format [value, color, alpha, textlabel]

None

Examples:

Source code in vedo/visual/runtime.py
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
def add_scalarbar3d(
    self,
    title="",
    pos=None,
    size=(0, 0),
    title_font="",
    title_xoffset=-1.2,
    title_yoffset=0.0,
    title_size=1.5,
    title_rotation=0.0,
    nlabels=9,
    label_font="",
    label_size=1,
    label_offset=0.375,
    label_rotation=0,
    label_format="",
    italic=0,
    c=None,
    draw_box=True,
    above_text=None,
    below_text=None,
    nan_text="NaN",
    categories=None,
) -> Self:
    """
    Associate a 3D scalar bar to the object and add it to the scene.
    The new scalarbar object (Assembly) will be accessible as obj.scalarbar

    Args:
        size (list):
            (thickness, length) of scalarbar
        title (str):
            scalar bar title
        title_xoffset (float):
            horizontal space btw title and color scalarbar
        title_yoffset (float):
            vertical space offset
        title_size (float):
            size of title wrt numeric labels
        title_rotation (float):
            title rotation in degrees
        nlabels (int):
            number of numeric labels
        label_font (str):
            font type for labels
        label_size (float):
            label scale factor
        label_offset (float):
            space btw numeric labels and scale
        label_rotation (float):
            label rotation in degrees
        label_format (str):
            label format for floats and integers (e.g. `':.2f'`)
        draw_box (bool):
            draw a box around the colorbar
        categories (list):
            make a categorical scalarbar,
            the input list will have the format `[value, color, alpha, textlabel]`

    Examples:
        - [scalarbars.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/scalarbars.py)
    """
    plt = vedo.current_plotter()
    if plt and c is None:  # automatic black or white
        c = (0.9, 0.9, 0.9)
        if np.sum(vedo.get_color(plt.backgrcol)) > 1.5:
            c = (0.1, 0.1, 0.1)
    if c is None:
        c = (0, 0, 0)
    c = vedo.get_color(c)

    self.scalarbar = vedo.addons.ScalarBar3D(
        self,
        title,
        pos,
        size,
        title_font,
        title_xoffset,
        title_yoffset,
        title_size,
        title_rotation,
        nlabels,
        label_font,
        label_size,
        label_offset,
        label_rotation,
        label_format,
        italic,
        c,
        draw_box,
        above_text,
        below_text,
        nan_text,
        categories,
    )
    return self

alpha(alpha, vmin=None, vmax=None)

Assign a set of tranparencies along the range of the scalar value. A single constant value can also be assigned.

E.g.: say alpha=(0.0, 0.3, 0.9, 1) and the scalar range goes from -10 to 150. Then all cells with a value close to -10 will be completely transparent, cells at 1/4 of the range will get an alpha equal to 0.3 and voxels with value close to 150 will be completely opaque.

As a second option one can set explicit (x, alpha_x) pairs to define the transfer function.

E.g.: say alpha=[(-5, 0), (35, 0.4) (123,0.9)] and the scalar range goes from -10 to 150. Then all cells below -5 will be completely transparent, cells with a scalar value of 35 will get an opacity of 40% and above 123 alpha is set to 90%.

Source code in vedo/visual/runtime.py
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
def alpha(self, alpha, vmin=None, vmax=None) -> Self:
    """
    Assign a set of tranparencies along the range of the scalar value.
    A single constant value can also be assigned.

    E.g.: say `alpha=(0.0, 0.3, 0.9, 1)` and the scalar range goes from -10 to 150.
    Then all cells with a value close to -10 will be completely transparent, cells at 1/4
    of the range will get an alpha equal to 0.3 and voxels with value close to 150
    will be completely opaque.

    As a second option one can set explicit (x, alpha_x) pairs to define the transfer function.

    E.g.: say `alpha=[(-5, 0), (35, 0.4) (123,0.9)]` and the scalar range goes from -10 to 150.
    Then all cells below -5 will be completely transparent, cells with a scalar value of 35
    will get an opacity of 40% and above 123 alpha is set to 90%.
    """
    if isinstance(self, (vedo.Assembly, vedo.Group)):
        for actor in self:
            try:
                actor.alpha(alpha)
            except Exception:
                continue
        return self

    if vmin is None:
        vmin, _ = self.dataset.GetScalarRange()
    if vmax is None:
        _, vmax = self.dataset.GetScalarRange()
    otf = self.properties.GetScalarOpacity()
    otf.RemoveAllPoints()

    if utils.is_sequence(alpha):
        alpha = np.array(alpha)
        if (
            len(alpha.shape) == 1
        ):  # user passing a flat list e.g. (0.0, 0.3, 0.9, 1)
            for i, al in enumerate(alpha):
                xalpha = vmin + (vmax - vmin) * i / (len(alpha) - 1)
                # Create transfer mapping scalar value to opacity
                otf.AddPoint(xalpha, al)
                # print("alpha at", round(xalpha, 1), "\tset to", al)
        elif len(alpha.shape) == 2:  # user passing [(x0,alpha0), ...]
            otf.AddPoint(vmin, alpha[0][1])
            for xalpha, al in alpha:
                # Create transfer mapping scalar value to opacity
                otf.AddPoint(xalpha, al)
            otf.AddPoint(vmax, alpha[-1][1])

    else:
        otf.AddPoint(vmin, alpha)  # constant alpha
        otf.AddPoint(vmax, alpha)

    return self

color(col, alpha=None, vmin=None, vmax=None)

Assign a color or a set of colors along the range of the scalar value. A single constant color can also be assigned. Any matplotlib color map name is also accepted, e.g. volume.color('jet').

E.g.: say that your cells scalar runs from -3 to 6, and you want -3 to show red and 1.5 violet and 6 green, then just set:

volume.color(['red', 'violet', 'green'])

You can also assign a specific color to a aspecific value with eg.:

volume.color([(0,'red'), (0.5,'violet'), (1,'green')])

Parameters:

Name Type Description Default
alpha list

use a list to specify transparencies along the scalar range

None
vmin float

force the min of the scalar range to be this value

None
vmax float

force the max of the scalar range to be this value

None
Source code in vedo/visual/runtime.py
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
def color(self, col, alpha=None, vmin=None, vmax=None):
    """
    Assign a color or a set of colors along the range of the scalar value.
    A single constant color can also be assigned.
    Any matplotlib color map name is also accepted, e.g. `volume.color('jet')`.

    E.g.: say that your cells scalar runs from -3 to 6,
    and you want -3 to show red and 1.5 violet and 6 green, then just set:

    `volume.color(['red', 'violet', 'green'])`

    You can also assign a specific color to a aspecific value with eg.:

    `volume.color([(0,'red'), (0.5,'violet'), (1,'green')])`

    Args:
        alpha (list):
            use a list to specify transparencies along the scalar range
        vmin (float):
            force the min of the scalar range to be this value
        vmax (float):
            force the max of the scalar range to be this value
    """
    # supersedes method in Points, Mesh

    if col is None:
        return self

    if vmin is None:
        vmin, _ = self.dataset.GetScalarRange()
    if vmax is None:
        _, vmax = self.dataset.GetScalarRange()
    ctf = self.properties.GetRGBTransferFunction()
    ctf.RemoveAllPoints()

    if utils.is_sequence(col):
        if utils.is_sequence(col[0]) and len(col[0]) == 2:
            # user passing [(value1, color1), ...]
            for x, ci in col:
                r, g, b = colors.get_color(ci)
                ctf.AddRGBPoint(x, r, g, b)
                # colors.printc('color at', round(x, 1),
                #               'set to', colors.get_color_name((r, g, b)), bold=0)
        else:
            # user passing [color1, color2, ..]
            for i, ci in enumerate(col):
                r, g, b = colors.get_color(ci)
                x = vmin + (vmax - vmin) * i / (len(col) - 1)
                ctf.AddRGBPoint(x, r, g, b)
    elif isinstance(col, str):
        if col in colors.colors.keys() or col in colors.color_nicks.keys():
            r, g, b = colors.get_color(col)
            ctf.AddRGBPoint(vmin, r, g, b)  # constant color
            ctf.AddRGBPoint(vmax, r, g, b)
        else:  # assume it's a colormap
            for x in np.linspace(vmin, vmax, num=64, endpoint=True):
                r, g, b = colors.color_map(x, name=col, vmin=vmin, vmax=vmax)
                ctf.AddRGBPoint(x, r, g, b)
    elif isinstance(col, int):
        r, g, b = colors.get_color(col)
        ctf.AddRGBPoint(vmin, r, g, b)  # constant color
        ctf.AddRGBPoint(vmax, r, g, b)
    elif isinstance(col, vtki.vtkLookupTable):
        alpha = []
        nt = col.GetNumberOfTableValues()
        for i in range(nt):
            r, g, b, a = col.GetTableValue(i)
            x = vmin + (vmax - vmin) * i / (nt - 1)
            ctf.AddRGBPoint(x, r, g, b)
            alpha.append(a)
    elif hasattr(col, "resampled"):  # cover the case of LinearSegmentedColormap
        N = col.N
        cs = np.array([col(i / N) for i in range(N)])
        alpha = cs[:, 3].copy()
        for i, v in enumerate(cs):
            r, g, b, _ = v
            x = vmin + (vmax - vmin) * i / (N - 1)
            ctf.AddRGBPoint(x, r, g, b)
    elif hasattr(col, "to_rgba"):  # col is a matplotlib colormap
        alpha = []
        for i in range(256):
            r, g, b, a = col(i / 255)
            x = vmin + (vmax - vmin) * i / 255
            ctf.AddRGBPoint(x, r, g, b)
            alpha.append(a)
    else:
        vedo.logger.warning(f"in color() unknown input type {type(col)}")

    if alpha is not None:
        self.alpha(alpha, vmin=vmin, vmax=vmax)
    return self

draggable(value=None)

Set/get the draggability property of an object.

Source code in vedo/visual/runtime.py
211
212
213
214
215
216
def draggable(self, value=None) -> Self:  # NOT FUNCTIONAL?
    """Set/get the draggability property of an object."""
    if value is None:
        return self.actor.GetDragable()
    self.actor.SetDragable(value)
    return self

invoke_event(event_name)

Invoke an event.

Source code in vedo/visual/runtime.py
126
127
128
129
130
def invoke_event(self, event_name) -> Self:
    """Invoke an event."""
    event_name = utils.get_vtk_name_event(event_name)
    self.actor.InvokeEvent(event_name)
    return self

off()

Switch off object visibility. Object is not removed.

Source code in vedo/visual/runtime.py
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
def off(self) -> Self:
    """Switch off object visibility. Object is not removed."""
    self.actor.VisibilityOff()
    try:
        self.scalarbar.actor.VisibilityOff()
    except AttributeError:
        pass
    try:
        self.trail.actor.VisibilityOff()
    except AttributeError:
        pass
    try:
        for sh in self.shadows:
            sh.actor.VisibilityOff()
    except AttributeError:
        pass
    return self

on()

Switch on object visibility. Object is not removed.

Source code in vedo/visual/runtime.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
def on(self) -> Self:
    """Switch on  object visibility. Object is not removed."""
    self.actor.VisibilityOn()
    try:
        self.scalarbar.actor.VisibilityOn()
    except AttributeError:
        pass
    try:
        self.trail.actor.VisibilityOn()
    except AttributeError:
        pass
    try:
        for sh in self.shadows:
            sh.actor.VisibilityOn()
    except AttributeError:
        pass
    return self

pickable(value=None)

Set/get the pickability property of an object.

Source code in vedo/visual/runtime.py
196
197
198
199
200
201
def pickable(self, value=None) -> Self:
    """Set/get the pickability property of an object."""
    if value is None:
        return self.actor.GetPickable()
    self.actor.SetPickable(value)
    return self

print()

Print object info.

Source code in vedo/visual/runtime.py
69
70
71
72
def print(self):
    """Print object info."""
    print(self.__str__())
    return self

scalar_range(vmin=None, vmax=None)

Set the range of the scalar value for visualization.

Source code in vedo/visual/runtime.py
111
112
113
114
115
116
117
118
def scalar_range(self, vmin=None, vmax=None):
    """Set the range of the scalar value for visualization."""
    if vmin is None and vmax is None:
        return np.array(self.mapper.GetScalarRange())
    if vmax is None:
        vmin, vmax = vmin  # assume it is a list
    self.mapper.SetScalarRange(float(vmin), float(vmax))
    return self

show(**options)

Create on the fly an instance of class Plotter or use the last existing one to show one single object.

This method is meant as a shortcut. If more than one object needs to be visualised please use the syntax show(mesh1, mesh2, volume, ..., options).

Returns the Plotter class instance.

Source code in vedo/visual/runtime.py
139
140
141
142
143
144
145
146
147
148
149
def show(self, **options) -> vedo.Plotter | None:
    """
    Create on the fly an instance of class `Plotter` or use the last existing one to
    show one single object.

    This method is meant as a shortcut. If more than one object needs to be visualised
    please use the syntax `show(mesh1, mesh2, volume, ..., options)`.

    Returns the `Plotter` class instance.
    """
    return vedo.plotter.show(self, **options)

thumbnail(zoom=1.25, size=(200, 200), bg='white', azimuth=0, elevation=0, axes=False)

Build a thumbnail of the object and return it as an array.

Source code in vedo/visual/runtime.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
def thumbnail(
    self, zoom=1.25, size=(200, 200), bg="white", azimuth=0, elevation=0, axes=False
) -> np.ndarray:
    """Build a thumbnail of the object and return it as an array."""
    # speed is about 20Hz for size=[200,200]
    ren = vtki.vtkRenderer()

    actor = self.actor
    if isinstance(self, vedo.UnstructuredGrid):
        geo = vtki.new("GeometryFilter")
        geo.SetInputData(self.dataset)
        geo.Update()
        actor = vedo.Mesh(geo.GetOutput()).cmap("rainbow").actor

    ren.AddActor(actor)
    if axes:
        axes = vedo.addons.Axes(self)
        ren.AddActor(axes.actor)
    ren.ResetCamera()
    cam = ren.GetActiveCamera()
    cam.Zoom(zoom)
    cam.Elevation(elevation)
    cam.Azimuth(azimuth)

    ren_win = vtki.vtkRenderWindow()
    ren_win.SetOffScreenRendering(True)
    ren_win.SetSize(size)
    ren.SetBackground(colors.get_color(bg))
    ren_win.AddRenderer(ren)
    ren.ResetCameraClippingRange()
    ren_win.Render()

    nx, ny = ren_win.GetSize()
    arr = vtki.vtkUnsignedCharArray()
    ren_win.GetRGBACharPixelData(0, 0, nx - 1, ny - 1, 0, arr)
    narr = utils.vtk2numpy(arr).T[:3].T.reshape([ny, nx, 3])
    narr = np.ascontiguousarray(np.flip(narr, axis=0))

    ren.RemoveActor(actor)
    if axes:
        ren.RemoveActor(axes.actor)
    ren_win.Finalize()
    del ren_win
    return narr

toggle()

Toggle object visibility on/off.

Source code in vedo/visual/runtime.py
254
255
256
257
258
259
260
261
def toggle(self) -> Self:
    """Toggle object visibility on/off."""
    v = self.actor.GetVisibility()
    if v:
        self.off()
    else:
        self.on()
    return self

use_bounds(value=True)

Instruct the current camera to either take into account or ignore the object bounds when resetting.

Source code in vedo/visual/runtime.py
203
204
205
206
207
208
209
def use_bounds(self, value=True) -> Self:
    """
    Instruct the current camera to either take into account or ignore
    the object bounds when resetting.
    """
    self.actor.SetUseBounds(value)
    return self

PointsVisual

Bases: PointsVisualEffectsMixin, PointsVisualAnnotationsMixin, CommonVisual

Class to manage the visual aspects of a Points object.

Source code in vedo/visual/runtime.py
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
class PointsVisual(
    PointsVisualEffectsMixin, PointsVisualAnnotationsMixin, CommonVisual
):
    """Class to manage the visual aspects of a ``Points`` object."""

    def __init__(self):
        # print("init PointsVisual")
        super().__init__()
        self.properties_backface = None
        self._cmap_name = None
        self.trail = None
        self.trail_offset = 0
        self.trail_points = []
        self._caption = None

    def clone2d(self, size=None, offset=(), scale=None):
        """
        Turn a 3D `Points` or `Mesh` into a flat 2D actor.
        Returns a `Actor2D`.

        Args:
            size (float):
                size as scaling factor for the 2D actor
            offset (list):
                2D (x, y) position of the actor in the range [-1, 1]
            scale (float):
                Deprecated. Use `size` instead.

        Examples:
            - [clone2d.py](https://github.com/marcomusy/vedo/tree/master/examples/extras/clone2d.py)

                ![](https://vedo.embl.es/images/extras/clone2d.png)
        """
        # assembly.Assembly.clone2d() superseeds this method
        if scale is not None:
            vedo.logger.warning("clone2d(): use keyword size not scale")
            size = scale

        if size is None:
            # work out a reasonable scale
            msiz = self.diagonal_size()
            plt = vedo.current_plotter()
            if plt and plt.window:
                sz = plt.window.GetSize()
                dsiz = utils.mag(sz)
                size = dsiz / msiz / 10
            else:
                size = 350 / msiz

        tp = vtki.new("TransformPolyDataFilter")
        transform = vtki.vtkTransform()
        transform.Scale(size, size, size)
        if len(offset) == 0:
            offset = self.pos()
        transform.Translate(-utils.make3d(offset))
        tp.SetTransform(transform)
        tp.SetInputData(self.dataset)
        tp.Update()
        poly = tp.GetOutput()

        cm = self.mapper.GetColorMode()
        lut = self.mapper.GetLookupTable()
        sv = self.mapper.GetScalarVisibility()
        use_lut = self.mapper.GetUseLookupTableScalarRange()
        vrange = self.mapper.GetScalarRange()
        sm = self.mapper.GetScalarMode()

        act2d = Actor2D(poly)
        act2d.mapper.SetColorMode(cm)
        act2d.mapper.SetLookupTable(lut)
        act2d.mapper.SetScalarVisibility(sv)
        act2d.mapper.SetUseLookupTableScalarRange(use_lut)
        act2d.mapper.SetScalarRange(vrange)
        act2d.mapper.SetScalarMode(sm)

        act2d.GetPositionCoordinate().SetCoordinateSystem(4)
        act2d.properties.SetColor(self.color())
        act2d.properties.SetOpacity(self.alpha())
        act2d.properties.SetLineWidth(self.properties.GetLineWidth())
        act2d.properties.SetPointSize(self.properties.GetPointSize())
        act2d.properties.SetDisplayLocation(0)  # 0 = back, 1 = front
        act2d.PickableOff()
        return act2d

    ##################################################
    def copy_properties_from(self, source, deep=True, actor_related=True) -> Self:
        """
        Copy properties from another ``Points`` object.
        """
        pr = vtki.vtkProperty()
        try:
            sp = source.properties
            mp = source.mapper
            sa = source.actor
        except AttributeError:
            sp = source.GetProperty()
            mp = source.GetMapper()
            sa = source

        if deep:
            pr.DeepCopy(sp)
        else:
            pr.ShallowCopy(sp)
        self.actor.SetProperty(pr)
        self.properties = pr

        if self.actor.GetBackfaceProperty():
            bfpr = vtki.vtkProperty()
            bfpr.DeepCopy(sa.GetBackfaceProperty())
            self.actor.SetBackfaceProperty(bfpr)
            self.properties_backface = bfpr

        if not actor_related:
            return self

        # mapper related:
        self.mapper.SetScalarVisibility(mp.GetScalarVisibility())
        self.mapper.SetScalarMode(mp.GetScalarMode())
        self.mapper.SetScalarRange(mp.GetScalarRange())
        self.mapper.SetLookupTable(mp.GetLookupTable())
        self.mapper.SetColorMode(mp.GetColorMode())
        self.mapper.SetInterpolateScalarsBeforeMapping(
            mp.GetInterpolateScalarsBeforeMapping()
        )
        self.mapper.SetUseLookupTableScalarRange(mp.GetUseLookupTableScalarRange())

        self.actor.SetPickable(sa.GetPickable())
        self.actor.SetDragable(sa.GetDragable())
        self.actor.SetTexture(sa.GetTexture())
        self.actor.SetVisibility(sa.GetVisibility())
        return self

    def color(self, c=False, alpha=None) -> np.ndarray | Self:
        """
        Set/get mesh's color. Call with no argument to get the current color.
        Pass `None` to disable a fixed color and use the active scalar array instead.
        Same as `mesh.c()`.
        """
        if c is False:
            return np.array(self.properties.GetColor())
        if c is None:
            self.mapper.ScalarVisibilityOn()
            return self
        self.mapper.ScalarVisibilityOff()
        cc = colors.get_color(c)
        self.properties.SetColor(cc)
        if self.trail:
            self.trail.properties.SetColor(cc)
        if alpha is not None:
            self.alpha(alpha)
        return self

    def c(self, color=False, alpha=None) -> np.ndarray | Self:
        """
        Shortcut for `color()`.
        If None is passed as input, will use colors from current active scalars.
        """
        return self.color(color, alpha)

    def alpha(self, opacity=None) -> float | Self:
        """Set/get mesh's transparency. Same as `mesh.opacity()`."""
        if opacity is None:
            return self.properties.GetOpacity()

        self.properties.SetOpacity(opacity)
        bfp = self.actor.GetBackfaceProperty()
        if bfp:
            if opacity < 1:
                self.properties_backface = bfp
                self.actor.SetBackfaceProperty(None)
            else:
                self.actor.SetBackfaceProperty(self.properties_backface)
        return self

    def lut_color_at(self, value) -> np.ndarray:
        """
        Return the color and alpha in the lookup table at given value.
        """
        lut = self.mapper.GetLookupTable()
        if not lut:
            return None
        rgb = [0, 0, 0]
        lut.GetColor(value, rgb)
        alpha = lut.GetOpacity(value)
        return np.array(rgb + [alpha])

    def opacity(self, alpha=None) -> float | Self:
        """Set/get mesh's transparency. Same as `mesh.alpha()`."""
        return self.alpha(alpha)

    def force_opaque(self, value=True) -> Self:
        """Force the Mesh, Line or point cloud to be treated as opaque"""
        ## force the opaque pass, fixes picking in vtk9
        # but causes other bad troubles with lines..
        self.actor.SetForceOpaque(value)
        return self

    def force_translucent(self, value=True) -> Self:
        """Force the Mesh, Line or point cloud to be treated as translucent"""
        self.actor.SetForceTranslucent(value)
        return self

    def point_size(self, value=None) -> int | Self:
        """Set/get mesh's point size of vertices. Same as `mesh.ps()`"""
        if value is None:
            return self.properties.GetPointSize()
            # self.properties.SetRepresentationToSurface()
        else:
            self.properties.SetRepresentationToPoints()
            self.properties.SetPointSize(value)
        return self

    def ps(self, pointsize=None) -> int | Self:
        """Set/get mesh's point size of vertices. Same as `mesh.point_size()`"""
        return self.point_size(pointsize)

    def render_points_as_spheres(self, value=True) -> Self:
        """Make points look spheric or else make them look as squares."""
        self.properties.SetRenderPointsAsSpheres(value)
        return self

    def lighting(
        self,
        style="",
        ambient=None,
        diffuse=None,
        specular=None,
        specular_power=None,
        specular_color=None,
        metallicity=None,
        roughness=None,
    ) -> Self:
        """
        Set the ambient, diffuse, specular and specular_power lighting constants.

        Args:
            style (str):
                preset style, options are `[metallic, plastic, shiny, glossy, ambient, off]`
            ambient (float):
                ambient fraction of emission [0-1]
            diffuse (float):
                emission of diffused light in fraction [0-1]
            specular (float):
                fraction of reflected light [0-1]
            specular_power (float):
                precision of reflection [1-100]
            specular_color (color):
                color that is being reflected by the surface

        <img src="https://upload.wikimedia.org/wikipedia/commons/6/6b/Phong_components_version_4.png" alt="", width=700px>

        Examples:
            - [specular.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/specular.py)
        """
        pr = self.properties

        if style:
            if style != "off":
                pr.LightingOn()

            if style == "off":
                pr.SetInterpolationToFlat()
                pr.LightingOff()
                return self  ##############

            if hasattr(pr, "GetColor"):  # could be Volume
                c = pr.GetColor()
            else:
                c = (1, 1, 0.99)
            mpr = self.mapper
            if hasattr(mpr, "GetScalarVisibility") and mpr.GetScalarVisibility():
                c = (1, 1, 0.99)
            if style == "metallic":
                pars = [0.1, 0.3, 1.0, 10, c]
            elif style == "plastic":
                pars = [0.3, 0.4, 0.3, 5, c]
            elif style == "shiny":
                pars = [0.2, 0.6, 0.8, 50, c]
            elif style == "glossy":
                pars = [0.1, 0.7, 0.9, 90, (1, 1, 0.99)]
            elif style == "ambient":
                pars = [0.8, 0.1, 0.0, 1, (1, 1, 1)]
            elif style == "default":
                pars = [0.1, 1.0, 0.05, 5, c]
            else:
                vedo.logger.error("in lighting(): Available styles are")
                vedo.logger.error(
                    "[default, metallic, plastic, shiny, glossy, ambient, off]"
                )
                raise RuntimeError()
            pr.SetAmbient(pars[0])
            pr.SetDiffuse(pars[1])
            pr.SetSpecular(pars[2])
            pr.SetSpecularPower(pars[3])
            if hasattr(pr, "GetColor"):
                pr.SetSpecularColor(pars[4])

        if ambient is not None:
            pr.SetAmbient(ambient)
        if diffuse is not None:
            pr.SetDiffuse(diffuse)
        if specular is not None:
            pr.SetSpecular(specular)
        if specular_power is not None:
            pr.SetSpecularPower(specular_power)
        if specular_color is not None:
            pr.SetSpecularColor(colors.get_color(specular_color))
        if metallicity is not None:
            pr.SetInterpolationToPBR()
            pr.SetMetallic(metallicity)
        if roughness is not None:
            pr.SetInterpolationToPBR()
            pr.SetRoughness(roughness)

        return self

    def point_blurring(self, r=1, alpha=1.0, emissive=False) -> Self:
        """Set point blurring.
        Apply a gaussian convolution filter to the points.
        In this case the radius `r` is in absolute units of the mesh coordinates.
        With emissive set, the halo of point becomes light-emissive.
        """
        self.properties.SetRepresentationToPoints()
        if emissive:
            self.mapper.SetEmissive(bool(emissive))
        self.mapper.SetScaleFactor(r * 1.4142)

        # https://kitware.github.io/vtk-examples/site/Python/Meshes/PointInterpolator/
        if alpha < 1:
            self.mapper.SetSplatShaderCode(
                "//VTK::Color::Impl\n"
                "float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
                "if (dist > 1.0) {\n"
                "   discard;\n"
                "} else {\n"
                f"  float scale = ({alpha} - dist);\n"
                "   ambientColor *= scale;\n"
                "   diffuseColor *= scale;\n"
                "}\n"
            )
            alpha = 1

        self.mapper.Modified()
        self.actor.Modified()
        self.properties.SetOpacity(alpha)
        self.actor.SetMapper(self.mapper)
        return self

    @property
    def cellcolors(self):
        """
        Colorize each cell (face) of a mesh by passing
        a 1-to-1 list of colors in format [R,G,B] or [R,G,B,A].
        Colors levels and opacities must be in the range [0,255].

        A single constant color can also be passed as string or RGBA.

        A cell array named "CellsRGBA" is automatically created.

        Examples:
            - [color_mesh_cells1.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/color_mesh_cells1.py)
            - [color_mesh_cells2.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/color_mesh_cells2.py)

            ![](https://vedo.embl.es/images/basic/colorMeshCells.png)
        """
        if "CellsRGBA" not in self.celldata.keys():
            lut = self.mapper.GetLookupTable()
            vscalars = self.dataset.GetCellData().GetScalars()
            if vscalars is None or lut is None:
                arr = np.zeros([self.ncells, 4], dtype=np.uint8)
                col = np.array(self.properties.GetColor())
                col = np.round(col * 255).astype(np.uint8)
                alf = self.properties.GetOpacity()
                alf = np.round(alf * 255).astype(np.uint8)
                arr[:, (0, 1, 2)] = col
                arr[:, 3] = alf
            else:
                cols = lut.MapScalars(vscalars, 0, 0)
                arr = utils.vtk2numpy(cols)
            self.celldata["CellsRGBA"] = arr
        self.celldata.select("CellsRGBA")
        return self.celldata["CellsRGBA"]

    @cellcolors.setter
    def cellcolors(self, value):
        if isinstance(value, str):
            c = colors.get_color(value)
            value = np.array([*c, 1]) * 255
            value = np.round(value)

        value = np.asarray(value)
        n = self.ncells

        if value.ndim == 1:
            value = np.repeat([value], n, axis=0)

        if value.shape[1] == 3:
            z = np.zeros((n, 1), dtype=np.uint8)
            value = np.append(value, z + 255, axis=1)

        assert n == value.shape[0]

        self.celldata["CellsRGBA"] = value.astype(np.uint8)
        # self.mapper.SetColorModeToDirectScalars() # done in select()
        self.celldata.select("CellsRGBA")

    @property
    def pointcolors(self):
        """
        Colorize each point (or vertex of a mesh) by passing
        a 1-to-1 list of colors in format [R,G,B] or [R,G,B,A].
        Colors levels and opacities must be in the range [0,255].

        A single constant color can also be passed as string or RGBA.

        A point array named "PointsRGBA" is automatically created.
        """
        if "PointsRGBA" not in self.pointdata.keys():
            lut = self.mapper.GetLookupTable()
            vscalars = self.dataset.GetPointData().GetScalars()
            if vscalars is None or lut is None:
                # create a constant array
                arr = np.zeros([self.npoints, 4], dtype=np.uint8)
                col = np.array(self.properties.GetColor())
                col = np.round(col * 255).astype(np.uint8)
                alf = self.properties.GetOpacity()
                alf = np.round(alf * 255).astype(np.uint8)
                arr[:, (0, 1, 2)] = col
                arr[:, 3] = alf
            else:
                cols = lut.MapScalars(vscalars, 0, 0)
                arr = utils.vtk2numpy(cols)
            self.pointdata["PointsRGBA"] = arr
        self.pointdata.select("PointsRGBA")
        return self.pointdata["PointsRGBA"]

    @pointcolors.setter
    def pointcolors(self, value):
        if isinstance(value, str):
            c = colors.get_color(value)
            value = np.array([*c, 1]) * 255
            value = np.round(value)

        value = np.asarray(value)
        n = self.npoints

        if value.ndim == 1:
            value = np.repeat([value], n, axis=0)

        if value.shape[1] == 3:
            z = np.zeros((n, 1), dtype=np.uint8)
            value = np.append(value, z + 255, axis=1)

        assert n == value.shape[0]

        self.pointdata["PointsRGBA"] = value.astype(np.uint8)
        self.mapper.SetColorModeToDirectScalars()  # also done in select()
        self.pointdata.select("PointsRGBA")

    #####################################################################################
    def cmap(
        self,
        input_cmap,
        input_array=None,
        on="",
        name="Scalars",
        vmin=None,
        vmax=None,
        n_colors=256,
        alpha=1.0,
        logscale=False,
    ) -> Self:
        """
        Set individual point/cell colors by providing a list of scalar values and a color map.

        Args:
            input_cmap (str, list, vtkLookupTable, matplotlib.colors.LinearSegmentedColormap):
                color map scheme to transform a real number into a color.
            input_array (str, list, vtkArray):
                can be the string name of an existing array, a new array or a `vtkArray`.
            on (str):
                either 'points' or 'cells' or blank (automatic).
                Apply the color map to data which is defined on either points or cells.
            name (str):
                give a name to the provided array (if input_array is an array)
            vmin (float):
                clip scalars to this minimum value
            vmax (float):
                clip scalars to this maximum value
            n_colors (int):
                number of distinct colors to be used in colormap table.
            alpha (float, list):
                Mesh transparency. Can be a `list` of values one for each vertex.
            logscale (bool):
                Use logscale

        Examples:
            - [mesh_coloring.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_coloring.py)
            - [mesh_alphas.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_alphas.py)
            - [mesh_custom.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_custom.py)
            - (and many others)

                ![](https://vedo.embl.es/images/basic/mesh_custom.png)
        """
        self._cmap_name = input_cmap

        if on == "":
            try:
                on = self.mapper.GetScalarModeAsString().replace("Use", "")
                if on not in ["PointData", "CellData"]:  # can be "Default"
                    on = "points"
                    self.mapper.SetScalarModeToUsePointData()
            except AttributeError:
                on = "points"
        elif on == "Default":
            on = "points"
            self.mapper.SetScalarModeToUsePointData()

        if input_array is None:
            if not self.pointdata.keys() and self.celldata.keys():
                on = "cells"
                if not self.dataset.GetCellData().GetScalars():
                    input_array = 0  # pick the first at hand

        if "point" in on.lower():
            data = self.dataset.GetPointData()
            n = self.dataset.GetNumberOfPoints()
        elif "cell" in on.lower():
            data = self.dataset.GetCellData()
            n = self.dataset.GetNumberOfCells()
        else:
            vedo.logger.error(
                f"Must specify in cmap(on=...) to either 'cells' or 'points', not {on}"
            )
            raise RuntimeError()

        if input_array is None:  # if None try to fetch the active scalars
            arr = data.GetScalars()
            if not arr:
                vedo.logger.error(
                    f"in cmap(), cannot find any {on} active array ...skip coloring."
                )
                return self

            if not arr.GetName():  # sometimes arrays dont have a name..
                arr.SetName(name)

        elif isinstance(input_array, str):  # if a string is passed
            arr = data.GetArray(input_array)
            if not arr:
                vedo.logger.error(
                    f"in cmap(), cannot find {on} array {input_array} ...skip coloring."
                )
                return self

        elif isinstance(input_array, int):  # if an int is passed
            if input_array < data.GetNumberOfArrays():
                arr = data.GetArray(input_array)
            else:
                vedo.logger.error(
                    f"in cmap(), cannot find {on} array at {input_array} ...skip coloring."
                )
                return self

        elif utils.is_sequence(input_array):  # if a numpy array is passed
            npts = len(input_array)
            if npts != n:
                vedo.logger.error(
                    f"in cmap(), nr. of input {on} scalars {npts} != {n} ...skip coloring."
                )
                return self
            arr = utils.numpy2vtk(input_array, name=name, dtype=float)
            data.AddArray(arr)
            data.Modified()

        elif isinstance(input_array, vtki.vtkArray):  # if a vtkArray is passed
            arr = input_array
            data.AddArray(arr)
            data.Modified()

        else:
            vedo.logger.error(
                f"in cmap(), cannot understand input type {type(input_array)}"
            )
            raise RuntimeError()

        # Now we have array "arr"
        array_name = arr.GetName()

        if arr.GetNumberOfComponents() == 1:
            if vmin is None:
                vmin = arr.GetRange()[0]
            if vmax is None:
                vmax = arr.GetRange()[1]
        else:
            if vmin is None or vmax is None:
                vn = utils.mag(utils.vtk2numpy(arr))
            if vmin is None:
                vmin = vn.min()
            if vmax is None:
                vmax = vn.max()

        # interpolate alphas if they are not constant
        if not utils.is_sequence(alpha):
            alpha = [alpha] * n_colors
        else:
            v = np.linspace(0, 1, n_colors, endpoint=True)
            xp = np.linspace(0, 1, len(alpha), endpoint=True)
            alpha = np.interp(v, xp, alpha)

        ########################### build the look-up table
        if isinstance(input_cmap, vtki.vtkLookupTable):  # vtkLookupTable
            lut = input_cmap

        elif utils.is_sequence(input_cmap):  # manual sequence of colors
            lut = vtki.vtkLookupTable()
            if logscale:
                lut.SetScaleToLog10()
            lut.SetRange(vmin, vmax)
            ncols = len(input_cmap)
            lut.SetNumberOfTableValues(ncols)

            for i, c in enumerate(input_cmap):
                r, g, b = colors.get_color(c)
                lut.SetTableValue(i, r, g, b, alpha[i])
            lut.Build()

        else:
            # assume string cmap name OR matplotlib.colors.LinearSegmentedColormap
            lut = vtki.vtkLookupTable()
            if logscale:
                lut.SetScaleToLog10()
            lut.SetVectorModeToMagnitude()
            lut.SetRange(vmin, vmax)
            lut.SetNumberOfTableValues(n_colors)
            mycols = colors.color_map(range(n_colors), input_cmap, 0, n_colors)
            for i, c in enumerate(mycols):
                r, g, b = c
                lut.SetTableValue(i, r, g, b, alpha[i])
            lut.Build()

        # TEST NEW WAY
        self.mapper.SetLookupTable(lut)
        self.mapper.ScalarVisibilityOn()
        self.mapper.SetColorModeToMapScalars()
        self.mapper.SetScalarRange(lut.GetRange())
        if "point" in on.lower():
            self.pointdata.select(array_name)
        else:
            self.celldata.select(array_name)
        return self

cellcolors property writable

Colorize each cell (face) of a mesh by passing a 1-to-1 list of colors in format [R,G,B] or [R,G,B,A]. Colors levels and opacities must be in the range [0,255].

A single constant color can also be passed as string or RGBA.

A cell array named "CellsRGBA" is automatically created.

Examples:

pointcolors property writable

Colorize each point (or vertex of a mesh) by passing a 1-to-1 list of colors in format [R,G,B] or [R,G,B,A]. Colors levels and opacities must be in the range [0,255].

A single constant color can also be passed as string or RGBA.

A point array named "PointsRGBA" is automatically created.

alpha(opacity=None)

Set/get mesh's transparency. Same as mesh.opacity().

Source code in vedo/visual/runtime.py
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
def alpha(self, opacity=None) -> float | Self:
    """Set/get mesh's transparency. Same as `mesh.opacity()`."""
    if opacity is None:
        return self.properties.GetOpacity()

    self.properties.SetOpacity(opacity)
    bfp = self.actor.GetBackfaceProperty()
    if bfp:
        if opacity < 1:
            self.properties_backface = bfp
            self.actor.SetBackfaceProperty(None)
        else:
            self.actor.SetBackfaceProperty(self.properties_backface)
    return self

c(color=False, alpha=None)

Shortcut for color(). If None is passed as input, will use colors from current active scalars.

Source code in vedo/visual/runtime.py
1040
1041
1042
1043
1044
1045
def c(self, color=False, alpha=None) -> np.ndarray | Self:
    """
    Shortcut for `color()`.
    If None is passed as input, will use colors from current active scalars.
    """
    return self.color(color, alpha)

clone2d(size=None, offset=(), scale=None)

Turn a 3D Points or Mesh into a flat 2D actor. Returns a Actor2D.

Parameters:

Name Type Description Default
size float

size as scaling factor for the 2D actor

None
offset list

2D (x, y) position of the actor in the range [-1, 1]

()
scale float

Deprecated. Use size instead.

None

Examples:

Source code in vedo/visual/runtime.py
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
def clone2d(self, size=None, offset=(), scale=None):
    """
    Turn a 3D `Points` or `Mesh` into a flat 2D actor.
    Returns a `Actor2D`.

    Args:
        size (float):
            size as scaling factor for the 2D actor
        offset (list):
            2D (x, y) position of the actor in the range [-1, 1]
        scale (float):
            Deprecated. Use `size` instead.

    Examples:
        - [clone2d.py](https://github.com/marcomusy/vedo/tree/master/examples/extras/clone2d.py)

            ![](https://vedo.embl.es/images/extras/clone2d.png)
    """
    # assembly.Assembly.clone2d() superseeds this method
    if scale is not None:
        vedo.logger.warning("clone2d(): use keyword size not scale")
        size = scale

    if size is None:
        # work out a reasonable scale
        msiz = self.diagonal_size()
        plt = vedo.current_plotter()
        if plt and plt.window:
            sz = plt.window.GetSize()
            dsiz = utils.mag(sz)
            size = dsiz / msiz / 10
        else:
            size = 350 / msiz

    tp = vtki.new("TransformPolyDataFilter")
    transform = vtki.vtkTransform()
    transform.Scale(size, size, size)
    if len(offset) == 0:
        offset = self.pos()
    transform.Translate(-utils.make3d(offset))
    tp.SetTransform(transform)
    tp.SetInputData(self.dataset)
    tp.Update()
    poly = tp.GetOutput()

    cm = self.mapper.GetColorMode()
    lut = self.mapper.GetLookupTable()
    sv = self.mapper.GetScalarVisibility()
    use_lut = self.mapper.GetUseLookupTableScalarRange()
    vrange = self.mapper.GetScalarRange()
    sm = self.mapper.GetScalarMode()

    act2d = Actor2D(poly)
    act2d.mapper.SetColorMode(cm)
    act2d.mapper.SetLookupTable(lut)
    act2d.mapper.SetScalarVisibility(sv)
    act2d.mapper.SetUseLookupTableScalarRange(use_lut)
    act2d.mapper.SetScalarRange(vrange)
    act2d.mapper.SetScalarMode(sm)

    act2d.GetPositionCoordinate().SetCoordinateSystem(4)
    act2d.properties.SetColor(self.color())
    act2d.properties.SetOpacity(self.alpha())
    act2d.properties.SetLineWidth(self.properties.GetLineWidth())
    act2d.properties.SetPointSize(self.properties.GetPointSize())
    act2d.properties.SetDisplayLocation(0)  # 0 = back, 1 = front
    act2d.PickableOff()
    return act2d

cmap(input_cmap, input_array=None, on='', name='Scalars', vmin=None, vmax=None, n_colors=256, alpha=1.0, logscale=False)

Set individual point/cell colors by providing a list of scalar values and a color map.

Parameters:

Name Type Description Default
input_cmap (str, list, vtkLookupTable, LinearSegmentedColormap)

color map scheme to transform a real number into a color.

required
input_array (str, list, vtkArray)

can be the string name of an existing array, a new array or a vtkArray.

None
on str

either 'points' or 'cells' or blank (automatic). Apply the color map to data which is defined on either points or cells.

''
name str

give a name to the provided array (if input_array is an array)

'Scalars'
vmin float

clip scalars to this minimum value

None
vmax float

clip scalars to this maximum value

None
n_colors int

number of distinct colors to be used in colormap table.

256
alpha (float, list)

Mesh transparency. Can be a list of values one for each vertex.

1.0
logscale bool

Use logscale

False

Examples:

Source code in vedo/visual/runtime.py
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
def cmap(
    self,
    input_cmap,
    input_array=None,
    on="",
    name="Scalars",
    vmin=None,
    vmax=None,
    n_colors=256,
    alpha=1.0,
    logscale=False,
) -> Self:
    """
    Set individual point/cell colors by providing a list of scalar values and a color map.

    Args:
        input_cmap (str, list, vtkLookupTable, matplotlib.colors.LinearSegmentedColormap):
            color map scheme to transform a real number into a color.
        input_array (str, list, vtkArray):
            can be the string name of an existing array, a new array or a `vtkArray`.
        on (str):
            either 'points' or 'cells' or blank (automatic).
            Apply the color map to data which is defined on either points or cells.
        name (str):
            give a name to the provided array (if input_array is an array)
        vmin (float):
            clip scalars to this minimum value
        vmax (float):
            clip scalars to this maximum value
        n_colors (int):
            number of distinct colors to be used in colormap table.
        alpha (float, list):
            Mesh transparency. Can be a `list` of values one for each vertex.
        logscale (bool):
            Use logscale

    Examples:
        - [mesh_coloring.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_coloring.py)
        - [mesh_alphas.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_alphas.py)
        - [mesh_custom.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/mesh_custom.py)
        - (and many others)

            ![](https://vedo.embl.es/images/basic/mesh_custom.png)
    """
    self._cmap_name = input_cmap

    if on == "":
        try:
            on = self.mapper.GetScalarModeAsString().replace("Use", "")
            if on not in ["PointData", "CellData"]:  # can be "Default"
                on = "points"
                self.mapper.SetScalarModeToUsePointData()
        except AttributeError:
            on = "points"
    elif on == "Default":
        on = "points"
        self.mapper.SetScalarModeToUsePointData()

    if input_array is None:
        if not self.pointdata.keys() and self.celldata.keys():
            on = "cells"
            if not self.dataset.GetCellData().GetScalars():
                input_array = 0  # pick the first at hand

    if "point" in on.lower():
        data = self.dataset.GetPointData()
        n = self.dataset.GetNumberOfPoints()
    elif "cell" in on.lower():
        data = self.dataset.GetCellData()
        n = self.dataset.GetNumberOfCells()
    else:
        vedo.logger.error(
            f"Must specify in cmap(on=...) to either 'cells' or 'points', not {on}"
        )
        raise RuntimeError()

    if input_array is None:  # if None try to fetch the active scalars
        arr = data.GetScalars()
        if not arr:
            vedo.logger.error(
                f"in cmap(), cannot find any {on} active array ...skip coloring."
            )
            return self

        if not arr.GetName():  # sometimes arrays dont have a name..
            arr.SetName(name)

    elif isinstance(input_array, str):  # if a string is passed
        arr = data.GetArray(input_array)
        if not arr:
            vedo.logger.error(
                f"in cmap(), cannot find {on} array {input_array} ...skip coloring."
            )
            return self

    elif isinstance(input_array, int):  # if an int is passed
        if input_array < data.GetNumberOfArrays():
            arr = data.GetArray(input_array)
        else:
            vedo.logger.error(
                f"in cmap(), cannot find {on} array at {input_array} ...skip coloring."
            )
            return self

    elif utils.is_sequence(input_array):  # if a numpy array is passed
        npts = len(input_array)
        if npts != n:
            vedo.logger.error(
                f"in cmap(), nr. of input {on} scalars {npts} != {n} ...skip coloring."
            )
            return self
        arr = utils.numpy2vtk(input_array, name=name, dtype=float)
        data.AddArray(arr)
        data.Modified()

    elif isinstance(input_array, vtki.vtkArray):  # if a vtkArray is passed
        arr = input_array
        data.AddArray(arr)
        data.Modified()

    else:
        vedo.logger.error(
            f"in cmap(), cannot understand input type {type(input_array)}"
        )
        raise RuntimeError()

    # Now we have array "arr"
    array_name = arr.GetName()

    if arr.GetNumberOfComponents() == 1:
        if vmin is None:
            vmin = arr.GetRange()[0]
        if vmax is None:
            vmax = arr.GetRange()[1]
    else:
        if vmin is None or vmax is None:
            vn = utils.mag(utils.vtk2numpy(arr))
        if vmin is None:
            vmin = vn.min()
        if vmax is None:
            vmax = vn.max()

    # interpolate alphas if they are not constant
    if not utils.is_sequence(alpha):
        alpha = [alpha] * n_colors
    else:
        v = np.linspace(0, 1, n_colors, endpoint=True)
        xp = np.linspace(0, 1, len(alpha), endpoint=True)
        alpha = np.interp(v, xp, alpha)

    ########################### build the look-up table
    if isinstance(input_cmap, vtki.vtkLookupTable):  # vtkLookupTable
        lut = input_cmap

    elif utils.is_sequence(input_cmap):  # manual sequence of colors
        lut = vtki.vtkLookupTable()
        if logscale:
            lut.SetScaleToLog10()
        lut.SetRange(vmin, vmax)
        ncols = len(input_cmap)
        lut.SetNumberOfTableValues(ncols)

        for i, c in enumerate(input_cmap):
            r, g, b = colors.get_color(c)
            lut.SetTableValue(i, r, g, b, alpha[i])
        lut.Build()

    else:
        # assume string cmap name OR matplotlib.colors.LinearSegmentedColormap
        lut = vtki.vtkLookupTable()
        if logscale:
            lut.SetScaleToLog10()
        lut.SetVectorModeToMagnitude()
        lut.SetRange(vmin, vmax)
        lut.SetNumberOfTableValues(n_colors)
        mycols = colors.color_map(range(n_colors), input_cmap, 0, n_colors)
        for i, c in enumerate(mycols):
            r, g, b = c
            lut.SetTableValue(i, r, g, b, alpha[i])
        lut.Build()

    # TEST NEW WAY
    self.mapper.SetLookupTable(lut)
    self.mapper.ScalarVisibilityOn()
    self.mapper.SetColorModeToMapScalars()
    self.mapper.SetScalarRange(lut.GetRange())
    if "point" in on.lower():
        self.pointdata.select(array_name)
    else:
        self.celldata.select(array_name)
    return self

color(c=False, alpha=None)

Set/get mesh's color. Call with no argument to get the current color. Pass None to disable a fixed color and use the active scalar array instead. Same as mesh.c().

Source code in vedo/visual/runtime.py
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
def color(self, c=False, alpha=None) -> np.ndarray | Self:
    """
    Set/get mesh's color. Call with no argument to get the current color.
    Pass `None` to disable a fixed color and use the active scalar array instead.
    Same as `mesh.c()`.
    """
    if c is False:
        return np.array(self.properties.GetColor())
    if c is None:
        self.mapper.ScalarVisibilityOn()
        return self
    self.mapper.ScalarVisibilityOff()
    cc = colors.get_color(c)
    self.properties.SetColor(cc)
    if self.trail:
        self.trail.properties.SetColor(cc)
    if alpha is not None:
        self.alpha(alpha)
    return self

copy_properties_from(source, deep=True, actor_related=True)

Copy properties from another Points object.

Source code in vedo/visual/runtime.py
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
def copy_properties_from(self, source, deep=True, actor_related=True) -> Self:
    """
    Copy properties from another ``Points`` object.
    """
    pr = vtki.vtkProperty()
    try:
        sp = source.properties
        mp = source.mapper
        sa = source.actor
    except AttributeError:
        sp = source.GetProperty()
        mp = source.GetMapper()
        sa = source

    if deep:
        pr.DeepCopy(sp)
    else:
        pr.ShallowCopy(sp)
    self.actor.SetProperty(pr)
    self.properties = pr

    if self.actor.GetBackfaceProperty():
        bfpr = vtki.vtkProperty()
        bfpr.DeepCopy(sa.GetBackfaceProperty())
        self.actor.SetBackfaceProperty(bfpr)
        self.properties_backface = bfpr

    if not actor_related:
        return self

    # mapper related:
    self.mapper.SetScalarVisibility(mp.GetScalarVisibility())
    self.mapper.SetScalarMode(mp.GetScalarMode())
    self.mapper.SetScalarRange(mp.GetScalarRange())
    self.mapper.SetLookupTable(mp.GetLookupTable())
    self.mapper.SetColorMode(mp.GetColorMode())
    self.mapper.SetInterpolateScalarsBeforeMapping(
        mp.GetInterpolateScalarsBeforeMapping()
    )
    self.mapper.SetUseLookupTableScalarRange(mp.GetUseLookupTableScalarRange())

    self.actor.SetPickable(sa.GetPickable())
    self.actor.SetDragable(sa.GetDragable())
    self.actor.SetTexture(sa.GetTexture())
    self.actor.SetVisibility(sa.GetVisibility())
    return self

force_opaque(value=True)

Force the Mesh, Line or point cloud to be treated as opaque

Source code in vedo/visual/runtime.py
1078
1079
1080
1081
1082
1083
def force_opaque(self, value=True) -> Self:
    """Force the Mesh, Line or point cloud to be treated as opaque"""
    ## force the opaque pass, fixes picking in vtk9
    # but causes other bad troubles with lines..
    self.actor.SetForceOpaque(value)
    return self

force_translucent(value=True)

Force the Mesh, Line or point cloud to be treated as translucent

Source code in vedo/visual/runtime.py
1085
1086
1087
1088
def force_translucent(self, value=True) -> Self:
    """Force the Mesh, Line or point cloud to be treated as translucent"""
    self.actor.SetForceTranslucent(value)
    return self

lighting(style='', ambient=None, diffuse=None, specular=None, specular_power=None, specular_color=None, metallicity=None, roughness=None)

Set the ambient, diffuse, specular and specular_power lighting constants.

Parameters:

Name Type Description Default
style str

preset style, options are [metallic, plastic, shiny, glossy, ambient, off]

''
ambient float

ambient fraction of emission [0-1]

None
diffuse float

emission of diffused light in fraction [0-1]

None
specular float

fraction of reflected light [0-1]

None
specular_power float

precision of reflection [1-100]

None
specular_color color

color that is being reflected by the surface

None

Examples:

Source code in vedo/visual/runtime.py
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
def lighting(
    self,
    style="",
    ambient=None,
    diffuse=None,
    specular=None,
    specular_power=None,
    specular_color=None,
    metallicity=None,
    roughness=None,
) -> Self:
    """
    Set the ambient, diffuse, specular and specular_power lighting constants.

    Args:
        style (str):
            preset style, options are `[metallic, plastic, shiny, glossy, ambient, off]`
        ambient (float):
            ambient fraction of emission [0-1]
        diffuse (float):
            emission of diffused light in fraction [0-1]
        specular (float):
            fraction of reflected light [0-1]
        specular_power (float):
            precision of reflection [1-100]
        specular_color (color):
            color that is being reflected by the surface

    <img src="https://upload.wikimedia.org/wikipedia/commons/6/6b/Phong_components_version_4.png" alt="", width=700px>

    Examples:
        - [specular.py](https://github.com/marcomusy/vedo/tree/master/examples/basic/specular.py)
    """
    pr = self.properties

    if style:
        if style != "off":
            pr.LightingOn()

        if style == "off":
            pr.SetInterpolationToFlat()
            pr.LightingOff()
            return self  ##############

        if hasattr(pr, "GetColor"):  # could be Volume
            c = pr.GetColor()
        else:
            c = (1, 1, 0.99)
        mpr = self.mapper
        if hasattr(mpr, "GetScalarVisibility") and mpr.GetScalarVisibility():
            c = (1, 1, 0.99)
        if style == "metallic":
            pars = [0.1, 0.3, 1.0, 10, c]
        elif style == "plastic":
            pars = [0.3, 0.4, 0.3, 5, c]
        elif style == "shiny":
            pars = [0.2, 0.6, 0.8, 50, c]
        elif style == "glossy":
            pars = [0.1, 0.7, 0.9, 90, (1, 1, 0.99)]
        elif style == "ambient":
            pars = [0.8, 0.1, 0.0, 1, (1, 1, 1)]
        elif style == "default":
            pars = [0.1, 1.0, 0.05, 5, c]
        else:
            vedo.logger.error("in lighting(): Available styles are")
            vedo.logger.error(
                "[default, metallic, plastic, shiny, glossy, ambient, off]"
            )
            raise RuntimeError()
        pr.SetAmbient(pars[0])
        pr.SetDiffuse(pars[1])
        pr.SetSpecular(pars[2])
        pr.SetSpecularPower(pars[3])
        if hasattr(pr, "GetColor"):
            pr.SetSpecularColor(pars[4])

    if ambient is not None:
        pr.SetAmbient(ambient)
    if diffuse is not None:
        pr.SetDiffuse(diffuse)
    if specular is not None:
        pr.SetSpecular(specular)
    if specular_power is not None:
        pr.SetSpecularPower(specular_power)
    if specular_color is not None:
        pr.SetSpecularColor(colors.get_color(specular_color))
    if metallicity is not None:
        pr.SetInterpolationToPBR()
        pr.SetMetallic(metallicity)
    if roughness is not None:
        pr.SetInterpolationToPBR()
        pr.SetRoughness(roughness)

    return self

lut_color_at(value)

Return the color and alpha in the lookup table at given value.

Source code in vedo/visual/runtime.py
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
def lut_color_at(self, value) -> np.ndarray:
    """
    Return the color and alpha in the lookup table at given value.
    """
    lut = self.mapper.GetLookupTable()
    if not lut:
        return None
    rgb = [0, 0, 0]
    lut.GetColor(value, rgb)
    alpha = lut.GetOpacity(value)
    return np.array(rgb + [alpha])

opacity(alpha=None)

Set/get mesh's transparency. Same as mesh.alpha().

Source code in vedo/visual/runtime.py
1074
1075
1076
def opacity(self, alpha=None) -> float | Self:
    """Set/get mesh's transparency. Same as `mesh.alpha()`."""
    return self.alpha(alpha)

point_blurring(r=1, alpha=1.0, emissive=False)

Set point blurring. Apply a gaussian convolution filter to the points. In this case the radius r is in absolute units of the mesh coordinates. With emissive set, the halo of point becomes light-emissive.

Source code in vedo/visual/runtime.py
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
def point_blurring(self, r=1, alpha=1.0, emissive=False) -> Self:
    """Set point blurring.
    Apply a gaussian convolution filter to the points.
    In this case the radius `r` is in absolute units of the mesh coordinates.
    With emissive set, the halo of point becomes light-emissive.
    """
    self.properties.SetRepresentationToPoints()
    if emissive:
        self.mapper.SetEmissive(bool(emissive))
    self.mapper.SetScaleFactor(r * 1.4142)

    # https://kitware.github.io/vtk-examples/site/Python/Meshes/PointInterpolator/
    if alpha < 1:
        self.mapper.SetSplatShaderCode(
            "//VTK::Color::Impl\n"
            "float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
            "if (dist > 1.0) {\n"
            "   discard;\n"
            "} else {\n"
            f"  float scale = ({alpha} - dist);\n"
            "   ambientColor *= scale;\n"
            "   diffuseColor *= scale;\n"
            "}\n"
        )
        alpha = 1

    self.mapper.Modified()
    self.actor.Modified()
    self.properties.SetOpacity(alpha)
    self.actor.SetMapper(self.mapper)
    return self

point_size(value=None)

Set/get mesh's point size of vertices. Same as mesh.ps()

Source code in vedo/visual/runtime.py
1090
1091
1092
1093
1094
1095
1096
1097
1098
def point_size(self, value=None) -> int | Self:
    """Set/get mesh's point size of vertices. Same as `mesh.ps()`"""
    if value is None:
        return self.properties.GetPointSize()
        # self.properties.SetRepresentationToSurface()
    else:
        self.properties.SetRepresentationToPoints()
        self.properties.SetPointSize(value)
    return self

ps(pointsize=None)

Set/get mesh's point size of vertices. Same as mesh.point_size()

Source code in vedo/visual/runtime.py
1100
1101
1102
def ps(self, pointsize=None) -> int | Self:
    """Set/get mesh's point size of vertices. Same as `mesh.point_size()`"""
    return self.point_size(pointsize)

render_points_as_spheres(value=True)

Make points look spheric or else make them look as squares.

Source code in vedo/visual/runtime.py
1104
1105
1106
1107
def render_points_as_spheres(self, value=True) -> Self:
    """Make points look spheric or else make them look as squares."""
    self.properties.SetRenderPointsAsSpheres(value)
    return self

VolumeVisual

Bases: CommonVisual

Class to manage the visual aspects of a Volume object.

Source code in vedo/visual/runtime.py
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
class VolumeVisual(CommonVisual):
    """Class to manage the visual aspects of a ``Volume`` object."""

    # def __init__(self) -> None:
    #     # print("INIT VolumeVisual")
    #     super().__init__()

    def alpha_unit(self, u=None) -> Self | float:
        """
        Defines light attenuation per unit length. Default is 1.
        The larger the unit length, the further light has to travel to attenuate the same amount.

        E.g., if you set the unit distance to 0, you will get full opacity.
        It means that when light travels 0 distance it's already attenuated a finite amount.
        Thus, any finite distance should attenuate all light.
        The larger you make the unit distance, the more transparent the rendering becomes.
        """
        if u is None:
            return self.properties.GetScalarOpacityUnitDistance()
        self.properties.SetScalarOpacityUnitDistance(u)
        return self

    def alpha_gradient(self, alpha_grad, vmin=None, vmax=None) -> Self:
        """
        Assign a set of tranparencies to a volume's gradient
        along the range of the scalar value.
        A single constant value can also be assigned.
        The gradient function is used to decrease the opacity
        in the "flat" regions of the volume while maintaining the opacity
        at the boundaries between material types.  The gradient is measured
        as the amount by which the intensity changes over unit distance.

        The format for alpha_grad is the same as for method `volume.alpha()`.
        """
        if vmin is None:
            vmin, _ = self.dataset.GetScalarRange()
        if vmax is None:
            _, vmax = self.dataset.GetScalarRange()

        if alpha_grad is None:
            self.properties.DisableGradientOpacityOn()
            return self

        self.properties.DisableGradientOpacityOff()

        gotf = self.properties.GetGradientOpacity()
        if utils.is_sequence(alpha_grad):
            alpha_grad = np.array(alpha_grad)
            if (
                len(alpha_grad.shape) == 1
            ):  # user passing a flat list e.g. (0.0, 0.3, 0.9, 1)
                for i, al in enumerate(alpha_grad):
                    xalpha = vmin + (vmax - vmin) * i / (len(alpha_grad) - 1)
                    # Create transfer mapping scalar value to gradient opacity
                    gotf.AddPoint(xalpha, al)
            elif len(alpha_grad.shape) == 2:  # user passing [(x0,alpha0), ...]
                gotf.AddPoint(vmin, alpha_grad[0][1])
                for xalpha, al in alpha_grad:
                    # Create transfer mapping scalar value to opacity
                    gotf.AddPoint(xalpha, al)
                gotf.AddPoint(vmax, alpha_grad[-1][1])
            # print("alpha_grad at", round(xalpha, 1), "\tset to", al)
        else:
            gotf.AddPoint(vmin, alpha_grad)  # constant alpha_grad
            gotf.AddPoint(vmax, alpha_grad)
        return self

    def cmap(self, c, alpha=None, vmin=None, vmax=None) -> Self:
        """Same as `color()`.

        Args:
            alpha (list):
                use a list to specify transparencies along the scalar range
            vmin (float):
                force the min of the scalar range to be this value
            vmax (float):
                force the max of the scalar range to be this value
        """
        return self.color(c, alpha, vmin, vmax)

    def jittering(self, status=None) -> Self | bool:
        """
        If `True`, each ray traversal direction will be perturbed slightly
        using a noise-texture to get rid of wood-grain effects.
        """
        if hasattr(self.mapper, "SetUseJittering"):  # tetmesh doesnt have it
            if status is None:
                return self.mapper.GetUseJittering()
            self.mapper.SetUseJittering(status)
        return self

    def hide_voxels(self, ids) -> Self:
        """
        Hide voxels (cells) from visualization.

        Examples:
            ```python
            from vedo import *
            embryo = Volume(dataurl+'embryo.tif')
            embryo.hide_voxels(list(range(400000)))
            show(embryo, axes=1).close()
            ```

        See also:
            `volume.mask()`
        """
        ghost_mask = np.zeros(self.ncells, dtype=np.uint8)
        ghost_mask[ids] = vtki.vtkDataSetAttributes.HIDDENCELL
        name = vtki.vtkDataSetAttributes.GhostArrayName()
        garr = utils.numpy2vtk(ghost_mask, name=name, dtype=np.uint8)
        self.dataset.GetCellData().AddArray(garr)
        self.dataset.GetCellData().Modified()
        return self

    def mask(self, data) -> Self:
        """
        Mask a volume visualization with a binary value.
        Needs to specify `volume.mapper = "gpu"`.

        Examples:
        ```python
        from vedo import np, Volume, show
        data_matrix = np.zeros([75, 75, 75], dtype=np.uint8)
        # all voxels have value zero except:
        data_matrix[ 0:35,  0:35,  0:35] = 1
        data_matrix[35:55, 35:55, 35:55] = 2
        data_matrix[55:74, 55:74, 55:74] = 3
        vol = Volume(data_matrix).cmap('Blues')
        vol.mapper = "gpu"
        data_mask = np.zeros_like(data_matrix)
        data_mask[10:65, 10:60, 20:70] = 1
        vol.mask(data_mask)
        show(vol, axes=1).close()
        ```
        See also:
            `volume.hide_voxels()`
        """
        rdata = data.astype(np.uint8).ravel(order="F")
        varr = utils.numpy2vtk(rdata, name="input_mask")

        img = vtki.vtkImageData()
        img.SetDimensions(self.dimensions())
        img.GetPointData().AddArray(varr)
        img.GetPointData().SetActiveScalars(varr.GetName())

        try:
            self.mapper.SetMaskTypeToBinary()
            self.mapper.SetMaskInput(img)
        except AttributeError:
            vedo.logger.error("volume.mask() must specify volume.mapper = 'gpu'")
        return self

    def mode(self, mode=None) -> Self | int:
        """
        Define the volumetric rendering mode following this:
            - 0, composite rendering
            - 1, maximum projection rendering
            - 2, minimum projection rendering
            - 3, average projection rendering
            - 4, additive mode

        The default mode is "composite" where the scalar values are sampled through
        the volume and composited in a front-to-back scheme through alpha blending.
        The final color and opacity is determined using the color and opacity transfer
        functions specified in alpha keyword.

        Maximum and minimum intensity blend modes use the maximum and minimum
        scalar values, respectively, along the sampling ray.
        The final color and opacity is determined by passing the resultant value
        through the color and opacity transfer functions.

        Additive blend mode accumulates scalar values by passing each value
        through the opacity transfer function and then adding up the product
        of the value and its opacity. In other words, the scalar values are scaled
        using the opacity transfer function and summed to derive the final color.
        Note that the resulting image is always grayscale i.e. aggregated values
        are not passed through the color transfer function.
        This is because the final value is a derived value and not a real data value
        along the sampling ray.

        Average intensity blend mode works similar to the additive blend mode where
        the scalar values are multiplied by opacity calculated from the opacity
        transfer function and then added.
        The additional step here is to divide the sum by the number of samples
        taken through the volume.
        As is the case with the additive intensity projection, the final image will
        always be grayscale i.e. the aggregated values are not passed through the
        color transfer function.
        """
        if mode is None:
            return self.mapper.GetBlendMode()

        if isinstance(mode, str):
            if "comp" in mode:
                mode = 0
            elif "proj" in mode:
                if "max" in mode:
                    mode = 1
                elif "min" in mode:
                    mode = 2
                elif "ave" in mode:
                    mode = 3
                else:
                    vedo.logger.warning(f"unknown mode {mode}")
                    mode = 0
            elif "add" in mode:
                mode = 4
            else:
                vedo.logger.warning(f"unknown mode {mode}")
                mode = 0

        self.mapper.SetBlendMode(mode)
        return self

    def shade(self, status=None) -> Self | bool:
        """
        Set/Get the shading of a Volume.
        Shading can be further controlled with `volume.lighting()` method.

        If shading is turned on, the mapper may perform shading calculations.
        In some cases shading does not apply
        (for example, in maximum intensity projection mode).
        """
        if status is None:
            return self.properties.GetShade()
        self.properties.SetShade(status)
        return self

    def interpolation(self, itype) -> Self:
        """
        Set interpolation type.

        0=nearest neighbour, 1=linear
        """
        self.properties.SetInterpolationType(itype)
        return self

alpha_gradient(alpha_grad, vmin=None, vmax=None)

Assign a set of tranparencies to a volume's gradient along the range of the scalar value. A single constant value can also be assigned. The gradient function is used to decrease the opacity in the "flat" regions of the volume while maintaining the opacity at the boundaries between material types. The gradient is measured as the amount by which the intensity changes over unit distance.

The format for alpha_grad is the same as for method volume.alpha().

Source code in vedo/visual/runtime.py
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
def alpha_gradient(self, alpha_grad, vmin=None, vmax=None) -> Self:
    """
    Assign a set of tranparencies to a volume's gradient
    along the range of the scalar value.
    A single constant value can also be assigned.
    The gradient function is used to decrease the opacity
    in the "flat" regions of the volume while maintaining the opacity
    at the boundaries between material types.  The gradient is measured
    as the amount by which the intensity changes over unit distance.

    The format for alpha_grad is the same as for method `volume.alpha()`.
    """
    if vmin is None:
        vmin, _ = self.dataset.GetScalarRange()
    if vmax is None:
        _, vmax = self.dataset.GetScalarRange()

    if alpha_grad is None:
        self.properties.DisableGradientOpacityOn()
        return self

    self.properties.DisableGradientOpacityOff()

    gotf = self.properties.GetGradientOpacity()
    if utils.is_sequence(alpha_grad):
        alpha_grad = np.array(alpha_grad)
        if (
            len(alpha_grad.shape) == 1
        ):  # user passing a flat list e.g. (0.0, 0.3, 0.9, 1)
            for i, al in enumerate(alpha_grad):
                xalpha = vmin + (vmax - vmin) * i / (len(alpha_grad) - 1)
                # Create transfer mapping scalar value to gradient opacity
                gotf.AddPoint(xalpha, al)
        elif len(alpha_grad.shape) == 2:  # user passing [(x0,alpha0), ...]
            gotf.AddPoint(vmin, alpha_grad[0][1])
            for xalpha, al in alpha_grad:
                # Create transfer mapping scalar value to opacity
                gotf.AddPoint(xalpha, al)
            gotf.AddPoint(vmax, alpha_grad[-1][1])
        # print("alpha_grad at", round(xalpha, 1), "\tset to", al)
    else:
        gotf.AddPoint(vmin, alpha_grad)  # constant alpha_grad
        gotf.AddPoint(vmax, alpha_grad)
    return self

alpha_unit(u=None)

Defines light attenuation per unit length. Default is 1. The larger the unit length, the further light has to travel to attenuate the same amount.

E.g., if you set the unit distance to 0, you will get full opacity. It means that when light travels 0 distance it's already attenuated a finite amount. Thus, any finite distance should attenuate all light. The larger you make the unit distance, the more transparent the rendering becomes.

Source code in vedo/visual/runtime.py
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
def alpha_unit(self, u=None) -> Self | float:
    """
    Defines light attenuation per unit length. Default is 1.
    The larger the unit length, the further light has to travel to attenuate the same amount.

    E.g., if you set the unit distance to 0, you will get full opacity.
    It means that when light travels 0 distance it's already attenuated a finite amount.
    Thus, any finite distance should attenuate all light.
    The larger you make the unit distance, the more transparent the rendering becomes.
    """
    if u is None:
        return self.properties.GetScalarOpacityUnitDistance()
    self.properties.SetScalarOpacityUnitDistance(u)
    return self

cmap(c, alpha=None, vmin=None, vmax=None)

Same as color().

Parameters:

Name Type Description Default
alpha list

use a list to specify transparencies along the scalar range

None
vmin float

force the min of the scalar range to be this value

None
vmax float

force the max of the scalar range to be this value

None
Source code in vedo/visual/runtime.py
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
def cmap(self, c, alpha=None, vmin=None, vmax=None) -> Self:
    """Same as `color()`.

    Args:
        alpha (list):
            use a list to specify transparencies along the scalar range
        vmin (float):
            force the min of the scalar range to be this value
        vmax (float):
            force the max of the scalar range to be this value
    """
    return self.color(c, alpha, vmin, vmax)

hide_voxels(ids)

Hide voxels (cells) from visualization.

Examples:

from vedo import *
embryo = Volume(dataurl+'embryo.tif')
embryo.hide_voxels(list(range(400000)))
show(embryo, axes=1).close()
See also

volume.mask()

Source code in vedo/visual/runtime.py
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
def hide_voxels(self, ids) -> Self:
    """
    Hide voxels (cells) from visualization.

    Examples:
        ```python
        from vedo import *
        embryo = Volume(dataurl+'embryo.tif')
        embryo.hide_voxels(list(range(400000)))
        show(embryo, axes=1).close()
        ```

    See also:
        `volume.mask()`
    """
    ghost_mask = np.zeros(self.ncells, dtype=np.uint8)
    ghost_mask[ids] = vtki.vtkDataSetAttributes.HIDDENCELL
    name = vtki.vtkDataSetAttributes.GhostArrayName()
    garr = utils.numpy2vtk(ghost_mask, name=name, dtype=np.uint8)
    self.dataset.GetCellData().AddArray(garr)
    self.dataset.GetCellData().Modified()
    return self

interpolation(itype)

Set interpolation type.

0=nearest neighbour, 1=linear

Source code in vedo/visual/runtime.py
1942
1943
1944
1945
1946
1947
1948
1949
def interpolation(self, itype) -> Self:
    """
    Set interpolation type.

    0=nearest neighbour, 1=linear
    """
    self.properties.SetInterpolationType(itype)
    return self

jittering(status=None)

If True, each ray traversal direction will be perturbed slightly using a noise-texture to get rid of wood-grain effects.

Source code in vedo/visual/runtime.py
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
def jittering(self, status=None) -> Self | bool:
    """
    If `True`, each ray traversal direction will be perturbed slightly
    using a noise-texture to get rid of wood-grain effects.
    """
    if hasattr(self.mapper, "SetUseJittering"):  # tetmesh doesnt have it
        if status is None:
            return self.mapper.GetUseJittering()
        self.mapper.SetUseJittering(status)
    return self

mask(data)

Mask a volume visualization with a binary value. Needs to specify volume.mapper = "gpu".

Examples:

from vedo import np, Volume, show
data_matrix = np.zeros([75, 75, 75], dtype=np.uint8)
# all voxels have value zero except:
data_matrix[ 0:35,  0:35,  0:35] = 1
data_matrix[35:55, 35:55, 35:55] = 2
data_matrix[55:74, 55:74, 55:74] = 3
vol = Volume(data_matrix).cmap('Blues')
vol.mapper = "gpu"
data_mask = np.zeros_like(data_matrix)
data_mask[10:65, 10:60, 20:70] = 1
vol.mask(data_mask)
show(vol, axes=1).close()
See also: volume.hide_voxels()

Source code in vedo/visual/runtime.py
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
def mask(self, data) -> Self:
    """
    Mask a volume visualization with a binary value.
    Needs to specify `volume.mapper = "gpu"`.

    Examples:
    ```python
    from vedo import np, Volume, show
    data_matrix = np.zeros([75, 75, 75], dtype=np.uint8)
    # all voxels have value zero except:
    data_matrix[ 0:35,  0:35,  0:35] = 1
    data_matrix[35:55, 35:55, 35:55] = 2
    data_matrix[55:74, 55:74, 55:74] = 3
    vol = Volume(data_matrix).cmap('Blues')
    vol.mapper = "gpu"
    data_mask = np.zeros_like(data_matrix)
    data_mask[10:65, 10:60, 20:70] = 1
    vol.mask(data_mask)
    show(vol, axes=1).close()
    ```
    See also:
        `volume.hide_voxels()`
    """
    rdata = data.astype(np.uint8).ravel(order="F")
    varr = utils.numpy2vtk(rdata, name="input_mask")

    img = vtki.vtkImageData()
    img.SetDimensions(self.dimensions())
    img.GetPointData().AddArray(varr)
    img.GetPointData().SetActiveScalars(varr.GetName())

    try:
        self.mapper.SetMaskTypeToBinary()
        self.mapper.SetMaskInput(img)
    except AttributeError:
        vedo.logger.error("volume.mask() must specify volume.mapper = 'gpu'")
    return self

mode(mode=None)

Define the volumetric rendering mode following this
  • 0, composite rendering
  • 1, maximum projection rendering
  • 2, minimum projection rendering
  • 3, average projection rendering
  • 4, additive mode

The default mode is "composite" where the scalar values are sampled through the volume and composited in a front-to-back scheme through alpha blending. The final color and opacity is determined using the color and opacity transfer functions specified in alpha keyword.

Maximum and minimum intensity blend modes use the maximum and minimum scalar values, respectively, along the sampling ray. The final color and opacity is determined by passing the resultant value through the color and opacity transfer functions.

Additive blend mode accumulates scalar values by passing each value through the opacity transfer function and then adding up the product of the value and its opacity. In other words, the scalar values are scaled using the opacity transfer function and summed to derive the final color. Note that the resulting image is always grayscale i.e. aggregated values are not passed through the color transfer function. This is because the final value is a derived value and not a real data value along the sampling ray.

Average intensity blend mode works similar to the additive blend mode where the scalar values are multiplied by opacity calculated from the opacity transfer function and then added. The additional step here is to divide the sum by the number of samples taken through the volume. As is the case with the additive intensity projection, the final image will always be grayscale i.e. the aggregated values are not passed through the color transfer function.

Source code in vedo/visual/runtime.py
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
def mode(self, mode=None) -> Self | int:
    """
    Define the volumetric rendering mode following this:
        - 0, composite rendering
        - 1, maximum projection rendering
        - 2, minimum projection rendering
        - 3, average projection rendering
        - 4, additive mode

    The default mode is "composite" where the scalar values are sampled through
    the volume and composited in a front-to-back scheme through alpha blending.
    The final color and opacity is determined using the color and opacity transfer
    functions specified in alpha keyword.

    Maximum and minimum intensity blend modes use the maximum and minimum
    scalar values, respectively, along the sampling ray.
    The final color and opacity is determined by passing the resultant value
    through the color and opacity transfer functions.

    Additive blend mode accumulates scalar values by passing each value
    through the opacity transfer function and then adding up the product
    of the value and its opacity. In other words, the scalar values are scaled
    using the opacity transfer function and summed to derive the final color.
    Note that the resulting image is always grayscale i.e. aggregated values
    are not passed through the color transfer function.
    This is because the final value is a derived value and not a real data value
    along the sampling ray.

    Average intensity blend mode works similar to the additive blend mode where
    the scalar values are multiplied by opacity calculated from the opacity
    transfer function and then added.
    The additional step here is to divide the sum by the number of samples
    taken through the volume.
    As is the case with the additive intensity projection, the final image will
    always be grayscale i.e. the aggregated values are not passed through the
    color transfer function.
    """
    if mode is None:
        return self.mapper.GetBlendMode()

    if isinstance(mode, str):
        if "comp" in mode:
            mode = 0
        elif "proj" in mode:
            if "max" in mode:
                mode = 1
            elif "min" in mode:
                mode = 2
            elif "ave" in mode:
                mode = 3
            else:
                vedo.logger.warning(f"unknown mode {mode}")
                mode = 0
        elif "add" in mode:
            mode = 4
        else:
            vedo.logger.warning(f"unknown mode {mode}")
            mode = 0

    self.mapper.SetBlendMode(mode)
    return self

shade(status=None)

Set/Get the shading of a Volume. Shading can be further controlled with volume.lighting() method.

If shading is turned on, the mapper may perform shading calculations. In some cases shading does not apply (for example, in maximum intensity projection mode).

Source code in vedo/visual/runtime.py
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
def shade(self, status=None) -> Self | bool:
    """
    Set/Get the shading of a Volume.
    Shading can be further controlled with `volume.lighting()` method.

    If shading is turned on, the mapper may perform shading calculations.
    In some cases shading does not apply
    (for example, in maximum intensity projection mode).
    """
    if status is None:
        return self.properties.GetShade()
    self.properties.SetShade(status)
    return self

MeshVisual

Bases: MeshVisualTextureMixin, PointsVisual

Class to manage the visual aspects of a Mesh object.

Source code in vedo/visual/runtime.py
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
class MeshVisual(MeshVisualTextureMixin, PointsVisual):
    """Class to manage the visual aspects of a `Mesh` object."""

    def __init__(self) -> None:
        # print("INIT MeshVisual", super())
        super().__init__()

    def follow_camera(self, camera=None, origin=None) -> Self:
        """
        Return an object that will follow camera movements and stay locked to it.
        Use `mesh.follow_camera(False)` to disable it.

        A `vtkCamera` object can also be passed.
        """
        if camera is False:
            try:
                self.SetCamera(None)
                return self
            except AttributeError:
                return self

        factor = vtki.vtkFollower()
        factor.SetMapper(self.mapper)
        factor.SetProperty(self.properties)
        factor.SetBackfaceProperty(self.actor.GetBackfaceProperty())
        factor.SetTexture(self.actor.GetTexture())
        factor.SetScale(self.actor.GetScale())
        # factor.SetOrientation(self.actor.GetOrientation())
        factor.SetPosition(self.actor.GetPosition())
        factor.SetUseBounds(self.actor.GetUseBounds())

        if origin is None:
            act_origin = np.array(self.actor.GetOrigin())
            if np.allclose(act_origin, 0):
                # geometry is baked into the dataset; use the transform position as pivot
                origin = self.transform.position
            else:
                origin = act_origin
        factor.SetOrigin(origin)

        factor.PickableOff()

        if isinstance(camera, vtki.vtkCamera):
            factor.SetCamera(camera)
        else:
            plt = vedo.current_plotter()
            if plt and plt.renderer and plt.renderer.GetActiveCamera():
                factor.SetCamera(plt.renderer.GetActiveCamera())

        self.actor = None
        factor.retrieve_object = weak_ref_to(self)
        self.actor = factor
        return self

    def wireframe(self, value=True) -> Self:
        """Set mesh's representation as wireframe or solid surface."""
        if value:
            self.properties.SetRepresentationToWireframe()
        else:
            self.properties.SetRepresentationToSurface()
        return self

    def flat(self) -> Self:
        """Set surface interpolation to flat.

        <img src="https://upload.wikimedia.org/wikipedia/commons/6/6b/Phong_components_version_4.png" width="700">
        """
        self.properties.SetInterpolationToFlat()
        return self

    def phong(self) -> Self:
        """Set surface interpolation to "phong"."""
        self.properties.SetInterpolationToPhong()
        return self

    def backface_culling(self, value=True) -> Self:
        """Set culling of polygons based on orientation of normal with respect to camera."""
        self.properties.SetBackfaceCulling(value)
        return self

    def render_lines_as_tubes(self, value=True) -> Self:
        """Wrap a fake tube around a simple line for visualization"""
        self.properties.SetRenderLinesAsTubes(value)
        return self

    def frontface_culling(self, value=True) -> Self:
        """Set culling of polygons based on orientation of normal with respect to camera."""
        self.properties.SetFrontfaceCulling(value)
        return self

    def backcolor(self, bc=None) -> Self | np.ndarray:
        """
        Set/get mesh's backface color.
        """
        back_prop = self.actor.GetBackfaceProperty()

        if bc is None:
            if back_prop:
                return back_prop.GetDiffuseColor()
            return self

        if self.properties.GetOpacity() < 1:
            return self

        if not back_prop:
            back_prop = vtki.vtkProperty()

        back_prop.SetDiffuseColor(colors.get_color(bc))
        back_prop.SetOpacity(self.properties.GetOpacity())
        self.actor.SetBackfaceProperty(back_prop)
        self.mapper.ScalarVisibilityOff()
        return self

    def bc(self, backcolor=False) -> Self | np.ndarray:
        """Shortcut for `mesh.backcolor()`."""
        return self.backcolor(backcolor)

    def linewidth(self, lw=None) -> Self | int:
        """Set/get width of mesh edges. Same as `lw()`."""
        if lw is not None:
            if lw == 0:
                self.properties.EdgeVisibilityOff()
                self.properties.SetRepresentationToSurface()
                return self
            self.properties.EdgeVisibilityOn()
            self.properties.SetLineWidth(lw)
        else:
            return self.properties.GetLineWidth()
        return self

    def lw(self, linewidth=None) -> Self | int:
        """Set/get width of mesh edges. Same as `linewidth()`."""
        return self.linewidth(linewidth)

    def linecolor(self, lc=None) -> Self | np.ndarray:
        """Set/get color of mesh edges. Same as `lc()`."""
        if lc is None:
            return np.array(self.properties.GetEdgeColor())
        self.properties.EdgeVisibilityOn()
        self.properties.SetEdgeColor(colors.get_color(lc))
        return self

    def lc(self, linecolor=None) -> Self | np.ndarray:
        """Set/get color of mesh edges. Same as `linecolor()`."""
        return self.linecolor(linecolor)

backcolor(bc=None)

Set/get mesh's backface color.

Source code in vedo/visual/runtime.py
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
def backcolor(self, bc=None) -> Self | np.ndarray:
    """
    Set/get mesh's backface color.
    """
    back_prop = self.actor.GetBackfaceProperty()

    if bc is None:
        if back_prop:
            return back_prop.GetDiffuseColor()
        return self

    if self.properties.GetOpacity() < 1:
        return self

    if not back_prop:
        back_prop = vtki.vtkProperty()

    back_prop.SetDiffuseColor(colors.get_color(bc))
    back_prop.SetOpacity(self.properties.GetOpacity())
    self.actor.SetBackfaceProperty(back_prop)
    self.mapper.ScalarVisibilityOff()
    return self

backface_culling(value=True)

Set culling of polygons based on orientation of normal with respect to camera.

Source code in vedo/visual/runtime.py
1641
1642
1643
1644
def backface_culling(self, value=True) -> Self:
    """Set culling of polygons based on orientation of normal with respect to camera."""
    self.properties.SetBackfaceCulling(value)
    return self

bc(backcolor=False)

Shortcut for mesh.backcolor().

Source code in vedo/visual/runtime.py
1679
1680
1681
def bc(self, backcolor=False) -> Self | np.ndarray:
    """Shortcut for `mesh.backcolor()`."""
    return self.backcolor(backcolor)

flat()

Set surface interpolation to flat.

Source code in vedo/visual/runtime.py
1628
1629
1630
1631
1632
1633
1634
def flat(self) -> Self:
    """Set surface interpolation to flat.

    <img src="https://upload.wikimedia.org/wikipedia/commons/6/6b/Phong_components_version_4.png" width="700">
    """
    self.properties.SetInterpolationToFlat()
    return self

follow_camera(camera=None, origin=None)

Return an object that will follow camera movements and stay locked to it. Use mesh.follow_camera(False) to disable it.

A vtkCamera object can also be passed.

Source code in vedo/visual/runtime.py
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
def follow_camera(self, camera=None, origin=None) -> Self:
    """
    Return an object that will follow camera movements and stay locked to it.
    Use `mesh.follow_camera(False)` to disable it.

    A `vtkCamera` object can also be passed.
    """
    if camera is False:
        try:
            self.SetCamera(None)
            return self
        except AttributeError:
            return self

    factor = vtki.vtkFollower()
    factor.SetMapper(self.mapper)
    factor.SetProperty(self.properties)
    factor.SetBackfaceProperty(self.actor.GetBackfaceProperty())
    factor.SetTexture(self.actor.GetTexture())
    factor.SetScale(self.actor.GetScale())
    # factor.SetOrientation(self.actor.GetOrientation())
    factor.SetPosition(self.actor.GetPosition())
    factor.SetUseBounds(self.actor.GetUseBounds())

    if origin is None:
        act_origin = np.array(self.actor.GetOrigin())
        if np.allclose(act_origin, 0):
            # geometry is baked into the dataset; use the transform position as pivot
            origin = self.transform.position
        else:
            origin = act_origin
    factor.SetOrigin(origin)

    factor.PickableOff()

    if isinstance(camera, vtki.vtkCamera):
        factor.SetCamera(camera)
    else:
        plt = vedo.current_plotter()
        if plt and plt.renderer and plt.renderer.GetActiveCamera():
            factor.SetCamera(plt.renderer.GetActiveCamera())

    self.actor = None
    factor.retrieve_object = weak_ref_to(self)
    self.actor = factor
    return self

frontface_culling(value=True)

Set culling of polygons based on orientation of normal with respect to camera.

Source code in vedo/visual/runtime.py
1651
1652
1653
1654
def frontface_culling(self, value=True) -> Self:
    """Set culling of polygons based on orientation of normal with respect to camera."""
    self.properties.SetFrontfaceCulling(value)
    return self

lc(linecolor=None)

Set/get color of mesh edges. Same as linecolor().

Source code in vedo/visual/runtime.py
1708
1709
1710
def lc(self, linecolor=None) -> Self | np.ndarray:
    """Set/get color of mesh edges. Same as `linecolor()`."""
    return self.linecolor(linecolor)

linecolor(lc=None)

Set/get color of mesh edges. Same as lc().

Source code in vedo/visual/runtime.py
1700
1701
1702
1703
1704
1705
1706
def linecolor(self, lc=None) -> Self | np.ndarray:
    """Set/get color of mesh edges. Same as `lc()`."""
    if lc is None:
        return np.array(self.properties.GetEdgeColor())
    self.properties.EdgeVisibilityOn()
    self.properties.SetEdgeColor(colors.get_color(lc))
    return self

linewidth(lw=None)

Set/get width of mesh edges. Same as lw().

Source code in vedo/visual/runtime.py
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
def linewidth(self, lw=None) -> Self | int:
    """Set/get width of mesh edges. Same as `lw()`."""
    if lw is not None:
        if lw == 0:
            self.properties.EdgeVisibilityOff()
            self.properties.SetRepresentationToSurface()
            return self
        self.properties.EdgeVisibilityOn()
        self.properties.SetLineWidth(lw)
    else:
        return self.properties.GetLineWidth()
    return self

lw(linewidth=None)

Set/get width of mesh edges. Same as linewidth().

Source code in vedo/visual/runtime.py
1696
1697
1698
def lw(self, linewidth=None) -> Self | int:
    """Set/get width of mesh edges. Same as `linewidth()`."""
    return self.linewidth(linewidth)

phong()

Set surface interpolation to "phong".

Source code in vedo/visual/runtime.py
1636
1637
1638
1639
def phong(self) -> Self:
    """Set surface interpolation to "phong"."""
    self.properties.SetInterpolationToPhong()
    return self

render_lines_as_tubes(value=True)

Wrap a fake tube around a simple line for visualization

Source code in vedo/visual/runtime.py
1646
1647
1648
1649
def render_lines_as_tubes(self, value=True) -> Self:
    """Wrap a fake tube around a simple line for visualization"""
    self.properties.SetRenderLinesAsTubes(value)
    return self

wireframe(value=True)

Set mesh's representation as wireframe or solid surface.

Source code in vedo/visual/runtime.py
1620
1621
1622
1623
1624
1625
1626
def wireframe(self, value=True) -> Self:
    """Set mesh's representation as wireframe or solid surface."""
    if value:
        self.properties.SetRepresentationToWireframe()
    else:
        self.properties.SetRepresentationToSurface()
    return self

ImageVisual

Bases: CommonVisual, Actor3DHelper

Class to manage the visual aspects of a Image object.

Source code in vedo/visual/runtime.py
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
class ImageVisual(CommonVisual, Actor3DHelper):
    """Class to manage the visual aspects of a ``Image`` object."""

    # def __init__(self) -> None:
    #     # print("init ImageVisual")
    #     super().__init__()

    def memory_size(self) -> int:
        """Return the size in bytes of the object in memory."""
        return self.dataset.GetActualMemorySize()

    def scalar_range(self) -> np.ndarray:
        """Return the scalar range of the image."""
        return np.array(self.dataset.GetScalarRange())

    def alpha(self, a=None) -> Self | float:
        """Set/get image's transparency in the rendering scene."""
        if a is not None:
            self.properties.SetOpacity(a)
            return self
        return self.properties.GetOpacity()

    def level(self, value=None) -> Self | float:
        """Get/Set the image color level (brightness) in the rendering scene."""
        if value is None:
            return self.properties.GetColorLevel()
        self.properties.SetColorLevel(value)
        return self

    def window(self, value=None) -> Self | float:
        """Get/Set the image color window (contrast) in the rendering scene."""
        if value is None:
            return self.properties.GetColorWindow()
        self.properties.SetColorWindow(value)
        return self

alpha(a=None)

Set/get image's transparency in the rendering scene.

Source code in vedo/visual/runtime.py
1968
1969
1970
1971
1972
1973
def alpha(self, a=None) -> Self | float:
    """Set/get image's transparency in the rendering scene."""
    if a is not None:
        self.properties.SetOpacity(a)
        return self
    return self.properties.GetOpacity()

level(value=None)

Get/Set the image color level (brightness) in the rendering scene.

Source code in vedo/visual/runtime.py
1975
1976
1977
1978
1979
1980
def level(self, value=None) -> Self | float:
    """Get/Set the image color level (brightness) in the rendering scene."""
    if value is None:
        return self.properties.GetColorLevel()
    self.properties.SetColorLevel(value)
    return self

memory_size()

Return the size in bytes of the object in memory.

Source code in vedo/visual/runtime.py
1960
1961
1962
def memory_size(self) -> int:
    """Return the size in bytes of the object in memory."""
    return self.dataset.GetActualMemorySize()

scalar_range()

Return the scalar range of the image.

Source code in vedo/visual/runtime.py
1964
1965
1966
def scalar_range(self) -> np.ndarray:
    """Return the scalar range of the image."""
    return np.array(self.dataset.GetScalarRange())

window(value=None)

Get/Set the image color window (contrast) in the rendering scene.

Source code in vedo/visual/runtime.py
1982
1983
1984
1985
1986
1987
def window(self, value=None) -> Self | float:
    """Get/Set the image color window (contrast) in the rendering scene."""
    if value is None:
        return self.properties.GetColorWindow()
    self.properties.SetColorWindow(value)
    return self

Actor2D

Bases: vtkActor2D

Wrapping of vtkActor2D class.

Source code in vedo/visual/runtime.py
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
class Actor2D(vtki.vtkActor2D):
    """Wrapping of `vtkActor2D` class."""

    def __init__(self, dataset=None):
        """Manage 2D objects."""
        super().__init__()

        self.name = "Actor2D"
        self.filename = ""
        self.file_size = 0
        self.pipeline = None
        self.shape = []  # for images
        self.coordinate = None

        if dataset is not None:
            mapp = vtki.new("PolyDataMapper2D")
            mapp.SetInputData(dataset)
            self.SetMapper(mapp)

        self.dataset = dataset
        self.properties = self.GetProperty()

    @property
    def mapper(self):
        """Get the internal vtkMapper."""
        return self.GetMapper()

    # not usable
    # @property
    # def properties(self):
    #     """Get the internal vtkProperty."""
    #     return self.GetProperty()

    # @properties.setter
    # def properties(self, prop):
    #     """Set the internal vtkProperty."""
    #     self.SetProperty(prop)

    @mapper.setter
    def mapper(self, amapper):
        """Set the internal vtkMapper."""
        self.SetMapper(amapper)

    def layer(self, value=None):
        """Set/Get the layer number in the overlay planes into which to render."""
        if value is None:
            return self.GetLayerNumber()
        self.SetLayerNumber(value)
        return self

    def pos(self, px=None, py=None) -> np.ndarray | Self:
        """Set/Get the screen-coordinate position."""
        if isinstance(px, str):
            vedo.logger.error("Use string descriptors only inside the constructor")
            return self
        if px is None:
            return np.array(self.GetPosition(), dtype=int)
        if py is not None:
            p = [px, py]
        else:
            p = px
        assert len(p) == 2, "Error: len(pos) must be 2 for Actor2D"
        self.SetPosition(p)
        return self

    def coordinate_system(self, value=None) -> Self:
        """
        Set/get the coordinate system which this coordinate is defined in.

        The options are:
            0. Display
            1. Normalized Display
            2. Viewport
            3. Normalized Viewport
            4. View
            5. Pose
            6. World
        """
        coor = self.GetPositionCoordinate()
        if value is None:
            return coor.GetCoordinateSystem()
        coor.SetCoordinateSystem(value)
        return self

    def set_position_coordinates(self, p1, p2):
        """Set the position coordinates."""
        self.GetPositionCoordinate().SetValue(*p1)
        self.GetPosition2Coordinate().SetValue(*p2)
        return self

    def on(self) -> Self:
        """Set object visibility."""
        self.VisibilityOn()
        return self

    def off(self) -> Self:
        """Set object visibility."""
        self.VisibilityOff()
        return self

    def toggle(self) -> Self:
        """Toggle object visibility."""
        self.SetVisibility(not self.GetVisibility())
        return self

    def visibility(self, value=None) -> bool:
        """Get/Set object visibility."""
        if value is not None:
            self.SetVisibility(value)
        return self.GetVisibility()

    def pickable(self, value=True) -> Self:
        """Set object pickability."""
        self.SetPickable(value)
        return self

    def color(self, value=False) -> np.ndarray | Self:
        """Set/Get the object color. Call with no argument to get the current color."""
        if value is False:
            return self.properties.GetColor()
        self.properties.SetColor(colors.get_color(value))
        return self

    def c(self, value=False) -> np.ndarray | Self:
        """Set/Get the object color. Same as `color()`."""
        return self.color(value)

    def alpha(self, value=None) -> float | Self:
        """Set/Get the object opacity."""
        if value is None:
            return self.properties.GetOpacity()
        self.properties.SetOpacity(value)
        return self

    def ps(self, point_size=None) -> int | Self:
        """Set/Get the point size of the object. Same as `point_size()`."""
        if point_size is None:
            return self.properties.GetPointSize()
        self.properties.SetPointSize(point_size)
        return self

    def lw(self, line_width=None) -> int | Self:
        """Set/Get the line width of the object. Same as `line_width()`."""
        if line_width is None:
            return self.properties.GetLineWidth()
        self.properties.SetLineWidth(line_width)
        return self

    def ontop(self, value=True) -> Self:
        """Keep the object always on top of everything else."""
        if value:
            self.properties.SetDisplayLocationToForeground()
        else:
            self.properties.SetDisplayLocationToBackground()
        return self

    def add_observer(self, event_name, func, priority=0) -> int:
        """Add a callback function that will be called when an event occurs."""
        event_name = utils.get_vtk_name_event(event_name)
        idd = self.AddObserver(event_name, func, priority)
        return idd

mapper property writable

Get the internal vtkMapper.

add_observer(event_name, func, priority=0)

Add a callback function that will be called when an event occurs.

Source code in vedo/visual/runtime.py
738
739
740
741
742
def add_observer(self, event_name, func, priority=0) -> int:
    """Add a callback function that will be called when an event occurs."""
    event_name = utils.get_vtk_name_event(event_name)
    idd = self.AddObserver(event_name, func, priority)
    return idd

alpha(value=None)

Set/Get the object opacity.

Source code in vedo/visual/runtime.py
709
710
711
712
713
714
def alpha(self, value=None) -> float | Self:
    """Set/Get the object opacity."""
    if value is None:
        return self.properties.GetOpacity()
    self.properties.SetOpacity(value)
    return self

c(value=False)

Set/Get the object color. Same as color().

Source code in vedo/visual/runtime.py
705
706
707
def c(self, value=False) -> np.ndarray | Self:
    """Set/Get the object color. Same as `color()`."""
    return self.color(value)

color(value=False)

Set/Get the object color. Call with no argument to get the current color.

Source code in vedo/visual/runtime.py
698
699
700
701
702
703
def color(self, value=False) -> np.ndarray | Self:
    """Set/Get the object color. Call with no argument to get the current color."""
    if value is False:
        return self.properties.GetColor()
    self.properties.SetColor(colors.get_color(value))
    return self

coordinate_system(value=None)

Set/get the coordinate system which this coordinate is defined in.

The options are
  1. Display
  2. Normalized Display
  3. Viewport
  4. Normalized Viewport
  5. View
  6. Pose
  7. World
Source code in vedo/visual/runtime.py
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
def coordinate_system(self, value=None) -> Self:
    """
    Set/get the coordinate system which this coordinate is defined in.

    The options are:
        0. Display
        1. Normalized Display
        2. Viewport
        3. Normalized Viewport
        4. View
        5. Pose
        6. World
    """
    coor = self.GetPositionCoordinate()
    if value is None:
        return coor.GetCoordinateSystem()
    coor.SetCoordinateSystem(value)
    return self

layer(value=None)

Set/Get the layer number in the overlay planes into which to render.

Source code in vedo/visual/runtime.py
625
626
627
628
629
630
def layer(self, value=None):
    """Set/Get the layer number in the overlay planes into which to render."""
    if value is None:
        return self.GetLayerNumber()
    self.SetLayerNumber(value)
    return self

lw(line_width=None)

Set/Get the line width of the object. Same as line_width().

Source code in vedo/visual/runtime.py
723
724
725
726
727
728
def lw(self, line_width=None) -> int | Self:
    """Set/Get the line width of the object. Same as `line_width()`."""
    if line_width is None:
        return self.properties.GetLineWidth()
    self.properties.SetLineWidth(line_width)
    return self

off()

Set object visibility.

Source code in vedo/visual/runtime.py
677
678
679
680
def off(self) -> Self:
    """Set object visibility."""
    self.VisibilityOff()
    return self

on()

Set object visibility.

Source code in vedo/visual/runtime.py
672
673
674
675
def on(self) -> Self:
    """Set object visibility."""
    self.VisibilityOn()
    return self

ontop(value=True)

Keep the object always on top of everything else.

Source code in vedo/visual/runtime.py
730
731
732
733
734
735
736
def ontop(self, value=True) -> Self:
    """Keep the object always on top of everything else."""
    if value:
        self.properties.SetDisplayLocationToForeground()
    else:
        self.properties.SetDisplayLocationToBackground()
    return self

pickable(value=True)

Set object pickability.

Source code in vedo/visual/runtime.py
693
694
695
696
def pickable(self, value=True) -> Self:
    """Set object pickability."""
    self.SetPickable(value)
    return self

pos(px=None, py=None)

Set/Get the screen-coordinate position.

Source code in vedo/visual/runtime.py
632
633
634
635
636
637
638
639
640
641
642
643
644
645
def pos(self, px=None, py=None) -> np.ndarray | Self:
    """Set/Get the screen-coordinate position."""
    if isinstance(px, str):
        vedo.logger.error("Use string descriptors only inside the constructor")
        return self
    if px is None:
        return np.array(self.GetPosition(), dtype=int)
    if py is not None:
        p = [px, py]
    else:
        p = px
    assert len(p) == 2, "Error: len(pos) must be 2 for Actor2D"
    self.SetPosition(p)
    return self

ps(point_size=None)

Set/Get the point size of the object. Same as point_size().

Source code in vedo/visual/runtime.py
716
717
718
719
720
721
def ps(self, point_size=None) -> int | Self:
    """Set/Get the point size of the object. Same as `point_size()`."""
    if point_size is None:
        return self.properties.GetPointSize()
    self.properties.SetPointSize(point_size)
    return self

set_position_coordinates(p1, p2)

Set the position coordinates.

Source code in vedo/visual/runtime.py
666
667
668
669
670
def set_position_coordinates(self, p1, p2):
    """Set the position coordinates."""
    self.GetPositionCoordinate().SetValue(*p1)
    self.GetPosition2Coordinate().SetValue(*p2)
    return self

toggle()

Toggle object visibility.

Source code in vedo/visual/runtime.py
682
683
684
685
def toggle(self) -> Self:
    """Toggle object visibility."""
    self.SetVisibility(not self.GetVisibility())
    return self

visibility(value=None)

Get/Set object visibility.

Source code in vedo/visual/runtime.py
687
688
689
690
691
def visibility(self, value=None) -> bool:
    """Get/Set object visibility."""
    if value is not None:
        self.SetVisibility(value)
    return self.GetVisibility()

Actor3DHelper

Helper class for 3D actors.

Source code in vedo/visual/runtime.py
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
class Actor3DHelper:
    """Helper class for 3D actors."""

    def apply_transform(self, LT) -> Self:
        """Apply a linear transformation to the actor."""
        self.transform.concatenate(LT)
        self.actor.SetPosition(self.transform.T.GetPosition())
        self.actor.SetOrientation(self.transform.T.GetOrientation())
        self.actor.SetScale(self.transform.T.GetScale())
        return self

    def pos(self, x=None, y=None, z=None) -> np.ndarray | Self:
        """Set/Get object position."""
        if x is None:  # get functionality
            return self.transform.position

        if z is None and y is None:  # assume x is of the form (x,y,z)
            if len(x) == 3:
                x, y, z = x
            else:
                x, y = x
                z = 0
        elif z is None:  # assume x,y is of the form x, y
            z = 0

        q = self.transform.position
        LT = vedo.LinearTransform().translate([x, y, z] - q)
        return self.apply_transform(LT)

    def shift(self, dx, dy=0, dz=0) -> Self:
        """Add a vector to the current object position."""
        if vedo.utils.is_sequence(dx):
            dx = vedo.utils.make3d(dx)
            dx, dy, dz = dx
        LT = vedo.LinearTransform().translate([dx, dy, dz])
        return self.apply_transform(LT)

    def origin(self, point=None) -> np.ndarray | Self:
        """
        Set/get origin of object.
        Useful for defining pivoting point when rotating and/or scaling.
        """
        if point is None:
            return np.array(self.actor.GetOrigin())
        self.actor.SetOrigin(point)
        return self

    def scale(self, s, origin=True) -> Self:
        """Multiply object size by `s` factor."""
        LT = vedo.LinearTransform().scale(s, origin=origin)
        return self.apply_transform(LT)

    def x(self, val=None) -> float | Self:
        """Set/Get object position along x axis."""
        p = self.transform.position
        if val is None:
            return p[0]
        self.pos(val, p[1], p[2])
        return self

    def y(self, val=None) -> float | Self:
        """Set/Get object position along y axis."""
        p = self.transform.position
        if val is None:
            return p[1]
        self.pos(p[0], val, p[2])
        return self

    def z(self, val=None) -> float | Self:
        """Set/Get object position along z axis."""
        p = self.transform.position
        if val is None:
            return p[2]
        self.pos(p[0], p[1], val)
        return self

    def rotate_x(self, angle) -> Self:
        """Rotate object around x axis."""
        LT = vedo.LinearTransform().rotate_x(angle)
        return self.apply_transform(LT)

    def rotate_y(self, angle) -> Self:
        """Rotate object around y axis."""
        LT = vedo.LinearTransform().rotate_y(angle)
        return self.apply_transform(LT)

    def rotate_z(self, angle) -> Self:
        """Rotate object around z axis."""
        LT = vedo.LinearTransform().rotate_z(angle)
        return self.apply_transform(LT)

    def reorient(self, old_axis, new_axis, rotation=0, rad=False) -> Self:
        """Rotate object to a new orientation."""
        if rad:
            rotation *= 180 / np.pi
        axis = old_axis / np.linalg.norm(old_axis)
        direction = new_axis / np.linalg.norm(new_axis)
        angle = np.arccos(np.dot(axis, direction)) * 180 / np.pi
        self.actor.RotateZ(rotation)
        a, b, c = np.cross(axis, direction)
        self.actor.RotateWXYZ(angle, c, b, a)
        return self

    def bounds(self) -> np.ndarray:
        """
        Get the object bounds.
        Returns a list in format `[xmin,xmax, ymin,ymax, zmin,zmax]`.
        """
        return np.array(self.actor.GetBounds())

    def xbounds(self, i=None) -> float | tuple:
        """Get the bounds `[xmin,xmax]`. Can specify upper or lower with i (0,1)."""
        b = self.bounds()
        if i is not None:
            return b[i]
        return (b[0], b[1])

    def ybounds(self, i=None) -> float | tuple:
        """Get the bounds `[ymin,ymax]`. Can specify upper or lower with i (0,1)."""
        b = self.bounds()
        if i == 0:
            return b[2]
        if i == 1:
            return b[3]
        return (b[2], b[3])

    def zbounds(self, i=None) -> float | tuple:
        """Get the bounds `[zmin,zmax]`. Can specify upper or lower with i (0,1)."""
        b = self.bounds()
        if i == 0:
            return b[4]
        if i == 1:
            return b[5]
        return (b[4], b[5])

    def diagonal_size(self) -> float:
        """Get the diagonal size of the bounding box."""
        b = self.bounds()
        return np.sqrt((b[1] - b[0]) ** 2 + (b[3] - b[2]) ** 2 + (b[5] - b[4]) ** 2)

apply_transform(LT)

Apply a linear transformation to the actor.

Source code in vedo/visual/runtime.py
749
750
751
752
753
754
755
def apply_transform(self, LT) -> Self:
    """Apply a linear transformation to the actor."""
    self.transform.concatenate(LT)
    self.actor.SetPosition(self.transform.T.GetPosition())
    self.actor.SetOrientation(self.transform.T.GetOrientation())
    self.actor.SetScale(self.transform.T.GetScale())
    return self

bounds()

Get the object bounds. Returns a list in format [xmin,xmax, ymin,ymax, zmin,zmax].

Source code in vedo/visual/runtime.py
849
850
851
852
853
854
def bounds(self) -> np.ndarray:
    """
    Get the object bounds.
    Returns a list in format `[xmin,xmax, ymin,ymax, zmin,zmax]`.
    """
    return np.array(self.actor.GetBounds())

diagonal_size()

Get the diagonal size of the bounding box.

Source code in vedo/visual/runtime.py
881
882
883
884
def diagonal_size(self) -> float:
    """Get the diagonal size of the bounding box."""
    b = self.bounds()
    return np.sqrt((b[1] - b[0]) ** 2 + (b[3] - b[2]) ** 2 + (b[5] - b[4]) ** 2)

origin(point=None)

Set/get origin of object. Useful for defining pivoting point when rotating and/or scaling.

Source code in vedo/visual/runtime.py
783
784
785
786
787
788
789
790
791
def origin(self, point=None) -> np.ndarray | Self:
    """
    Set/get origin of object.
    Useful for defining pivoting point when rotating and/or scaling.
    """
    if point is None:
        return np.array(self.actor.GetOrigin())
    self.actor.SetOrigin(point)
    return self

pos(x=None, y=None, z=None)

Set/Get object position.

Source code in vedo/visual/runtime.py
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
def pos(self, x=None, y=None, z=None) -> np.ndarray | Self:
    """Set/Get object position."""
    if x is None:  # get functionality
        return self.transform.position

    if z is None and y is None:  # assume x is of the form (x,y,z)
        if len(x) == 3:
            x, y, z = x
        else:
            x, y = x
            z = 0
    elif z is None:  # assume x,y is of the form x, y
        z = 0

    q = self.transform.position
    LT = vedo.LinearTransform().translate([x, y, z] - q)
    return self.apply_transform(LT)

reorient(old_axis, new_axis, rotation=0, rad=False)

Rotate object to a new orientation.

Source code in vedo/visual/runtime.py
837
838
839
840
841
842
843
844
845
846
847
def reorient(self, old_axis, new_axis, rotation=0, rad=False) -> Self:
    """Rotate object to a new orientation."""
    if rad:
        rotation *= 180 / np.pi
    axis = old_axis / np.linalg.norm(old_axis)
    direction = new_axis / np.linalg.norm(new_axis)
    angle = np.arccos(np.dot(axis, direction)) * 180 / np.pi
    self.actor.RotateZ(rotation)
    a, b, c = np.cross(axis, direction)
    self.actor.RotateWXYZ(angle, c, b, a)
    return self

rotate_x(angle)

Rotate object around x axis.

Source code in vedo/visual/runtime.py
822
823
824
825
def rotate_x(self, angle) -> Self:
    """Rotate object around x axis."""
    LT = vedo.LinearTransform().rotate_x(angle)
    return self.apply_transform(LT)

rotate_y(angle)

Rotate object around y axis.

Source code in vedo/visual/runtime.py
827
828
829
830
def rotate_y(self, angle) -> Self:
    """Rotate object around y axis."""
    LT = vedo.LinearTransform().rotate_y(angle)
    return self.apply_transform(LT)

rotate_z(angle)

Rotate object around z axis.

Source code in vedo/visual/runtime.py
832
833
834
835
def rotate_z(self, angle) -> Self:
    """Rotate object around z axis."""
    LT = vedo.LinearTransform().rotate_z(angle)
    return self.apply_transform(LT)

scale(s, origin=True)

Multiply object size by s factor.

Source code in vedo/visual/runtime.py
793
794
795
796
def scale(self, s, origin=True) -> Self:
    """Multiply object size by `s` factor."""
    LT = vedo.LinearTransform().scale(s, origin=origin)
    return self.apply_transform(LT)

shift(dx, dy=0, dz=0)

Add a vector to the current object position.

Source code in vedo/visual/runtime.py
775
776
777
778
779
780
781
def shift(self, dx, dy=0, dz=0) -> Self:
    """Add a vector to the current object position."""
    if vedo.utils.is_sequence(dx):
        dx = vedo.utils.make3d(dx)
        dx, dy, dz = dx
    LT = vedo.LinearTransform().translate([dx, dy, dz])
    return self.apply_transform(LT)

x(val=None)

Set/Get object position along x axis.

Source code in vedo/visual/runtime.py
798
799
800
801
802
803
804
def x(self, val=None) -> float | Self:
    """Set/Get object position along x axis."""
    p = self.transform.position
    if val is None:
        return p[0]
    self.pos(val, p[1], p[2])
    return self

xbounds(i=None)

Get the bounds [xmin,xmax]. Can specify upper or lower with i (0,1).

Source code in vedo/visual/runtime.py
856
857
858
859
860
861
def xbounds(self, i=None) -> float | tuple:
    """Get the bounds `[xmin,xmax]`. Can specify upper or lower with i (0,1)."""
    b = self.bounds()
    if i is not None:
        return b[i]
    return (b[0], b[1])

y(val=None)

Set/Get object position along y axis.

Source code in vedo/visual/runtime.py
806
807
808
809
810
811
812
def y(self, val=None) -> float | Self:
    """Set/Get object position along y axis."""
    p = self.transform.position
    if val is None:
        return p[1]
    self.pos(p[0], val, p[2])
    return self

ybounds(i=None)

Get the bounds [ymin,ymax]. Can specify upper or lower with i (0,1).

Source code in vedo/visual/runtime.py
863
864
865
866
867
868
869
870
def ybounds(self, i=None) -> float | tuple:
    """Get the bounds `[ymin,ymax]`. Can specify upper or lower with i (0,1)."""
    b = self.bounds()
    if i == 0:
        return b[2]
    if i == 1:
        return b[3]
    return (b[2], b[3])

z(val=None)

Set/Get object position along z axis.

Source code in vedo/visual/runtime.py
814
815
816
817
818
819
820
def z(self, val=None) -> float | Self:
    """Set/Get object position along z axis."""
    p = self.transform.position
    if val is None:
        return p[2]
    self.pos(p[0], p[1], val)
    return self

zbounds(i=None)

Get the bounds [zmin,zmax]. Can specify upper or lower with i (0,1).

Source code in vedo/visual/runtime.py
872
873
874
875
876
877
878
879
def zbounds(self, i=None) -> float | tuple:
    """Get the bounds `[zmin,zmax]`. Can specify upper or lower with i (0,1)."""
    b = self.bounds()
    if i == 0:
        return b[4]
    if i == 1:
        return b[5]
    return (b[4], b[5])

LightKit

A LightKit consists of three lights, a 'key light', a 'fill light', and a 'head light'.

The main light is the key light. It is usually positioned so that it appears like an overhead light (like the sun, or a ceiling light). It is generally positioned to shine down on the scene from about a 45 degree angle vertically and at least a little offset side to side. The key light usually at least about twice as bright as the total of all other lights in the scene to provide good modeling of object features.

The other lights in the kit (the fill light, headlight, and a pair of back lights) are weaker sources that provide extra illumination to fill in the spots that the key light misses. The fill light is usually positioned across from or opposite from the key light (though still on the same side of the object as the camera) in order to simulate diffuse reflections from other objects in the scene.

The headlight, always located at the position of the camera, reduces the contrast between areas lit by the key and fill light. The two back lights, one on the left of the object as seen from the observer and one on the right, fill on the high-contrast areas behind the object. To enforce the relationship between the different lights, the intensity of the fill, back and headlights are set as a ratio to the key light brightness. Thus, the brightness of all the lights in the scene can be changed by changing the key light intensity.

All lights are directional lights, infinitely far away with no falloff. Lights move with the camera.

For simplicity, the position of lights in the LightKit can only be specified using angles: the elevation (latitude) and azimuth (longitude) of each light with respect to the camera, in degrees. For example, a light at (elevation=0, azimuth=0) is located at the camera (a headlight). A light at (elevation=90, azimuth=0) is above the lookat point, shining down. Negative azimuth values move the lights clockwise as seen above, positive values counter-clockwise. So, a light at (elevation=45, azimuth=-20) is above and in front of the object and shining slightly from the left side.

LightKit limits the colors that can be assigned to any light to those of incandescent sources such as light bulbs and sunlight. It defines a special color spectrum called "warmth" from which light colors can be chosen, where 0 is cold blue, 0.5 is neutral white, and 1 is deep sunset red. Colors close to 0.5 are "cool whites" and "warm whites," respectively.

Since colors far from white on the warmth scale appear less bright, key-to-fill and key-to-headlight ratios are skewed by key, fill, and headlight colors. If maintain_luminance is set, LightKit will attempt to compensate for these perceptual differences by increasing the brightness of more saturated colors.

To specify the color of a light, positioning etc you can pass a dictionary with the following keys: - intensity : (float) The intensity of the key light. Default is 1. - ratio : (float) The ratio of the light intensity wrt key light. - warmth : (float) The warmth of the light. Default is 0.5. - elevation : (float) The elevation of the light in degrees. - azimuth : (float) The azimuth of the light in degrees.

Examples:

from vedo import *
lightkit = LightKit(head={"warmth":0.6})
mesh = Mesh(dataurl+"bunny.obj")
plt = Plotter()
plt.remove_lights().add(mesh, lightkit)
plt.show().close()
Source code in vedo/visual/runtime.py
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
class LightKit:
    """
    A LightKit consists of three lights, a 'key light', a 'fill light', and a 'head light'.

    The main light is the key light. It is usually positioned so that it appears like
    an overhead light (like the sun, or a ceiling light).
    It is generally positioned to shine down on the scene from about a 45 degree angle vertically
    and at least a little offset side to side. The key light usually at least about twice as bright
    as the total of all other lights in the scene to provide good modeling of object features.

    The other lights in the kit (the fill light, headlight, and a pair of back lights)
    are weaker sources that provide extra illumination to fill in the spots that the key light misses.
    The fill light is usually positioned across from or opposite from the key light
    (though still on the same side of the object as the camera) in order to simulate diffuse reflections
    from other objects in the scene.

    The headlight, always located at the position of the camera, reduces the contrast between areas lit
    by the key and fill light. The two back lights, one on the left of the object as seen from the observer
    and one on the right, fill on the high-contrast areas behind the object.
    To enforce the relationship between the different lights, the intensity of the fill, back and headlights
    are set as a ratio to the key light brightness.
    Thus, the brightness of all the lights in the scene can be changed by changing the key light intensity.

    All lights are directional lights, infinitely far away with no falloff. Lights move with the camera.

    For simplicity, the position of lights in the LightKit can only be specified using angles:
    the elevation (latitude) and azimuth (longitude) of each light with respect to the camera, in degrees.
    For example, a light at (elevation=0, azimuth=0) is located at the camera (a headlight).
    A light at (elevation=90, azimuth=0) is above the lookat point, shining down.
    Negative azimuth values move the lights clockwise as seen above, positive values counter-clockwise.
    So, a light at (elevation=45, azimuth=-20) is above and in front of the object and shining
    slightly from the left side.

    LightKit limits the colors that can be assigned to any light to those of incandescent sources such as
    light bulbs and sunlight. It defines a special color spectrum called "warmth" from which light colors
    can be chosen, where 0 is cold blue, 0.5 is neutral white, and 1 is deep sunset red.
    Colors close to 0.5 are "cool whites" and "warm whites," respectively.

    Since colors far from white on the warmth scale appear less bright, key-to-fill and key-to-headlight
    ratios are skewed by key, fill, and headlight colors. If `maintain_luminance` is set, LightKit will
    attempt to compensate for these perceptual differences by increasing the brightness of more saturated colors.

    To specify the color of a light, positioning etc you can pass a dictionary with the following keys:
        - `intensity` : (float) The intensity of the key light. Default is 1.
        - `ratio`     : (float) The ratio of the light intensity wrt key light.
        - `warmth`    : (float) The warmth of the light. Default is 0.5.
        - `elevation` : (float) The elevation of the light in degrees.
        - `azimuth`   : (float) The azimuth of the light in degrees.

    Examples:
        ```python
        from vedo import *
        lightkit = LightKit(head={"warmth":0.6})
        mesh = Mesh(dataurl+"bunny.obj")
        plt = Plotter()
        plt.remove_lights().add(mesh, lightkit)
        plt.show().close()
        ```
    """

    def __init__(
        self, key=(), fill=(), back=(), head=(), maintain_luminance=False
    ) -> None:

        self.lightkit = vtki.new("LightKit")
        self.lightkit.SetMaintainLuminance(maintain_luminance)
        self.key = dict(key)
        self.head = dict(head)
        self.fill = dict(fill)
        self.back = dict(back)
        self.update()

    def update(self) -> None:
        """Update the LightKit properties."""
        if "warmth" in self.key:
            self.lightkit.SetKeyLightWarmth(self.key["warmth"])
        if "warmth" in self.fill:
            self.lightkit.SetFillLightWarmth(self.fill["warmth"])
        if "warmth" in self.head:
            self.lightkit.SetHeadLightWarmth(self.head["warmth"])
        if "warmth" in self.back:
            self.lightkit.SetBackLightWarmth(self.back["warmth"])

        if "intensity" in self.key:
            self.lightkit.SetKeyLightIntensity(self.key["intensity"])
        if "ratio" in self.fill:
            self.lightkit.SetKeyToFillRatio(self.fill["ratio"])
        if "ratio" in self.head:
            self.lightkit.SetKeyToHeadRatio(self.head["ratio"])
        if "ratio" in self.back:
            self.lightkit.SetKeyToBackRatio(self.back["ratio"])

        if "elevation" in self.key:
            self.lightkit.SetKeyLightElevation(self.key["elevation"])
        if "elevation" in self.fill:
            self.lightkit.SetFillLightElevation(self.fill["elevation"])
        if "elevation" in self.head:
            self.lightkit.SetHeadLightElevation(self.head["elevation"])
        if "elevation" in self.back:
            self.lightkit.SetBackLightElevation(self.back["elevation"])

        if "azimuth" in self.key:
            self.lightkit.SetKeyLightAzimuth(self.key["azimuth"])
        if "azimuth" in self.fill:
            self.lightkit.SetFillLightAzimuth(self.fill["azimuth"])
        if "azimuth" in self.head:
            self.lightkit.SetHeadLightAzimuth(self.head["azimuth"])
        if "azimuth" in self.back:
            self.lightkit.SetBackLightAzimuth(self.back["azimuth"])

update()

Update the LightKit properties.

Source code in vedo/visual/runtime.py
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
def update(self) -> None:
    """Update the LightKit properties."""
    if "warmth" in self.key:
        self.lightkit.SetKeyLightWarmth(self.key["warmth"])
    if "warmth" in self.fill:
        self.lightkit.SetFillLightWarmth(self.fill["warmth"])
    if "warmth" in self.head:
        self.lightkit.SetHeadLightWarmth(self.head["warmth"])
    if "warmth" in self.back:
        self.lightkit.SetBackLightWarmth(self.back["warmth"])

    if "intensity" in self.key:
        self.lightkit.SetKeyLightIntensity(self.key["intensity"])
    if "ratio" in self.fill:
        self.lightkit.SetKeyToFillRatio(self.fill["ratio"])
    if "ratio" in self.head:
        self.lightkit.SetKeyToHeadRatio(self.head["ratio"])
    if "ratio" in self.back:
        self.lightkit.SetKeyToBackRatio(self.back["ratio"])

    if "elevation" in self.key:
        self.lightkit.SetKeyLightElevation(self.key["elevation"])
    if "elevation" in self.fill:
        self.lightkit.SetFillLightElevation(self.fill["elevation"])
    if "elevation" in self.head:
        self.lightkit.SetHeadLightElevation(self.head["elevation"])
    if "elevation" in self.back:
        self.lightkit.SetBackLightElevation(self.back["elevation"])

    if "azimuth" in self.key:
        self.lightkit.SetKeyLightAzimuth(self.key["azimuth"])
    if "azimuth" in self.fill:
        self.lightkit.SetFillLightAzimuth(self.fill["azimuth"])
    if "azimuth" in self.head:
        self.lightkit.SetHeadLightAzimuth(self.head["azimuth"])
    if "azimuth" in self.back:
        self.lightkit.SetBackLightAzimuth(self.back["azimuth"])