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 g g c c g->c b b b->c e e b->e f f d d c->d a a a->b d->f e->d
structs Inference in   2.76ms a 2025-10-29T14:42:38.795472 image/svg+xml Matplotlib v3.10.7, b 2025-10-29T14:42:38.818767 image/svg+xml Matplotlib v3.10.7, a->b c 2025-10-29T14:42:38.840157 image/svg+xml Matplotlib v3.10.7, b->c e 2025-10-29T14:42:38.886414 image/svg+xml Matplotlib v3.10.7, b->e d 2025-10-29T14:42:38.863169 image/svg+xml Matplotlib v3.10.7, c->d f 2025-10-29T14:42:38.908752 image/svg+xml Matplotlib v3.10.7, d->f e->d g 2025-10-29T14:42:38.930754 image/svg+xml Matplotlib v3.10.7, 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 g g c c g->c b b b->c e e b->e f f d d c->d a a a->b d->f e->d
structs Inference in   1.86ms a 2025-10-29T14:42:39.744791 image/svg+xml Matplotlib v3.10.7, b 2025-10-29T14:42:39.766757 image/svg+xml Matplotlib v3.10.7, a->b c 2025-10-29T14:42:39.787975 image/svg+xml Matplotlib v3.10.7, b->c e 2025-10-29T14:42:39.832762 image/svg+xml Matplotlib v3.10.7, b->e d 2025-10-29T14:42:39.809028 image/svg+xml Matplotlib v3.10.7, c->d f 2025-10-29T14:42:39.854455 image/svg+xml Matplotlib v3.10.7, d->f e->d g 2025-10-29T14:42:39.878069 image/svg+xml Matplotlib v3.10.7, 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 g g c c g->c b b b->c e e b->e f f d d c->d a a a->b d->f e->d
structs Inference in   1.84ms a 2025-10-29T14:42:40.141133 image/svg+xml Matplotlib v3.10.7, b 2025-10-29T14:42:40.161856 image/svg+xml Matplotlib v3.10.7, a->b c 2025-10-29T14:42:40.181924 image/svg+xml Matplotlib v3.10.7, b->c e 2025-10-29T14:42:40.224310 image/svg+xml Matplotlib v3.10.7, b->e d 2025-10-29T14:42:40.203155 image/svg+xml Matplotlib v3.10.7, c->d f 2025-10-29T14:42:40.245634 image/svg+xml Matplotlib v3.10.7, d->f e->d g 2025-10-29T14:42:40.266480 image/svg+xml Matplotlib v3.10.7, 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 :{'C': DotPoint(x=1.375, y=1.25), 'B': DotPoint(x=0.875, y=0.25), 'D': DotPoint(x=1.375, y=2.25), 'A': DotPoint(x=0.375, y=1.25)}
G C C B B C->B D D D->C A A A->B
BN
G C C B B B->C D D D->C A A A->B
BN2
G C C B B B->C D D D->C A A A->B
BN2 with the same layoutas BN
G C C B B B->C D D D->C A A A->B
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()
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 30.05 (stdev=4.97) Inference in   0.16ms D 2025-10-29T14:42:41.205488 image/svg+xml Matplotlib v3.10.7, L L : 30.05 (4.97) D->L E 2025-10-29T14:42:41.230866 image/svg+xml Matplotlib v3.10.7, E->D E->L H 2025-10-29T14:42:41.258246 image/svg+xml Matplotlib v3.10.7, H->L H->E
structs MEU 30.05 (stdev=4.97) Inference in   0.37ms D 2025-10-29T14:42:41.444332 image/svg+xml Matplotlib v3.10.7, L L : 30.05 (4.97) D->L E 2025-10-29T14:42:41.473429 image/svg+xml Matplotlib v3.10.7, E->D E->L H 2025-10-29T14:42:41.515979 image/svg+xml Matplotlib v3.10.7, 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 pyagrum.lib.image as gumimage
from IPython.display import Image # to display the exported images
gumimage.export(bn, "out/test_export.png")
Image(filename="out/test_export.png")

png

bn = gum.fastBN("a->b->d;a->c->d[3]->e;f->b")
gumimage.export(
bn,
"out/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/test_export.png")

png

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

png

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

Link to out/test_export.pdf

bn = gum.loadBN("res/alarm.dsl")
gumimage.exportInference(
bn,
"out/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/test_export.pdf

Other models can also use these functions.

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

Link to out/test_export.pdf

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

Link to out/test_export.pdf

import pyagrum.causal as csl
obs1 = gum.fastBN("Smoking->Cancer")
modele3 = csl.CausalModel(obs1, [("Genotype", ["Smoking", "Cancer"])], True)
gumimage.export(modele3, "out/test_export.png") # a causal model has a toDot method.
Image(filename="out/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/test_export.png") # a JunctionTree has a method jt.toDot()
Image(filename="out/test_export.png")

png

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

Exporting CPTs, sideBySide, explain.Information (and other html strings)

Section titled “Exporting CPTs, sideBySide, explain.Information (and other html strings)”

pyAgrum uses the package playwright in order to export html string. It proposes a function pyagrum.utils.async_html2image. In pyagrum.notebook, the functions get... return HTML objects. The functions show... display the result.

As a result, every pyagrum.lib.notebook.get... can be exported as pdf, png … using pyagrum.utils.async_html2image.

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