Draw.ioのグラフ図を自動レイアウトするプログラムを生成AIに作らせてみた

## はじめに
最近ITの関連では、生成AIに関する話題を目にしない日はないくらいですね。
でも実際にはどう使っていけばいいか、正直悩むところです。

さしあたっては、まず生成AIにプログラムを作らせてみるのが手を付けやすいかなということで、タイトルにあるようなプログラムを作らせてみようと思いやってみました。この記事ではそこでやったこと、わかったことを記載します。

ところで、生成AIに要件を指示してプログラムを作る手法をVibeCodingというんですね。初めて知りました。

## 前提環境
今回の作業は以下の環境で実施しました。
- 生成AI: ChatGPT4.1
- OS: Windows11
- python: 3.13.3
- pip: 25.0.1
- Visual Studio: 2022Pro

## 対象プログラム
システム開発をしていると、RDBMSを使用することが多々あるかと思います。RDBMSといえば、ER図ですよね。
新規開発の際は、ERモデリングから実装という形で作業をするのが普通ですが、たまに既存システムのテーブルレイアウトからER図を起こしたりすることがありませんか？

その場合、エンティティとリレーションはCREATE TABLE文やFOREIGN KEY制約などから把握することができますが、それを図として描いた時の配置情報は、当たり前ですが取得することができません。エンティティ数が数十程度であれば人手でもなんとかレイアウトできますが、数百くらいになってくるとレイアウトを整えるだけで一苦労です。

専用のERモデリングツールであれば、リバースエンジニアリングという形でモデルを構築し、もしかしたらレイアウトの自動調整までやってくれるかもしれません。ただそこまでカバーしてくれるような、モデリングツールは高額なのでは。。。と思うと、ITに携わる者としては、なんとかそのあたりを程よくできそうなプログラムが作れないかと思ったりしました。

とはいっても、実際にそういうプログラムを作るためには「グラフ」に関する知識が必要そうです。残念ながらこれまでの人生で、そのような知識を習得する機会には恵まれませんでした。そこで、生成AIです。

プログラムで「グラフ」の処理をさせるためには、プログラムが図の情報を取得できる必要があります。その点でいえば、<a href="https://www.drawio.com/">draw.io</a>というツールは、ファイルがXMLとして保存されるようです。拡張子.drawioとなっていますが、実際には以下のようにテキストとして読める形式になっています。

```xml:draw.ioファイル
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/25.0.1 Chrome/128.0.6613.186 Electron/32.2.6 Safari/537.36" version="25.0.1">
  <diagram name="ページ1" id="X1_xDsdXHNz_inRhL5BB">
    <mxGraphModel dx="1098" dy="820" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
      <root>
        <mxCell id="0" />
        <mxCell id="1" parent="0" />
        <mxCell id="7Afdme-BcSAetjFRxMsf-1" value="Node1" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
          <mxGeometry x="150" y="260" width="120" height="80" as="geometry" />
        </mxCell>

（以下省略）
```

無料で使用できてちょうどいいツールだということで、draw.ioを使用して描いたグラフを対象に、グラフの自動レイアウトをするプログラムを作ってみることにしました。

## 最初のプロンプト
まずこんなプロンプトからスタートしてみました。

```text:prompt1
以下のテキストはdraw.ioで描画した有向グラフです。しかし、ノードとリレーションが折り重なっています。
位置を調整して、ノードやリレーションができるだけ折り重ならないようにしてください。
特にノードについては重なっている箇所がないよう調整してください。
```

