daisukeの技術ブログ

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

JGraphTのサンプルソースの解説と可視化の補足(Ubuntu22.04、IntelliJ、Gradle)

前回 は、JGraphT というグラフ理論のライブラリを Gradle プロジェクトで実行して、GraphViz で可視化するところまでやりました。

今回は、前回の補足として、サンプルソースの解説と、可視化のソースを完成させようと思います。

それではやっていきます!

参考文献

はじめに

「Javaでデザインパターンを学ぶ」の記事一覧です。良かったら参考にしてください。

Javaでデザインパターンの記事一覧

JGraphT の公式サイトは以下です。

jgrapht.org

それではやっていきます!

HelloJGraphT.javaの説明

簡単に HelloJGraphT.java のメインの内容を説明しておきます。

HelloJGraphT クラスの先頭です。

final なので、HelloJGraphT クラスを派生させることは出来ません。

また、コンストラクタを private にすることでインスタンス化を防ぎ、クラスメソッドだけを使うようにしています。

public final class HelloJGraphT
{
    private HelloJGraphT()
    {
    } // ensure non-instantiability.

クラスメソッドとして、main メソッドの定義です。

最初は、String と DefaultEdge の Graph を作るメソッドの createStringGraph() を実行しています。

DefaultEdge は、名前の通り、特別な用途が必要ないときのデフォルトのエッジ(辺)です。

    public static void main(String[] args)
        throws URISyntaxException, ExportException
    {
        Graph<String, DefaultEdge> stringGraph = createStringGraph();

        // note undirected edges are printed as: {<v1>,<v2>}
        System.out.println("-- toString output");
        System.out.println(stringGraph.toString());
        System.out.println();

次は、URI と DefaultEdge の Graph を作るメソッドの createHrefGraph() を実行しています。

URI(Uniform Resource Indentifier)クラスは、Java に用意されているクラスで、URL と同じくアドレスを扱うクラスです。

その後は難しいですが、次に使うので、ノード(頂点)から "www.jgrapht.org" を検索しています。

        // create a graph based on URI objects
        Graph<URI, DefaultEdge> hrefGraph = createHrefGraph();

        // find the vertex corresponding to www.jgrapht.org
        URI start = hrefGraph
            .vertexSet().stream().filter(uri -> uri.getHost().equals("www.jgrapht.org")).findAny()
            .get();

メインの最後です。

先ほど検索したノードを起点として、グラフを深さ優先順に走査して、頂点を出力します。

最後は、前回から使っている可視化のメソッドを実行していまうs。

        // perform a graph traversal starting from that vertex
        System.out.println("-- traverseHrefGraph output");
        traverseHrefGraph(hrefGraph, start);
        System.out.println();

        System.out.println("-- renderHrefGraph output");
        renderHrefGraph(hrefGraph);
        System.out.println();

dotファイルを出力するようにHelloJGraphT.javaを変更する

前回 は、標準出力の DOT 形式の内容をファイルに貼り付けて、GraphViz で画像ファイルを作りました。

今回は、HelloJGraphT.java を変更して、DOT ファイルを出力するようにしたいと思います。

HelloJGraphT.java の DOT 形式の内容を作っているのは以下の部分です。

Write として、StringWrite クラスを使っています。

/**
 * Render a graph in DOT format.
 *
 * @param hrefGraph a graph based on URI objects
 */
private static void renderHrefGraph(Graph<URI, DefaultEdge> hrefGraph)
    throws ExportException
{
    DOTExporter<URI, DefaultEdge> exporter =
        new DOTExporter<>(v -> v.getHost().replace('.', '_'));
    exporter.setVertexAttributeProvider((v) -> {
        Map<String, Attribute> map = new LinkedHashMap<>();
        map.put("label", DefaultAttribute.createAttribute(v.toString()));
        return map;
    });
    Writer writer = new StringWriter();
    exporter.exportGraph(hrefGraph, writer);
    System.out.println(writer.toString());
}

ファイル出力するには、StringWrite クラスを、FileWrite クラスに変更すればいいです。

    //Writer writer = new StringWriter();
    Writer writer = new FileWriter("HelloJGraphT.dot");

また、ファイル出力する場合は、try catch で囲う必要があります。

結果としては、以下のように変更しました。

private static void renderHrefGraph(Graph<URI, DefaultEdge> hrefGraph)
    throws ExportException
{
    DOTExporter<URI, DefaultEdge> exporter =
        new DOTExporter<>(v -> v.getHost().replace('.', '_'));
    exporter.setVertexAttributeProvider((v) -> {
        Map<String, Attribute> map = new LinkedHashMap<>();
        map.put("label", DefaultAttribute.createAttribute(v.toString()));
        return map;
    });
    try {
        //Writer writer = new StringWriter();
        Writer writer = new FileWriter("HelloJGraphT.dot");
        exporter.exportGraph(hrefGraph, writer);
        //System.out.println(writer.toString());
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

これを実行すると、プロジェクトのトップに、HelloJGraphT.dot が作られます。

あとは、前回 と同様に、GraphViz で、画像ファイルを作れば完成です。

$ dot -Tpng HelloJGraphT.dot -oHelloJGraphT.png

前回 と同じく、以下の画像ファイルが出力されます。

HelloJGraphT.png
HelloJGraphT.png

ついでにdotファイルからPNG画像を出力するようにHelloJGraphT.javaを変更する

さらに、Java を実行した後に、dot を実行するのは面倒なので、Java の中で、PNG ファイルを出力します。

ChatGPT に教えてもらいました。コマンドで実行するのと同じでいいようですね。

// Graphvizを使ってDOTファイルをPNGに変換
try {
    ProcessBuilder pb = new ProcessBuilder("dot", "-Tpng", "graph.dot", "-o", "graph.png");
    pb.redirectErrorStream(true);
    Process process = pb.start();
    process.waitFor();
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

例外を複数まとめて記述する方法は初めて知りました。ChatGPT は本当に助かります。

最終的に、以下のようになりました。

private static void renderHrefGraph(Graph<URI, DefaultEdge> hrefGraph)
    throws ExportException
{
    DOTExporter<URI, DefaultEdge> exporter =
        new DOTExporter<>(v -> v.getHost().replace('.', '_'));
    exporter.setVertexAttributeProvider((v) -> {
        Map<String, Attribute> map = new LinkedHashMap<>();
        map.put("label", DefaultAttribute.createAttribute(v.toString()));
        return map;
    });
    try {
        //Writer writer = new StringWriter();
        Writer writer = new FileWriter("HelloJGraphT.dot");
        exporter.exportGraph(hrefGraph, writer);
        //System.out.println(writer.toString());
        
        ProcessBuilder pb = new ProcessBuilder("dot", "-Tpng", "HelloJGraphT.dot", "-o", "HelloJGraphT.png");
        pb.redirectErrorStream(true);
        Process process = pb.start();
        process.waitFor();
    }
    catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

おわりに

今回は、前回、十分に書けてなかったところを補足しました。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。