使用 networkx 绘制三个人的共同朋友关系

Draw common friends connections of three people using networkx

我有三个人(可以选择添加更多人),我想将每个人的朋友列表显示为一个圈子。所以,每人 1 个圆圈。接下来,如果两个人有相同的朋友,我想添加边(连接)。

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")

问题:我得到空图,没有显示 3 个有连接的圆圈。感谢帮助。已删除 'Return G'。

这是一种方法。首先,您会发现 有多少 个共同朋友有 Mike、Alex 和 Stephen。我通过使用 set 来做到这一点;这是迈克和亚历克斯的例子。

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

我图中的节点称为 MikeAlexStephen。下面我设置边 Mike -- Alex 所以它的值为 M_A_common.

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

这是所有朋友的完整示例,我用 nx.draw 绘制网络,用 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()

您可以不写共同朋友的数量,例如显示边厚的普通朋友数量。

当然,朋友越多,组合就越多,所以您可能希望自动计算普通朋友。

另外,如果你想为每个共同的朋友设置多个边,你需要使用 MultiGraph 而不是 Graph。要绘制多条边,请查看 here.

编辑:

要为上面的代码添加自定义节点标签(例如节点名称 + 好友总数),您可以像这样使用 nx.draw_networkx_labels

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()

如果你有 20 个朋友,上面的代码会变得非常混乱。下面是一种更优雅的方法,我将节点及其朋友存储在名为 friends.

的字典中

为了获得所有可能的边,我使用 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()

输出:

编辑 2:

我更正了代码中的一行,该行现在提供了不同的边缘标签(只有 edge_labels 没有键的值)。