そうしたら、いきなり折り重なりを解消するPythonプログラムを提示してきました。以下の内容になります。
（本来はマークダウンでほかのメッセージとかも返してきていましたが、それらをうまく記載できないので主となるプログラム部分を中心に掲載します）
```python:response1
draw.io（mxGraphModel XML）のノードが重なっている場合、ノードの座標（x, y）を読み取り、ノードが重ならないように再配置することができます。  
以下は、**ノード同士が重ならないように座標を自動調整し、ノードのy座標を縦方向に適度に並べて出力するPythonスクリプト例**です。

このスクリプトは、重なりを解消するためにノードを縦一列に並べる簡単なアルゴリズムを採用しています。draw.ioのXMLファイルを修正し、上書き保存できます。

---

import xml.etree.ElementTree as ET

def adjust_node_positions(input_file, output_file, x_start=100, y_start=100, x_step=200, y_step=120):
    # XMLを読み込む
    tree = ET.parse(input_file)
    root = tree.getroot()

    # ノード(mxCellでvertex=1)のリストを取得
    nodes = []
    for cell in root.iter('mxCell'):
        if cell.attrib.get('vertex') == '1':
            geom = cell.find('mxGeometry')
            if geom is not None:
                nodes.append((cell, geom))

    # ノードを等間隔で縦一列に配置（x: x_start, y: y_start + n*y_step）
    for idx, (cell, geom) in enumerate(nodes):
        geom.set('x', str(x_start))
        geom.set('y', str(y_start + idx * y_step))
        # （必要に応じてノード幅や高さも調整可能）

    # 保存
    tree.write(output_file, encoding='utf-8', xml_declaration=True)

if __name__ == "__main__":
    # 入力ファイル名と出力ファイル名
    infile = "input_overlap.drawio.xml"    # ここに元のdrawio XMLファイル名
    outfile = "output_adjusted.drawio.xml" # ここに出力ファイル名

    adjust_node_positions(infile, outfile)
    print(f"ノードの重なりを解消し、{outfile} として保存しました。")
```

まずはdraw.ioファイルを読んで処理できるかを確認するつもりだったのですが、最初からプログラムを提示してきました。正直ちょっと驚きでした。

このプログラムを、実際に次のようなつながりを持つグラフを、すべてのノードが重なるような状態にしたファイルを対象に実行してみることにしました。

***
###### グラフ概観
![グラフ概観](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/eb73c371-7cff-4920-ae45-2cd7f67132d4.png "グラフ概観")

###### 折り重ねたグラフ
![折り重ねたグラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/579d8cd1-e24f-4624-90e7-bd35bd9b308a.png "折り重ねたグラフ")
***
プログラムで処理した結果の図がこれです。
###### 縦1列に展開
![縦1列に展開](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/bb5622c8-b1ea-43d6-b6ae-13660dd494bb.png "縦1列に展開")

チャットの応答に記載のとおり、ノードが縦1列に並んでいます。
あっさりとこんなプログラムができあがってしまいました。もちろん、人が見るにはまだまだ不十分ですが、その後の展開にちょっと期待を抱きました。

## もっと見やすいレイアウトを追求
先ほどの図ではノードの折り重なりは解消されていますが、すべてのノードが縦1列に並んでいます。ノード数が100とかになると、ノード間のつながりもほぼわからなくなりそう。なので、もう少し見やすいレイアウトを追求することにしました。続いてのプロンプトは以下のものにしました。

```text:prompt2
だいぶ見やすいですが、やはりリレーションが重なりすぎてどこが起点でどこが終点かわかりづらいですね。
もっといいアルゴリズムはありますか？
```

