Skip to content

Customizing and exporting graphical models and CPTs as image (pdf, png)

Creative Commons LicenseaGrUMinteractive online version
from pylab import *
import matplotlib.pyplot as plt
import pyagrum as gum
import pyagrum.lib.notebook as gnb
bn = gum.fastBN("a->b->c->d;b->e->d->f;g->c")
gnb.flow.row(bn, gnb.getInference(bn))
G b b c c b->c e e b->e d d c->d f f d->f a a a->b e->d g g g->c
structs Inference in   0.91ms a 2026-09-28T17:47:40.639721 image/svg+xml Matplotlib v3.11.2, b 2026-09-28T17:47:40.669290 image/svg+xml Matplotlib v3.11.2, a->b c 2026-09-28T17:47:40.705181 image/svg+xml Matplotlib v3.11.2, b->c e 2026-09-28T17:47:40.794613 image/svg+xml Matplotlib v3.11.2, b->e d 2026-09-28T17:47:40.750966 image/svg+xml Matplotlib v3.11.2, c->d f 2026-09-28T17:47:40.824255 image/svg+xml Matplotlib v3.11.2, d->f e->d g 2026-09-28T17:47:40.886969 image/svg+xml Matplotlib v3.11.2, g->c

customizing colours and width for model and inference

Section titled “customizing colours and width for model and inference”
def nodevalue(n):
return 0.5 if n in "aeiou" else 0.7
def arcvalue(a):
return (10 - a[0]) * a[1]
def arcvalue2(a):
return (a[0] + a[1] + 5) / 22
gnb.showBN(
bn,
nodeColor={n: nodevalue(n) for n in bn.names()},
arcWidth={a: arcvalue(a) for a in bn.arcs()},
arcLabel={a: f"v={arcvalue(a):02d}" for a in bn.arcs()},
arcColor={a: arcvalue2(a) for a in bn.arcs()},
)

svg

gnb.showInference(
bn,
targets={"a", "g", "f", "b"},
evs={"e": 0},
nodeColor={n: nodevalue(n) for n in bn.names()},
arcWidth={a: arcvalue(a) for a in bn.arcs()},
)

svg

gnb.flow.row(
gnb.getBN(bn, nodeColor={n: nodevalue(n) for n in bn.names()}, arcWidth={a: arcvalue(a) for a in bn.arcs()}),
gnb.getInference(bn, nodeColor={n: nodevalue(n) for n in bn.names()}, arcWidth={a: arcvalue(a) for a in bn.arcs()}),
)
G b b c c b->c e e b->e d d c->d f f d->f a a a->b e->d g g g->c
structs Inference in   0.32ms a 2026-09-28T17:47:42.491219 image/svg+xml Matplotlib v3.11.2, b 2026-09-28T17:47:42.533821 image/svg+xml Matplotlib v3.11.2, a->b c 2026-09-28T17:47:42.584342 image/svg+xml Matplotlib v3.11.2, b->c e 2026-09-28T17:47:42.669980 image/svg+xml Matplotlib v3.11.2, b->e d 2026-09-28T17:47:42.627089 image/svg+xml Matplotlib v3.11.2, c->d f 2026-09-28T17:47:42.708645 image/svg+xml Matplotlib v3.11.2, d->f e->d g 2026-09-28T17:47:42.760739 image/svg+xml Matplotlib v3.11.2, g->c
mycmap = plt.get_cmap("Reds")
formyarcs = plt.get_cmap("winter")
gnb.flow.row(
gnb.getBN(
bn,
nodeColor={n: nodevalue(n) for n in bn.names()},
arcColor={a: arcvalue2(a) for a in bn.arcs()},
cmapNode=mycmap,
cmapArc=formyarcs,
),
gnb.getInference(
bn,
nodeColor={n: nodevalue(n) for n in bn.names()},
arcColor={a: arcvalue2(a) for a in bn.arcs()},
arcWidth={a: arcvalue(a) for a in bn.arcs()},
cmapNode=mycmap,
cmapArc=formyarcs,
),
)
G b b c c b->c e e b->e d d c->d f f d->f a a a->b e->d g g g->c
structs Inference in   0.52ms a 2026-09-28T17:47:43.245616 image/svg+xml Matplotlib v3.11.2, b 2026-09-28T17:47:43.289830 image/svg+xml Matplotlib v3.11.2, a->b c 2026-09-28T17:47:43.324130 image/svg+xml Matplotlib v3.11.2, b->c e 2026-09-28T17:47:43.482852 image/svg+xml Matplotlib v3.11.2, b->e d 2026-09-28T17:47:43.364639 image/svg+xml Matplotlib v3.11.2, c->d f 2026-09-28T17:47:43.524477 image/svg+xml Matplotlib v3.11.2, d->f e->d g 2026-09-28T17:47:43.561626 image/svg+xml Matplotlib v3.11.2, g->c

