Yog.IO.JSON (YogEx v1.0.0)

Copy Markdown View Source

JSON format import/export for graph data exchange.

This module provides comprehensive JSON serialization capabilities for graph data, supporting multiple formats used by popular visualization libraries, as well as import functionality for round-trip serialization.

Format Support

  • Generic: Full metadata with type preservation
  • D3Force: D3.js force-directed graphs
  • Cytoscape: Cytoscape.js network visualization
  • VisJs: vis.js network format
  • NetworkX: Python NetworkX compatibility

Examples

Export to JSON

iex> graph = Yog.directed()
...> |> Yog.add_node(1, "Alice")
...> |> Yog.add_node(2, "Bob")
...> |> Yog.add_edge_ensure(from: 1, to: 2, with: "follows")
iex>
iex> json_string = Yog.IO.JSON.to_json(graph)
iex> String.contains?(json_string, "Alice")
true

Import from JSON

iex> json = ~s|{"graph_type":"directed","nodes":[{"id":1,"data":"Alice"},{"id":2,"data":"Bob"}],"edges":[{"source":1,"target":2,"weight":"follows"}]}|
iex> {:ok, graph} = Yog.IO.JSON.from_json(json)
iex> Yog.Model.order(graph)
2

Import from Map (PostgreSQL JSONB)

iex> map = %{
...>   "graph_type" => "undirected",
...>   "nodes" => [%{"id" => 1, "data" => "A"}, %{"id" => 2, "data" => "B"}],
...>   "edges" => [%{"source" => 1, "target" => 2, "weight" => 1}]
...> }
iex> {:ok, graph} = Yog.IO.JSON.from_map(map)
iex> Yog.Model.edge_count(graph)
1

Summary

Functions

Creates default export options for String node and edge data.

Converts a JsonError to a string.

Creates export options with custom serializers for generic types.

Parses a JSON string and creates a graph.

Parses a JSON string and creates a graph, raising on error.

Creates a graph from a map (useful for PostgreSQL JSONB).

Detects the JSON graph format of the given input.

Detects the JSON graph format, raising on error for string input.

Quick export for Cytoscape.js with default settings.

Quick export for D3.js force-directed graphs with default settings.

Converts a graph to a JSON string according to options.

Converts a multigraph to a JSON string.

Quick export for vis.js networks with default settings.

Writes a graph to a JSON file using default export options.

Writes a graph to a JSON file with custom export options.

Functions

default_export_options()

@spec default_export_options() :: tuple()

Creates default export options for String node and edge data.

Time complexity: $\mathcal{O}(1)$

error_to_string(error)

@spec error_to_string(any()) :: String.t()

Converts a JsonError to a string.

Time complexity: $\mathcal{O}(1)$

export_options_with(node_serializer, edge_serializer, opts \\ [])

@spec export_options_with((any() -> any()), (any() -> any()), keyword()) :: tuple()

Creates export options with custom serializers for generic types.

Raises ArgumentError if serializers or keyword options are invalid.

Time complexity: $\mathcal{O}(1)$

from_json(json_string)

@spec from_json(String.t()) :: {:ok, Yog.graph()} | {:error, term()}

Parses a JSON string and creates a graph.

Supports the generic Yog format and common variations.

Raises ArgumentError if json_string is not a binary string.

Time complexity: $\mathcal{O}(V + E)$

Parameters

  • json_string - JSON string to parse

Returns

  • {:ok, graph} - Successfully parsed graph
  • {:error, reason} - Parsing failed

Examples

iex> json = ~s|{"graph_type":"directed","nodes":[{"id":1,"data":"A"}],"edges":[]}|
iex> {:ok, graph} = Yog.IO.JSON.from_json(json)
iex> Yog.Model.order(graph)
1

iex> # NetworkX format
iex> nx_json = ~s|{"directed":true,"multigraph":false,"nodes":[{"id":1}],"links":[]}|
iex> {:ok, graph} = Yog.IO.JSON.from_json(nx_json)
iex> Yog.Model.type(graph)
:directed

iex> # D3 format (nodes + links)
iex> d3_json = ~s|{"nodes":[{"id":1},{"id":2}],"links":[{"source":1,"target":2,"weight":5}]}|
iex> {:ok, graph} = Yog.IO.JSON.from_json(d3_json)
iex> Yog.Model.edge_count(graph)
1

iex> # Cytoscape format
iex> cy_json = ~s|{"elements":[{"data":{"id":1}},{"data":{"id":2}},{"data":{"source":1,"target":2}}]}|
iex> {:ok, graph} = Yog.IO.JSON.from_json(cy_json)
iex> Yog.Model.order(graph)
2

from_json!(json_string)

@spec from_json!(String.t()) :: Yog.graph()

Parses a JSON string and creates a graph, raising on error.

Time complexity: $\mathcal{O}(V + E)$

Examples

iex> json = ~s|{"graph_type":"undirected","nodes":[],"edges":[]}|
iex> graph = Yog.IO.JSON.from_json!(json)
iex> Yog.Model.order(graph)
0

from_map(map)

@spec from_map(map()) :: {:ok, Yog.graph()} | {:error, String.t()}

Creates a graph from a map (useful for PostgreSQL JSONB).

Auto-detects format based on keys present in the map.

Raises ArgumentError if map is not a map.

Time complexity: $\mathcal{O}(V + E)$

Parameters

  • map - Map containing graph data

