defmodule Archeometer.Graphs.Graphviz do
@moduledoc """
Functions for working with Graphviz graphs
"""
require EEx
alias Archeometer.Graphs.Colors
EEx.function_from_file(
:defp,
:render_simple_dot,
"priv/templates/graphviz/simple.eex",
[:xrefs, :color]
)
EEx.function_from_file(
:defp,
:render_centrality_colored_dot,
"priv/templates/graphviz/centrality_colored.eex",
[:xrefs, :color, :centrality]
)
@doc """
Renders an graph represented by an adjacency list into .dot format.
Returns a string containing de rendered graph.
## Examples
iex(2)> graph = %{
...(2)> :a => [:b, :c],
...(2)> :b => [:c, :d],
...(2)> :d => [:a]
...(2)> }
%{a: [:b, :c], b: [:c, :d], d: [:a]}
iex(3)> dot_str = Graphviz.render_dot(graph)
iex(3)> assert is_binary(dot_str)
"""
def render_dot(xrefs, centrality \\ %{}) do
do_render_dot(xrefs, centrality)
|> String.replace(~r/(\n\s+\n)+|\n{2,}/, "\n")
end
defp do_render_dot(xrefs, centrality) when centrality == %{} do
render_simple_dot(xrefs, Colors)
end
defp do_render_dot(xrefs, centrality) do
render_centrality_colored_dot(xrefs, Colors, centrality)
end
@doc """
Renders an graph represented by an adjacency list into .png format.
Returns a binary containing the rendered graph.
"""
def render_image(xrefs, centrality \\ %{}, format \\ "png") do
xrefs
|> render_dot(centrality)
|> write_temp_file()
|> gen_from_dot(format)
end
defp write_temp_file(dot_str) do
{:ok, fd, file_path} = Mix.Project.config()[:app] |> to_string() |> Temp.open()
IO.write(fd, dot_str)
File.close(fd)
file_path
end
defp gen_from_dot(dot_path, format) do
png_path = Temp.path!(suffix: ".#{format}")
System.cmd("dot", ["-T#{format}", dot_path, "-o", png_path])
File.read!(png_path)
end
end