Every graph or graphical models can be translated into a pyDot’s representaton (a pydot.Dot object). In this graphical representation, it is possible to manipulate the positions of the node. pyAgrum proposes two functions gum.utils.dot_layout to help modifying this layout.

import pyagrum as gum
import pyagrum.lib.notebook as gnb
import pyagrum.lib.utils as gutils
import pyagrum.lib.bn2graph as gumb2g
bn = gum.fastBN("A->B<-C<-D")
bn2 = gum.fastBN("A->B->C<-D")
graph = gumb2g.BN2dot(bn)
graph2 = gumb2g.BN2dot(bn2)
l = gutils.dot_layout(graph)
print(f"Layout proposed by dot for BN :{l}")
gutils.apply_dot_layout(graph2, l)
graph3 = gumb2g.BN2dot(bn2)
## l["C"],l["A"]=l["A"],l["C"]
l["D"], l["C"], l["B"], l["A"] = (
gutils.DotPoint(0, 0),
gutils.DotPoint(1, 1),
gutils.DotPoint(2, 2),
gutils.DotPoint(3, 3),
)
gutils.apply_dot_layout(graph3, l)
gnb.flow.row(bn, bn2, graph2, graph3, captions=["BN", "BN2", "BN2 with the same layoutas BN", "Layout changed by hand"])
Layout proposed by dot for BN :{'D': DotPoint(x=0.375, y=2.25), 'A': DotPoint(x=1.375, y=1.25), 'B': DotPoint(x=0.875, y=0.25), 'C': DotPoint(x=0.375, y=1.25)}
G D D C C D->C A A B B A->B C->B
BN
G D D C C D->C A A B B A->B B->C
BN2
G D D C C D->C A A B B A->B B->C
BN2 with the same layoutas BN
G D D C C D->C A A B B A->B B->C
Layout changed by hand

Layout for other graphical models and for inference

Section titled “Layout for other graphical models and for inference”
import pyagrum as gum
import pyagrum.lib.notebook as gnb
import pyagrum.lib.utils as gutils
import pyagrum.lib.id2graph as gum2gr
model = gum.fastID("*D->$L<-E<-H->L;E->D")
gnb.flow.add(model)
gum.config.push()
gum.config["influenceDiagram", "utility_shape"] = "diamond"
figure = gum2gr.ID2dot(model)
l = gutils.dot_layout(figure)
## changing LAYOUT
## making some horizontal space
for i, p in l.items():
l[i] = gutils.DotPoint(1.5 * p.x, p.y)
## E at the vertical of L, at the horizontal of D
l["E"] = gutils.DotPoint(l["L"].x, l["D"].y)
## H symetric of D w.r.t (EL)
l["H"] = gutils.DotPoint(2 * l["E"].x - l["D"].x, l["D"].y)
gutils.apply_dot_layout(figure, l)
gnb.flow.add(figure)
gnb.flow.display()
gum.config.pop()
G D D C C D->C A A B B A->B C->B
BN
G D D C C D->C A A B B A->B B->C
BN2
G D D C C D->C A A B B A->B B->C
BN2 with the same layoutas BN
G D D C C D->C A A B B A->B B->C
Layout changed by hand
E E D D E->D L L E->L H H H->E H->L D->L
E E D D E->D L L E->L H H H->E H->L D->L
import pyagrum as gum
import pyagrum.lib.notebook as gnb
import pyagrum.lib.utils as gutils
import pyagrum.lib.id2graph as gum2gr
model = gum.fastID("*D->$L<-E<-H->L;E->D")
gnb.flow.add(gnb.getInference(model))
figure = gum2gr.LIMIDinference2dot(model, evs={}, targets={}, size=None, engine=None)
l = gutils.dot_layout(figure)
## changing LAYOUT
## making some horizontal space
for i, p in l.items():
l[i] = gutils.DotPoint(3 * p.x, p.y)
## E at the vertical of L, at the horizontal of D
l["E"] = gutils.DotPoint(l["L"].x, l["D"].y)
l["D"] = gutils.DotPoint(l["D"].x / 2, l["D"].y)
l["H"] = gutils.DotPoint(l["L"].x * 3 / 2, l["D"].y)
gutils.apply_dot_layout(figure, l)
gnb.flow.add(figure)
gnb.flow.display()
structs MEU 26.02 (stdev=5.69) Inference in   0.12ms D 2026-09-28T17:47:45.623037 image/svg+xml Matplotlib v3.11.2, L L : 26.02 (5.69) D->L E 2026-09-28T17:47:45.661980 image/svg+xml Matplotlib v3.11.2, E->D E->L H 2026-09-28T17:47:45.695210 image/svg+xml Matplotlib v3.11.2, H->L H->E
structs MEU 26.02 (stdev=5.69) Inference in   0.36ms D 2026-09-28T17:47:45.948060 image/svg+xml Matplotlib v3.11.2, L L : 26.02 (5.69) D->L E 2026-09-28T17:47:45.974925 image/svg+xml Matplotlib v3.11.2, E->D E->L H 2026-09-28T17:47:46.003858 image/svg+xml Matplotlib v3.11.2, H->L H->E

