diff --git a/lib/graph.ex b/lib/graph.ex index 19bf9d4..8030bdd 100644 --- a/lib/graph.ex +++ b/lib/graph.ex @@ -142,6 +142,38 @@ defmodule Graph do Graph.Serializers.DOT.serialize(g) end + @doc """ + Converts the given Graph to DOT format, saves it under filename, and + compiles the file to png. + + For more information see the to_dot function. + + ## Example + + > g = Graph.new |> Graph.add_vertices([:a, :b, :c, :d]) + > g = Graph.add_edges([{:a, :b}, {:b, :c}, {:b, :d}, {:c, :d}]) + > g = Graph.label_vertex(g, :a, :start) + > g = Graph.label_vertex(g, :d, :finish) + > g = Graph.update_edge(g, :b, :d, weight: 3) + > IO.puts(Graph.to_png(g, "./test")) + + Now you find two files, test.dot with the graphviz content and + test.png with the compiled image of the graph. + """ + @spec to_png(t, String.t) :: {:ok, binary} | {:error, term} + def to_png(%__MODULE__{} = g, filename, format \\ :png) do + case Graph.Serializers.DOT.serialize(g) do + {:ok, ser} -> + File.write(filename <> ".dot", ser) + {res, 0} = System.cmd("dot", [ + "-T", "#{format}", filename <> ".dot", + "-o", filename <> ".#{format}" + ]) + {:ok, res} + {err, msg} -> {err, msg} + end + end + @spec to_edgelist(t) :: {:ok, binary} | {:error, term} def to_edgelist(%__MODULE__{} = g) do Graph.Serializers.Edgelist.serialize(g) @@ -1974,8 +2006,8 @@ defmodule Graph do end) end) else - _ -> - [] + _ -> + [] end end diff --git a/test/serializer_test.exs b/test/serializer_test.exs index f216172..f701c3f 100644 --- a/test/serializer_test.exs +++ b/test/serializer_test.exs @@ -18,6 +18,29 @@ defmodule Graph.SerializerTests do """} = Graph.to_dot(g) end + + test "to_png/1" do + test_file = "test" + g = kitchen_sink_graph() + + assert {:ok, ""} = Graph.to_png(g, test_file) + assert """ + strict digraph { + "start" + "{:complex, :label}" + "c" + "finish" + "start" -> "{:complex, :label}" [weight=3] + "{:complex, :label}" -> "c" [label=5; weight=1] + "{:complex, :label}" -> "finish" [label=1.0; weight=3] + "c" -> "finish" [weight=1] + } + """ = File.read! "#{test_file}.dot" + assert File.exists? "#{test_file}.png" + File.rm "#{test_file}.dot" + File.rm "#{test_file}.png" + end + test "to_edgelist" do g = kitchen_sink_graph()