Skip to content

VisualizeDirectedGraph

Repository source: VisualizeDirectedGraph

Other languages

See (Cxx), (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

VisualizeDirectedGraph.py

#!/usr/bin/env python3

from dataclasses import dataclass

# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.util.execution_model import select_ports
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonDataModel import vtkMutableDirectedGraph
from vtkmodules.vtkFiltersCore import vtkGlyph3D
from vtkmodules.vtkFiltersSources import (
    vtkGlyphSource2D,
    vtkGraphToPolyData
)
from vtkmodules.vtkInfovisLayout import (
    vtkGraphLayout,
    vtkSimple2DLayoutStrategy
)
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper
)
from vtkmodules.vtkViewsInfovis import vtkGraphLayoutView


def main():
    colors = vtkNamedColors()

    g = vtkMutableDirectedGraph()

    v1 = g.AddVertex()
    v2 = g.AddVertex()
    v3 = g.AddVertex()

    g.AddEdge(v1, v2)
    g.AddEdge(v2, v3)
    g.AddEdge(v3, v1)

    strategy = vtkSimple2DLayoutStrategy()
    layout = vtkGraphLayout(input_data=g, layout_strategy=strategy)

    # Do layout manually before handing graph to the view.
    # This allows us to know the positions of edge arrows.
    graph_layout_view = vtkGraphLayoutView()

    # Tell the view to use the vertex layout we provide
    graph_layout_view.SetLayoutStrategyToPassThrough()
    # The arrows will be positioned on a straight line between two
    # vertices so tell the view not to draw arcs for parallel edges
    graph_layout_view.SetEdgeLayoutStrategyToPassThrough()

    # Add the graph to the view. This will render vertices and edges,
    # but not edge arrows.
    graph_layout_view.AddRepresentationFromInputConnection(layout.output_port)

    # Manually create an actor containing the glyphed arrows.
    # Set the position (0: edge start, 1: edge end) where
    # the edge arrows should go.
    graph_to_poly = vtkGraphToPolyData(edge_glyph_output=True, edge_glyph_position=0.98)
    layout >> graph_to_poly

    # Make a simple edge arrow for glyphing.
    arrow_source = vtkGlyphSource2D(scale=0.1, glyph_type=GlyphSource2D.GlyphType.VTK_EDGEARROW_GLYPH)

    # Use Glyph3D to repeat the glyph on all edges.
    arrow_glyph = vtkGlyph3D()
    select_ports(graph_to_poly, 1) >> arrow_glyph
    arrow_source >> select_ports(1, arrow_glyph)

    # Add the edge arrow actor to the view.
    arrow_mapper = vtkPolyDataMapper()
    arrow_glyph >> arrow_mapper
    arrow_actor = vtkActor(mapper=arrow_mapper)

    graph_layout_view.renderer.background = colors.GetColor3d('SaddleBrown')
    graph_layout_view.renderer.background2 = colors.GetColor3d('Wheat')
    graph_layout_view.renderer.AddActor(arrow_actor)

    graph_layout_view.ResetCamera()
    graph_layout_view.Render()
    graph_layout_view.interactor.Start()


@dataclass(frozen=True)
class GlyphSource2D:
    @dataclass(frozen=True)
    class GlyphType:
        VTK_NO_GLYPH: int = 0
        VTK_VERTEX_GLYPH: int = 1
        VTK_DASH_GLYPH: int = 2
        VTK_CROSS_GLYPH: int = 3
        VTK_THICKCROSS_GLYPH: int = 4
        VTK_TRIANGLE_GLYPH: int = 5
        VTK_SQUARE_GLYPH: int = 6
        VTK_CIRCLE_GLYPH: int = 7
        VTK_DIAMOND_GLYPH: int = 8
        VTK_ARROW_GLYPH: int = 9
        VTK_THICKARROW_GLYPH: int = 10
        VTK_HOOKEDARROW_GLYPH: int = 11
        VTK_EDGEARROW_GLYPH: int = 12


if __name__ == '__main__':
    main()