0

I have three people (with option of adding more people) and I want to show each person friends list as a circle. So, 1 circle per person. Next, I want to add edges(connections) if two people have same friend.

Mike_friends = ['Al', 'Niki', 'Silvia', 'Anna', 'Matt', 'Gia', 'Nick', 'Maud', 'Sarah', 'Lisa', 'Kelvin']
Alex_friends = ['Harvey', 'Steve', 'Michael', 'Maud', 'Al', 'Kam', 'Hank']
Stephen_friends = ['Lisa','Rosie','Mango','Kate','Nate','Maud','Kelvin','Elvis','Arstad','Jesus','Johan','Jay','Gia','Niki','Harvey','Paul','Mike','Alex','Anna']
import networkx as nx
import matplotlib.pyplot as plt

def link_networks(N1, N2, N3, N4=None, N5=None, N6=None, N7=None, N8=None, N9=None):
    G = nx.Graph()
    for item1 in N1:
        for item2 in N2:
            for item3 in N3:
                if item1 in N1 == item2 in N2:
                    G.add_edge(item1, item2)
                elif item1 in N1 == item3 in N3:
                    G.add_edge(item1, item3)
                elif item2 in N2 == item3 in N3:
                    G.add_edge(item2, item3)
link_networks(Mike_friends, Alex_friends, Stephen_friends)
plt.figure(figsize = (20, 10))
mytitle = "friend circle connections"
plt.title(mytitle, fontsize=40)
nx.draw_networkx(G, font_size=10, node_size=2000, alpha=0.6)
plt.savefig("friend_circles.pdf")

The problem: I get empty figure, 3 circles with connections do not show up. Thanks for help. Removed 'Return G'.

J.A
  • 204
  • 1
  • 4
  • 13
  • @Bonlenfum you helped with my earlier networkx question, any suggestions on how I can go about the drawing social friend connections? – J.A Mar 29 '17 at 10:33
  • You need to really back up and come at this again. The number of misunderstandings in your code is really big. – Joel Mar 29 '17 at 21:12
  • @Joel Thanks for comments. I called the function. i in N1,N2, N3 stands for each item in the list. 'Return G' will now be called after all iterations. I edited from add.edge to add.edges_from . Same problem exists, just empty square with no circles. – J.A Mar 30 '17 at 02:31
  • There's also the question of what is going on with `G`. It's currently a global variable. Your function is returning `G` as well, but the returned value isn't sent anywhere. – Joel Mar 30 '17 at 03:42
  • @Joel any better? – J.A Mar 30 '17 at 08:06
  • It's getting better, but `item1 in N1` will be `True`, as will `item2 in N2`. So now you're going to have the first `if` statement execute every time through. – Joel Mar 30 '17 at 17:39
  • And now your function doesn't return anything - the rest of the program never knows anything about `G` existing. So it'll crash when you ask it to plot `G`. – Joel Mar 30 '17 at 17:40

1 Answers1

1

Here is one way of doing it. First you find how many common friends have Mike, Alex and Stephen. I do this by using set; here's the example for Mike and Alex.

M_A_common = len(set(Mike_friends) & set(Alex_friends))

The nodes in my graph are called Mike, Alex and Stephen. Below I set the edge Mike -- Alex so it has the value of M_A_common.

G.add_edge('Mike', 'Alex', common_friends=M_A_common)

Here is the full example with all friends where I draw the network with nx.draw and the edge labels with nx.draw_networkx_edge_labels.

import networkx as nx
import matplotlib.pyplot as plt

Mike_friends = ['Al', 'Niki', 'Silvia', 'Anna', 'Matt', 'Gia', 'Nick', 'Maud', 'Sarah', 'Lisa', 'Kelvin']
Alex_friends = ['Harvey', 'Steve', 'Michael', 'Maud', 'Al', 'Kam', 'Hank']
Stephen_friends = ['Lisa','Rosie','Mango','Kate','Nate','Maud','Kelvin','Elvis','Arstad','Jesus','Johan','Jay','Gia','Niki','Harvey','Paul','Mike','Alex','Anna']

G = nx.Graph()
G.add_node('Mike')
G.add_node('Alex')
G.add_node('Stephen')

M_A_common = len(set(Mike_friends) & set(Alex_friends))  # number of common friends
M_S_common = len(set(Mike_friends) & set(Stephen_friends))  # number of common friends
S_A_common = len(set(Stephen_friends) & set(Alex_friends))  # number of common friends

G.add_edge('Mike', 'Alex', common_friends=M_A_common)
G.add_edge('Mike', 'Stephen', common_friends=M_S_common)
G.add_edge('Stephen', 'Alex', common_friends=S_A_common)

pos = nx.circular_layout(G)
nx.draw(G, pos, node_size=2000, with_labels=True)
edge_labels = nx.get_edge_attributes(G, 'common_friends')
nx.draw_networkx_edge_labels(G, pos, labels=edge_labels)
plt.show()

