Exemple #1
0
 def _cellColors(scale, scalars, cmap, alpha):
     mapper = scale.GetMapper()
     cpoly = mapper.GetInput()
     n = len(scalars)
     lut = vtk.vtkLookupTable()
     lut.SetNumberOfTableValues(n)
     lut.Build()
     for i in range(n):
         r, g, b = colors.colorMap(i, cmap, 0, n)
         lut.SetTableValue(i, r, g, b, alpha)
     arr = numpy_to_vtk(numpy.ascontiguousarray(scalars), deep=True)
     vmin, vmax = numpy.min(scalars), numpy.max(scalars)
     mapper.SetScalarRange(vmin, vmax)
     mapper.SetLookupTable(lut)
     mapper.ScalarVisibilityOn()
     cpoly.GetCellData().SetScalars(arr)
Exemple #2
0
    def color(self, col):
        """Assign a color or a set of colors to a volume 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 voxel 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'])``
        """
        smin, smax = self._imagedata.GetScalarRange()
        volumeProperty = self.GetProperty()
        ctf = vtk.vtkColorTransferFunction()
        self._color = col

        if utils.isSequence(col):
            for i, ci in enumerate(col):
                r, g, b = colors.getColor(ci)
                xalpha = smin + (smax - smin) * i / (len(col) - 1)
                ctf.AddRGBPoint(xalpha, r, g, b)
                #colors.printc('\tcolor at', round(xalpha, 1),
                #              '\tset to', colors.getColorName((r, g, b)), c='b', bold=0)
        elif isinstance(col, str):
            if col in colors.colors.keys() or col in colors.color_nicks.keys():
                r, g, b = colors.getColor(col)
                ctf.AddRGBPoint(smin, r, g, b)  # constant color
                ctf.AddRGBPoint(smax, r, g, b)
            elif colors._mapscales:
                for x in np.linspace(smin, smax, num=64, endpoint=True):
                    r, g, b = colors.colorMap(x,
                                              name=col,
                                              vmin=smin,
                                              vmax=smax)
                    ctf.AddRGBPoint(x, r, g, b)
        elif isinstance(col, int):
            r, g, b = colors.getColor(col)
            ctf.AddRGBPoint(smin, r, g, b)  # constant color
            ctf.AddRGBPoint(smax, r, g, b)
        else:
            colors.printc("volume.color(): unknown input type:", col, c=1)

        volumeProperty.SetColor(ctf)
        volumeProperty.SetInterpolationTypeToLinear()
        #volumeProperty.SetInterpolationTypeToNearest()
        return self
Exemple #3
0
def cellColors(actor, scalars, cmap='jet'):
    """
        Set individual cell colors by setting a scalar
        """
    poly = polydata(actor, False)
    if len(scalars) != poly.GetNumberOfCells():
        colors.printc('Number of scalars != nr. of cells', 1)
        exit()

    lut = vtk.vtkLookupTable()
    lut.SetNumberOfTableValues(len(scalars))
    lut.Build()
    vmin, vmax = np.min(scalars), np.max(scalars)
    n = len(scalars)
    for i in range(n):
        c = colors.colorMap(i, cmap, 0, n)
        lut.SetTableValue(i, c[0], c[1], c[2], 1)
    arr = numpy_to_vtk(np.ascontiguousarray(scalars), deep=True)
    arr.SetName('cellcolors_' + cmap)
    poly.GetCellData().AddArray(arr)
    poly.GetCellData().SetActiveScalars('cellcolors_' + cmap)
    actor.GetMapper().SetScalarRange(vmin, vmax)
    actor.GetMapper().SetLookupTable(lut)
    actor.GetMapper().ScalarVisibilityOn()
