# Define reusable helpers for the Drawing Helper For DAG-Style Graphs section.
node_labels = {
"need": "Need\nscore",
"intent": "Intent\nsignal",
"match": "Match\nquality",
"engagement": "Engagement",
"renewal": "Renewal\nvalue",
"support": "Support\nload",
}
node_positions = {
"need": (0.10, 0.76),
"intent": (0.10, 0.24),
"match": (0.34, 0.52),
"engagement": (0.66, 0.52),
"renewal": (0.90, 0.72),
"support": (0.90, 0.30),
}
node_colors = {
"need": "#eef2ff",
"intent": "#eef2ff",
"match": "#e0f2fe",
"engagement": "#e0f2fe",
"renewal": "#dcfce7",
"support": "#dcfce7",
}
edge_radii = {
("need", "match"): -0.04,
("intent", "match"): 0.04,
("match", "engagement"): 0.00,
("intent", "renewal"): 0.18,
("engagement", "renewal"): -0.04,
("engagement", "support"): 0.04,
("need", "renewal"): -0.20,
("need", "support"): -0.08,
("intent", "support"): 0.18,
("match", "renewal"): -0.08,
("support", "need"): 0.12,
("renewal", "need"): -0.18,
}
def draw_edge_table_graph(edge_table, title, path, positions=node_positions, labels=node_labels, colors=node_colors):
"""
Draw a learned or true graph in the shared tutorial style.
Parameters
----------
edge_table : pd.DataFrame
Table of source-target edges and endpoint marks to convert, draw, or score.
title : str
Title shown above the plot.
path : str or pathlib.Path
Optional output path for the figure.
positions : dict
Node positions used to draw the graph.
labels : dict[str, str]
Display labels used for graph nodes in the rendered figure.
colors : dict[str, str]
Mapping from node names or groups to display colors.
Returns
-------
pathlib.Path
Path to the saved graph figure drawn from the edge table.
"""
fig, ax = plt.subplots(figsize=(12, 6))
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_axis_off()
for row in edge_table.itertuples(index=False):
source = row.source
target = row.target
mark = row.mark
rad = edge_radii.get((source, target), edge_radii.get((target, source), 0.0))
arrowstyle = "-|>" if mark == "-->" else "-"
linestyle = "--" if mark in {"o->", "<-o", "o-o"} else "-"
ax.annotate(
"",
xy=positions[target],
xytext=positions[source],
arrowprops=dict(
arrowstyle=arrowstyle,
color="#334155",
linewidth=1.5,
mutation_scale=18,
shrinkA=34,
shrinkB=46,
linestyle=linestyle,
connectionstyle=f"arc3,rad={rad}",
),
zorder=1,
)
for node, (x, y) in positions.items():
ax.text(
x,
y,
labels[node],
ha="center",
va="center",
fontsize=10.5,
fontweight="bold",
bbox=dict(
boxstyle="round,pad=0.45",
facecolor=colors.get(node, "#e0f2fe"),
edgecolor="#334155",
linewidth=1.2,
),
zorder=2,
)
ax.set_title(title, pad=18)
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(path, dpi=160, bbox_inches="tight")
plt.show()
return path
true_graph_path = FIGURE_DIR / f"{NOTEBOOK_PREFIX}_true_dag.png"
draw_edge_table_graph(true_edge_table, "True Teaching DAG", true_graph_path)