Skip to content

Commit

Permalink
feat(graphviz): support custom node and edge attributes in `ibis.visu…
Browse files Browse the repository at this point in the history
…alize` (#8510)
  • Loading branch information
peter-gy authored Mar 1, 2024
1 parent 5006f2d commit ee821b1
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
30 changes: 29 additions & 1 deletion ibis/expr/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ def visualize(
*,
label_edges: bool = False,
verbose: bool = False,
node_attr: Mapping[str, str] | None = None,
edge_attr: Mapping[str, str] | None = None,
) -> None:
"""Visualize an expression as a GraphViz graph in the browser.
Expand All @@ -175,6 +177,27 @@ def visualize(
Show operation input names as edge labels
verbose
Print the graphviz DOT code to stderr if [](`True`)
node_attr
Mapping of ``(attribute, value)`` pairs set for all nodes.
Options are specified by the ``graphviz`` Python library.
edge_attr
Mapping of ``(attribute, value)`` pairs set for all edges.
Options are specified by the ``graphviz`` Python library.
Examples
--------
Open the visualization of an expression in default browser:
>>> import ibis
>>> left = ibis.table(dict(a="int64", b="string"), name="left")
>>> right = ibis.table(dict(b="string", c="int64", d="string"), name="right")
>>> expr = left.inner_join(right, "b").select(left.a, b=right.c, c=right.d)
>>> expr.visualize(
... format="svg",
... label_edges=True,
... node_attr={"fontname": "Roboto Mono", "fontsize": "10"},
... edge_attr={"fontsize": "8"},
... ) # quartodoc: +SKIP # doctest: +SKIP
Raises
------
Expand All @@ -184,7 +207,12 @@ def visualize(
import ibis.expr.visualize as viz

path = viz.draw(
viz.to_graph(self, label_edges=label_edges),
viz.to_graph(
self,
node_attr=node_attr,
edge_attr=edge_attr,
label_edges=label_edges,
),
format=format,
verbose=verbose,
)
Expand Down
27 changes: 24 additions & 3 deletions ibis/expr/visualize.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ def to_graph(expr, node_attr=None, edge_attr=None, label_edges: bool = False):
graph = Graph.from_bfs(expr.op(), filter=ops.Node)

g = gv.Digraph(
node_attr=node_attr or DEFAULT_NODE_ATTRS,
edge_attr=edge_attr or DEFAULT_EDGE_ATTRS,
node_attr=DEFAULT_NODE_ATTRS | (node_attr or {}),
edge_attr=DEFAULT_EDGE_ATTRS | (edge_attr or {}),
)

g.attr(rankdir="BT")
Expand Down Expand Up @@ -152,6 +152,7 @@ def draw(graph, path=None, format="png", verbose: bool = False):


if __name__ == "__main__":
import json
from argparse import ArgumentParser

from ibis import _
Expand All @@ -173,6 +174,20 @@ def draw(graph, path=None, format="png", verbose: bool = False):
action="store_true",
help="Show operation inputs as edge labels.",
)
p.add_argument(
"-n",
"--node-attr",
type=lambda x: json.loads(x) if x else {},
default="{}",
help='JSON string of node attributes. E.g., \'{"fontname": "Roboto Mono", "fontsize": "10"}\'',
)
p.add_argument(
"-e",
"--edge-attr",
type=lambda x: json.loads(x) if x else {},
default="{}",
help='JSON string of edge attributes. E.g., \'{"fontsize": "8"}\'',
)

args = p.parse_args()

Expand All @@ -191,4 +206,10 @@ def draw(graph, path=None, format="png", verbose: bool = False):
structs=ibis.struct({"a": [1, 2, 3], "b": {"c": 1, "d": 2}}),
)
)
expr.visualize(verbose=args.verbose > 0, label_edges=args.label_edges)

expr.visualize(
verbose=args.verbose > 0,
label_edges=args.label_edges,
node_attr=args.node_attr,
edge_attr=args.edge_attr,
)

0 comments on commit ee821b1

Please sign in to comment.