Exemple #4
0
def Glyph(actor,
          glyphObj,
          orientationArray="",
          scaleByVectorSize=False,
          c=None,
          alpha=1):
    """
    At each vertex of a mesh, another mesh - a `'glyph'` - is shown with
    various orientation options and coloring.

    Color can be specfied as a colormap which maps the size of the orientation
    vectors in `orientationArray`.

    :param orientationArray: list of vectors, ``vtkAbstractArray``
        or the name of an already existing points array.
    :type orientationArray: list, str, vtkAbstractArray
    :param bool scaleByVectorSize: glyph mesh is scaled by the size of
        the vectors.

    .. hint:: |glyphs.py|_ |glyphs_arrows.py|_

        |glyphs| |glyphs_arrows|
    """
    cmap = None
    # user passing a color map to map orientationArray sizes
    if c in list(colors._mapscales.cmap_d.keys()):
        cmap = c
        c = None

    # user is passing an array of point colors
    if utils.isSequence(c) and len(c) > 3:
        ucols = vtk.vtkUnsignedCharArray()
        ucols.SetNumberOfComponents(3)
        ucols.SetName("glyphRGB")
        for col in c:
            cl = colors.getColor(col)
            ucols.InsertNextTuple3(cl[0] * 255, cl[1] * 255, cl[2] * 255)
        actor.polydata().GetPointData().SetScalars(ucols)
        c = None

    if isinstance(glyphObj, Actor):
        glyphObj = glyphObj.clean().polydata()

    gly = vtk.vtkGlyph3D()
    gly.SetInputData(actor.polydata())
    gly.SetSourceData(glyphObj)
    gly.SetColorModeToColorByScalar()

    if orientationArray != "":
        gly.OrientOn()
        gly.SetScaleFactor(1)

        if scaleByVectorSize:
            gly.SetScaleModeToScaleByVector()
        else:
            gly.SetScaleModeToDataScalingOff()

        if orientationArray == "normals" or orientationArray == "Normals":
            gly.SetVectorModeToUseNormal()
        elif isinstance(orientationArray, vtk.vtkAbstractArray):
            actor.GetMapper().GetInput().GetPointData().AddArray(
                orientationArray)
            actor.GetMapper().GetInput().GetPointData().SetActiveVectors(
                "glyph_vectors")
            gly.SetInputArrayToProcess(0, 0, 0, 0, "glyph_vectors")
            gly.SetVectorModeToUseVector()
        elif utils.isSequence(orientationArray):  # passing a list
            actor.addPointVectors(orientationArray, "glyph_vectors")
            gly.SetInputArrayToProcess(0, 0, 0, 0, "glyph_vectors")
        else:  # passing a name
            gly.SetInputArrayToProcess(0, 0, 0, 0, orientationArray)
            gly.SetVectorModeToUseVector()
        if cmap:
            gly.SetColorModeToColorByVector()
        else:
            gly.SetColorModeToColorByScalar()

    gly.Update()
    pd = gly.GetOutput()

    actor = Actor(pd, c, alpha)

    if cmap:
        lut = vtk.vtkLookupTable()
        lut.SetNumberOfTableValues(512)
        lut.Build()
        for i in range(512):
            r, g, b = colors.colorMap(i, cmap, 0, 512)
            lut.SetTableValue(i, r, g, b, 1)
        actor.mapper.SetLookupTable(lut)
        actor.mapper.ScalarVisibilityOn()
        actor.mapper.SetScalarModeToUsePointData()
        rng = pd.GetPointData().GetScalars().GetRange()
        actor.mapper.SetScalarRange(rng[0], rng[1])

    actor.GetProperty().SetInterpolationToFlat()
    settings.collectable_actors.append(actor)
    return actor