Exporting as image (pdf, png, etc.) has been gathered in 2 functions : pyagrum.lib.image.export() and pyagrum.lib.image.exportInference(). The argument are the same as for pyagrum.notebook.show{Model} and pyagrum.notebook.show{Inference}.

import os
import pyagrum.lib.image as gumimage
from IPython.display import Image # to display the exported images
os.makedirs("out/export", exist_ok=True)
gumimage.export(bn, "out/export/test_export.png")
Image(filename="out/export/test_export.png")

png

bn = gum.fastBN("a->b->d;a->c->d[3]->e;f->b")
gumimage.export(
bn,
"out/export/test_export.png",
nodeColor={"a": 1, "b": 0.3, "c": 0.4, "d": 0.1, "e": 0.2, "f": 0.5},
arcColor={(0, 1): 0.2, (1, 2): 0.5},
arcWidth={(0, 3): 0.4, (3, 2): 0.5, (2, 4): 0.6},
)
Image(filename="out/export/test_export.png")

png

gumimage.exportInference(bn, "out/export/test_export.png")
Image(filename="out/export/test_export.png")

png

gumimage.export(bn, "out/export/test_export.pdf")

Link to out/export/test_export.pdf

bn = gum.loadBN("res/alarm.bgum")
gumimage.exportInference(
bn,
"out/export/test_export.pdf",
evs={"CO": 1, "VENTLUNG": 1},
targets={
"VENTALV",
"CATECHOL",
"HR",
"MINVOLSET",
"ANAPHYLAXIS",
"STROKEVOLUME",
"ERRLOWOUTPUT",
"HBR",
"PULMEMBOLUS",
"HISTORY",
"BP",
"PRESS",
"CO",
},
size="15!",
)

Link to out/export/test_export.pdf

Other models can also use these functions.

infdiag = gum.loadID("res/OilWildcatter.bgum")
gumimage.export(infdiag, "out/export/test_export.pdf")

Link to out/export/test_export.pdf

gumimage.exportInference(infdiag, "out/export/test_export.pdf")

Link to out/export/test_export.pdf

obs1 = gum.fastBN("Smoking->Cancer")
modele3 = gum.CausalModel(obs1, [("Genotype", ["Smoking", "Cancer"])], True)
gumimage.export(modele3, "out/export/test_export.png") # a causal model has a toDot method.
Image(filename="out/export/test_export.png")

png

bn = gum.fastBN("a->b->c->d;b->e->d->f;g->c")
ie = gum.LazyPropagation(bn)
jt = ie.junctionTree()
gumimage.export(jt, "out/export/test_export.png") # a JunctionTree has a method jt.toDot()
Image(filename="out/export/test_export.png")

png

gumimage.export(
jt.toDotWithNames(bn), "out/export/test_export.png"
) # jt.toDotWithNames(bn) creates a dot-string for a junction tree with names of variables
Image(filename="out/export/test_export.png")

png

import matplotlib.pyplot as plt
bn = gum.fastBN("A->B->C<-D")
plt.imshow(gumimage.export(bn))
plt.show()
plt.imshow(gumimage.exportInference(bn, size="15!"))
plt.show()
plt.figure(figsize=(10, 10))
plt.imshow(gumimage.exportInference(bn, size="15!"))
plt.show()

svg

svg

svg

pyagrum.lib.image.export() handles any object with a _repr_html_() method (CPTs, inspectBN, sideBySide, explain.Information…) in addition to graphical models.

bn = gum.fastBN("A->B<-C", 3)
gumimage.export(bn.cpt("B"), "out/export/cpt_B_.pdf")
gumimage.export(gnb.getSideBySide(bn, bn.cpt("A"), bn.cpt("B"), bn.cpt("C")), "out/export/sideBySide.pdf")
import pyagrum.explain as gexplain
gumimage.export(gexplain.getInformation(bn), "out/export/informationBN.pdf")
gumimage.export(gnb.inspectBN(bn), "out/export/inspectBN.pdf")

PDF export adds margins around the content (default: 50px horizontal, 37px vertical). These can be changed via gum.config — using push/pop to restore defaults afterwards.

gum.config.push()
gum.config.typed["notebook", "export_pdf_margin_x"] = 10
gum.config.typed["notebook", "export_pdf_margin_y"] = 10
gumimage.export(bn.cpt("B"), "out/export/cpt_B_tight.pdf")
gum.config.pop()
gum.config.push()
gum.config.typed["notebook", "export_pdf_margin_x"] = 30
gum.config.typed["notebook", "export_pdf_margin_y"] = 30
gumimage.export(gnb.inspectBN(bn), "out/export/tootight_inspectBN.pdf")
gum.config.pop()