Yog.Render.DOT (YogEx v0.70.0)

Copy Markdown View Source

DOT (Graphviz) format export for visualizing graphs.

This module exports graphs to the DOT language, which is the native format for Graphviz - a powerful open-source graph visualization tool. The exported files can be rendered to PNG, SVG, PDF, and other formats using the dot, neato, circo, or other Graphviz layout engines.

Quick Start

# Export with default styling
dot_string = Yog.Render.DOT.to_dot(my_graph, Yog.Render.DOT.default_options())

# Write to file and render with Graphviz CLI
# $ dot -Tpng output.dot -o graph.png

Customization

Use options/0 to customize:

  • Node labels and shapes
  • Edge labels and styles
  • Per-node and per-edge attributes (custom colors, shapes, etc.)
  • Subgraphs/clusters for visual grouping
  • Highlight specific nodes or paths
  • Graph direction (LR, TB, etc.)

Generic Data Types

The to_dot function works with any node and edge data types. Use default_options_with_edge_formatter/1 when your edge data is not a String.

Per-Element Styling

Provide custom attribute functions for fine-grained control:

options = %{
  Yog.Render.DOT.default_options() |
  node_attributes: fn id, data ->
    case id do
      1 -> [{:fillcolor, "green"}, {:shape, "diamond"}]
      _ -> []
    end
  end,
  edge_attributes: fn from, to, weight ->
    if weight > 10 do
      [{:color, "red"}, {:penwidth, 2}]
    else
      []
    end
  end
}

Subgraphs and Clusters

Group nodes visually using subgraphs:

options = %{
  Yog.Render.DOT.default_options() |
  subgraphs: [
    %{
      name: "cluster_0",
      label: "Cluster A",
      node_ids: [1, 2, 3],
      style: :filled,
      fillcolor: "lightgrey",
      color: nil
    }
  ]
}

Rendering Options

EngineBest For
dotHierarchical layouts (DAGs, trees)
neatoSpring-based layouts (undirected)
circoCircular layouts
fdpForce-directed layouts
sfdpLarge graphs

References

Migration Note: Enhanced in v0.53.0 with full Gleam parity: subgraphs, per-element attributes, layout engines, advanced styling options.

Summary

Types

Arrow head/tail style

Graphviz layout engine

Node shapes

Options for customizing DOT (Graphviz) diagram rendering

Overlap handling

Graph direction (rank direction)

Edge routing style

Visual style

A subgraph (cluster) for grouping nodes visually in the diagram.

Functions

Creates default DOT options with simple labeling and sensible styling.

Creates default DOT options with custom label formatters for both nodes and edges.

Creates default DOT options with a custom edge formatter.

Converts a shortest path result to highlighted DOT options.

Converts a graph to DOT (Graphviz) syntax.

Types

arrow_style()

@type arrow_style() ::
  :normal
  | :dot
  | :diamond
  | :odiamond
  | :box
  | :crow
  | :vee
  | :inv
  | :tee
  | :none
  | {:custom, String.t()}

Arrow head/tail style

layout()

@type layout() ::
  :dot
  | :neato
  | :circo
  | :fdp
  | :sfdp
  | :twopi
  | :osage
  | {:custom, String.t()}

Graphviz layout engine

node_shape()

@type node_shape() ::
  :box
  | :circle
  | :ellipse
  | :diamond
  | :hexagon
  | :pentagon
  | :octagon
  | :triangle
  | :rectangle
  | :square
  | :rect
  | :invtriangle
  | :house
  | :invhouse
  | :parallelogram
  | :trapezoid
  | {:custom, String.t()}

Node shapes

options()

