Skip to content

qref.experimental.rendering

Experimental visualization capabilities for QREF.

Currently, the visualizations are done with graphviz, which does not suport hierarchical structures. Therefore, we have to use a somewhat hacky representation of our routines:

  • The leaf nodes are drawn as a single graphviz node (this is not surprising) with Mrecord shape. This allows to visually separate routine name from its ports.
  • The non-leaf nodes are represented as clusters.
  • Clusters can't use Mrecord shape, and so the ports are drawn as separate nodes.
  • Input and output ports are grouped into subgraphs with the same rank, which forces all inputs / all outputs to be placed in a single column.

Because of the above dichotomy, care has to be taken when constructing edges. - If addressing port of a leaf, it must be specified as graphviz port, e.g: "root.child:in_0" - If addressing port of a non-leaf, you use normal node reference, e.g: "root.child.in_0"

GRAPH_ATTRS module-attribute

GRAPH_ATTRS = {
    "rankdir": "LR",
    "fontname": "Helvetica",
    "splines": "false",
}

LEAF_NODE_KWARGS module-attribute

LEAF_NODE_KWARGS = {
    "shape": "Mrecord",
    "style": "bold",
    "color": "#0288f5",
    "fontsize": "12",
}

PORT_NODE_KWARGS module-attribute

PORT_NODE_KWARGS = {
    "style": "bold",
    "color": "#ffa44a",
    "fontsize": "10",
    "shape": "circle",
}

PORT_GROUP_ATTRS module-attribute

PORT_GROUP_ATTRS = {'rank': 'same'}

CLUSTER_KWARGS module-attribute

CLUSTER_KWARGS = {'style': 'rounded'}

to_graphviz

to_graphviz(routine: RoutineV1) -> graphviz.Digraph

Convert routine encoded with v1 schema to a graphviz DAG.

Source code in src/qref/experimental/rendering.py
@accepts_all_qref_types
def to_graphviz(routine: RoutineV1) -> graphviz.Digraph:
    """Convert routine encoded with v1 schema to a graphviz DAG."""
    dag = graphviz.Digraph(graph_attr=GRAPH_ATTRS)
    _add_routine(ensure_routine(routine), dag)
    return dag

render_entry_point

render_entry_point()
Source code in src/qref/experimental/rendering.py
def render_entry_point():
    parser = ArgumentParser()
    parser.add_argument("input", help="Path to the YAML or JSON file with Routine in V1 schema", type=Path)
    parser.add_argument(
        "output",
        help=(
            "Path to the output file. File format is determined based on the extension, "
            "which should be either .svg or .pdf"
        ),
        type=Path,
    )

    args = parser.parse_args()

    with open(args.input) as f:
        routine = SchemaV1.model_validate(yaml.safe_load(f))

    dag = to_graphviz(routine)
    dag.render(args.output.with_suffix(""), format=args.output.suffix.strip("."))