yog_io/graphml
GraphML (Graph Markup Language) serialization support.
Provides functions to serialize and deserialize graphs in the GraphML format, an XML-based format widely supported by graph visualization and analysis tools like Gephi, yEd, Cytoscape, and NetworkX.
Quick Start
import yog/model.{Directed}
import yog_io/graphml
// Create a simple graph
let graph =
model.new(Directed)
|> model.add_node(1, "Alice")
|> model.add_node(2, "Bob")
let assert Ok(graph) = model.add_edge(graph, from: 1, to: 2, with: "friend")
// Serialize to GraphML
let xml = graphml.serialize(graph)
// Write to file
let assert Ok(Nil) = graphml.write("graph.graphml", graph)
// Read from file
let assert Ok(loaded) = graphml.read("graph.graphml")
Format Overview
GraphML is an XML-based format that supports:
- Nodes with custom attributes
- Edges with custom attributes
- Directed and undirected graphs
- Hierarchical graphs (not yet supported)
References
Types
Attribute data type for GraphML attributes.
These types are compatible with Gephi, yEd, and other GraphML tools.
pub type AttributeType {
StringType
IntType
FloatType
DoubleType
BooleanType
LongType
}
Constructors
-
StringTypeString type - for text data
-
IntTypeInteger type - for whole numbers
-
FloatTypeFloat type - for decimal numbers (32-bit)
-
DoubleTypeDouble type - for decimal numbers (64-bit, preferred for Gephi)
-
BooleanTypeBoolean type - for true/false values
-
LongTypeLong type - for large whole numbers (64-bit)
A graph with string-based attributes for nodes and edges.
This is the default format used by serialize and deserialize.
pub type AttributedGraph =
model.Graph(
dict.Dict(String, String),
dict.Dict(String, String),
)
Attributes for an edge as a dictionary of string key-value pairs.
pub type EdgeAttributes =
dict.Dict(String, String)
Options for GraphML serialization.
pub type GraphMLOptions {
GraphMLOptions(indent: Int, xml_declaration: Bool)
}
Constructors
-
GraphMLOptions(indent: Int, xml_declaration: Bool)Arguments
- indent
-
XML indentation spaces (0 for no formatting)
- xml_declaration
-
Include XML declaration
Attributes for a node as a dictionary of string key-value pairs.
pub type NodeAttributes =
dict.Dict(String, String)
Typed attributes for edges - maps attribute name to (value, type) pairs. Use this for proper Gephi compatibility with numeric and boolean attributes.
pub type TypedEdgeAttributes =
dict.Dict(String, #(String, AttributeType))
Typed attributes for nodes - maps attribute name to (value, type) pairs. Use this for proper Gephi compatibility with numeric and boolean attributes.
pub type TypedNodeAttributes =
dict.Dict(String, #(String, AttributeType))
Values
pub fn default_options() -> GraphMLOptions
Default GraphML serialization options.
pub fn deserialize(
xml: String,
) -> Result(
model.Graph(
dict.Dict(String, String),
dict.Dict(String, String),
),
String,
)
Deserializes a GraphML string to a graph.
This is a simplified version of deserialize_with for graphs where
you want node data and edge data as string dictionaries containing all attributes.
Time Complexity: O(V + E)
Example
import yog_io/graphml
let xml = "..."
let assert Ok(graph) = graphml.deserialize(xml)
// Access node data
let node1_data = dict.get(graph.nodes, 1) // Dict(String, String)
let label = dict.get(node1_data, "label")
pub fn deserialize_with(
node_folder: fn(dict.Dict(String, String)) -> n,
edge_folder: fn(dict.Dict(String, String)) -> e,
xml: String,
) -> Result(model.Graph(n, e), String)
Deserializes a GraphML string into a graph with custom data mappers.
This function allows you to control how GraphML attributes are converted
to your node and edge data types. Use deserialize for simple cases
where you want node/edge data as string dictionaries.
Time Complexity: O(V + E)
Example
import gleam/dict
import yog/model.{Directed}
import yog_io/graphml
type Person {
Person(name: String, age: Int)
}
let node_folder = fn(attrs: dict.Dict(String, String)) {
let name = dict.get(attrs, "name") |> result.unwrap("")
let age = dict.get(attrs, "age") |> result.unwrap("0") |> int.parse |> result.unwrap(0)
Person(name, age)
}
let edge_folder = fn(attrs: dict.Dict(String, String)) {
dict.get(attrs, "type") |> result.unwrap("")
}
let xml = "..."
let assert Ok(graph) = graphml.deserialize_with(node_folder, edge_folder, xml)
pub fn read(
path: String,
) -> Result(
model.Graph(
dict.Dict(String, String),
dict.Dict(String, String),
),
String,
)
Reads a graph from a GraphML file.
Example
import yog_io/graphml
let assert Ok(graph) = graphml.read("graph.graphml")
// Access node data
import gleam/dict
for node in dict.to_list(graph.nodes) {
let #(id, data) = node
io.debug("Node " <> int.to_string(id) <> ": " <> data)
}
pub fn read_with(
path: String,
node_folder: fn(dict.Dict(String, String)) -> n,
edge_folder: fn(dict.Dict(String, String)) -> e,
) -> Result(model.Graph(n, e), String)
Reads a graph from a GraphML file with custom data mappers.
Example
import gleam/dict
import yog_io/graphml
type Person {
Person(name: String, age: Int)
}
let node_folder = fn(attrs) {
Person(
dict.get(attrs, "name") |> result.unwrap(""),
dict.get(attrs, "age") |> result.unwrap("0") |> int.parse |> result.unwrap(0)
)
}
let assert Ok(graph) = graphml.read_with("people.graphml", node_folder, fn(attrs) {
dict.get(attrs, "weight") |> result.unwrap("0") |> int.parse |> result.unwrap(0)
})
pub fn serialize(graph: model.Graph(String, String)) -> String
Serializes a graph to a GraphML string.
This is a simplified version of serialize_with for graphs where
node data and edge data are already strings. The string data is stored
as a “label” attribute.
Time Complexity: O(V + E)
Example
import yog/model.{Directed}
import yog_io/graphml
let graph =
model.new(Directed)
|> model.add_node(1, "Alice")
|> model.add_node(2, "Bob")
let assert Ok(graph) = model.add_edge(graph, from: 1, to: 2, with: "5")
let xml = graphml.serialize(graph)
// <?xml version="1.0" encoding="UTF-8"?>
// <graphml xmlns="http://graphml.graphdrawing.org/xmlns">
// <key id="label" for="node" attr.name="label" attr.type="string"/>
// <key id="weight" for="edge" attr.name="weight" attr.type="string"/>
// <graph id="G" edgedefault="directed">
// <node id="1"><data key="label">Alice</data></node>
// <node id="2"><data key="label">Bob</data></node>
// <edge source="1" target="2"><data key="weight">5</data></edge>
// </graph>
// </graphml>
pub fn serialize_with(
node_attr: fn(n) -> dict.Dict(String, String),
edge_attr: fn(e) -> dict.Dict(String, String),
graph: model.Graph(n, e),
) -> String
Serializes a graph to a GraphML string with custom attribute mappers.
This function allows you to control how node and edge data are converted
to GraphML attributes. Use serialize for simple cases where node/edge
data are strings.
Time Complexity: O(V + E)
Example
import gleam/dict
import yog/model.{Directed}
import yog_io/graphml
type Person {
Person(name: String, age: Int)
}
type Connection {
Connection(weight: Int, relation: String)
}
let graph =
model.new(Directed)
|> model.add_node(1, Person("Alice", 30))
|> model.add_node(2, Person("Bob", 25))
let node_attrs = fn(p: Person) {
dict.from_list([#("name", p.name), #("age", int.to_string(p.age))])
}
let edge_attrs = fn(c: Connection) {
dict.from_list([#("weight", int.to_string(c.weight)), #("type", c.relation)])
}
let xml = graphml.serialize_with(node_attrs, edge_attrs, graph)
pub fn serialize_with_options(
node_attr: fn(n) -> dict.Dict(String, String),
edge_attr: fn(e) -> dict.Dict(String, String),
options: GraphMLOptions,
graph: model.Graph(n, e),
) -> String
Serializes a graph to a GraphML string with custom options.
pub fn serialize_with_types(
node_attr: fn(n) -> dict.Dict(String, #(String, AttributeType)),
edge_attr: fn(e) -> dict.Dict(String, #(String, AttributeType)),
graph: model.Graph(n, e),
) -> String
Serializes a graph to GraphML with typed attributes for Gephi compatibility.
This function allows you to specify the GraphML data type for each attribute, which is essential for proper Gephi compatibility. Numeric attributes (Int, Float, Double) will be recognized correctly for visualizations, layouts, and filters.
Time Complexity: O(V + E)
Example
import gleam/dict
import gleam/int
import yog/model.{Directed}
import yog_io/graphml.{DoubleType, IntType, StringType}
type Person {
Person(name: String, age: Int, score: Float)
}
let node_attrs = fn(p: Person) {
dict.from_list([
#("name", #(p.name, StringType)),
#("age", #(int.to_string(p.age), IntType)),
#("score", #(float.to_string(p.score), DoubleType)),
])
}
let edge_attrs = fn(weight: Int) {
dict.from_list([
#("weight", #(int.to_string(weight), DoubleType)),
])
}
let xml = graphml.serialize_with_types(node_attrs, edge_attrs, graph)
pub fn serialize_with_types_and_options(
node_attr: fn(n) -> dict.Dict(String, #(String, AttributeType)),
edge_attr: fn(e) -> dict.Dict(String, #(String, AttributeType)),
options: GraphMLOptions,
graph: model.Graph(n, e),
) -> String
Serializes a graph to GraphML with typed attributes and custom options.
pub fn write(
path: String,
graph: model.Graph(String, String),
) -> Result(Nil, simplifile.FileError)
Writes a graph to a GraphML file.
Example
import yog/model.{Directed}
import yog_io/graphml
let graph =
model.new(Directed)
|> model.add_node(1, "Start")
|> model.add_node(2, "End")
let assert Ok(graph) = model.add_edge(graph, from: 1, to: 2, with: "connection")
let assert Ok(Nil) = graphml.write("mygraph.graphml", graph)
pub fn write_with(
path: String,
node_attr: fn(n) -> dict.Dict(String, String),
edge_attr: fn(e) -> dict.Dict(String, String),
graph: model.Graph(n, e),
) -> Result(Nil, simplifile.FileError)
Writes a graph to a GraphML file with custom attribute mappers.
Example
import gleam/dict
import yog/model.{Directed}
import yog_io/graphml
type Person {
Person(name: String, age: Int)
}
let node_attrs = fn(p: Person) {
dict.from_list([#("name", p.name), #("age", int.to_string(p.age))])
}
let graph =
model.new(Directed)
|> model.add_node(1, Person("Alice", 30))
let assert Ok(Nil) = graphml.write_with(
"people.graphml",
node_attrs,
fn(e) { dict.from_list([#("type", e)]) },
graph
)
pub fn write_with_types(
path: String,
node_attr: fn(n) -> dict.Dict(String, #(String, AttributeType)),
edge_attr: fn(e) -> dict.Dict(String, #(String, AttributeType)),
graph: model.Graph(n, e),
) -> Result(Nil, simplifile.FileError)
Writes a graph to a GraphML file with typed attributes for Gephi compatibility.
This function creates GraphML files with proper attribute types that work seamlessly with Gephi for visualizations, layouts, and statistical analysis.
Example
import gleam/dict
import gleam/int
import yog/model.{Directed}
import yog_io/graphml.{DoubleType, IntType, StringType}
type Person {
Person(name: String, age: Int, score: Float)
}
let node_attrs = fn(p: Person) {
dict.from_list([
#("label", #(p.name, StringType)),
#("age", #(int.to_string(p.age), IntType)),
#("score", #(float.to_string(p.score), DoubleType)),
])
}
let assert Ok(Nil) = graphml.write_with_types(
"people.graphml",
node_attrs,
fn(e) { dict.from_list([#("weight", #(e, DoubleType))]) },
graph
)