Python ブロック図を生成するスクリプトを作成したい

はじめに

Pythonでブロック図を作成したいです。

とりあえず、ブロック2つで作ってみました。

サンプルコード

import matplotlib.pyplot as plt
import matplotlib.patches as patches


class _Wire_config:
    def __init__(self, name, x, y, direction, connect_to="", disable=False):
        self.name = name
        self.x = x
        self.y = y
        self.connect_to = connect_to
        self.disable = disable
        if direction == "in":
            self.direction = "->"
        elif direction == "out":
            self.direction = "<-"
        else:
            self.direction = "<->"


class Create_circuit:
    def __init__(self, dut, blocks):
        self.fig = plt.figure()
        self.ax = plt.axes()

        height = 200 + 10*self._count(dut, blocks)
        
        # Draw DUT
        start_w = 100
        start_h = 50
        end_w = start_w + 100
        end_h = start_h + height - 50

        self._draw_block(start_w, start_h, end_w, end_h, "dut")
        dut_ports = [i for i in self._draw_port(dut, end_w, start_h, "dut")]

        # Draw Verification Components
        start_w = 300
        start_h = 50
        end_w = start_w + 100

        for k, v in blocks.items():
            end_h = start_h + 50 + 10*len(v)
            self._draw_block(start_w, start_h, end_w, end_h, k)

            # Draw Verification Component Ports
            for component_port in self._draw_port(v, start_w, start_h):
                if component_port.disable:
                    continue

                # Draw line from dut to component
                for dut_port in dut_ports:
                    if component_port.connect_to != dut_port.name:
                        continue

                    self.ax.annotate(
                        "", xy=(component_port.x, component_port.y),
                        xytext=(dut_port.x, dut_port.y), size=10, 
                        arrowprops={"arrowstyle": component_port.direction, "color": "black"}
                    )

            start_h = end_h + 10  # For Next Component

    def run(self):
        plt.axis("scaled")  # サイズをいい感じにする
        plt.axis("off")  # 目盛りを消す
        plt.show()
        self.fig.savefig("circuit.png")

    def _draw_block(self, start_w, start_h, end_w, end_h, name):
        self.ax.add_patch(patches.Rectangle(
            xy=(start_w, start_h),
            width=end_w - start_w, height=end_h - start_h,
            fill=False,
        ))

        plt.text((start_w+end_w)/2, start_h, name, ha="center",
            fontdict=dict(fontsize=8), bbox=dict(boxstyle="round",color="white"))

    def _draw_port(self, block, start_w, start_h, mode=""):
        _offset_h = 10
        for k, v in block.items():
            if mode=="dut":
                self.ax.add_patch(patches.Circle(
                    xy=(start_w, start_h + _offset_h), radius=3, color="black"))

                plt.text(start_w - 5, start_h + _offset_h, k,
                    fontdict=dict(fontsize=6), ha="right")

                yield _Wire_config(
                    k, start_w, start_h + _offset_h,
                    v["direction"],
                    v["connect_to"],
                    v["disable"],
                )
            else:
                self.ax.add_patch(patches.Circle(
                    xy=(start_w, start_h + _offset_h), radius=3, color="black"))

                plt.text(start_w + 5, start_h + _offset_h, k,
                    fontdict=dict(fontsize=6), ha="left")

                yield _Wire_config(
                    k, start_w, start_h + _offset_h,
                    v["direction"],
                    v["connect_to"],
                    v["disable"],
                )
            _offset_h += 20  # For next port

    def _count(self, dut, block):
        cnt = 0
        for i in block.values():
            cnt += len(i.keys())
        return max([len(dut.keys()), cnt])

if __name__ == "__main__":
    dut = {
        "clk": {"direction": "in", "connect_to": "", "disable": True},
        "reset_n": {"direction": "in", "connect_to": "", "disable": True},
        "din": {"direction": "in", "connect_to": "", "disable": ""},
        "valid": {"direction": "in", "connect_to": "", "disable": ""},
        "ready": {"direction": "out", "connect_to": "", "disable": ""},
        "dout": {"direction": "out", "connect_to": "", "disable": ""},
    }
    blocks = {
        "Model": {
            "clk": {"direction": "in", "connect_to": "clk", "disable": True},
            "reset_n": {"direction": "in", "connect_to": "reset_n", "disable": True},
            "data": {"direction": "out", "connect_to": "din", "disable": ""},
            "valid": {"direction": "out", "connect_to": "valid", "disable": ""},
            "ready": {"direction": "in", "connect_to": "ready", "disable": ""},
        },
    }
    a = Create_circuit(dut, blocks)
    a.run()
実行結果

まとめ

Pythonでブロック図を作成するスクリプトを作成しました

コメント

タイトルとURLをコピーしました