Exemple #5
0
def polarHistogram(
    values,
    title="",
    bins=10,
    r1=0.25,
    r2=1,
    phigap=3,
    rgap=0.05,
    lpos=1,
    lsize=0.05,
    c=None,
    bc="k",
    alpha=1,
    cmap=None,
    deg=False,
    vmin=None,
    vmax=None,
    labels=(),
    showDisc=True,
    showLines=True,
    showAngles=True,
    showErrors=False,
):
    """
    Polar histogram with errorbars.

    :param str title: histogram title
    :param int bins: number of bins in phi
    :param float r1: inner radius
    :param float r2: outer radius
    :param float phigap: gap angle btw 2 radial bars, in degrees
    :param float rgap: gap factor along radius of numeric angle labels
    :param float lpos: label gap factor along radius
    :param float lsize: label size
    :param c: color of the histogram bars, can be a list of length `bins`.
    :param bc: color of the frame and labels
    :param alpha: alpha of the frame
    :param str cmap: color map name
    :param bool deg: input array is in degrees
    :param float vmin: minimum value of the radial axis
    :param float vmax: maximum value of the radial axis
    :param list labels: list of labels, must be of length `bins`
    :param bool showDisc: show the outer ring axis
    :param bool showLines: show lines to the origin
    :param bool showAngles: show angular values
    :param bool showErrors: show error bars

    |polarHisto| |polarHisto.py|_
    """
    k = 180 / np.pi
    if deg:
        values = np.array(values) / k

    dp = np.pi / bins
    vals = []
    for v in values:  # normalize range
        t = np.arctan2(np.sin(v), np.cos(v))
        if t < 0:
            t += 2 * np.pi
        vals.append(t - dp)

    histodata, edges = np.histogram(vals,
                                    bins=bins,
                                    range=(-dp, 2 * np.pi - dp))
    thetas = []
    for i in range(bins):
        thetas.append((edges[i] + edges[i + 1]) / 2)

    if vmin is None:
        vmin = np.min(histodata)
    if vmax is None:
        vmax = np.max(histodata)

    errors = np.sqrt(histodata)
    r2e = r1 + r2
    if showErrors:
        r2e += np.max(errors) / vmax * 1.5

    back = None
    if showDisc:
        back = shapes.Disc(r1=r2e, r2=r2e * 1.01, c=bc, res=1, resphi=360)
        back.z(-0.01).lighting(diffuse=0, ambient=1).alpha(alpha)

    slices = []
    lines = []
    angles = []
    labs = []
    errbars = []

    for i, t in enumerate(thetas):
        r = histodata[i] / vmax * r2
        d = shapes.Disc((0, 0, 0), r1, r1 + r, res=1, resphi=360)
        delta = dp - np.pi / 2 - phigap / k
        d.cutWithPlane(normal=(np.cos(t + delta), np.sin(t + delta), 0))
        d.cutWithPlane(normal=(np.cos(t - delta), np.sin(t - delta), 0))
        if cmap is not None:
            cslice = colors.colorMap(histodata[i], cmap, vmin, vmax)
            d.color(cslice)
        else:
            if c is None:
                d.color(i)
            elif utils.isSequence(c) and len(c) == bins:
                d.color(c[i])
            else:
                d.color(c)
        slices.append(d)

        ct, st = np.cos(t), np.sin(t)

        if showErrors:
            showLines = False
            err = np.sqrt(histodata[i]) / vmax * r2
            errl = shapes.Line(
                ((r1 + r - err) * ct, (r1 + r - err) * st, 0.01),
                ((r1 + r + err) * ct, (r1 + r + err) * st, 0.01),
            )
            errl.alpha(alpha).lw(3).color(bc)
            errbars.append(errl)

        if showDisc:
            if showLines:
                l = shapes.Line((0, 0, -0.01),
                                (r2e * ct * 1.03, r2e * st * 1.03, -0.01))
                lines.append(l)
            elif showAngles:  # just the ticks
                l = shapes.Line(
                    (r2e * ct * 0.98, r2e * st * 0.98, -0.01),
                    (r2e * ct * 1.03, r2e * st * 1.03, -0.01),
                )
                lines.append(l)

        if showAngles:
            if 0 <= t < np.pi / 2:
                ju = "bottom-left"
            elif t == np.pi / 2:
                ju = "bottom-center"
            elif np.pi / 2 < t <= np.pi:
                ju = "bottom-right"
            elif np.pi < t < np.pi * 3 / 2:
                ju = "top-right"
            elif t == np.pi * 3 / 2:
                ju = "top-center"
            else:
                ju = "top-left"
            a = shapes.Text(int(t * k),
                            pos=(0, 0, 0),
                            s=lsize,
                            depth=0,
                            justify=ju)
            a.pos(r2e * ct * (1 + rgap), r2e * st * (1 + rgap), -0.01)
            angles.append(a)

        if len(labels) == bins:
            lab = shapes.Text(labels[i], (0, 0, 0),
                              s=lsize,
                              depth=0,
                              justify="center")
            lab.pos(r2e * ct * (1 + rgap) * lpos / 2,
                    r2e * st * (1 + rgap) * lpos / 2, 0.01)
            labs.append(lab)

    ti = None
    if title:
        ti = shapes.Text(title, (0, 0, 0),
                         s=lsize * 2,
                         depth=0,
                         justify="top-center")
        ti.pos(0, -r2e * 1.15, 0.01)

    mrg = merge(back, lines, angles, labs, ti)
    if mrg:
        mrg.color(bc).alpha(alpha).lighting(diffuse=0, ambient=1)
    rh = Assembly(slices + errbars + [mrg])
    rh.base = np.array([0, 0, 0])
    rh.top = np.array([0, 0, 1])
    return rh