@type options() :: %{
  node_label: (Yog.node_id(), any() -> String.t()),
  edge_label: (any() -> String.t()),
  highlighted_nodes: [Yog.node_id()] | nil,
  highlighted_edges: [{Yog.node_id(), Yog.node_id()}] | nil,
  node_attributes: (Yog.node_id(), any() -> [{atom(), String.t()}]),
  edge_attributes: (Yog.node_id(), Yog.node_id(), any() ->
                      [{atom(), String.t()}]),
  subgraphs: [subgraph()] | nil,
  graph_name: String.t(),
  layout: layout() | nil,
  rankdir: rank_dir() | nil,
  bgcolor: String.t() | nil,
  splines: splines() | nil,
  overlap: overlap() | nil,
  nodesep: float() | nil,
  ranksep: float() | nil,
  node_shape: node_shape(),
  node_color: String.t(),
  node_style: style(),
  node_fontname: String.t(),
  node_fontsize: integer(),
  node_fontcolor: String.t(),
  edge_color: String.t(),
  edge_style: style(),
  edge_fontname: String.t(),
  edge_fontsize: integer(),
  edge_penwidth: float(),
  arrowhead: arrow_style() | nil,
  arrowtail: arrow_style() | nil,
  highlight_color: String.t(),
  highlight_penwidth: float()
}

Options for customizing DOT (Graphviz) diagram rendering

overlap()

@type overlap() :: true | false | :scale | :scalexy | :prism | {:custom, String.t()}

Overlap handling

rank_dir()

@type rank_dir() :: :tb | :lr | :bt | :rl

Graph direction (rank direction)

splines()

@type splines() :: :line | :polyline | :curved | :ortho | :spline | :none

Edge routing style

style()

@type style() ::
  :solid
  | :dashed
  | :dotted
  | :bold
  | :filled
  | :rounded
  | :diagonals
  | :striped
  | :wedged

Visual style

subgraph()

@type subgraph() :: %{
  name: String.t(),
  label: String.t() | nil,
  node_ids: [Yog.node_id()],
  style: style() | nil,
  fillcolor: String.t() | nil,
  color: String.t() | nil
}

A subgraph (cluster) for grouping nodes visually in the diagram.

In Graphviz, subgraphs with names starting with "cluster_" are rendered as bounded rectangles around the contained nodes.

Functions

default_options()

@spec default_options() :: options()

Creates default DOT options with simple labeling and sensible styling.

Default configuration:

  • Layout: Auto-detected by Graphviz
  • Direction: Top-to-bottom
  • Node shape: Ellipse
  • Colors: Light blue nodes, black edges
  • Font: Helvetica 12pt

Examples

iex> opts = Yog.Render.DOT.default_options()
iex> opts.graph_name
"G"
iex> opts.node_shape
:ellipse
iex> opts.node_color
"lightblue"

default_options_with(list)

@spec default_options_with(
  node_label: (Yog.node_id(), any() -> String.t()),
  edge_label: (any() -> String.t())
) :: options()

Creates default DOT options with custom label formatters for both nodes and edges.

Example

options = Yog.Render.DOT.default_options_with(
  node_label: fn id, data -> "#{data} (#{id})" end,
  edge_label: fn weight -> "#{weight} ms" end
)

default_options_with_edge_formatter(edge_formatter)

@spec default_options_with_edge_formatter((any() -> String.t())) :: options()

Creates default DOT options with a custom edge formatter.

Use this when your graph has non-String edge data (e.g., Int, Float, custom types).

Example

# For a graph with Int edge weights
options = Yog.Render.DOT.default_options_with_edge_formatter(fn weight ->
  Integer.to_string(weight)
end)

path_to_options(path, base_options)

@spec path_to_options(map(), options()) :: options()

Converts a shortest path result to highlighted DOT options.

Creates a copy of the base options with the path's nodes and edges set to be highlighted. This is useful for visualizing algorithm results.

Example

case Yog.Pathfinding.Dijkstra.shortest_path(...) do
  {:some, path} ->
    options = Yog.Render.DOT.path_to_options(path, Yog.Render.DOT.default_options())
    dot_string = Yog.Render.DOT.to_dot(graph, options)
  :none ->
    ""
end

to_dot(graph, options)

@spec to_dot(Yog.graph(), options()) :: String.t()

Converts a graph to DOT (Graphviz) syntax.

Works with any node data type and edge data type. Use the options to customize labels, styling, and to define subgraphs.

Time Complexity: O(V + E + S) where S is the total number of nodes across all subgraphs.

Example

graph =
  Yog.directed()
  |> Yog.add_node(1, "Start")
  |> Yog.add_node(2, "Process")
  |> Yog.add_edge!(from: 1, to: 2, with: "5")

diagram = Yog.Render.DOT.to_dot(graph, Yog.Render.DOT.default_options())