Source code for vtkplotlib.plots.Text3D

# -*- coding: utf-8 -*-

from vtkplotlib._get_vtk import vtk
import numpy as np

from vtkplotlib.plots.BasePlot import SourcedPlot
from vtkplotlib import geometry as geom
from vtkplotlib.plots.Arrow import Arrow


class Text3D(SourcedPlot):
    """Create floating text in 3D space. Optionally can be set to orientate
    itself to follow the camera (defaults to on) with the **follow_cam**
    argument.

    :param text: The text to be shown.

    :param position: The position of the start of the text, defaults to (0, 0, 0).
    :type position: tuple

    :param follow_cam: Automatically rotates to follow the camera, defaults to True.
    :type follow_cam: bool

    :param scale: The height in world coordinates of one line of text. Use a 3-tuple of values to stretch or squash it.
    :type scale: float or tuple

    :param color: The color of the text, defaults to white.
    :type color: str or tuple or numpy.ndarray

    :param opacity: The translucency of the plot. Ranges from ``0.0`` (invisible) to ``1.0`` (solid).
    :type opacity: float

    :param fig: The figure to plot into, use `None` for no figure, defaults to the output of `vtkplotlib.gcf()`.
    :type fig: :class:`~vtkplotlib.figure` or :class:`~vtkplotlib.QtFigure`

    :param label: Give the plot a label to use in a `legend`.
    :type label: str

    :return: text3D plot object
    :rtype: `vtkplotlib.text3d`


    .. warning::

        This can't be passed about between figures if ``follow_cam=True``
        (the default). The figure who's camera it follows is frozen to the
        figure given to it on first construction.

    .. seealso:: ``vpl.text`` for 2D text at a fixed point on the screen.
    .. seealso:: ``vpl.annotate`` for a convenient way to label features with text and an arrow.


    """

    def __init__(self, text, position=(0, 0, 0), follow_cam=True, scale=1,
                 color=None, opacity=None, fig="gcf", label=None):
        super().__init__(fig)
        # Create the 3D text and the associated mapper and follower (a type of
        # actor). Position the text so it is displayed over the origin of the
        # axes.

        self.source = vtk.vtkVectorText()
        # This chunk is different to how most plots objects construct
        # themselves. So super().connect() wont work unfortunately.
        self.actor = vtk.vtkFollower()
        self.actor.SetMapper(self.mapper)
        self.property = self.actor.GetProperty()
        self.mapper.SetInputConnection(self.source.GetOutputPort())

        self.__setstate__(locals())

        self.fig += self

        if follow_cam:
            self.actor.SetCamera(self.fig.renderer.GetActiveCamera())

    @property
    def text(self):
        return self.source.GetText()

    @text.setter
    def text(self, text):
        if not isinstance(text, str):
            text = str(text)
        self.source.SetText(text)

    position = property(lambda self: self.actor.GetPosition(),
                        lambda self, position: self.actor.SetPosition(position))

    scale = property(lambda self: self.actor.GetScale())

    @scale.setter
    def scale(self, scale):
        if np.isscalar(scale):
            scale = (scale,) * 3
        self.actor.SetScale(*scale)


[docs]def annotate(points, text, direction, text_color="w", arrow_color="k", distance=3., text_size=1., fig="gcf"): """Annotate a feature with an arrow pointing at a point and a text label on the reverse end of the arrow. This is just a convenience call to `arrow()` and `text3d()`. See there for just one or the other. :param points: The position of the feature where the arrow's tip should be. :type points: numpy.ndarray :param text: The text to put in the label. :param direction: The direction from the feature to the text position as a unit vector. :type direction: numpy.ndarray :param text_color: The color of the label, defaults to 'w'. :param arrow_color: The color of the arrow, defaults to 'k'. :param distance: The distance from the feature to the label. :param text_size: The height of one line of text, can have 3 values, defaults to 1.0. :type text_size: float or tuple :param fig: The figure to plot into, use `None` for no figure, defaults to the output of `vtkplotlib.gcf()`. :type fig: :class:`~vtkplotlib.figure` or :class:`~vtkplotlib.QtFigure` :return: An (`arrow`, `text3d`) pair. The arrow points to the highest point and the text is placed at a point **distance** above (where above also is determined by direction). If **text** is not a `str` then it is automatically converted to one. .. code-block:: python import vtkplotlib as vpl import numpy as np # Create a ball at a point in space. point = np.array([1, 2, 3]) vpl.scatter(point) vpl.annotate(point, "This ball is at {}".format(point), np.array([0, 0, 1])) vpl.show() If multiple points are given the farthest in the direction **direction** is selected. The idea is to try to prevent the annotations ending up in amongst the plots or, when plotting meshes, inside the mesh. .. code-block:: python import vtkplotlib as vpl import numpy as np # Create several balls. points = np.random.uniform(-30, 30, (30, 3)) vpl.scatter(points, color=np.random.random(points.shape)) vpl.annotate(points, "This ball is the highest", np.array([0, 0, 1]), text_color="k", arrow_color="orange" ) vpl.annotate(points, "This ball is the lowest", np.array([0, 0, -1]), text_color="rust", arrow_color="hunter green" ) vpl.show() """ point = geom.highest(points, direction) arrow = Arrow(point + (distance - .5 * text_size) * direction, point, color=arrow_color, fig=fig) text = Text3D(text, point + distance * direction, color=text_color, scale=text_size, fig=fig) return arrow, text