応答で返された内容は以下のとおりでした。
```text:response2
とても良いご指摘です！
ノードを縦一列や単純なグリッドに並べるだけでは、リレーション（エッジ）が交差・重複しやすく、複雑なグラフになるほど「どこからどこへ」が直感的に分かりにくいです。
見やすい有向グラフレイアウトのための代表的な配置アルゴリズム
1. 階層（Layered/Sugiyama）レイアウト

    特徴：有向グラフを、「上から下」「左から右」などの明確な階層構造で描画します。
    利点：リレーション（エッジ）がほぼ一方向に流れ、エッジの交差が最小化されます。
    draw.ioの自動レイアウトや、Graphvizのdotエンジンもこの系統です。

2. Force-directed（力学モデル）レイアウト

    特徴：ノード間にばねや電荷のような力を与え、全体の重なりやエッジの交差を減らすように自動配置します。
    利点：特に無向グラフや小～中規模のグラフで、全体のバランスよい見た目になりやすい。
    有向グラフにも使えますが、階層構造が分かりづらいこともあります。

3. ツリー（Tree）レイアウト

    特徴：明確な親子構造（木構造）がある場合、親から子へ分岐する形で配置します。
    利点：エッジが交差しにくく、階層構造が分かりやすい。

draw.ioやPythonでの具体的な対応方法
A. draw.ioでの解決策

    draw.ioには「自動レイアウト」機能があります。図を選択し、**配置→階層レイアウト（Arrange → Layout → Hierarchical）**を使うことで階層レイアウトが簡単に適用できます。

B. Pythonによる自動レイアウト生成例

有名なグラフ描画ライブラリ「networkx」と「pygraphviz」（dotエンジン）を使えば、階層レイアウト（Sugiyama）を自動計算し、ノード座標をdraw.io XMLに反映できます。

サンプル：階層レイアウトの自動計算とdraw.io XMLへの組み込み

networkxとpygraphvizをインストール
    pip install networkx pygraphviz
```
```python
# 階層レイアウトに基づくノード位置調整スクリプト例
import xml.etree.ElementTree as ET
import networkx as nx

def parse_drawio_nodes_and_edges(file_path):
    tree = ET.parse(file_path)
    root = tree.getroot()

    nodes, edges = {}, []
    for cell in root.iter('mxCell'):
        if cell.attrib.get('vertex') == '1':
            geom = cell.find('mxGeometry')
            if geom is not None:
                nodes[cell.attrib['id']] = {
                    'cell': cell,
                    'geom': geom,
                    'label': cell.attrib.get('value', '')
                }
        elif cell.attrib.get('edge') == '1':
            src = cell.attrib.get('source')
            tgt = cell.attrib.get('target')
            if src and tgt:
                edges.append((src, tgt))
    return tree, root, nodes, edges

def hierarchical_layout(nodes, edges):
    G = nx.DiGraph()
    for nid, node in nodes.items():
        G.add_node(nid)
    G.add_edges_from(edges)
    # pygraphvizのdotを使って階層レイアウト
    try:
        pos = nx.nx_agraph.graphviz_layout(G, prog='dot')
    except Exception as e:
        print("pygraphvizが必要です。pip install pygraphviz を実行してください。")
        raise
    return pos

def apply_positions_to_drawio(nodes, pos, x_shift=50, y_shift=50, scale=1.2):
    # draw.ioの座標系に合わせて座標を適用
    for nid, (x, y) in pos.items():
        node = nodes[nid]
        node['geom'].set('x', str(int(x * scale + x_shift)))
        node['geom'].set('y', str(int(y * scale + y_shift)))

def main():
    infile = "input_overlap.drawio.xml"
    outfile = "output_hierarchical.drawio.xml"
    tree, root, nodes, edges = parse_drawio_nodes_and_edges(infile)
    pos = hierarchical_layout(nodes, edges)
    apply_positions_to_drawio(nodes, pos)
    tree.write(outfile, encoding='utf-8', xml_declaration=True)
    print(f"階層レイアウトを適用し、{outfile} として保存しました。draw.ioで開いて確認してください。")

if __name__ == "__main__":
    main()
```

