Skip to content

relationalai.std.graphs.Graph

class relationalai.std.graphs.Graph(
model: Model,
undirected: bool = False,
weighted: bool = False,
default_weight: float = 1.0
)

Use the Graph class to Create graphs representing relationships between objects in a model and perform graph reasoning. RelationalAI supports directed and undirected graphs, as well as edge-weighted graphs. Multigraphs are currently not supported. This means that if you have multiple edges between two nodes, you may need to preprocess them in advance.

NameTypeDescription
modelModelThe model on which the Graph is instantiated.
undirectedboolWhether the graph is undirected. Default is False.
weightedboolWhether the graph is weighted. Default is False.
default_weightfloatThe default weight for edges in the graph. Default is 1.0. Ignored if weighted is set to False.

Use the Graph() constructor to create a new graph object and add nodes and edges using the graph.Node and graph.Edge objects.

This example creates a directed graph from a basic social network model and visualizes it with node and edge labels:

import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with a `Person` type.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
# Add people to the model connected by a multi-valued `follows` property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
# Create a graph. By default, graphs are directed and unweighted.
graph = Graph(model)
# Add all 'Person' objects to the graph as nodes, labeling them by their
# 'name' property. Node and edge labels are optional and are shown in visualizations.
graph.Node.extend(Person, label=Person.name)
# Add edges using the 'Person.follows' property to connect nodes.
graph.Edge.extend(Person.follows, label="follows")
# Visualize the graph. In Jupyter notebooks, '.display()' is not needed.
graph.visualize().display()

A graph with two nodes labeled Alice and Bob and an arrow pointing from Alice to Bob.

Set the undirected parameter to True to create an undirected graph. In visualizations, undirected edges are drawn as lines without arrows:

graph = Graph(model, undirected=True)
graph.Node.extend(Person, label=Person.name)
graph.Edge.extend(Person.follows, label="follows")
graph.visualize().display()

An undirected graph with two nodes labeled Alice and Bob and an line (with no arrow) connecting them.

To create a weighted graph, set the weighted parameter to True. In a weighted graph, edges have a weight property that can be used in graph algorithms. The default_weight parameter, which defaults to 1.0, sets the default weight for any edges without a weight property. Both directed and undirected graphs can be weighted.

In the next example, we create a weighted, directed graph from a model of financial transactions between people:

import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with 'Person' and 'Transaction' types.
model = rai.Model("transactions")
Person = model.Type("Person")
Transaction = model.Type("Transaction")
# Add some people and a transaction to the model.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
transaction = Transaction.add(sender=alice, recipient=bob, amount=100.0)
# Create a weighted, directed graph.
graph = Graph(model, weighted=True)
# Add all 'Person' objects to the graph as nodes, labeling them by their 'name' property.
graph.Node.extend(Person, label=Person.name)
# Add edges to the graph from the 'Transaction' type.
# The edge weights are set to the transaction's 'amount' property.
with model.rule():
t = Transaction()
graph.Edge.add(t.sender, t.recipient, weight=t.amount)
# Visualize the graph with edges labeled by their weight.
# Use a lambda function to access the weight of each edge,
# since no label property is set. Note that properties are
# accessed using subscript notation instead of dot notation.
graph.visualize(style={"edge": {"label": lambda e: e['weight']}}).display()

A directed, weighted graph with two nodes labeled Alice and Bob and an arrow pointing from Alice to Bob with a label of 100.

Graphs are visualized using the gravis package. See .visualize() for more examples of customizing graph visualizations.

Use the .compute property to access graph reasoning methods, such as computing the PageRank of nodes in the graph:

with model.query() as select:
person = Person()
pagerank = graph.compute.pagerank(person)
response = select(person.name, pagerank)
print(response.results)
# Output:
# name v
# 0 Alice 0.350877
# 1 Bob 0.649123

See the Compute class for a list of available graph reasoning methods.

NameTypeDescription
.idintThe unique system ID of the graph.
.modelModelThe model on which the graph is based.
.undirectedboolWhether the graph is undirected. Read-only.
.weightedboolWhether the graph is weighted. Read-only.
.NodeTypeA type containing the graph’s nodes.
.EdgeEdgeA type-like object containing the graph’s edges.
.computeComputeA namespace for graph reasoning methods.
Graph.compute

Returns a Compute object for computing graph analytical methods on the graph:

import relationalai as rai
from relationalai.std import alias
from relationalai.std.graphs import Graph
# Create a model with a 'Person' type.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
# Add people to the model connected by a multi-valued 'follows' property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
# Create a directed graph with 'Person' nodes and 'follows' edges.
graph = Graph(model)
graph.Edge.extend(Person.follows)
# Compute the PageRank of each person in the graph.
with model.query() as select:
person = Person()
pagerank = graph.compute.pagerank(person)
response = select(person.name, alias(pagerank, "pagerank"))
print(response.results)
# Output:
# name v
# 0 Alice 0.350877
# 1 Bob 0.649123

