# Describing connections between people (with triples)

If you have seen a simple graph database query, you probably know the pattern "object 1 - relationship - object 2". What is interesting is that this can be described through a simple Python triple, without having to type strange characters. Here we illustrate this on a simple example: a set of people and three possible connection types. Once we have defined them, we can construct triples of simple numbers, which is both expressive and elegant.

For instance the triple (3, 0, 5) could mean that the 3rd person in the list knows (connection type 0) the 5th person on the list. Adding the (5, 0, 7) and (7, 0 , 3) triples would then create a triangle of connections—these individuals know each other. This enables us to visualize the connections and use different colors for each connection type. If, for instance, the connection types were "knows", "speaks with" and "works with", we understand intuitively that there is a degree of gradation, since the first one is the weakest and the last one the strongest one. This gradation can then be used to offer progressively richer colors in the visualization of these connections.

```import matplotlib.pyplot as plt def connection_in_words(triple): p1, conn, p2 = triple return ' '.join([people_coords[p1][0], connections_types[conn], people_coords[p2][0]]) # Reserve 2D point coordinates for each person people_coords = [ ('Sonya', [13, 17]), ('Karl', [14, 28]), ('Tatiana', [15, 24]), ('Felix', [18, 20]), ('John', [25, 17]), ('Johanna', [30, 19]), ('Alexander', [28, 27]), ('Berndt', [22, 22]), ('Peter', [27, 21]), ('Manuel', [25, 28]), ('Chris', [23, 18]), ('Christina', [19, 26]), ('Emiliano', [21, 25]), ('Ines', [27, 23]), ('Hilary', [15, 19]), ('Dennis', [19, 17]), ('Nathan', [20, 21]), ('Fabian', [24, 26]), ('Stefan', [16, 26]), ('Stella', [26, 18]), ('Benedict', [24, 23]), ('Fiona', [25, 19]) ] connections_types = ['knows', 'speaks with', 'works with'] colors = ['yellow', 'orange', 'red'] hor_point_name_dist, vert_point_name_dist = -0.5, 0.2 annotated_names = set() unique_labels = set() # For debugging triple numbers #for i, p in enumerate(people_coords): #print(i, p[0]) # Describe connections (person1_idx, connection_type_idx, person2_idx) connections = [ (0, 0, 1), (9, 0, 3), (2, 0, 15), (12, 0, 14), (15, 0, 20), (2, 0, 0), (9, 0, 8), (13, 0, 16), (16, 0, 21), (8, 0, 4), (4, 0, 5), (11, 0, 14), (10, 0, 6), (20, 0, 18), (15, 0, 13), (9, 0, 18), (17, 0, 12), (12, 0, 0), (13, 0, 11), (21, 0, 15), (12, 0, 10), (3, 0, 1), (14, 0, 16), (18, 0, 8), (11, 0, 1), (20, 0, 8), (15, 1, 20), (10, 1, 6), (9, 1, 18), (11, 1, 14), (12, 1, 10), (11, 1, 1), (8, 1, 4), (15, 1, 13), (12, 1, 0), (15, 1, 20), (4, 1, 5), (12, 2, 10), (11, 2, 1), (8, 2, 4), (15, 2, 13) ] # Example print(connection_in_words(connections[3])) # Dennis knows Benedict # Draw from most to least specific connection with decreasing linewidth for triple in sorted(connections, key=lambda x: x[1], reverse=True): p1, conn, p2 = triple name1, (p1x, p1y) = people_coords[p1] name2, (p2x, p2y) = people_coords[p2] lw = (conn+1) * 5 label = connections_types[conn] plt.plot([p1x, p2x], [p1y, p2y], '-', color=colors[conn], linewidth = lw, alpha = 0.5, label = label if label not in unique_labels else '') unique_labels.add(label) if name1 not in annotated_names: plt.annotate(name1, xy=(p1x, p1y), xytext=( p1x+hor_point_name_dist, p1y+vert_point_name_dist )) annotated_names.add(name1) if name2 not in annotated_names: plt.annotate(name2, xy=(p2x, p2y), xytext=( p2x+hor_point_name_dist, p2y+vert_point_name_dist )) annotated_names.add(name2) plt.title('People and the type of their connection') plt.axis('off') plt.legend(bbox_to_anchor=(-0.14, -0.085, 1, 0.102), ncol=3, frameon=False, fontsize=9) plt.tight_layout() plt.show()```

Now we see why graph databases are often preferred for relationship visualization, although with too much data any figure would become unreadable. For our quick example using a graph was not needed. We can adjust the point coordinates to prevent overlap until we are satisfied with the result. Although the code isn't entirely free of duplication, it offers a simple way to see the connections in a small sized network of annotated nodes. If Karl and Manuel were to be connected, it is easy to see that they both know Felix, who can eventually introduce them to each other. We don't even need a graph library to see details like this. With the help of triples we can build networks and answer queries on them. We need not stop here though: whenever it is needed, we may add further details like edge cost or current flow and total capacity for shortest paths or network flows. The applications are many.