この指示に従いパッケージをインストール。すると、以下のようなエラーが返されました。
```shell:pip install error
PS D:\Test> pip install networkx pygraphviz
Requirement already satisfied: networkx in c:\python313\lib\site-packages (3.4.2)
Collecting pygraphviz
  Using cached pygraphviz-1.14.tar.gz (106 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: pygraphviz
  Building wheel for pygraphviz (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building wheel for pygraphviz (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [94 lines of output]
      C:\Users\user1\AppData\Local\Temp\pip-build-env-cymior43\overlay\Lib\site-packages\setuptools\config\_apply_pyprojecttoml.py:82: SetuptoolsDeprecationWarning: `project.license` as a TOML table is deprecated
      !!

              ********************************************************************************
              Please use a simple string containing a SPDX expression for `project.license`. You can also use `project.license-files`. (Both options available on setuptools>=77.0.0).

              By 2026-Feb-18, you need to update your project and remove deprecated calls
              or your builds will no longer be supported.

              See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details.
              ********************************************************************************

      !!
        corresp(dist, value, root_dir)
      C:\Users\user1\AppData\Local\Temp\pip-build-env-cymior43\overlay\Lib\site-packages\setuptools\config\_apply_pyprojecttoml.py:61: SetuptoolsDeprecationWarning: License classifiers are deprecated.
      !!

              ********************************************************************************
              Please consider removing the following classifiers in favor of a SPDX license expression:

              License :: OSI Approved :: BSD License

              See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details.
              ********************************************************************************

      !!
        dist._finalize_license_expression()
      C:\Users\user1\AppData\Local\Temp\pip-build-env-cymior43\overlay\Lib\site-packages\setuptools\dist.py:759: SetuptoolsDeprecationWarning: License classifiers are deprecated.
      !!

              ********************************************************************************
              Please consider removing the following classifiers in favor of a SPDX license expression:

              License :: OSI Approved :: BSD License

              See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#license for details.
              ********************************************************************************

      !!
        self._finalize_license_expression()
      running bdist_wheel
      running build
      running build_py
      creating build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\agraph.py -> build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\graphviz.py -> build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\scraper.py -> build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\testing.py -> build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\__init__.py -> build\lib.win-amd64-cpython-313\pygraphviz
      creating build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_attribute_defaults.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_clear.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_close.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_drawing.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_edge_attributes.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_graph.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_html.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_layout.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_node_attributes.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_readwrite.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_repr_mimebundle.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_scraper.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_string.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_subgraph.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\test_unicode.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      copying pygraphviz\tests\__init__.py -> build\lib.win-amd64-cpython-313\pygraphviz\tests
      running egg_info
      writing pygraphviz.egg-info\PKG-INFO
      writing dependency_links to pygraphviz.egg-info\dependency_links.txt
      writing top-level names to pygraphviz.egg-info\top_level.txt
      reading manifest file 'pygraphviz.egg-info\SOURCES.txt'
      reading manifest template 'MANIFEST.in'
      warning: no files found matching '*.swg'
      warning: no files found matching '*.png' under directory 'doc'
      warning: no files found matching '*.html' under directory 'doc'
      warning: no files found matching '*.txt' under directory 'doc'
      warning: no files found matching '*.css' under directory 'doc'
      warning: no previously-included files matching '*~' found anywhere in distribution
      warning: no previously-included files matching '*.pyc' found anywhere in distribution
      warning: no previously-included files matching '.svn' found anywhere in distribution
      no previously-included directories found matching 'doc\build'
      adding license file 'LICENSE'
      writing manifest file 'pygraphviz.egg-info\SOURCES.txt'
      copying pygraphviz\graphviz.i -> build\lib.win-amd64-cpython-313\pygraphviz
      copying pygraphviz\graphviz_wrap.c -> build\lib.win-amd64-cpython-313\pygraphviz
      running build_ext
      building 'pygraphviz._graphviz' extension
      creating build\temp.win-amd64-cpython-313\Release\pygraphviz
      "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -DSWIG_PYTHON_STRICT_BYTE_CHAR -DGVDLL -IC:\Python313\include -IC:\Python313\Include "-IC:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt" /Tcpygraphviz/graphviz_wrap.c /Fobuild\temp.win-amd64-cpython-313\Release\pygraphviz\graphviz_wrap.obj 
      graphviz_wrap.c
      pygraphviz/graphviz_wrap.c(9): warning C4005: 'SWIG_PYTHON_STRICT_BYTE_CHAR': マクロが再定義されました。
      pygraphviz/graphviz_wrap.c: note: 'SWIG_PYTHON_STRICT_BYTE_CHAR' の以前の定義を確認してください
      pygraphviz/graphviz_wrap.c(3023): fatal error C1083: include ファイルを開けません。'graphviz/cgraph.h':No such file or directory
      error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.29.30133\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for pygraphviz
Failed to build pygraphviz

[notice] A new release of pip is available: 25.0.1 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip
ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (pygraphviz)
```

この対処も生成AIに聞いてみます。
```text:prompt3
pip installを行ったら以下のようにエラーが出ました。どう対処したらいいですか？

#
(以下上記エラーをそのまま貼り付け)
```