enter image description here

Instead of writing the number of common friends you could e.g. show the amount of common friends with edge thickness.

Of course, with more friends you will have more combinations so you'll probably want to automate the calculation of common friends.

Also, if you want multiple edges for each common friend you need to use MultiGraph instead of Graph. For drawing multiple edges take a look here.

EDIT:

To add custom node labels (e.g. node name + number of total friends) for the code above you could use nx.draw_networkx_labels like this:

pos = nx.circular_layout(G)
nx.draw(G, pos, node_size=2000, with_labels=False)
node_labels = {
    'Mike': 'Mike (' + str(len(Mike_friends)) + ' total)',
    'Alex': 'Alex (' + str(len(Alex_friends)) + ' total)',
    'Stephen': 'Stephen (' + str(len(Stephen_friends)) + ' total)'
}
nx.draw_networkx_labels(G, pos, labels=node_labels)
edge_labels = nx.get_edge_attributes(G, 'common_friends')
nx.draw_networkx_edge_labels(G, pos, labels=edge_labels)
plt.show()

If you had 20 friends the code above would get really messy. Below is a more elegant approach where I store the nodes and their friends in a dictionary called friends.

To get all possible edges I use itertools.combinations

import networkx as nx
import matplotlib.pyplot as plt
from itertools import combinations

G = nx.Graph()
friends = {
    'Mike': ['Al', 'Niki', 'Silvia', 'Anna', 'Matt', 'Gia', 'Nick', 'Maud', 'Sarah', 'Lisa', 'Kelvin'],
    'Alex': ['Harvey', 'Steve', 'Michael', 'Maud', 'Al', 'Kam', 'Hank'],
    'Stephen': ['Lisa','Rosie','Mango','Kate','Nate','Maud','Kelvin','Elvis','Arstad','Jesus','Johan','Jay','Gia','Niki','Harvey','Paul','Mike','Alex','Anna']
}

persons = list(friends.keys())  # Mike, Alex, Stephen
G.add_nodes_from(persons)
combos = list(combinations(persons, 2))  # all 2-combinations of `persons`

for edge in combos:
    node_1, node_2 = edge[0], edge[1]
    common = len(set(friends[node_1]) & set(friends[node_2]))  # number of common friends
    G.add_edge(node_1, node_2, common_friends=common)

node_labels = {person: person + ' (' + str(len(friends[person])) + ' total)' for person in persons}
edge_labels = nx.get_edge_attributes(G, 'common_friends')

pos = nx.circular_layout(G)
nx.draw(G, pos, node_size=2000, with_labels=False)
nx.draw_networkx_labels(G, pos, labels=node_labels)
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
plt.show()

Output:

enter image description here

EDIT 2:

I corrected a line in my code that now gives different edge labels (only values without keys for edge_labels).

Community
  • 1
  • 1
edo
  • 1,712
  • 1
  • 18
  • 19
  • Thanks a lot @edo Is there a way to show the total number of friends for each node? I can do this social circle for 10-20 friends in the same way right? – J.A Mar 30 '17 at 12:56
  • I have an unrelated question: Is there a quick way to show the names of 2 common friends between nodes Mike and Alex? – J.A Mar 31 '17 at 10:46
  • 1
    You could set an edge attribute that holds the names of common friends in a string, like e.g. `', '.join(list(set(friends[node_1]) & set(friends[node_2])))`, and that draw this new edge label. – edo Mar 31 '17 at 11:27
  • Thanks a lot, it works fine. And finally, if I were to work with 20,50 or 100 nodes networks instead of 3 in here, would you still use this networkx library? Or is there better visualisation for more nodes with highly-dimensional data? – J.A Mar 31 '17 at 13:41
  • Networkx is fine for processing data but if you have a lot of nodes its worth looking into other solutions for graph visualisation. I only used networkx so I don't have any alternative tools to recommend. – edo Mar 31 '17 at 13:52
  • One more related question: Since I have a lot of nodes, it is messy to have all possible edges between any 2 nodes. I wanted to ask if you know quick way to have one node as a parent node and all other nodes as children nodes and show common friends between the parent and each of children nodes only? In the example of 3 friends above, I will have 2 edges only: Mike is a parent node, and it will have 2 connections, to Alex and Stephen. And each edge will show number of common friends. – J.A Apr 03 '17 at 11:14
  • To draw only some edges and edge labels you need to use the `edgelist` keyword in `nx.draw` and the `edge_labels` keyword in `nx.draw_networkx_edge_labels`. You need to define a new list/dict of edges and edge labels that contain `Mike` as one of the nodes. Note that I corrected a mistake in my code. – edo Apr 03 '17 at 15:35
  • Hi @edo, could you help with this question? https://stackoverflow.com/questions/46751996/selecting-and-importing-only-certain-columns-from-excel-for-importing – J.A Oct 16 '17 at 03:46