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.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
model | Model | The model on which the Graph is instantiated. |
undirected | bool | Whether the graph is undirected. Default is False . |
weighted | bool | Whether the graph is weighted. Default is False . |
default_weight | float | The default weight for edges in the graph. Default is 1.0 . Ignored if weighted is set to False . |
Example
Section titled “Example”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 raifrom 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()
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()
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 raifrom 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()
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.
Attributes
Section titled “Attributes”Name | Type | Description |
---|---|---|
.id | int | The unique system ID of the graph. |
.model | Model | The model on which the graph is based. |
.undirected | bool | Whether the graph is undirected. Read-only. |
.weighted | bool | Whether the graph is weighted. Read-only. |
.Node | Type | A type containing the graph’s nodes. |
.Edge | Edge | A type-like object containing the graph’s edges. |
.compute | Compute | A namespace for graph reasoning methods. |
.compute
Section titled “.compute”Graph.compute
Returns a Compute
object for computing graph analytical methods on the graph:
import relationalai as raifrom relationalai.std import aliasfrom 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 raifrom relationalai.std import aliasfrom 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 raifrom relationalai.std.graphs import Graph
model = rai.Model("myModel")graph = Graph(model)
print(graph.id)# Output:# 1
.model
Section titled “.model”Graph.model
Returns the model from which a Graph
was created:
import relationalai as raifrom 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 raifrom 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
.undirected
Section titled “.undirected”Graph.undirected
Returns True
if the graph is undirected and False
if it is directed.
By default, graphs are directed:
import relationalai as raifrom 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
.weighted
Section titled “.weighted”Graph.weighted
Returns True
if the graph is weighted and False
otherwise.
By default, graphs are unweighted:
import relationalai as raifrom 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
Methods
Section titled “Methods”Name | Description | Returns |
---|---|---|
.fetch() | Get a dictionary representation of the graph. | dict |
.visualize(style, **kwargs) | Visualize the graph. | A gravis Figure object. |
.fetch()
Section titled “.fetch()”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.
Returns
Section titled “Returns”A dict
object.
Example
Section titled “Example”from pprint import pprint
import relationalai as raifrom 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'}})}
.visualize()
Section titled “.visualize()”Graph.visualize(three: bool = False, style: dict = {}, **kwargs) -> Figure
Visualize a graph.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
three | bool | Whether or not to use the three.js 3D render engine. Defaults to False . |
style | dict | A dictionary of visual properties for nodes and edges. |
**kwargs | Any | Additional keyword arguments to pass to the gravis visualization library. See the gravis docs for full details. |
Returns
Section titled “Returns”A gravis Figure
object.
Example
Section titled “Example”import relationalai as raifrom 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)
You may change the label, color, and size of nodes and edges:
import relationalai as raifrom 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)
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 raifrom 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)