Exemple #1
0
def BNinference2dot(bn,
                    size=None,
                    engine=None,
                    evs=None,
                    targets=None,
                    nodeColor=None,
                    arcWidth=None,
                    arcColor=None,
                    cmapNode=None,
                    cmapArc=None,
                    dag=None):
    """
  create a pydot representation of an inference in a BN

  Parameters
  ----------
    bn : pyAgrum.BayesNet
      the Bayesian network
    size: str
      size of the rendered graph
    engine:  pyAgrum.Inference
      inference algorithm used. If None, LazyPropagation will be used
    evs: dict
      map of evidence
    targets: set
      set of targets. If targets={} then each node is a target
    nodeColor: dict
      a nodeMap of values to be shown as color nodes (with special color for 0 and 1)
    arcWidth: dict
      a arcMap of values to be shown as bold arcs
    arcColor: dict
      a arcMap of values (between 0 and 1) to be shown as color of arcs
    cmapNode: ColorMap
      color map to show the vals of Nodes
    cmapArc: ColorMap
      color map to show the vals of Arcs
    dag : pyAgrum.DAG
      only shows nodes that have their id in the dag (and not in the whole BN)

  Returns
  -------
    the desired representation of the inference
  """
    if evs is None:
        evs = {}
    if targets is None:
        targets = {}
    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    if cmapArc is None:
        cmapArc = plt.get_cmap(gum.config["notebook", "default_arc_cmap"])

    # defaukt
    maxarcs = 100
    minarcs = 0

    if arcWidth is not None:
        minarcs = min(arcWidth.values())
        maxarcs = max(arcWidth.values())

    startTime = time.time()
    if engine is None:
        ie = gum.LazyPropagation(bn)
    else:
        ie = engine
    ie.setEvidence(evs)
    ie.makeInference()
    stopTime = time.time()

    temp_dir = mkdtemp("", "tmp",
                       None)  # with TemporaryDirectory() as temp_dir:

    dotstr = "digraph structs {\n  fontcolor=\"" + \
             gumcols.getBlackInTheme() + "\";bgcolor=\"transparent\";"

    if gum.config["notebook", "show_inference_time"] == "True":
        dotstr += f"  label=\"Inference in {1000 * (stopTime - startTime):6.2f}ms\";\n"

    dotstr += '  node [fillcolor="' + gum.config["notebook", "default_node_bgcolor"] + \
              '", style=filled,color="' + \
              gum.config["notebook", "default_node_fgcolor"] + '"];' + "\n"
    dotstr += '  edge [color="' + gumcols.getBlackInTheme() + '"];' + "\n"

    showdag = bn.dag() if dag is None else dag
    for nid in showdag.nodes():
        name = bn.variable(nid).name()

        # defaults
        bgcol = gum.config["notebook", "default_node_bgcolor"]
        fgcol = gum.config["notebook", "default_node_fgcolor"]
        if len(targets) == 0 or name in targets or nid in targets:
            bgcol = gum.config["notebook", "figure_facecolor"]

        if nodeColor is not None:
            if name in nodeColor or nid in nodeColor:
                bgcol = gumcols.proba2bgcolor(nodeColor[name], cmapNode)
                fgcol = gumcols.proba2fgcolor(nodeColor[name], cmapNode)

        # 'hard' colour for evidence (?)
        if name in evs or nid in evs:
            bgcol = gum.config["notebook", "evidence_bgcolor"]
            fgcol = gum.config["notebook", "evidence_fgcolor"]

        colorattribute = f'fillcolor="{bgcol}", fontcolor="{fgcol}", color="#000000"'
        if len(targets) == 0 or name in targets or nid in targets:
            filename = temp_dir + \
                       hashlib.md5(name.encode()).hexdigest() + "." + \
                       gum.config["notebook", "graph_format"]
            proba_histogram.saveFigProba(ie.posterior(name),
                                         filename,
                                         bgcolor=bgcol)
            dotstr += f' "{name}" [shape=rectangle,image="{filename}",label="", {colorattribute}];\n'
        else:
            dotstr += f' "{name}" [{colorattribute}]'

    for a in showdag.arcs():
        (n, j) = a
        if arcWidth is None:
            pw = 1
            av = ""
        else:
            if (n, j) in arcWidth:
                if maxarcs == minarcs:
                    pw = 1
                else:
                    pw = 0.1 + 5 * (arcWidth[a] - minarcs) / (maxarcs -
                                                              minarcs)
                av = arcWidth[a]
            else:
                pw = 1
                av = ""

        if arcColor is None:
            col = gumcols.getBlackInTheme()
        else:
            if a in arcColor:
                col = gumcols.proba2color(arcColor[a], cmapArc)
            else:
                col = gumcols.getBlackInTheme()

        dotstr += f' "{bn.variable(n).name()}"->"{bn.variable(j).name()}" [penwidth="{pw}",tooltip="{a}:{av}",color="{col}"];'

    dotstr += '}'

    g = dot.graph_from_dot_data(dotstr)[0]

    # workaround for some badly parsed graph (pyparsing>=3.03)
    g.del_node('"\\n"')

    if size is None:
        size = gum.config["notebook", "default_graph_inference_size"]
    g.set_size(size)
    g.temp_dir = temp_dir

    return g
