前回 は、JGraphT というグラフ理論のライブラリを Gradle プロジェクトで実行して、GraphViz で可視化するところまでやりました。
今回は、前回の補足として、サンプルソースの解説と、可視化のソースを完成させようと思います。
それではやっていきます!
参考文献
はじめに
「Javaでデザインパターンを学ぶ」の記事一覧です。良かったら参考にしてください。
Javaでデザインパターンの記事一覧
JGraphT の公式サイトは以下です。
jgrapht.org
それではやっていきます!
HelloJGraphT.javaの説明
簡単に HelloJGraphT.java のメインの内容を説明しておきます。
HelloJGraphT クラスの先頭です。
final
なので、HelloJGraphT クラスを派生させることは出来ません。
また、コンストラクタを private
にすることでインスタンス化を防ぎ、クラスメソッドだけを使うようにしています。
public final class HelloJGraphT
{
private HelloJGraphT()
{
}
クラスメソッドとして、main
メソッドの定義です。
最初は、String と DefaultEdge の Graph を作るメソッドの createStringGraph()
を実行しています。
DefaultEdge は、名前の通り、特別な用途が必要ないときのデフォルトのエッジ(辺)です。
public static void main(String[] args)
throws URISyntaxException, ExportException
{
Graph<String, DefaultEdge> stringGraph = createStringGraph();
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" を検索しています。
Graph<URI, DefaultEdge> hrefGraph = createHrefGraph();
URI start = hrefGraph
.vertexSet().stream().filter(uri -> uri.getHost().equals("www.jgrapht.org")).findAny()
.get();
メインの最後です。
先ほど検索したノードを起点として、グラフを深さ優先順に走査して、頂点を出力します。
最後は、前回から使っている可視化のメソッドを実行していまうs。
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
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 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 FileWriter("HelloJGraphT.dot");
exporter.exportGraph(hrefGraph, writer);
}
catch (IOException e) {
e.printStackTrace();
}
}
これを実行すると、プロジェクトのトップに、HelloJGraphT.dot が作られます。
あとは、前回 と同様に、GraphViz で、画像ファイルを作れば完成です。
$ dot -Tpng HelloJGraphT.dot -oHelloJGraphT.png
前回 と同じく、以下の画像ファイルが出力されます。
ついでにdotファイルからPNG画像を出力するようにHelloJGraphT.javaを変更する
さらに、Java を実行した後に、dot を実行するのは面倒なので、Java の中で、PNG ファイルを出力します。
ChatGPT に教えてもらいました。コマンドで実行するのと同じでいいようですね。
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 FileWriter("HelloJGraphT.dot");
exporter.exportGraph(hrefGraph, writer);
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();
}
}
おわりに
今回は、前回、十分に書けてなかったところを補足しました。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。