interactive notebooks

Creative Commons License

aGrUM

interactive online version

pyAgrum can easily interact with other applications. In this notebook, we propose for example some application tracks with notebook ipywidgets to make the exploration of graphical models and their inferences more interactive.

In [1]:
import pyagrum as gum
import pyagrum.lib.notebook as gnb

Listeners and progress bars

In [2]:
import glob
import os.path
from tqdm.auto import tqdm


class TqdmProgressBarLoadListener:
  def __init__(self, filename: str):
    self.pbar = tqdm(total=100, desc=filename, bar_format="{desc}: {percentage:3.0f}%|{bar}|")

  def update(self, progress):
    if progress == 200:
      self.pbar.close()
    else:
      self.pbar.update()
      self.pbar.display()


bns = {}
for ext in ["dsl", "bif"]:
  for name in glob.glob(f"res/*.{ext}"):
    progbar = TqdmProgressBarLoadListener(name)
    bns[os.path.basename(name)] = gum.loadBN(name, listeners=[lambda progress: progbar.update(progress)])

Which should give you something like

progess bars

Animated graphs

ipywidget can be used with different types of objects. Let’s say that you have a class that show the arcs of a Bayesian network only the mutual information of this arc is above a certain threshold:

In [3]:
import pydot as dot


class InformationViewer:
  def __init__(self, bn: gum.BayesNet):
    self.bn = bn

    ie = gum.LazyPropagation(bn)
    self._min = float("inf")
    self._max = float("-inf")
    self._arcs = {}
    for x, y in bn.arcs():
      nameX = bn.variable(x).name()
      nameY = bn.variable(y).name()
      ie.addJointTarget({nameX, nameY})
      info = gum.InformationTheory(ie, [nameX], [nameY])
      m = info.mutualInformationXY()
      if self._min > m:
        self._min = m
      if self._max < m:
        self._max = m
      self._arcs[x, y] = m

  def min(self):
    return self._min

  def max(self):
    return self._max

  def showBN(self, minVal: float = 0):
    graph = dot.Dot(graph_type="digraph", bgcolor="transparent")
    bgcol = gum.config["notebook", "default_node_bgcolor"]
    fgcol = gum.config["notebook", "default_node_fgcolor"]
    for n in self.bn.names():
      graph.add_node(dot.Node('"' + n + '"', style="filled", fillcolor=bgcol, fontcolor=fgcol))
    for x, y in self.bn.arcs():
      graph.add_edge(
        dot.Edge(
          '"' + self.bn.variable(x).name() + '"',
          '"' + self.bn.variable(y).name() + '"',
          style="invis" if self._arcs[x, y] < minVal else "",
        )
      )

    size = gum.config["notebook", "default_graph_size"]
    graph.set_size(size)
    return graph


view = InformationViewer(bns["alarm.dsl"])
print(f"min={view.min()} ,max={view.max()}")
gnb.sideBySide(view.showBN(0.3), view.showBN(0.5), captions=["BN filtered by $MI>0.3$", "BN filtered by $MI>0.5$"])
min=7.940532588368974e-06 ,max=0.8850119269966232
G PVSAT PVSAT SAO2 SAO2 STROKEVOLUME STROKEVOLUME CO CO STROKEVOLUME->CO VENTMACH VENTMACH VENTTUBE VENTTUBE VENTMACH->VENTTUBE PAP PAP LVFAILURE LVFAILURE LVEDVOLUME LVEDVOLUME HISTORY HISTORY CATECHOL CATECHOL HYPOVOLEMIA HYPOVOLEMIA HYPOVOLEMIA->STROKEVOLUME HYPOVOLEMIA->LVEDVOLUME CVP CVP LVEDVOLUME->CVP PCWP PCWP LVEDVOLUME->PCWP HREKG HREKG HR HR ERRCAUTER ERRCAUTER HRSAT HRSAT ERRCAUTER->HRSAT ERRLOWOUTPUT ERRLOWOUTPUT HRBP HRBP KINKEDTUBE KINKEDTUBE VENTLUNG VENTLUNG PRESS PRESS DISCONNECT DISCONNECT INTUBATION INTUBATION MINVOL MINVOL VENTALV VENTALV SHUNT SHUNT ANAPHYLAXIS ANAPHYLAXIS TPR TPR VENTALV->PVSAT ARTCO2 ARTCO2 VENTALV->ARTCO2 BP BP MINVOLSET MINVOLSET MINVOLSET->VENTMACH PULMEMBOLUS PULMEMBOLUS EXPCO2 EXPCO2 CO->BP INSUFFANESTH INSUFFANESTH VENTLUNG->VENTALV VENTLUNG->EXPCO2 HR->HRSAT HR->HRBP FIO2 FIO2
BN filtered by $MI>0.3$
G PVSAT PVSAT SAO2 SAO2 STROKEVOLUME STROKEVOLUME CO CO STROKEVOLUME->CO VENTMACH VENTMACH VENTTUBE VENTTUBE VENTMACH->VENTTUBE PAP PAP LVFAILURE LVFAILURE LVEDVOLUME LVEDVOLUME HISTORY HISTORY CATECHOL CATECHOL HYPOVOLEMIA HYPOVOLEMIA CVP CVP LVEDVOLUME->CVP PCWP PCWP LVEDVOLUME->PCWP HREKG HREKG HR HR ERRCAUTER ERRCAUTER HRSAT HRSAT ERRLOWOUTPUT ERRLOWOUTPUT HRBP HRBP KINKEDTUBE KINKEDTUBE VENTLUNG VENTLUNG PRESS PRESS DISCONNECT DISCONNECT INTUBATION INTUBATION MINVOL MINVOL VENTALV VENTALV SHUNT SHUNT ANAPHYLAXIS ANAPHYLAXIS TPR TPR ARTCO2 ARTCO2 BP BP MINVOLSET MINVOLSET PULMEMBOLUS PULMEMBOLUS EXPCO2 EXPCO2 INSUFFANESTH INSUFFANESTH VENTLUNG->VENTALV VENTLUNG->EXPCO2 FIO2 FIO2
BN filtered by $MI>0.5$

Now we can use this class for animation :

In [4]:
import ipywidgets as widgets


def interactive_view(threshold: float):
  return view.showBN(threshold)


widgets.interact(interactive_view, threshold=(view.min(), view.max(), (view.max() - view.min()) / 100.0));

Which should give you something like

informationVisualisation

Vizualizing evidence impact

In [5]:
from ipywidgets import interact, fixed

bn = bns["asia.bif"]

asia = list(bn["visit_to_Asia"].labels())
smoking = list(bn["smoking"].labels())
XraY = list(bn["positive_XraY"].labels())
cig_ped_day = gum.RangeVariable("cigarettes_per_day", "cigarettes_per_day in [0, 10]?", 0, 10)
bn.add(cig_ped_day)


@interact(
  bn=fixed(bn),
  visit_to_Asia=asia,
  smoking=smoking,
  positive_XraY=XraY,
  smoked_cigarettes=(cig_ped_day.minVal(), cig_ped_day.maxVal(), 1),
)
def evidence_impact(bn, visit_to_Asia, smoking, positive_XraY, smoked_cigarettes):
  evs = {
    "visit_to_Asia": visit_to_Asia,
    "smoking": smoking,
    "positive_XraY": positive_XraY,
    "cigarettes_per_day": smoked_cigarettes,
  }
  gnb.showInference(bn, evs=evs)