Exemple #2
0
def BN2dot(bn,
           size=None,
           nodeColor=None,
           arcWidth=None,
           arcColor=None,
           cmapNode=None,
           cmapArc=None,
           showMsg=None):
    """
  create a pydot representation of the BN

  Parameters
  ----------
    bn : pyAgrum.BayesNet
      the Bayesian network
    size: str
      size of the rendered graph
    nodeColor: dict
      a nodeMap of values to be shown as color nodes (with special color for 0 and 1)
    arcWidth: dict
      a arcMap of values to be shown as bold arcs
    arcColor: dict
      a arcMap of values (between 0 and 1) to be shown as color of arcs
    cmapNode: ColorMap
      color map to show the vals of Nodes
    cmapArc: ColorMap
      color map to show the vals of Arcs
    showMsg: dict
      a nodeMap of values to be shown as tooltip

  Returns
  -------
    the desired representation of the Bayesian network
  """
    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    if cmapArc is None:
        cmapArc = plt.get_cmap(gum.config["notebook", "default_arc_cmap"])

    # default
    maxarcs = 100
    minarcs = 0

    if arcWidth is not None:
        minarcs = min(arcWidth.values())
        maxarcs = max(arcWidth.values())

    dotobj = dot.Dot(graph_type='digraph', bgcolor="transparent")

    for n in bn.names():
        if nodeColor is None or n not in nodeColor:
            bgcol = gum.config["notebook", "default_node_bgcolor"]
            fgcol = gum.config["notebook", "default_node_fgcolor"]
            res = ""
        else:
            bgcol = gumcols.proba2bgcolor(nodeColor[n], cmapNode)
            fgcol = gumcols.proba2fgcolor(nodeColor[n], cmapNode)
            res = f" : {nodeColor[n] if showMsg is None else showMsg[n]:2.5f}"

        node = dot.Node('"' + n + '"',
                        style="filled",
                        fillcolor=bgcol,
                        fontcolor=fgcol,
                        tooltip=f'"({bn.idFromName(n)}) {n}{res}"')
        dotobj.add_node(node)

    for a in bn.arcs():
        if arcWidth is None:
            pw = 1
            av = ""
        else:
            if a in arcWidth:
                if maxarcs == minarcs:
                    pw = 1
                else:
                    pw = 0.1 + 5 * (arcWidth[a] - minarcs) / (maxarcs -
                                                              minarcs)
                av = arcWidth[a]
            else:
                pw = 1
                av = 1
        if arcColor is None:
            col = gumcols.getBlackInTheme()
        else:
            if a in arcColor:
                col = gumcols.proba2color(arcColor[a], cmapArc)
            else:
                col = gumcols.getBlackInTheme()

        edge = dot.Edge('"' + bn.variable(a[0]).name() + '"',
                        '"' + bn.variable(a[1]).name() + '"',
                        penwidth=pw,
                        color=col,
                        tooltip=f"{a} : {av}")
        dotobj.add_edge(edge)

    if size is None:
        size = gum.config["notebook", "default_graph_size"]

    # dynamic member makes pylink unhappy
    # pylint: disable=no-member
    dotobj.set_size(size)

    return dotobj
Exemple #3
0
def MN2UGdot(mn,
             size="4",
             nodeColor=None,
             edgeWidth=None,
             edgeColor=None,
             cmapNode=None,
             cmapEdge=None,
             showMsg=None):
    """
  Create a pydot representation of the Markov Network as an undirected graph

  Parameters
  ----------
  mn : pyAgrum.MarkovNet
    The Markov network
  size : int |str
    Size of the rendered graph
  nodeColor : Dict[int,float]
    a nodeMap of values (between 0 and 1) to be shown as color of nodes (with special colors for 0 and 1)
  edgeWidth : Dict[Tuple(int,int),float]
    a edgeMap of values to be shown as width of edges
  edgeColor: Dict[Tuple(int,int),float]
    a edgeMap of values to be shown as color of edges
  cmapNode : matplotlib.color.colormap
    color map to show the vals of Nodes
  cmapEdge
    color map to show the vals of Edges.
  showMsg : Dict[int,str]
     a nodeMap of values to be shown as tooltip

  Returns
  -------
  pydot.Dot
    the desired representation of the MN as a dot graph
  """
    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    if cmapEdge is None:
        cmapEdge = plt.get_cmap(gum.config["notebook", "default_edge_cmap"])

    # default
    maxedges = 100
    minedges = 0

    if edgeWidth is not None:
        minedges = min(edgeWidth.values())
        maxedges = max(edgeWidth.values())

    graph = dot.Dot(graph_type='graph', bgcolor="transparent")

    for n in mn.names():
        if nodeColor is None or n not in nodeColor:
            bgcol = gum.config["notebook", "default_node_bgcolor"]
            fgcol = gum.config["notebook", "default_node_fgcolor"]
            res = ""
        else:
            bgcol = gumcols.proba2bgcolor(nodeColor[n], cmapNode)
            fgcol = gumcols.proba2fgcolor(nodeColor[n], cmapNode)
            res = f" : {nodeColor[n] if showMsg is None else showMsg[n]:2.5f}"

        node = dot.Node('"' + n + '"',
                        style="filled",
                        fillcolor=bgcol,
                        fontcolor=fgcol,
                        tooltip=f'"({mn.idFromName(n)}) {n}{res}"')
        graph.add_node(node)

    for a in mn.edges():
        if edgeWidth is None:
            pw = 1
            av = ""
        else:
            if a in edgeWidth:
                if maxedges == minedges:
                    pw = 1
                else:
                    pw = 0.1 + 5 * (edgeWidth[a] - minedges) / (maxedges -
                                                                minedges)
                av = edgeWidth[a]
            else:
                pw = 1
                av = 1
        if edgeColor is None:
            col = gumcols.getBlackInTheme()
        else:
            if a in edgeColor:
                col = gumcols.proba2color(edgeColor[a], cmapEdge)
            else:
                col = gumcols.getBlackInTheme()

        edge = dot.Edge('"' + mn.variable(a[0]).name() + '"',
                        '"' + mn.variable(a[1]).name() + '"',
                        penwidth=pw,
                        color=col,
                        tooltip=f"{a} : {av}")
        graph.add_edge(edge)

    if size is None:
        size = gum.config["notebook", "default_graph_size"]
    graph.set_size(size)
    return graph
Exemple #4
0
def MNinference2FactorGraphdot(mn,
                               size=None,
                               engine=None,
                               evs=None,
                               targets=None,
                               nodeColor=None,
                               factorColor=None,
                               cmapNode=None):
    """
  create a pydot representation of an inference in a MN as an factor graph

  :param pyAgrum.MarkovNet mn:
  :param string size: size of the rendered graph
  :param pyAgrum Inference engine: inference algorithm used. If None, ShaferShenoyMNInference will be used
  :param dictionnary evs: map of evidence
  :param set targets: set of targets. If targets={} then each node is a target
  :param nodeColor: a nodeMap of values to be shown as color nodes (with special color for 0 and 1)
  :param cmapNode: color map to show the vals of Nodes

  :return: the desired representation of the inference
  """
    if evs is None:
        evs = {}
    if targets is None:
        targets = {}
    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    startTime = time.time()
    if engine is None:
        ie = gum.ShaferShenoyMNInference(mn)
    else:
        ie = engine
    ie.setEvidence(evs)
    ie.makeInference()
    stopTime = time.time()

    from tempfile import mkdtemp
    temp_dir = mkdtemp("", "tmp",
                       None)  # with TemporaryDirectory() as temp_dir:

    dotstr = "graph {\n  layout=\"neato\";\n  fontcolor=\"" + \
             gumcols.getBlackInTheme() + "\";bgcolor=\"transparent\";"

    if gum.config["notebook", "show_inference_time"] == "True":
        dotstr += f'  label="Inference in {1000 * (stopTime - startTime):6.2f}ms";\n'

    dotstr += '  node [fillcolor="' + gum.config["notebook", 'default_node_bgcolor'] + \
              '", style=filled,color="' + \
              gum.config["notebook", "default_node_fgcolor"] + '"];' + "\n"
    dotstr += '  edge [color="' + gumcols.getBlackInTheme() + '"];' + "\n"

    for nid in mn.nodes():
        name = mn.variable(nid).name()

        # defaults
        bgcol = gum.config["notebook", "default_node_bgcolor"]
        fgcol = gum.config["notebook", "default_node_fgcolor"]
        if len(targets) == 0 or name in targets or nid in targets:
            bgcol = gum.config["notebook", "figure_facecolor"]

        if nodeColor is not None:
            if name in nodeColor or nid in nodeColor:
                bgcol = gumcols.proba2bgcolor(nodeColor[name], cmapNode)
                fgcol = gumcols.proba2fgcolor(nodeColor[name], cmapNode)

        # 'hard' colour for evidence (?)
        if name in evs or nid in evs:
            bgcol = gum.config["notebook", "evidence_bgcolor"]
            fgcol = gum.config["notebook", "evidence_fgcolor"]

        colorattribute = f'fillcolor="{bgcol}", fontcolor="{fgcol}", color="#000000"'
        if len(targets) == 0 or name in targets or nid in targets:
            filename = temp_dir + \
                       hashlib.md5(name.encode()).hexdigest() + "." + \
                       gum.config["notebook", "graph_format"]
            saveFigProba(ie.posterior(name), filename, bgcolor=bgcol)
            dotstr += f' "{name}" [shape=rectangle,image="{filename}",label="", {colorattribute}];\n'
        else:
            dotstr += f' "{name}" [shape=rectangle,margin=0.04,width=0,height=0,{colorattribute}];\n'

    def factorname(f):
        return '"f' + "#".join(map(str, sorted(list(f)))) + '"'

    for f in mn.factors():
        if factorColor is None:
            bgcol = gum.config["factorgraph", "default_factor_bgcolor"]
        else:
            bgcol = gumcols.proba2bgcolor(factorColor(f), cmapNode)
        dotstr += f'  {factorname(f)} [style=filled,fillcolor={bgcol},shape=point,width=0.1,height=0.1];\n'

    for f in mn.factors():
        col = gumcols.getBlackInTheme()
        for n in f:
            dotstr += f' {factorname(f)}->"{mn.variable(n).name()}" [tooltip="{f}:{n}",color="{col}",fillcolor="{bgcol}",len="{gum.config["factorgraph", "edge_length_inference"]}"];\n'
    dotstr += '}'

    g = dot.graph_from_dot_data(dotstr)[0]

    # workaround for some badly parsed graph (pyparsing>=3.03)
    g.del_node('"\\n"')

    if size is None:
        size = gum.config["notebook", "default_graph_inference_size"]
    g.set_size(size)
    g.temp_dir = temp_dir

    return g
Exemple #5
0
def MNinference2UGdot(mn,
                      size=None,
                      engine=None,
                      evs=None,
                      targets=None,
                      nodeColor=None,
                      factorColor=None,
                      arcWidth=None,
                      arcColor=None,
                      cmapNode=None,
                      cmapArc=None,
                      view=None):
    """
  create a pydot representation of an inference in a MN as an UG

  :param pyAgrum.MarkovNet mn:
  :param string size: size of the rendered graph
  :param pyAgrum Inference engine: inference algorithm used. If None, ShaferShenoyMNInference will be used
  :param dictionnary evs: map of evidence
  :param set targets: set of targets. If targets={} then each node is a target
  :param nodeColor: a nodeMap of values to be shown as color nodes (with special color for 0 and 1)
  :param arcWidth: a arcMap of values to be shown as bold arcs
  :param arcColor: a arcMap of values (between 0 and 1) to be shown as color of arcs
  :param cmapNode: color map to show the vals of Nodes
  :param cmapArc: color map to show the vals of Arcs

  :return: the desired representation of the inference
  """
    if evs is None:
        evs = {}
    if targets is None:
        targets = {}

    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    if cmapArc is None:
        cmapArc = plt.get_cmap(gum.config["notebook", "default_arc_cmap"])

    # default
    minarcs = 0
    maxarcs = 100

    if arcWidth is not None:
        minarcs = min(arcWidth.values())
        maxarcs = max(arcWidth.values())

    startTime = time.time()
    if engine is None:
        ie = gum.ShaferShenoyMNInference(mn)
    else:
        ie = engine
    ie.setEvidence(evs)
    ie.makeInference()
    stopTime = time.time()

    from tempfile import mkdtemp
    temp_dir = mkdtemp("", "tmp",
                       None)  # with TemporaryDirectory() as temp_dir:

    dotstr = "graph structs {\n  fontcolor=\"" + \
             gumcols.getBlackInTheme() + "\";bgcolor=\"transparent\";"

    if gum.config["notebook", "show_inference_time"] == "True":
        dotstr += f'  label="Inference in {1000 * (stopTime - startTime):6.2f}ms";\n'

    dotstr += '  node [fillcolor="' + gum.config["notebook", "default_node_bgcolor"] + \
              '", style=filled,color="' + \
              gum.config["notebook", "default_node_fgcolor"] + '"];' + "\n"
    dotstr += '  edge [color="' + gumcols.getBlackInTheme() + '"];' + "\n"

    for nid in mn.nodes():
        name = mn.variable(nid).name()

        # defaults
        bgcol = gum.config["notebook", "default_node_bgcolor"]
        fgcol = gum.config["notebook", "default_node_fgcolor"]
        if len(targets) == 0 or name in targets or nid in targets:
            bgcol = gum.config["notebook", "figure_facecolor"]

        if nodeColor is not None:
            if name in nodeColor or nid in nodeColor:
                bgcol = gumcols.proba2bgcolor(nodeColor[name], cmapNode)
                fgcol = gumcols.proba2fgcolor(nodeColor[name], cmapNode)

        # 'hard' colour for evidence (?)
        if name in evs or nid in evs:
            bgcol = gum.config["notebook", "evidence_bgcolor"]
            fgcol = gum.config["notebook", "evidence_fgcolor"]

        colorattribute = f'fillcolor="{bgcol}", fontcolor="{fgcol}", color="#000000"'

        if len(targets) == 0 or name in targets or nid in targets:
            filename = temp_dir + \
                       hashlib.md5(name.encode()).hexdigest() + "." + \
                       gum.config["notebook", "graph_format"]
            saveFigProba(ie.posterior(name), filename, bgcolor=bgcol)
            dotstr += f' "{name}" [shape=rectangle,image="{filename}",label="", {colorattribute}];\n'
        else:
            dotstr += f' "{name}" [{colorattribute}]'

    for a in mn.edges():
        (n, j) = a
        if arcWidth is None:
            pw = 1
            av = ""
        else:
            if (n, j) in arcWidth:
                if maxarcs == minarcs:
                    pw = 1
                else:
                    pw = 0.1 + 5 * (arcWidth[a] - minarcs) / (maxarcs -
                                                              minarcs)
                av = arcWidth[a]
            else:
                pw = 1
                av = ""

        if arcColor is None:
            col = gumcols.getBlackInTheme()
        else:
            if a in arcColor:
                col = gumcols.proba2color(arcColor[a], cmapArc)
            else:
                col = gumcols.getBlackInTheme()

        dotstr += f' "{mn.variable(n).name()}"--"{mn.variable(j).name()}" [penwidth="{pw}",tooltip="{a}:{av}",color="{col}"];'
    dotstr += '}'

    g = dot.graph_from_dot_data(dotstr)[0]

    # workaround for some badly parsed graph (pyparsing>=3.03)
    g.del_node('"\\n"')

    if size is None:
        size = gum.config["notebook", "default_graph_inference_size"]
    g.set_size(size)
    g.temp_dir = temp_dir

    return g
Exemple #6
0
def MN2FactorGraphdot(mn,
                      size=None,
                      nodeColor=None,
                      factorColor=None,
                      cmapNode=None,
                      showMsg=None):
    """
  Create a pydot representation of the Markov Network as a factor graph

  Parameters
  ----------
  mn: pyAgrum.MarkovNet
    the model
  size: float|str
    the size of the rendered graph
  nodeColor: Dict[str,float]
    a nodeMap of values (between 0 and 1) to be shown as color of nodes (with special colors for 0 and 1)
  factorColor:
    a function returning a value (between 0 and 1) to be shown as a color of factor.
  cmapNode: matplotlib.colors.Colormap
    colormap for nodes
  showMsg: Dict[str,str]
    a nodeMap of values to be shown as tooltip

  Returns
  -------
  pydot.Dot
    the desired representation of the MN as a dot graph
  """
    if cmapNode is None:
        cmapNode = plt.get_cmap(gum.config["notebook", "default_node_cmap"])

    graph = dot.Dot(graph_type='graph', bgcolor="transparent", layout="neato")

    for n in mn.names():
        if nodeColor is None or n not in nodeColor:
            bgcol = gum.config["factorgraph", "default_node_bgcolor"]
            fgcol = gum.config["factorgraph", "default_node_fgcolor"]
            res = ""
        else:
            bgcol = gumcols.proba2bgcolor(nodeColor[n], cmapNode)
            fgcol = gumcols.proba2fgcolor(nodeColor[n], cmapNode)
            res = f" : {nodeColor[n] if showMsg is None else showMsg[n]:2.5f}"

        node = dot.Node('"' + n + '"',
                        style="filled",
                        fillcolor=bgcol,
                        fontcolor=fgcol,
                        shape="rectangle",
                        margin=0.04,
                        width=0,
                        height=0,
                        tooltip=f'"({mn.idFromName(n)}) {n}{res}"')
        graph.add_node(node)

    def factorname(factor):
        return '"f' + "#".join(map(str, sorted(list(factor)))) + '"'

    for f in mn.factors():
        if factorColor is None:
            bgcol = gum.config["factorgraph", "default_factor_bgcolor"]
        else:
            bgcol = gumcols.proba2bgcolor(factorColor(f), cmapNode)
        node = dot.Node(factorname(f),
                        style="filled",
                        fillcolor=bgcol,
                        shape="point",
                        width=0.1,
                        height=0.1)
        graph.add_node(node)

    for f in mn.factors():
        for n in f:
            edge = dot.Edge(factorname(f),
                            '"' + mn.variable(n).name() + '"',
                            color=gumcols.getBlackInTheme(),
                            len=gum.config["factorgraph", "edge_length"])
            graph.add_edge(edge)

    if size is None:
        size = gum.config["notebook", "default_graph_size"]
    graph.set_size(size)
    return graph
Exemple #7
0
def _reprInformation(bn, evs=None, size=None, cmap=_INFOcmap, asString=False):
    """
  repr a bn annotated with results from inference : Information and mutual information

  Parameters
  ----------
  bn: pyAgrum.BayesNet
    the model
  evs: Dict[str|int,str|int|List[float]]
    the observations
  size: int|str
    size of the rendered graph
  cmap: matplotlib.colours.Colormap
    the cmap
  asString: bool
    returns the string or display the HTML

  Returns
  -------
  str|None
    return the HTML string or directly display it.
  """
    if size is None:
        size = gum.config["notebook", "default_graph_size"]

    if evs is None:
        evs = {}

    gr, mi, ma = getInformationGraph(bn, evs, size, cmap, withMinMax=True)
    # dynamic member makes pylink unhappy
    # pylint: disable=no-member
    gsvg = IPython.display.SVG(gr.create_svg(encoding="utf-8"))
    width = int(gsvg.data.split("width=")[1].split('"')[1].split("pt")
                [0]) / mpl.pyplot.rcParams['figure.dpi']  # pixel in inches
    if width < 5:
        width = 5

    fig = mpl.figure.Figure(figsize=(width, 1))
    fig.patch.set_alpha(0)
    canvas = fc(fig)
    ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
    norm = mpl.colors.Normalize(vmin=mi, vmax=ma)
    cb1 = mpl.colorbar.ColorbarBase(ax1,
                                    cmap=cmap,
                                    norm=norm,
                                    orientation='horizontal')
    cb1.set_label('Entropy')
    cb1.ax.text(mi,
                -2,
                f"{mi:.4f}",
                ha='left',
                va='top',
                color=gumcols.proba2bgcolor(0.01, cmap))
    cb1.ax.text(ma,
                -2,
                f"{ma:.4f}",
                ha='right',
                va='top',
                color=gumcols.proba2bgcolor(0.99, cmap))
    png = IPython.core.pylabtools.print_figure(
        canvas.figure, "png")  # from IPython.core.pylabtools
    png_legend = f"<img style='vertical-align:middle' src='data:image/png;base64,{encodebytes(png).decode('ascii')}'>"

    sss = f"<div align='center'>{gsvg.data}<br/>{png_legend}</div>"

    if asString:
        return sss

    return IPython.display.display(IPython.display.HTML(sss))