Exemple #6
0
def hexHistogram(
    xvalues,
    yvalues,
    xtitle="",
    ytitle="",
    ztitle="",
    bins=12,
    norm=1,
    fill=True,
    c=None,
    cmap="terrain_r",
    alpha=1,
):
    """
    Build a hexagonal histogram from a list of x and y values.

    :param bool bins: nr of bins for the smaller range in x or y.
    :param float norm: sets a scaling factor for the z axis (freq. axis).
    :param bool fill: draw solid hexagons.
    :param str cmap: color map name for elevation.

    |histoHexagonal| |histoHexagonal.py|_
    """
    if xtitle:
        from vtkplotter import settings

        settings.xtitle = xtitle
    if ytitle:
        from vtkplotter import settings

        settings.ytitle = ytitle
    if ztitle:
        from vtkplotter import settings

        settings.ztitle = ztitle

    xmin, xmax = np.min(xvalues), np.max(xvalues)
    ymin, ymax = np.min(yvalues), np.max(yvalues)
    dx, dy = xmax - xmin, ymax - ymin

    if xmax - xmin < ymax - ymin:
        n = bins
        m = np.rint(dy / dx * n / 1.2 + 0.5).astype(int)
    else:
        m = bins
        n = np.rint(dx / dy * m * 1.2 + 0.5).astype(int)

    src = vtk.vtkPointSource()
    src.SetNumberOfPoints(len(xvalues))
    src.Update()
    pointsPolydata = src.GetOutput()

    #values = list(zip(xvalues, yvalues))
    values = np.stack((xvalues, yvalues), axis=1)
    zs = [[0.0]] * len(values)
    values = np.append(values, zs, axis=1)

    pointsPolydata.GetPoints().SetData(numpy_to_vtk(values, deep=True))
    cloud = Actor(pointsPolydata)

    col = None
    if c is not None:
        col = colors.getColor(c)

    hexs, binmax = [], 0
    ki, kj = 1.33, 1.12
    r = 0.47 / n * 1.2 * dx
    for i in range(n + 3):
        for j in range(m + 2):
            cyl = vtk.vtkCylinderSource()
            cyl.SetResolution(6)
            cyl.CappingOn()
            cyl.SetRadius(0.5)
            cyl.SetHeight(0.1)
            cyl.Update()
            t = vtk.vtkTransform()
            if not i % 2:
                p = (i / ki, j / kj, 0)
            else:
                p = (i / ki, j / kj + 0.45, 0)
            q = (p[0] / n * 1.2 * dx + xmin, p[1] / m * dy + ymin, 0)
            ids = cloud.closestPoint(q, radius=r, returnIds=True)
            ne = len(ids)
            if fill:
                t.Translate(p[0], p[1], ne / 2)
                t.Scale(1, 1, ne * 10)
            else:
                t.Translate(p[0], p[1], ne)
            t.RotateX(90)  # put it along Z
            tf = vtk.vtkTransformPolyDataFilter()
            tf.SetInputData(cyl.GetOutput())
            tf.SetTransform(t)
            tf.Update()
            if c is None:
                col = i
            h = Actor(tf.GetOutput(), c=col, alpha=alpha).flat()
            h.GetProperty().SetSpecular(0)
            h.GetProperty().SetDiffuse(1)
            h.PickableOff()
            hexs.append(h)
            if ne > binmax:
                binmax = ne

    if cmap is not None:
        for h in hexs:
            z = h.GetBounds()[5]
            col = colors.colorMap(z, cmap, 0, binmax)
            h.color(col)

    asse = Assembly(hexs)
    asse.SetScale(1.2 / n * dx, 1 / m * dy, norm / binmax * (dx + dy) / 4)
    asse.SetPosition(xmin, ymin, 0)
    return asse