Supported Formats

  • Yog Generic: %{"graph_type" => "directed", "nodes" => [...], "edges" => [...]}
  • NetworkX: %{"directed" => true, "nodes" => [...], "links" => [...]}
  • D3: %{"nodes" => [...], "links" => [...]}
  • Cytoscape: %{"elements" => [...]}
  • VisJs: %{"nodes" => [...], "edges" => [...]} (with from/to)

Examples

iex> map = %{
...>   "graph_type" => "undirected",
...>   "nodes" => [%{"id" => 1, "data" => "Node A"}],
...>   "edges" => []
...> }
iex> {:ok, graph} = Yog.IO.JSON.from_map(map)
iex> Yog.Model.order(graph)
1

iex> # From PostgreSQL JSONB (simple format)
iex> simple = %{
...>   "type" => "directed",
...>   "nodes" => [%{"id" => 1}, %{"id" => 2}],
...>   "edges" => [%{"from" => 1, "to" => 2}]
...> }
iex> {:ok, graph} = Yog.IO.JSON.from_map(simple)
iex> Yog.has_edge?(graph, 1, 2)
true

json_type(input)

@spec json_type(String.t() | map()) :: {:ok, atom()} | {:error, Jason.DecodeError.t()}

Detects the JSON graph format of the given input.

Supports detection from both JSON strings and decoded maps.

Raises ArgumentError if input is neither a binary string nor a map.

Time complexity: $\mathcal{O}(V + E)$

Parameters

  • input - JSON string or map to detect the format of

Returns

  • {:ok, type} - One of :yog_generic, :network_x, :d3_force, :cytoscape, :visjs, or :simple
  • {:error, reason} - If input is a string and parsing fails

Examples

iex> json = ~s|{"graph_type":"directed","nodes":[],"edges":[]}|
iex> Yog.IO.JSON.json_type(json)
{:ok, :yog_generic}

iex> network_x_map = %{"nodes" => [], "links" => [], "directed" => true}
iex> Yog.IO.JSON.json_type(network_x_map)
{:ok, :network_x}

iex> d3_force_map = %{"nodes" => [], "links" => []}
iex> Yog.IO.JSON.json_type(d3_force_map)
{:ok, :d3_force}

json_type!(input)

@spec json_type!(String.t() | map()) :: atom()

Detects the JSON graph format, raising on error for string input.

Time complexity: $\mathcal{O}(V + E)$

Examples

iex> json = ~s|{"elements": []}|
iex> Yog.IO.JSON.json_type!(json)
:cytoscape

to_cytoscape_json(graph, node_serializer, edge_serializer)

@spec to_cytoscape_json(Yog.graph() | Yog.DAG.t(), (any() -> any()), (any() -> any())) ::
  String.t()

Quick export for Cytoscape.js with default settings.

Raises ArgumentError if serializers or graph are invalid.

Time complexity: $\mathcal{O}(V + E)$

to_d3_json(graph, node_serializer, edge_serializer)

@spec to_d3_json(Yog.graph() | Yog.DAG.t(), (any() -> any()), (any() -> any())) ::
  String.t()

Quick export for D3.js force-directed graphs with default settings.

Raises ArgumentError if serializers or graph are invalid.

Time complexity: $\mathcal{O}(V + E)$

to_json(graph, options \\ default_export_options())

@spec to_json(Yog.graph() | Yog.DAG.t(), tuple()) :: String.t()

Converts a graph to a JSON string according to options.

Raises ArgumentError if graph or options are invalid.

Time complexity: $\mathcal{O}(V + E)$

to_json_file(graph, path, options \\ default_export_options())

@spec to_json_file(Yog.graph() | Yog.DAG.t(), String.t(), tuple()) ::
  {:ok, nil} | {:error, atom()}

Exports a graph to a JSON file.

Raises ArgumentError if path is not a binary string or graph/options are invalid.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

to_json_file_multi(graph, path, options \\ default_export_options())

@spec to_json_file_multi(any(), String.t(), tuple()) :: :ok | {:error, atom()}

Exports a multigraph to a JSON file.

Raises ArgumentError if path is not a binary string.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

to_json_multi(graph, options \\ default_export_options())

@spec to_json_multi(any(), tuple()) :: String.t()

Converts a multigraph to a JSON string.

Time complexity: $\mathcal{O}(V + E)$

to_visjs_json(graph, node_serializer, edge_serializer)

@spec to_visjs_json(Yog.graph() | Yog.DAG.t(), (any() -> any()), (any() -> any())) ::
  String.t()

Quick export for vis.js networks with default settings.

Raises ArgumentError if serializers or graph are invalid.

Time complexity: $\mathcal{O}(V + E)$

write(path, graph)

@spec write(String.t(), Yog.graph() | Yog.DAG.t()) :: {:ok, nil} | {:error, atom()}

Writes a graph to a JSON file using default export options.

Raises ArgumentError if path is not a binary string or graph is invalid.

Time complexity: $\mathcal{O}(V + E)$ + file I/O

write_with(path, options, graph)

@spec write_with(String.t(), tuple(), Yog.graph() | Yog.DAG.t()) ::
  {:ok, nil} | {:error, atom()}

Writes a graph to a JSON file with custom export options.

Raises ArgumentError if path is not a binary string or graph/options are invalid.

Time complexity: $\mathcal{O}(V + E)$ + file I/O