Skip to content

Commit

Permalink
feat: allow exporting/rendering monochrome graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkolenz committed May 31, 2023
1 parent fd0da41 commit 6937a8a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 24 deletions.
8 changes: 4 additions & 4 deletions arguebuf/cli/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def render(
max_nodes: t.Optional[int] = None,
prog: str = "dot",
dpi: int = 300,
monochrome: bool = False,
) -> None:
if not output_folder:
output_folder = input_folder
Expand Down Expand Up @@ -116,6 +117,7 @@ def render(
scheme_label=_strip_node_labels if strip_node_labels else None,
edge_style=edge_style,
max_nodes=max_nodes,
monochrome=monochrome,
)
ag.render.graphviz(gv, path_pair.target, prog, dpi)

Expand Down Expand Up @@ -180,8 +182,7 @@ def statistics(
total_scheme_nodes = sum(scheme_nodes)
total_edges = sum(edges)

typer.echo(
f"""Total Graphs: {total_graphs}
typer.echo(f"""Total Graphs: {total_graphs}
Total Atom Nodes: {total_atom_nodes}
Total Scheme Nodes: {total_scheme_nodes}
Expand All @@ -197,5 +198,4 @@ def statistics(
Min. Atom Nodes: {min(atom_nodes)}
Min. Scheme Nodes: {min(scheme_nodes)}
Min. Edges: {min(edges)}"""
)
Min. Edges: {min(edges)}""")
13 changes: 8 additions & 5 deletions arguebuf/dump/_dump_d2.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import textwrap
import typing as t

from arguebuf.model import Graph
from arguebuf.model.edge import Edge
from arguebuf.model.node import AtomNode, SchemeNode, AbstractNode
from arguebuf.schemas.d2 import D2Graph, D2Edge, D2Node, D2Style
from arguebuf.model.node import AbstractNode, AtomNode, SchemeNode
from arguebuf.schemas.d2 import D2Edge, D2Graph, D2Node, D2Style


def dump_d2(
graph: Graph,
atom_label: t.Optional[t.Callable[[AtomNode], str]] = None,
scheme_label: t.Optional[t.Callable[[SchemeNode], str]] = None,
max_nodes: t.Optional[int] = None,
monochrome: bool = False,
) -> t.Optional[D2Graph]:
if len(graph.nodes) > (max_nodes or 1000):
return None
Expand All @@ -27,6 +27,7 @@ def dump_d2(
d2_graph,
major_claim=graph.major_claim == node,
label_func=atom_label,
monochrome=monochrome,
)

for node in graph._scheme_nodes.values():
Expand All @@ -35,6 +36,7 @@ def dump_d2(
d2_graph,
label_func=scheme_label,
major_claim=False,
monochrome=monochrome,
)

for edge in graph._edges.values():
Expand All @@ -47,14 +49,15 @@ def _dump_node(
node: AbstractNode,
g: D2Graph,
major_claim: bool,
monochrome: bool,
label_func: t.Optional[t.Callable[[AbstractNode], str]] = None,
) -> None:
label: str = label_func(node) if label_func else node.label
label = label.replace("\n", "")
if type(node) == AtomNode:
color = node.color(major_claim)
color = node.color(major_claim, monochrome)
else:
color = node.color(major_claim=False)
color = node.color(False, monochrome)

nodeStyle: D2Style = D2Style(
font_color=color.fg,
Expand Down
19 changes: 10 additions & 9 deletions arguebuf/dump/_dump_graphviz.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def dump_graphviz(
edge_attr: t.Optional[t.Mapping[str, str]] = None,
edge_style: t.Optional[EdgeStyle] = None,
max_nodes: t.Optional[int] = None,
monochrome: bool = False,
) -> t.Optional[GraphvizGraph]:
"""Transform a Graph instance into an instance of GraphViz directed graph. Make sure that a GraphViz Executable path is set on your machine for visualization. Refer to the GraphViz library for additional information."""

Expand Down Expand Up @@ -86,10 +87,11 @@ def gv_margin(x):
**node_attr,
}
)
gv_graph.edge_attr.update({"color": "#9E9E9E", **edge_attr})
gv_graph.edge_attr.update(
{"color": "#000000" if monochrome else "#9E9E9E", **edge_attr}
)
gv_graph.graph_attr.update(
{
# "bgcolor": "#000000",
"rankdir": "BT",
"margin": "0",
"nodesep": str(nodesep or 0.25),
Expand All @@ -107,14 +109,11 @@ def gv_margin(x):
graph.major_claim == node,
label_func=atom_label,
wrap_col=wrap_col or 36,
monochrome=monochrome,
)

for node in graph._scheme_nodes.values():
_dump_scheme(
node,
gv_graph,
label_func=scheme_label,
)
_dump_scheme(node, gv_graph, label_func=scheme_label, monochrome=monochrome)

for edge in graph._edges.values():
_dump_edge(edge, gv_graph)
Expand All @@ -127,10 +126,11 @@ def _dump_atom(
g: GraphvizGraph,
major_claim: bool,
wrap_col: int,
monochrome: bool,
label_func: t.Optional[t.Callable[[AtomNode], str]] = None,
) -> None:
"""Submethod used to export Graph object g into GV Graph format."""
color = node.color(major_claim)
color = node.color(major_claim, monochrome)
label = label_func(node) if label_func else node.label

# TODO: Improve wrapping
Expand All @@ -149,11 +149,12 @@ def _dump_atom(
def _dump_scheme(
node: SchemeNode,
g: GraphvizGraph,
monochrome: bool,
label_func: t.Optional[t.Callable[[SchemeNode], str]] = None,
) -> None:
"""Submethod used to export Graph object g into GV Graph format."""

color = node.color(major_claim=False)
color = node.color(False, monochrome)
label = label_func(node) if label_func else node.label

add_gv_node(
Expand Down
13 changes: 10 additions & 3 deletions arguebuf/model/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def __init__(
self.border = border or self.bg


COLOR_MONOCHROME = Color(bg="#ffffff", fg="#000000", border="#000000")


scheme2color: t.Dict[t.Type[Scheme], Color] = {
Support: Color(bg="#4CAF50"),
Attack: Color(bg="#F44336"),
Expand Down Expand Up @@ -98,7 +101,7 @@ def label(self) -> str:
"""Generate a matching node label (e.g., for graphviz)"""

@abstractmethod
def color(self, major_claim: bool) -> Color:
def color(self, major_claim: bool, monochrome: bool) -> Color:
"""Get the color used in OVA based on `category`."""


Expand Down Expand Up @@ -165,8 +168,10 @@ def from_argdown_json(
metadata=Metadata(timestamp, timestamp),
)

def color(self, major_claim: bool) -> Color:
def color(self, major_claim: bool, monochrome: bool) -> Color:
"""Get the color for rendering the node."""
if monochrome:
return COLOR_MONOCHROME

return Color(bg="#0D47A1") if major_claim else Color(bg="#2196F3")

Expand Down Expand Up @@ -218,8 +223,10 @@ def label(self) -> str:

return label

def color(self, major_claim: bool) -> Color:
def color(self, major_claim: bool, monochrome: bool) -> Color:
"""Get the color used in OVA based on `category`."""
if monochrome:
return COLOR_MONOCHROME

return scheme2color[type(self.scheme)] if self.scheme else Color(bg="#009688")

Expand Down
12 changes: 9 additions & 3 deletions tests/test_render_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ def test_render_graph():
an1 = ag.AtomNode(text="Lincoln Chafee just isn't presidential material")
an2 = ag.AtomNode(text="Chafee is president material")
an3 = ag.AtomNode(
text="if elections weren't just popularity contests Chafee would probably do just fine"
text=(
"if elections weren't just popularity contests Chafee would probably do"
" just fine"
)
)
an4 = ag.AtomNode(text="Chafee is just not figurehead material")
an5 = ag.AtomNode(text="Chafee does have good positions")
Expand Down Expand Up @@ -63,5 +66,8 @@ def test_render_graph():
graphviz_graph = ag.dump.graphviz(g)

# Render d2 graph and graphviz graph
ag.render.d2(d2_graph, "test_d2.png")
ag.render.graphviz(graphviz_graph, "test_graphviz.png")
if d2_graph is not None:
ag.render.d2(d2_graph, "test_d2.png")

if graphviz_graph is not None:
ag.render.graphviz(graphviz_graph, "test_graphviz.png")

0 comments on commit 6937a8a

Please sign in to comment.