See the Compute class docs for a full list of available methods.

Graph.Edge

Returns an Edge object that can be used to add and query edges in a graph

import relationalai as rai
from relationalai.std import alias
from relationalai.std.graphs import Graph
# Create a model with a 'Person' and 'Message' types.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
Message = model.Type("Message")
# Add people and messages to the model.
# People are connected by a multi-valued 'follows' property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
Message.add(sender=alice, recipient=bob, text="Hey Bob!")
# Create a weighted, directed graph.
# Graphs are directed by default, so only the 'weighted' parameter is needed.
graph = Graph(model, weighted=True)
# Add edges using the 'Person.follows'. Person nodes are automatically added
# to the graph. The 'label' parameter is optional and sets the edge's label
# in the graph visualization.
graph.Edge.extend(Person.follows, label="follows")
# Alternatively, you can add specific edges in a rule using 'Edge.add()'.
# For example, this rule adds edges of type "message" between all senders and recipients.
with model.rule():
message = Message()
graph.Edge.add(from_=message.sender, to=message.recipient, label="message")
# You can query edges using `Graph.Edge`, which behaves like a 'Type' object.
# It returns an 'EdgeInstance' object that can be used to access the edge's
# properties. Use the 'from_' and 'to' properties to access the nodes at
# either end of the edge.
with model.query() as select:
edge = graph.Edge()
response = select(edge.from_.name, edge.to.name, alias(edge.label, "label"))
print(response.results)
# Output:
# name name2 v
# 0 Alice Bob follows
# 1 Alice Bob message
Graph.id

Returns the unique integer ID assigned to the graph instance:

import relationalai as rai
from relationalai.std.graphs import Graph
model = rai.Model("myModel")
graph = Graph(model)
print(graph.id)
# Output:
# 1
Graph.model

Returns the model from which a Graph was created:

import relationalai as rai
from relationalai.std.graphs import Graph
model = rai.Model("myModel")
graph = Graph(model)
print(graph.model == model)
# Output:
# True
Graph.Node

Returns a Type object representing the set of nodes in a graph. Use its .add() and .extend() methods to add nodes to the graph:

import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with a `Person` type.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
# Add people to the model connected by a multi-valued 'follows' property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
# Create a directed graph.
graph = Graph(model)
# Add all 'Person' objects to the graph's nodes using 'Node.extend()'.
# The 'label' parameter is optional and sets the node's label in the graph visualization.
graph.Node.extend(Person, label=Person.name)
# Alternatively, you can add specific nodes in a rule using 'Node.add()'.
# For example, this rule adds all of Bob's followers to the graph.
with model.rule():
person = Person()
person.follows == Person(name="Bob")
graph.Node.add(person, label=person.name)
# You can query the nodes the same way you query any other `Type` object.
with model.query() as select:
node = graph.Node()
response = select(node.label)
print(response.results)
# Output:
# label
# 0 Alice
# 1 Bob
Graph.undirected

Returns True if the graph is undirected and False if it is directed. By default, graphs are directed:

import relationalai as rai
from relationalai.std.graphs import Graph
model = rai.Model("MyModel")
graph = Graph(model)
# By default, graphs are directed.
print(graph.undirected)
# Output:
# False

To create an undirected graph, set the Graph() constructor’s undirected parameter to True:

graph = Graph(model, undirected=True)
print(graph.undirected)
# Output:
# True

.undirected is a read-only attribute and cannot be changed after a graph is created. Attempting to do so raises an AttributeError:

graph.undirected = False
# Output:
# AttributeError: property 'undirected' of 'Graph' object has no setter
Graph.weighted

Returns True if the graph is weighted and False otherwise. By default, graphs are unweighted:

import relationalai as rai
from relationalai.std.graphs import Graph
model = rai.Model("myModel")
graph = Graph(model)
# By default, graphs are unweighted.
print(graph.weighted)
# Output:
# False

To create a weighted graph, set the Graph() constructor’s weighted parameter to True:

graph = Graph(model, weighted=True)
print(graph.weighted)
# Output:
# True

.weighted is a read-only attribute and cannot be changed after a graph is created. Attempting to do so raises an AttributeError:

graph.weighted = False
# Output:
# AttributeError: property 'weighted' of 'Graph' object has no setter
NameDescriptionReturns
.fetch()Get a dictionary representation of the graph.dict
.visualize(style, **kwargs)Visualize the graph.A gravis Figure object.
Graph.fetch() -> dict