Exemple #7
0
def RayCaster(volume):
    """
    Generate a ``Plotter`` window for Volume rendering using ray casting.
    Returns the ``Plotter`` object.
    """
    vp = settings.plotter_instance
    if not vp:
        vp = Plotter(axes=4, bg='bb')

    volumeProperty = volume.GetProperty()
    img = volume.imagedata()

    if volume.dimensions()[2] < 3:
        print("Error in raycaster: not enough depth", volume.dimensions())
        return vp
    printc("GPU Ray-casting tool", c="b", invert=1)

    smin, smax = img.GetScalarRange()

    x0alpha = smin + (smax - smin) * 0.25
    x1alpha = smin + (smax - smin) * 0.5
    x2alpha = smin + (smax - smin) * 1.0

    ############################## color map slider
    # Create transfer mapping scalar value to color
    cmaps = [
        "jet",
        "viridis",
        "bone",
        "hot",
        "plasma",
        "winter",
        "cool",
        "gist_earth",
        "coolwarm",
        "tab10",
    ]
    cols_cmaps = []
    for cm in cmaps:
        cols = colorMap(range(0, 21), cm, 0, 20)  # sample 20 colors
        cols_cmaps.append(cols)
    Ncols = len(cmaps)
    csl = (0.9, 0.9, 0.9)
    if sum(getColor(vp.renderer.GetBackground())) > 1.5:
        csl = (0.1, 0.1, 0.1)

    def sliderColorMap(widget, event):
        sliderRep = widget.GetRepresentation()
        k = int(sliderRep.GetValue())
        sliderRep.SetTitleText(cmaps[k])
        volume.color(cmaps[k])

    w1 = vp.addSlider2D(
        sliderColorMap,
        0,
        Ncols - 1,
        value=0,
        showValue=0,
        title=cmaps[0],
        c=csl,
        pos=[(0.8, 0.05), (0.965, 0.05)],
    )
    w1.GetRepresentation().SetTitleHeight(0.018)

    ############################## alpha sliders
    # Create transfer mapping scalar value to opacity
    opacityTransferFunction = volumeProperty.GetScalarOpacity()

    def setOTF():
        opacityTransferFunction.RemoveAllPoints()
        opacityTransferFunction.AddPoint(smin, 0.0)
        opacityTransferFunction.AddPoint(smin + (smax - smin) * 0.1, 0.0)
        opacityTransferFunction.AddPoint(x0alpha, _alphaslider0)
        opacityTransferFunction.AddPoint(x1alpha, _alphaslider1)
        opacityTransferFunction.AddPoint(x2alpha, _alphaslider2)

    setOTF()

    def sliderA0(widget, event):
        global _alphaslider0
        _alphaslider0 = widget.GetRepresentation().GetValue()
        setOTF()

    vp.addSlider2D(sliderA0,
                   0,
                   1,
                   value=_alphaslider0,
                   pos=[(0.84, 0.1), (0.84, 0.26)],
                   c=csl,
                   showValue=0)

    def sliderA1(widget, event):
        global _alphaslider1
        _alphaslider1 = widget.GetRepresentation().GetValue()
        setOTF()

    vp.addSlider2D(sliderA1,
                   0,
                   1,
                   value=_alphaslider1,
                   pos=[(0.89, 0.1), (0.89, 0.26)],
                   c=csl,
                   showValue=0)

    def sliderA2(widget, event):
        global _alphaslider2
        _alphaslider2 = widget.GetRepresentation().GetValue()
        setOTF()

    w2 = vp.addSlider2D(sliderA2,
                        0,
                        1,
                        value=_alphaslider2,
                        pos=[(0.96, 0.1), (0.96, 0.26)],
                        c=csl,
                        showValue=0,
                        title="Opacity levels")
    w2.GetRepresentation().SetTitleHeight(0.016)

    # add a button
    def buttonfuncMode():
        s = volume.mode()
        snew = (s + 1) % 2
        volume.mode(snew)
        bum.switch()

    bum = vp.addButton(
        buttonfuncMode,
        pos=(0.7, 0.035),
        states=["composite", "max proj."],
        c=["bb", "gray"],
        bc=["gray", "bb"],  # colors of states
        font="arial",
        size=16,
        bold=0,
        italic=False,
    )
    bum.status(volume.mode())

    def CheckAbort(obj, event):
        if obj.GetEventPending() != 0:
            obj.SetAbortRender(1)

    vp.window.AddObserver("AbortCheckEvent", CheckAbort)

    # add histogram of scalar
    from vtkplotter.pyplot import cornerHistogram

    plot = cornerHistogram(volume.getPointArray(),
                           bins=25,
                           logscale=1,
                           c="gray",
                           bg="gray",
                           pos=(0.78, 0.065))
    plot.GetPosition2Coordinate().SetValue(0.197, 0.20, 0)
    plot.GetXAxisActor2D().SetFontFactor(0.7)
    plot.GetProperty().SetOpacity(0.5)

    vp.add(plot)
    vp.add(volume)

    return vp