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

Creative Commons License

aGrUM

interactive online version

In [1]:
from pylab import *
import matplotlib.pyplot as plt

In [2]:
import pyagrum as gum
import pyagrum.lib.notebook as gnb
In [3]:
bn=gum.fastBN("a->b->c->d;b->e->d->f;g->c")
gnb.flow.row(bn,gnb.getInference(bn))
G d d f f d->f a a b b a->b g g c c g->c e e b->e b->c e->d c->d
structs Inference in   2.52ms a 2025-03-24T11:35:54.617783 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b 2025-03-24T11:35:54.635959 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ a->b c 2025-03-24T11:35:54.653474 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->c e 2025-03-24T11:35:54.710638 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->e d 2025-03-24T11:35:54.692916 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ c->d f 2025-03-24T11:35:54.727581 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ d->f e->d g 2025-03-24T11:35:54.744938 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ g->c

customizing colours and width for model and inference

In [4]:
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()})
../_images/notebooks_98-Tools_customizingAndExportingBNs_6_0.svg
In [5]:
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()})
../_images/notebooks_98-Tools_customizingAndExportingBNs_7_0.svg
In [6]:
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 d d f f d->f a a b b a->b g g c c g->c e e b->e b->c e->d c->d
structs Inference in   1.93ms a 2025-03-24T11:35:55.397212 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b 2025-03-24T11:35:55.414672 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ a->b c 2025-03-24T11:35:55.431949 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->c e 2025-03-24T11:35:55.468505 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->e d 2025-03-24T11:35:55.450162 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ c->d f 2025-03-24T11:35:55.485317 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ d->f e->d g 2025-03-24T11:35:55.502645 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ g->c
In [7]:
import matplotlib.pyplot as plt
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 d d f f d->f a a b b a->b g g c c g->c e e b->e b->c e->d c->d
structs Inference in   2.03ms a 2025-03-24T11:35:55.740449 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b 2025-03-24T11:35:55.760708 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ a->b c 2025-03-24T11:35:55.779394 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->c e 2025-03-24T11:35:55.814627 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ b->e d 2025-03-24T11:35:55.797373 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ c->d f 2025-03-24T11:35:55.831626 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ d->f e->d g 2025-03-24T11:35:55.887975 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ g->c

Modifying graph’s layout

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.

Layout for Bayesian network

In [8]:
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

In [9]:
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 E E D D E->D L L E->L H H H->E H->L D->L
G E E D D E->D L L E->L H H H->E H->L D->L
In [10]:
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 12.02 (stdev=3.07) Inference in   0.10ms D 2025-03-24T11:35:56.727312 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ L L : 12.02 (3.07) D->L E 2025-03-24T11:35:56.746613 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ E->D E->L H 2025-03-24T11:35:56.765192 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ H->L H->E
structs MEU 12.02 (stdev=3.07) Inference in   0.25ms D 2025-03-24T11:35:56.898944 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ L L : 12.02 (3.07) D->L E 2025-03-24T11:35:56.918653 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ E->D E->L H 2025-03-24T11:35:56.937724 image/svg+xml Matplotlib v3.10.1, https://matplotlib.org/ H->L H->E

Exporting model and inference as image

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}.

In [11]:
import pyagrum.lib.image as gumimage
from IPython.display import Image # to display the exported images
In [12]:
gumimage.export(bn,"out/test_export.png")

Image(filename='out/test_export.png')
Out[12]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_17_0.png
In [13]:
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')
Out[13]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_18_0.png
In [14]:
gumimage.exportInference(bn,"out/test_export.png")

Image(filename='out/test_export.png')
Out[14]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_19_0.png
In [15]:
gumimage.export(bn,"out/test_export.pdf")

Link to out/test_export.pdf

exporting inference with evidence

In [16]:
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

Other models can also use these functions.

In [17]:
infdiag=gum.loadID("res/OilWildcatter.bifxml")
gumimage.export(infdiag,"out/test_export.pdf")

Link to out/test_export.pdf

In [18]:
gumimage.exportInference(infdiag,"out/test_export.pdf")

Link to out/test_export.pdf

Exporting any object with toDot() method

In [19]:
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')
Out[19]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_31_0.png
In [20]:
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')
Out[20]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_32_0.png

… or even a string in dot syntax

In [21]:
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')
Out[21]:
../_images/notebooks_98-Tools_customizingAndExportingBNs_34_0.png

Exporting to pyplot

In [22]:
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()
../_images/notebooks_98-Tools_customizingAndExportingBNs_36_0.svg
../_images/notebooks_98-Tools_customizingAndExportingBNs_36_1.svg
../_images/notebooks_98-Tools_customizingAndExportingBNs_36_2.svg

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.

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