# How-To: Importing & Exporting Graphs

```elixir
Mix.install([
  {:yog_ex, "~> 0.98"},
  {:jason, "~> 1.4"}, # Optional, but needed for JSON serialization
  {:libgraph, "~> 0.16.0"},
  {:kino_vizjs, "~> 0.8.0"} # Needed to render Graphviz DOT diagrams
])
```

## Introduction

`Yog` is built to be a highly interoperable participant in the data ecosystem. It supports a wide range of industry-standard serialization and graph exchange formats. This makes it seamless to move graph datasets between `Yog` and external toolkits (such as Gephi, NetworkX, Cytoscape, or mathematical database archives).

This guide showcases all of `Yog`'s import/export engines.

---

## 1. Structured XML Formats

### GraphML (The Enterprise Standard)

GraphML is the de-facto XML standard for graph interchange. It supports comprehensive node and edge properties.

```elixir
g = Yog.Generator.Classic.petersen()

# Export to GraphML string
graphml_xml = Yog.IO.GraphML.serialize(g)
IO.puts(String.slice(graphml_xml, 0, 250) <> "...\n")

# Import back from GraphML
{:ok, imported_g} = Yog.IO.GraphML.deserialize(graphml_xml)
IO.puts("Imported GraphML: #{Yog.node_count(imported_g)} nodes, #{Yog.edge_count(imported_g)} edges")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported_g))
```

### GEXF (Gephi Exchange Format)

GEXF is the native format for **Gephi**. It supports structural components, hierarchical structures, and visual styling metadata.

```elixir
g = Yog.directed()
  |> Yog.add_node(1, %{label: "A"})
  |> Yog.add_node(2, %{label: "B"})
  |> Yog.add_edge_ensure(1, 2, 5.5)

# Export to GEXF
gexf_xml = Yog.IO.GEXF.serialize(g)
IO.puts(String.slice(gexf_xml, 0, 250) <> "...\n")

# Import back from GEXF
{:ok, imported_g} = Yog.IO.GEXF.deserialize(gexf_xml)
IO.puts("Imported GEXF: #{Yog.node_count(imported_g)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported_g))
```

---

## 2. Web Serialization

### JSON (Cytoscape & D3.js)

JSON is the standard format for pushing graph databases to frontend clients using visualization libraries like Cytoscape.js or D3.js.

```elixir
g = Yog.undirected()
  |> Yog.add_node(1, %{name: "Alice"})
  |> Yog.add_node(2, %{name: "Bob"})
  |> Yog.add_edge!(1, 2, %{type: "friends"})

# Export to JSON (returns the JSON string directly)
json = Yog.IO.JSON.to_json(g)
IO.puts(json)

# Import back from JSON
{:ok, imported_g} = Yog.IO.JSON.from_json(json)
IO.puts("\nImported JSON: #{Yog.node_count(imported_g)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported_g))
```

---

## 3. Compact Mathematical Representations

### Graph6 (For Small Graphs)

Graph6 is an extremely compact ASCII format for storing small, undirected graphs. It is widely used in graph databases, graph theory contests, and academic databases.

```elixir
g = Yog.Generator.Classic.petersen()

# Export to Graph6
{:ok, g6_str} = Yog.IO.Graph6.serialize(g)
IO.puts("Petersen in Graph6: #{g6_str}")

# Import back from Graph6
{:ok, imported} = Yog.IO.Graph6.parse(g6_str)
IO.puts("Imported Graph6: #{Yog.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

### Sparse6 (For Large Sparse Graphs)

Sparse6 is a companion format to Graph6 designed for much larger, sparse graphs where Graph6 becomes inefficient.

```elixir
g = Yog.Generator.Classic.cycle(20)

# Export to Sparse6
{:ok, s6_str} = Yog.IO.Sparse6.serialize(g)
IO.puts("Cycle(20) in Sparse6: #{s6_str}")