こんな回答が。
```text:response3
このエラーは「pygraphvizのC拡張をビルドするためにGraphviz本体が必要だが、Graphvizの開発用ヘッダ（cgraph.hなど）が見つからない」ことが原因です。  
**pygraphvizのインストールには、Graphviz本体（特に開発用ファイル）のインストールが必要です。**

---

対処方法

### 1. Graphviz本体をインストール（Windowsの場合）

#### 1-1. Graphvizの公式バイナリをダウンロード

- [Graphviz公式ダウンロードページ](https://graphviz.gitlab.io/download/)
- Windows用インストーラ（例：graphviz-2.50.0-win64.exe など）をダウンロードしてインストール  
  ※ デフォルトで `C:\Program Files\Graphviz` にインストールされます。

#### 1-2. 環境変数の設定

- `C:\Program Files\Graphviz\bin` を **Path** に追加してください。

#### 1-3. 必要なヘッダファイルのパスをpygraphvizに伝える

pipでインストールする際に、Graphvizのincludeとlibディレクトリを指定します。
（例: GraphvizをC:\Program Files\Graphvizにインストールした場合）

pip install pygraphviz --install-option="--include-path=C:\Program Files\Graphviz\include" --install-option="--library-path=C:\Program Files\Graphviz\lib"

**注意**: pipのバージョンによっては`--install-option`が効かない場合もあります。
その場合は「whl（wheel）ファイル」やconda-forge経由がおすすめです。

---

### 2. Anaconda/Miniconda環境が使える場合（推奨）

condaの場合はGraphviz本体ごと自動で依存解決されるので非常に簡単です。

conda install -c conda-forge pygraphviz

---

### 3. それでも難しい場合

- [Unofficial Windows Binaries for Python Extension Packages](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pygraphviz)  
  ここから **pygraphviz の whlファイル** をダウンロードし、手動インストールも可能です（Pythonのバージョンに合わせて対応するものを選択）。

pip install ダウンロードしたファイル名.whl

---

## 補足

- Graphvizのインストール後、`dot -V` でコマンドプロンプトからバージョン表示できるか確認してください。
- Graphvizのパスが通っていない場合、pygraphvizのインストール・実行時に再度エラーが出ます。

---

## まとめ

1. Graphviz本体（開発用ヘッダ含む）をインストール
2. Pathを通す
3. pipに--include-path/--library-pathで場所を明示する（もしくはcondaで簡単インストール）

---

ご不明な点や環境に合わせた具体的な手順が必要な場合は、バージョン・OSを追記の上で再度ご質問ください！
```

再び指示に従いGraphvizをインストール。また、pip installの際にCプログラムのビルドが実行されるようですね。たまたま本環境にはVisual Studioをインストールしていたため、その点はクリアされていました。

改めて、pipにオプションをつけて実行。すると再びエラーが。
```shell:pip install error2
D:\Test>pip install pygraphviz --install-option="--include-path=C:\Program Files\Graphviz\include" --install-option="--library-path=C:\Program Files\Graphviz\lib"

Usage:
  pip install [options] <requirement specifier> [package-index-options] ...
  pip install [options] -r <requirements file> [package-index-options] ...
  pip install [options] [-e] <vcs project url> ...
  pip install [options] [-e] <local project path> ...
  pip install [options] <archive url/path> ...

no such option: --install-option

D:\Test>
```

生成AIの応答にも記載がありましたが、--install-optionは使用できず。これについては以下のサイトに記載がありました（このあたりはWebサイトをあちこち見ている間に見つかりました）。
<a href="https://pygraphviz.github.io/documentation/stable/install.html#windows">PyGraphvizをWindowsにインストール</a>

以下のコマンドで再度インストール。無事成功。
```shell:pip install success
D:\Test>python -m pip install --config-settings="--global-option=build_ext" --config-settings="--global-option=-IC:\Program Files\Graphviz\include"  --config-settings="--global-option=-LC:\Program Files\Graphviz\lib"  pygraphviz
Collecting pygraphviz
  Using cached pygraphviz-1.14.tar.gz (106 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: pygraphviz
  Building wheel for pygraphviz (pyproject.toml) ... done
  Created wheel for pygraphviz: filename=pygraphviz-1.14-cp313-cp313-win_amd64.whl size=99427 sha256=223ec9cdc8b445b80c5bbfb614db1c865a9da11c5d218310dcc3ab705766e829
  Stored in directory: c:\users\user1\appdata\local\pip\cache\wheels\20\62\e8\1c65bd9a08c9473ba98a15c4c7f62132ef090acec34b69a881
Successfully built pygraphviz
Installing collected packages: pygraphviz
Successfully installed pygraphviz-1.14

[notice] A new release of pip is available: 25.0.1 -> 25.1.1
[notice] To update, run: python.exe -m pip install --upgrade pip

D:\Test>
```

