In this notebook, we demonstrate how to create and modify a Titan graph in python, and then visualize the result using Graphistry's visual graph explorer.

We assume the gremlin server for our Titan graph is hosted locally on port 8182

- This notebook utilizes the python modules aiogremlin and asyncio.
- The GremlinClient class of aiogremlin communicates asynchronously with the gremlin server using websockets via asyncio coroutines.
- This implementation allows you to submit additional requests to the server before any responses are recieved, which is much faster than synchronous request / response cycles. 
- For more information about these modules, please visit:
    - aiogremlin: http://aiogremlin.readthedocs.org/en/latest/index.html
    - asyncio: https://pypi.python.org/pypi/asyncio

In [1]:
import asyncio
import aiogremlin

In [2]:
# Create event loop and initialize gremlin client
loop = asyncio.get_event_loop()
client = aiogremlin.GremlinClient(url='ws://localhost:8182/', loop=loop)  # Default url

Functions for graph modification


In [3]:
@asyncio.coroutine
def add_vertex_routine(name, label):
    yield from client.execute("graph.addVertex(label, l, 'name', n)", bindings={"l":label, "n":name})

def add_vertex(name, label):
    loop.run_until_complete(add_vertex_routine(name, label))

@asyncio.coroutine
def add_relationship_routine(who, relationship, whom):
    yield from client.execute("g.V().has('name', p1).next().addEdge(r, g.V().has('name', p2).next())", bindings={"p1":who, "p2":whom, "r":relationship})
    
def add_relationship(who, relationship, whom):
    loop.run_until_complete(add_relationship_routine(who, relationship, whom))

@asyncio.coroutine
def remove_all_vertices_routine():
    resp = yield from client.submit("g.V()")
    results = []
    while True:
        msg = yield from resp.stream.read();
        if msg is None:
            break
        if msg.data is None:
            break
        for vertex in msg.data:
            yield from client.submit("g.V(" + str(vertex['id']) + ").next().remove()")
            
def remove_all_vertices():
    results = loop.run_until_complete(remove_all_vertices_routine())

@asyncio.coroutine
def remove_vertex_routine(name):
    return client.execute("g.V().has('name', n).next().remove()", bindings={"n":name})

def remove_vertex(name):
    return loop.run_until_complete(remove_vertex_routine(name));

Functions for translating a graph to node and edge lists:

- Currently, our API can only upload data from a pandas DataFrame, but we plan to implement more flexible uploads in the future.
- For now, we can rely on the following functions to create the necessary DataFrames from our graph.

In [4]:
@asyncio.coroutine
def get_node_list_routine():
    resp = yield from client.submit("g.V().as('node')\
                          .label().as('type')\
                          .select('node').values('name').as('name')\
                          .select('name', 'type')")
    results = [];
    while True:
        msg = yield from resp.stream.read();
        if msg is None:
            break;
        if msg.data is None:
            break;
        else:
            results.extend(msg.data)
    return results

def get_node_list():
    results =  loop.run_until_complete(get_node_list_routine())
    return results

@asyncio.coroutine
def get_edge_list_routine():
    resp = yield from client.submit("g.E().as('edge')\
                          .label().as('relationship')\
                          .select('edge').outV().values('name').as('source')\
                          .select('edge').inV().values('name').as('dest')\
                          .select('source', 'relationship', 'dest')")
    
    results = [];
    while True:
        msg = yield from resp.stream.read();
        if msg is None:
            break;
        if msg.data is None:
            break;
        else:
            results.extend(msg.data)
    return results
def get_edge_list():
    results =  loop.run_until_complete(get_edge_list_routine())
    return results

Let's start with an empty graph:


In [5]:
remove_all_vertices()

And then populate it with the Graphistry team members and some of thier relationships:


In [6]:
add_vertex("Paden", "Person")
add_vertex("Thibaud", "Person")
add_vertex("Leo", "Person")
add_vertex("Matt", "Person")
add_vertex("Brian", "Person")
add_vertex("Quinn", "Person")
add_vertex("Paul", "Person")
add_vertex("Lee", "Person")

add_vertex("San Francisco", "Place")
add_vertex("Oakland", "Place")
add_vertex("Berkeley", "Place")

add_vertex("Turkey", "Thing")
add_vertex("Rocks", "Thing")
add_vertex("Motorcycles", "Thing")

add_relationship("Paden", "lives in", "Oakland")
add_relationship("Quinn", "lives in", "Oakland")
add_relationship("Thibaud", "lives in", "Berkeley")
add_relationship("Matt", "lives in", "Berkeley")
add_relationship("Leo", "lives in", "San Francisco")
add_relationship("Paul", "lives in", "San Francisco")
add_relationship("Brian", "lives in", "Oakland")

add_relationship("Paden", "eats", "Turkey")
add_relationship("Quinn", "cooks", "Turkey")
add_relationship("Thibaud", "climbs", "Rocks")
add_relationship("Matt", "climbs", "Rocks")
add_relationship("Brian", "rides", "Motorcycles")

add_vertex("Graphistry", "Work")

add_relationship("Paden", "works at", "Graphistry")
add_relationship("Thibaud", "works at", "Graphistry")
add_relationship("Matt", "co-founded", "Graphistry")
add_relationship("Leo", "co-founded", "Graphistry")
add_relationship("Paul", "works at", "Graphistry")
add_relationship("Quinn", "works at", "Graphistry")
add_relationship("Brian", "works at", "Graphistry")

Now, let's convert our graph database to a pandas DataFrame, so it can be uploaded into our tool:


In [7]:
import pandas

In [8]:
nodes = pandas.DataFrame(get_node_list())
edges = pandas.DataFrame(get_edge_list())

And color the nodes based on their "type" property:


In [9]:
# Assign different color to each type in a round robin fashion. 
# For more information and coloring options please visit: https://graphistry.github.io/docs/legacy/api/0.9.2/api.html
unique_types = list(nodes['type'].unique())
nodes['color'] = nodes['type'].apply(lambda x: unique_types.index(x) % 11)

In [10]:
nodes


Out[10]:
name type color
0 Paden Person 0
1 Quinn Person 0
2 Turkey Thing 1
3 Thibaud Person 0
4 Matt Person 0
5 Leo Person 0
6 Berkeley Place 2
7 Rocks Thing 1
8 Motorcycles Thing 1
9 Graphistry Work 3
10 Lee Person 0
11 Oakland Place 2
12 Brian Person 0
13 Paul Person 0
14 San Francisco Place 2

In [11]:
edges


Out[11]:
dest relationship source
0 Oakland lives in Paden
1 Turkey eats Paden
2 Graphistry works at Paden
3 Oakland lives in Quinn
4 Turkey cooks Quinn
5 Graphistry works at Quinn
6 Berkeley lives in Thibaud
7 Rocks climbs Thibaud
8 Graphistry works at Thibaud
9 Berkeley lives in Matt
10 Rocks climbs Matt
11 Graphistry co-founded Matt
12 San Francisco lives in Leo
13 Graphistry co-founded Leo
14 Oakland lives in Brian
15 Motorcycles rides Brian
16 Graphistry works at Brian
17 San Francisco lives in Paul
18 Graphistry works at Paul

Finally, let's vizualize the results!


In [12]:
import graphistry
#graphistry.register(key='YOUR API KEY', server='labs.graphistry.como') #https://www.graphistry.com/api-request
g = graphistry.bind(source="source", destination="dest", node='name', point_color='color', edge_title='relationship')
g.plot(edges, nodes)


Out[12]:

In [ ]: