"""
graphviz helper
:githublink:`%|py|5`
"""
import os
import sys
from pyquickhelper.loghelper import run_cmd
from pyquickhelper.helpgen.conf_path_tools import find_graphviz_dot
[docs]def run_graphviz(filename, image, engine="dot"):
"""
Run :epkg:`GraphViz`.
:param filename: filename which contains the graph definition
:param image: output image
:param engine: *dot* or *neato*
:return: output of graphviz
:githublink:`%|py|19`
"""
ext = os.path.splitext(image)[-1]
if ext != ".png":
raise Exception("extension should be .png not " + str(ext))
if sys.platform.startswith("win"):
bin_ = os.path.dirname(find_graphviz_dot())
# if bin not in os.environ["PATH"]:
# os.environ["PATH"] = os.environ["PATH"] + ";" + bin
cmd = '"{0}\\{3}" -Tpng "{1}" -o "{2}"'.format(
bin_, filename, image, engine)
else:
cmd = '"{0}" -Tpng "{1}" -o "{2}"'.format(engine, filename, image)
out, err = run_cmd(cmd, wait=True)
if len(err) > 0:
raise Exception(
"Unable to run Graphviz\nCMD:\n{0}\nOUT:\n{1}\nERR:\n{2}".format(cmd, out, err))
return out
[docs]def edges2gv(vertices, edges):
"""
Converts a graph into a :epkg:`GraphViz` file format.
:param edges: see below
:param vertices: see below
:return: gv format
The function creates a file ``<image>.gv``.
.. runpython::
:showcode:
from mlstatpy.graph.graphviz_helper import edges2gv
gv = edges2gv([(1, "eee", "red")],
[(1, 2, "blue"), (3, 4), (1, 3)])
print(gv)
:githublink:`%|py|56`
"""
memovertex = {}
for v in vertices:
if isinstance(v, tuple):
if len(v) == 1:
memovertex[v[0]] = None
else:
memovertex[v[0]] = v[1:]
else:
memovertex[v] = None
for edge in edges:
i, j = edge[:2]
if i not in memovertex:
memovertex[i] = None
if j not in memovertex:
memovertex[j] = None
li = ["digraph{"]
for k, v in memovertex.items():
if v is None:
li.append("%s ;" % k)
elif len(v) == 1:
li.append("\"%s\" [label=\"%s\"];" % (k, v[0]))
elif len(v) == 2:
li.append("\"%s\" [label=\"%s\",fillcolor=%s,color=%s];" % (
k, v[0], v[1], v[1]))
else:
raise ValueError("unable to understand " + str(v))
for edge in edges:
i, j = edge[:2]
if len(edge) == 2:
li.append("\"%s\" -> \"%s\";" % (i, j))
elif len(edge) == 3:
li.append("\"%s\" -> \"%s\" [label=\"%s\"];" % (i, j, edge[2]))
elif len(edge) == 4:
li.append(
"\"%s\" -> \"%s\" [label=\"%s\",color=%s];" % (i, j, edge[2], edge[3]))
else:
raise ValueError("unable to understand " + str(edge))
li.append("}")
text = "\n".join(li)
return text
[docs]def draw_graph_graphviz(vertices, edges, image, engine="dot"):
"""
Draws a graph using :epkg:`Graphviz`.
:param edges: see below
:param vertices: see below
:param image: output image
:param engine: *dot* or *neato*
:return: :epkg:`Graphviz`
The function creates a file ``<image>.gv``.
::
edges = [ (1,2, label, color), (3,4), (1,3), ... ] , liste d'arcs
vertices = [ (1, label, color), (2), ... ] , liste de noeuds
image = nom d'image (format png)
:githublink:`%|py|119`
"""
text = edges2gv(vertices, edges)
filename = image + ".gv"
with open(filename, "w", encoding="utf-8") as f:
f.write(text)
out = run_graphviz(filename, image, engine=engine)
if not os.path.exists(image):
raise FileNotFoundError(
"GraphViz failed with no reason. '{0}' not found.".format(image))
return out