***
環境が整ったところで改めてプログラムを実行。実行は無事に終了。生成されたファイルは以下のような形でした。

###### 階層レイアウト1-dot
![階層レイアウト1-dot](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/07660a3a-510e-4dd8-bb73-0687d3c7b023.png "階層レイアウト1-dot")

縦1列に比べたら、だいぶリレーションの様子が見やすくなっている感じですね。[もとの図](#グラフ概観)と比べると、ノードの上下の並びが逆順になっているようですが。

## ほかのアルゴリズムも試す
プログラムを見ると、実際のレイアウト処理は graphviz_layout() 関数で実行しているようです。

```python:graphviz_layout()
def hierarchical_layout(nodes, edges):
    G = nx.DiGraph()
    for nid, node in nodes.items():
        G.add_node(nid)
    G.add_edges_from(edges)
    # pygraphvizのdotを使って階層レイアウト
    try:
        pos = nx.nx_agraph.graphviz_layout(G, prog='dot')    # <= ここ
    except Exception as e:
        print("pygraphvizが必要です。pip install pygraphviz を実行してください。")
        raise
    return pos
```

関数には、prog引数が指定できるようになっています。ひょっとしたら、この指定を変えるとほかのアルゴリズムでレイアウトができるかも。Webで調べてみると、以下のサイトにちょっと記載が見つかりました。
[graphviz_layout](https://networkx.org/documentation/stable/reference/generated/networkx.drawing.nx_pydot.graphviz_layout.html)

関数引数の説明にはこう記載されています。

~~~python: prog引数
    prog
    string (default: ‘neato’)
        The name of the GraphViz program to use for layout.
        Options depend on GraphViz version but may include: ‘dot’, ‘twopi’, ‘fdp’, ‘sfdp’, ‘circo’
~~~

細かいところはわかりませんが、引数として以下の値をとれる可能性があり、それによってレイアウト結果が変わりそうです。
- dot
- twopi
- fdp
- sfdp
- circo

また既定値は'neato'のようですが、サンプルとして提示されたプログラムには'dot'と指定されており、先ほどの[階層レイアウト1-dot](#階層レイアウト1-dot)はその設定で変換したものです。そこで、引数の値を'neato'及び'dot'以外の4つについて指定し、結果を確認してみました。それらを以下に示します。

###### 階層レイアウト2-neato
![階層レイアウト2-neato](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/86024fbb-f2bd-4568-9c4f-879b24421a77.png "階層レイアウト2-neato")

###### 階層レイアウト3-twopi
![階層レイアウト3-twopi](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/fbce9f18-9eb1-41df-8983-5c37497df23b.png "階層レイアウト3-twopi")

###### 階層レイアウト4-fdp
![階層レイアウト4-fdp](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/9d0a7b96-eb1e-40c6-ae9c-c5b5f79e3ec5.png "階層レイアウト4-fdp")

###### 階層レイアウト5-sfdp
![階層レイアウト5-sfdp](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/e32e89a7-f5d9-4497-8d4f-528bfcdf3539.png "階層レイアウト5-sfdp")

###### 階層レイアウト6-circo
![階層レイアウト6-circo](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622594/21a58b8d-fe70-4d5b-85fd-990043cd45ce.png "階層レイアウト6-circo")

[階層レイアウト6-circo](#階層レイアウト6-circo)が最もきれいに見えますが、[もとの図](#グラフ概観)がそれに近い感じのレイアウトだったためかもしれません。個人的には[階層レイアウト5-sfdp](#階層レイアウト5-sfdp)が、間延びはしているものの比較的よくレイアウトされているような気がします。この辺は、もっといろんなグラフを試してみる必要はありそうです。皆さんはどう思われますでしょうか。

## まとめ
今回は、生成AIを使用したプログラム作成についてのお試しした結果を記載してみました。初めて実施してみましたが、これからのプログラム開発には大きな効果がある手法だと実感しました。この記事がどなたかの参考になれば幸いです。