Quick Start#

This library introduces a Graph object. It will contain all the nodes and connections of your graph. It can also contain any additional data.

A Graph can be directed (the link between two nodes has a single direction) or undirected (any link between two nodes is symmetrical). By default, it is directed.

from galaxy_graph import Graph

# Family tree can be considered as directed graph, a relationship is not symmetrical
family_tree = Graph(
    data="This graph stores my family tree. As I did not specify `is_directed`, it is directed, which is nice for a family graph"
) # create a directed graph with a description in its data

# A hiking trail with nodes for intersection, relationships are symmetrical
hiking_trails = Graph(
    is_directed=False,
) # create a undirected graph without any data

There is also a Node object, that can contain any data.

from galaxy_graph import Node

# In these example, data contains a dictionary, but data can contains any value !

# For the family tree
michel = Node(data={"Name": "Michel", "age": 48})
alberto = Node(data={"Name": "Alberto", "age": 46})
alice = Node(data={"Name": "Alice", "age": 20})

# For the hiking trail
city_entrance = Node(data={"x": 5, "y": 10})
rocky_promontory = Node(data={"x": 18, "y": 13})
oak_forest = Node(data={"x": 10, "y": 10})
lake = Node(data={"x": -3, "y": 4})

Without Connection, there is no link between Node and your graphs would be boring… Again, these can contain any data.

from galaxy_graph import Connection

# For the hiking trail
straight_road = Connection(data={"ground type": "dirt"})

You can then add your nodes to the graph and connect them.

hiking_trails.add(city_entrance) # add city entrance to the graph
city_entrance.connect(straight_road, rocky_promontory) # the city entrance
# and the rocky promontory are linked together. The straight road allows
# traversal in both direction because hiking_trails is an undirected graph.

Warning

Adding a node to the graph is mandatory for adding connection to it. Any node connected to this one will be automatically added to the graph.

Note

It is also possible to create the connection in the connect call.

rocky_promontory.connect(
    Connection(data={"ground type": "dirt"}),
    oak_forest,
)
city_entrance.connect(
    Connection(data={"ground type": "asphalt"}),
    oak_forest,
)
oak_forest.connect(
    Connection(data={"ground type": "dirt"}),
    lake,
)
lake.connect(
    Connection(data={"ground type": "dirt"}),
    city_entrance,
)
family_tree.add(michel)
michel.connect(Connection(data="is married to"), alberto) # Michel and Alberto are married
alberto.connect(Connection(data="is married to"), michel) # symmetrical link
# here, so we add a connection in the other direction.

michel.connect(Connection(data="is parent of"), alice)
alberto.connect(Connection(data="is parent of"), alice)
alice.connect(Connection(data="is child of"), michel)
alice.connect(Connection(data="is child of"), alberto)

Warning

As family tree is a directed graph, the connection Michel->Alberto is different than the connection Alberto->Michel.

michel_alberto = Connection(data="is married to")
michel.connect(michel_alberto, alberto)
alberto.connect(michel_alberto, michel) # will fail: the connection is
# already used.

If you run all the python code above, your hiking_trails graph will look like this:

        ---
title: Hiking trails
---
graph TD
 A[City entrance] <-->|dirt road| B[Rocky promontory]
 B <-->|dirt road| C[Oak forest]
 C <-->|dirt road| D[Lake]
 D <-->|dirt road| A
 A <-->|asphalt road| C
    

For the family tree, the resulting graph will be:

        ---
title: Family tree
---
graph TD
 Michel -->|is married to| Alberto
 Alberto -->|is married to| Michel
 Michel -->|is parent of| Alice
 Alberto -->|is parent of| Alice
 Alice -->|is child of| Michel
 Alice -->|is child of| Alberto