コンテンツにスキップ

Graphvizのノードの配置情報をパースする

PySideのNodeEditorのレイアウト部分にGraphvizを使っているケースが多かったので、
実行結果をパースしてNodeとして取得するる方法をテストしてみました。

import tempfile
import os.path
import subprocess

DOT_FILE = """
strict graph {
  a -- b
  b -- a
  a -- c
}
"""

tmp = tempfile.TemporaryDirectory()

dot_file = os.path.join(tmp.name, 'dot_file.dot')
xdot_txt = os.path.join(tmp.name, 'xdot.txt')

with open(dot_file, 'w') as f:
    f.write(DOT_FILE)

subprocess.call(f"dot -T plain-ext -o {xdot_txt} {dot_file}")

class Node(object):

    def __init__(self):

        self.name = ""
        self.pos_X = 0
        self.pos_Y = 0
        self.size_X = 0
        self.size_Y = 0
        self._inputs = []
        self._outputs = []

    def addInputs(self, n):
        if n not in self._inputs:
            self._inputs.append(n)

    def addOutputs(self, n):
        if n not in self._outputs:
            self._outputs.append(n)


nodes = {}

with open(xdot_txt, 'r') as f:
    for i in f.readlines():
        print(i)
        buff = i.split(" ")
        if buff[0] == "node":
            node = Node()
            node.name = buff[1]
            node.pos_X = float(buff[2])
            node.pos_Y = float(buff[3])
            node.size_X = float(buff[4])
            node.size_Y = float(buff[5])
            nodes[buff[1]] = node
        elif buff[0] == "edge":
            nodes[buff[1]].addOutputs(nodes[buff[2]])
            nodes[buff[2]].addInputs(nodes[buff[1]])

print(nodes)
tmp.cleanup()

実行すると、こんな感じでNodeオブジェクトを取得できます。

Nodeオブジェクトの中身。

まず、出力したいdotファイルをPythonのtempfileモジュールで作ったフォルダ下に
一端出力します。
出力したら、その結果をtxtで出力します。

dot.exeはpngのような画像でも出力できるのですが、

こんな感じのテキストでも出力できるので
パースのしやすさから -T plain-ext 形式でレイアウトした状態の結果を取得します。

https://www.graphviz.org/doc/info/output.html#d:plain-ext

フォーマットのルールはDocs参照。
Docsにはjsonもあるっぽいことが書かれているのですが、Versionのせいなのかなんなのかは
わかりませんがErrorになってしまい使えませんでした。
何故。

NodeEditor回りのもろもろはもちおさんのGitHubにアップされている
mochinode(https://github.com/mochio326/mochinode)
を参考にさせてもらいました。
いつもありがとうございます。


最終更新日: 2020-01-11 15:02:44