# Import back from Sparse6
{:ok, imported} = Yog.IO.Sparse6.parse(s6_str)
IO.puts("Imported Sparse6: #{Yog.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

---

## 4. Trivial & Legacy Formats

### TGF (Trivial Graph Format)

TGF is the simplest possible text format: nodes on top, a separator line `#`, and edges on the bottom. It's excellent for rapid debugging.

```elixir
g = Yog.directed()
  |> Yog.add_node(1, "Alice")
  |> Yog.add_node(2, "Bob")
  |> Yog.add_edge_ensure(1, 2, "follows")

# Export to TGF
tgf = Yog.IO.TGF.serialize(g)
IO.puts(tgf)

# Import back from TGF
{:ok, {:tgf_result, imported, _warnings}} = Yog.IO.TGF.parse(tgf, :directed)
IO.puts("Imported TGF: #{Yog.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

### GDF (GUESS Format)

GDF is a CSV-like flat structure used by the GUESS visualization tool.

```elixir
g = Yog.Generator.Classic.cycle(4)

# Export to GDF
gdf = Yog.IO.GDF.serialize(g)
IO.puts(gdf)

# Import back from GDF
{:ok, imported} = Yog.IO.GDF.deserialize(gdf)
IO.puts("Imported GDF: #{Yog.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

### Pajek (`.net` format)

Pajek format is a popular format used by the Pajek social network analysis package.

```elixir
g = Yog.from_edges(:directed, [{1, 2, 10}, {2, 3, 5}])

# Export to Pajek format
pajek = Yog.IO.Pajek.serialize(g)
IO.puts(pajek)

# Import back from Pajek
{:ok, {_, imported, _}} = Yog.IO.Pajek.parse(pajek)
IO.puts("Imported Pajek: #{Yog.Model.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

### Matrix Market (Scientific / Sparse Matrix)

The Matrix Market coordinate format represents a graph as a sparse matrix, used heavily in scientific and numerical computing packages.

```elixir
g = Yog.from_edges(:undirected, [{1, 2, 5.0}, {2, 3, 12.5}])

# Export to Matrix Market Format
matrix_market = Yog.IO.MatrixMarket.serialize(g)
IO.puts(matrix_market)

# Import back from Matrix Market
{:ok, {_, imported, _}} = Yog.IO.MatrixMarket.parse(matrix_market)
IO.puts("Imported Matrix Market: #{Yog.node_count(imported)} nodes")

# Render imported graph
Kino.VizJS.render(Yog.Render.DOT.to_dot(imported))
```

---

## 5. Elixir Ecosystem Interoperability

### libgraph Bridge

If you are using Elixir's classic `libgraph` package elsewhere in your architecture, `Yog` provides an adapter to convert graphs back and forth seamlessly.

```elixir
# Create a libgraph graph
lg = Graph.new() |> Graph.add_edge(1, 2)

# Convert libgraph -> Yog
{:ok, yg} = Yog.IO.Libgraph.from_libgraph(lg)
IO.puts("Yog graph nodes: #{Yog.DAG.to_graph(yg) |> Yog.node_count()}")

# Convert Yog -> libgraph
lg_back = Yog.IO.Libgraph.to_libgraph(yg)
IO.puts("libgraph vertices back: #{length(Graph.vertices(lg_back))}")

# Render the Yog equivalent
Kino.VizJS.render(Yog.Render.DOT.to_dot(Yog.DAG.to_graph(yg)))
```

---

## I/O Modules Summary

| Format            | Module                | Typical File Ext | Description                                         |
| ----------------- | --------------------- | ---------------- | --------------------------------------------------- |
| **GraphML**       | `Yog.IO.GraphML`      | `.graphml`       | XML standard, retains attributes                    |
| **GEXF**          | `Yog.IO.GEXF`         | `.gexf`          | Gephi XML format, retains styles/hierarchies        |
| **JSON**          | `Yog.IO.JSON`         | `.json`          | Web frontend/interop (requires `jason`)             |
| **Graph6**        | `Yog.IO.Graph6`       | `.g6`            | Compact mathematical format for small graphs        |
| **Sparse6**       | `Yog.IO.Sparse6`      | `.s6`            | Compact mathematical format for large sparse graphs |
| **TGF**           | `Yog.IO.TGF`          | `.tgf`           | Simple space-separated text layout                  |
| **GDF**           | `Yog.IO.GDF`          | `.gdf`           | CSV-like layout for GUESS / Gephi                   |
| **Pajek**         | `Yog.IO.Pajek`        | `.net` / `.paj`  | Pajek social network representation                 |
| **Matrix Market** | `Yog.IO.MatrixMarket` | `.mtx`           | Scientific coordinate sparse matrix format          |
| **libgraph**      | `Yog.IO.Libgraph`     | N/A              | Convert between `Yog` and legacy `libgraph` structs |