Returns a dictionary with two keys, "nodes" and "edges", containing the graph’s data. .fetch() is a blocking operation that queries the model and returns the data locally. It may be slow and consume a lot of memory for large graphs. Use .fetch() to pass graph data to external libraries, such as alternative visualization tools.

A dict object.

from pprint import pprint
import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with a 'Person' type.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
# Add people to the model connected by a multi-valued 'follows' property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
# Create a directed graph with 'Person' nodes and 'follows' edges.
graph = Graph(model)
graph.Node.extend(Person, label=Person.name)
graph.Edge.extend(Person.follows, label="follows")
# Fetch the graph.
# NOTE: Fetching the graph queries the model and returns the data locally.
# If the graph is large, fetching it may be slow and consume a lot of memory.
pprint(graph.fetch())
# Output:
# {'edges': defaultdict(<class 'dict'>,
# {('+0JKlsJxRGKBYFiMq/o/Sg', 'ru89MBnrLAPLQFVtoYdnfQ'): {'label': 'follows'}}),
# 'nodes': defaultdict(<class 'dict'>,
# {'+0JKlsJxRGKBYFiMq/o/Sg': {'label': 'Alice'},
# 'ru89MBnrLAPLQFVtoYdnfQ': {'label': 'Bob'}})}
Graph.visualize(three: bool = False, style: dict = {}, **kwargs) -> Figure

Visualize a graph.

NameTypeDescription
threeboolWhether or not to use the three.js 3D render engine. Defaults to False.
styledictA dictionary of visual properties for nodes and edges.
**kwargsAnyAdditional keyword arguments to pass to the gravis visualization library. See the gravis docs for full details.

A gravis Figure object.

import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with a 'Person' type.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
# Add people to the model connected by a multi-valued 'follows' property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
alice.follows.add(bob)
# Create a graph with edges from the `Person.follows` property.
graph = Graph(model)
graph.Node.extend(Person)
graph.Edge.extend(Person.follows)
# Visualize the graph.
fig = graph.visualize()
# To display the graph in a new browser tab.
fig.display()
# To display the graph inline in a Jupyter or Snowflake notebook.
fig.display(inline=True)

A graph with two nodes and one edge.

You may change the label, color, and size of nodes and edges:

import relationalai as rai
from relationalai.std.graphs import Graph
# Create a model with 'Person' and 'Brand' types.
model = rai.Model("socialNetwork")
Person = model.Type("Person")
Brand = model.Type("Brand")
# Add some people to the model and connect them with a multi-valued `follows` property.
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
acme = Brand.add(name="Acme")
alice.follows.extend([bob, acme])
bob.follows.add(acme)
# Create a directed graph with 'Person' and 'Brand' nodes and 'follows' edges.
graph = Graph(model)
graph.Node.extend(Person, label=Person.name, color="blue")
graph.Node.extend(Brand, label=Brand.name, color="red")
graph.Edge.extend(Person.follows, label="follows")
# Compute the PageRank of people in the graph and use it for the node's size.
with model.rule():
person = Person()
rank = graph.compute.pagerank(person)
graph.Node.add(person, size=rank * 50)
# Visualize the graph.
fig = graph.visualize()
# Display the graph in a new browser tab.
fig.display()
# Display the graph inline in a Jupyter or Snowflake notebook.
fig.display(inline=True)

A graph with two blue nodes labeled "Bob" and "Alice" and one red node labeled "Acme." The "Bob" node is larger than the "Alice" node.

You can also describe the visual properties of nodes and edges by passing a dictionary to the style parameter. The following example produces the same visualization as the preceding example:

import relationalai as rai
from relationalai.std.graphs import Graph
model = rai.Model("socialNetwork")
Person = model.Type("Person")
Brand = model.Type("Brand")
with model.rule():
alice = Person.add(name="Alice")
bob = Person.add(name="Bob")
acme = Brand.add(name="Acme")
alice.follows.extend([bob, acme])
bob.follows.add(acme)
graph = Graph(model)
graph.Node.extend(Person, kind="person")
graph.Node.extend(Brand, kind="brand")
graph.Edge.extend(Person.follows)
with model.rule():
person = Person()
rank = graph.compute.pagerank(person)
graph.Node.add(person)
fig = graph.visualize(style={
"nodes": {
# Color nodes by their 'kind' property.
"color": lambda n: {"person": "blue", "brand": "red"}.get(n["kind"]),
# Size nodes by their 'rank' property and scale them.
"size": lambda n: n.get("rank", 1.0) * 50,
},
# Label edges as "follows."
"edges": {"label": "follows"}
})
# Display the graph in a new browser tab.
fig.display()
# Display the graph inline in a Jupyter or Snowflake notebook.
fig.display(inline=True)