使用 matplotlib 在网络中设置动态节点形状
Set dynamic node shape in network with matplotlib
第一次发帖,请大家文静。 :)
我正在尝试在 Networkx 中绘制不同类型字符的网络,并想为每种类型设置不同的节点形状。例如,我希望角色是圆圈,生物是三角形,等等。我花了几个小时试图弄清楚这一点,并进行了广泛的搜索,但除了为每种类型的字符设置不同的 node_lists 并分别渲染它们,这似乎违反直觉。
问题是我无法从内部访问 node_shape 字典值:
nx.draw_networkx_nodes(G, pos)
我尝试了多种解决方案,包括尝试访问节点属性、创建外部字典或列表并从调用中访问它、设置列表理解或迭代器,但似乎没有任何效果。
要么我传递一个列表,它被批量提取,一个字典,函数无法散列,或者列表的一个实例,例如 shape_list.pop(0)
,在这种情况下,函数只获取第一个值并将其应用于所有节点。
我可以通过创建一个单独的 node_colors 列表来设置颜色,该列表由函数迭代,甚至尝试创建一个字典,以便 node_shape 由 node_color 触发,但这也没有用。
我希望将代码用作在 Python 3.4 和 Django 1.8 中开发的 Web 应用程序的附加组件,因此 Graphviz 不是一个选项。
提前感谢您提供任何帮助或参考备用库。
这是我的代码:
import json
import requests
import networkx as nx
import matplotlib.pyplot as plt
personas = 'http://story-chronicles.herokuapp.com/storyobjects/'
target = requests.get(personas)
x = target.json()
story_objects = {}
labels = {}
node_colors = []
for character in x:
name = character["name"]
story = character["story"]
c_type = character["c_type"]
story_objects[name] = {}
story_objects[name]['name'] = name
story_objects[name]['story'] = story
story_objects[name]['c_type'] = c_type
story_objects[name]['to_relationships'] = []
if character['c_type'] == "Character":
story_objects[name]['node_shape'] = 'o'
story_objects[name]['node_color'] = 'r'
elif character['c_type'] == "Organization":
story_objects[name]['node_shape'] = 'h'
story_objects[name]['node_color'] = 'b'
elif character['c_type'] == "Creature":
story_objects[name]['node_shape'] = '^'
story_objects[name]['node_color'] = 'g'
elif character['c_type'] == "Force":
story_objects[name]['node_shape'] = 'v'
story_objects[name]['node_color'] = 'c'
elif character['c_type'] == "Thing":
story_objects[name]['node_shape'] = 's'
story_objects[name]['node_color'] = 'y'
for relationship in character["to_relationships"]:
break_1 = relationship.find(">>")
break_2 = relationship.find("weight:")
sub_1 = relationship[0:break_1].strip()
context = relationship[break_1:break_2]
weight = relationship[break_2+8:-1]
story_objects[name]['to_relationships'].append([sub_1, context, weight])
G=nx.MultiDiGraph()
for sub in story_objects:
s = story_objects[sub]
if s['story'] == "http://story-chronicles.herokuapp.com/story/1/":
G.add_node(s['name'], node_shape=s['node_shape'])
labels[s['name']] = s['name']
node_colors.append(s['node_color'])
print("***", s['name'], "***", s['c_type'])
print("details:", s['node_color'], s['node_shape'])
for i in s['to_relationships']:
print('target:', i[0])
print('context:', i[1])
print('weight:', i[2])
G.add_edge(s['name'], i[0], weight=int(i[2]))
print("")
node_shapes=nx.get_node_attributes(G, 'node_shape') # Latest attempt at getting this to work
node_shapes = [v for k,v in node_shapes.items()]
pos=nx.spring_layout(G)
G.degree(weight=weight)
nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_shape=node_shapes.pop(0)) # <--- This is where I'm having problems
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos, labels)
plt.show()
恐怕这必须使用多次传递来完成。
主要思想是对 n
个不同的 类 节点重复使用 layout to get the positions of the nodes and then use draw_networkx_nodes。
例如:
import networkx
import pylab
#Build a graph (Node attribute 's' determines the node shape here)
G = networkx.Graph()
G.add_node(0, s="^", b=1)
G.add_node(1, s="^", b=2)
G.add_node(2, s="o", b=3)
G.add_node(3, s="o", b=4)
G.add_node(4, s="v", b=5)
G.add_node(5, s="v", b=6)
networkx.add_path(G, [0,2,5])
networkx.add_path(G, [1,4,3,0])
networkx.add_path(G, [2,4,0,5])
#Drawing the graph
#First obtain the node positions using one of the layouts
nodePos = networkx.layout.spring_layout(G)
#The rest of the code here attempts to automate the whole process by
#first determining how many different node classes (according to
#attribute 's') exist in the node set and then repeatedly calling
#draw_networkx_node for each. Perhaps this part can be optimised further.
#Get all distinct node classes according to the node shape attribute
nodeShapes = set((aShape[1]["s"] for aShape in G.nodes(data = True)))
#For each node class...
for aShape in nodeShapes:
#...filter and draw the subset of nodes with the same symbol in the positions that are now known through the use of the layout.
networkx.draw_networkx_nodes(G,nodePos,node_shape = aShape, nodelist = [sNode[0] for sNode in filter(lambda x: x[1]["s"]==aShape,G.nodes(data = True))])
#Finally, draw the edges between the nodes
networkx.draw_networkx_edges(G,nodePos)
#And show the final result
pylab.show()
最终结果如下所示:
希望这对您有所帮助。
这里与之前的 post(A_A)略有不同。我的使用了很多相同的东西,只放了一条画线并包含了一些标签,并显示了一个二分图。它可能对互联网上的其他人有用,所以我把它放在这里。enter image description here
import networkx as nx
% matplotlib inline
from networkx.algorithms import bipartite
B = nx.Graph()
B.add_nodes_from(['$x_1$','$x_2$','$x_3$'], s='o', bipartite=0) # Add the node attribute 'bipartite'
B.add_nodes_from(['$f_a$','$f_b$','$f_c$','$f_d$'], s='s', bipartite=1)
B.add_edges_from([('$x_1$','$f_a$'),('$x_1$','$f_b$'),('$x_2$','$f_a$'),('$x_2$','$f_b$'),('$x_2$','$f_c$'),('$x_3$','$f_c$'),('$x_3$','$f_d$')])
pos = dict()
X, Y = bipartite.sets(B)
pos.update((n, (i,1)) for i, n in enumerate(X))
pos.update((n, (i+0.5,2)) for i, n in enumerate(Y))
nodeShapes = set((aShape[1]["s"] for aShape in B.nodes(data=True)))
for aShape in nodeShapes:
nx.draw(
B,
pos,
with_labels=True,
node_shape = aShape,
node_color = '0.95',
node_size=1000,
nodelist = [
sNode[0] for sNode in filter(lambda x: x[1]["s"]==aShape, B.nodes(data=True))
]
)
plt.savefig("img/15_Graphical_Models_12b.png") # save as png
第一次发帖,请大家文静。 :)
我正在尝试在 Networkx 中绘制不同类型字符的网络,并想为每种类型设置不同的节点形状。例如,我希望角色是圆圈,生物是三角形,等等。我花了几个小时试图弄清楚这一点,并进行了广泛的搜索,但除了为每种类型的字符设置不同的 node_lists 并分别渲染它们,这似乎违反直觉。
问题是我无法从内部访问 node_shape 字典值:
nx.draw_networkx_nodes(G, pos)
我尝试了多种解决方案,包括尝试访问节点属性、创建外部字典或列表并从调用中访问它、设置列表理解或迭代器,但似乎没有任何效果。
要么我传递一个列表,它被批量提取,一个字典,函数无法散列,或者列表的一个实例,例如 shape_list.pop(0)
,在这种情况下,函数只获取第一个值并将其应用于所有节点。
我可以通过创建一个单独的 node_colors 列表来设置颜色,该列表由函数迭代,甚至尝试创建一个字典,以便 node_shape 由 node_color 触发,但这也没有用。
我希望将代码用作在 Python 3.4 和 Django 1.8 中开发的 Web 应用程序的附加组件,因此 Graphviz 不是一个选项。
提前感谢您提供任何帮助或参考备用库。
这是我的代码:
import json
import requests
import networkx as nx
import matplotlib.pyplot as plt
personas = 'http://story-chronicles.herokuapp.com/storyobjects/'
target = requests.get(personas)
x = target.json()
story_objects = {}
labels = {}
node_colors = []
for character in x:
name = character["name"]
story = character["story"]
c_type = character["c_type"]
story_objects[name] = {}
story_objects[name]['name'] = name
story_objects[name]['story'] = story
story_objects[name]['c_type'] = c_type
story_objects[name]['to_relationships'] = []
if character['c_type'] == "Character":
story_objects[name]['node_shape'] = 'o'
story_objects[name]['node_color'] = 'r'
elif character['c_type'] == "Organization":
story_objects[name]['node_shape'] = 'h'
story_objects[name]['node_color'] = 'b'
elif character['c_type'] == "Creature":
story_objects[name]['node_shape'] = '^'
story_objects[name]['node_color'] = 'g'
elif character['c_type'] == "Force":
story_objects[name]['node_shape'] = 'v'
story_objects[name]['node_color'] = 'c'
elif character['c_type'] == "Thing":
story_objects[name]['node_shape'] = 's'
story_objects[name]['node_color'] = 'y'
for relationship in character["to_relationships"]:
break_1 = relationship.find(">>")
break_2 = relationship.find("weight:")
sub_1 = relationship[0:break_1].strip()
context = relationship[break_1:break_2]
weight = relationship[break_2+8:-1]
story_objects[name]['to_relationships'].append([sub_1, context, weight])
G=nx.MultiDiGraph()
for sub in story_objects:
s = story_objects[sub]
if s['story'] == "http://story-chronicles.herokuapp.com/story/1/":
G.add_node(s['name'], node_shape=s['node_shape'])
labels[s['name']] = s['name']
node_colors.append(s['node_color'])
print("***", s['name'], "***", s['c_type'])
print("details:", s['node_color'], s['node_shape'])
for i in s['to_relationships']:
print('target:', i[0])
print('context:', i[1])
print('weight:', i[2])
G.add_edge(s['name'], i[0], weight=int(i[2]))
print("")
node_shapes=nx.get_node_attributes(G, 'node_shape') # Latest attempt at getting this to work
node_shapes = [v for k,v in node_shapes.items()]
pos=nx.spring_layout(G)
G.degree(weight=weight)
nx.draw_networkx_nodes(G, pos, node_color=node_colors, node_shape=node_shapes.pop(0)) # <--- This is where I'm having problems
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos, labels)
plt.show()
恐怕这必须使用多次传递来完成。
主要思想是对 n
个不同的 类 节点重复使用 layout to get the positions of the nodes and then use draw_networkx_nodes。
例如:
import networkx
import pylab
#Build a graph (Node attribute 's' determines the node shape here)
G = networkx.Graph()
G.add_node(0, s="^", b=1)
G.add_node(1, s="^", b=2)
G.add_node(2, s="o", b=3)
G.add_node(3, s="o", b=4)
G.add_node(4, s="v", b=5)
G.add_node(5, s="v", b=6)
networkx.add_path(G, [0,2,5])
networkx.add_path(G, [1,4,3,0])
networkx.add_path(G, [2,4,0,5])
#Drawing the graph
#First obtain the node positions using one of the layouts
nodePos = networkx.layout.spring_layout(G)
#The rest of the code here attempts to automate the whole process by
#first determining how many different node classes (according to
#attribute 's') exist in the node set and then repeatedly calling
#draw_networkx_node for each. Perhaps this part can be optimised further.
#Get all distinct node classes according to the node shape attribute
nodeShapes = set((aShape[1]["s"] for aShape in G.nodes(data = True)))
#For each node class...
for aShape in nodeShapes:
#...filter and draw the subset of nodes with the same symbol in the positions that are now known through the use of the layout.
networkx.draw_networkx_nodes(G,nodePos,node_shape = aShape, nodelist = [sNode[0] for sNode in filter(lambda x: x[1]["s"]==aShape,G.nodes(data = True))])
#Finally, draw the edges between the nodes
networkx.draw_networkx_edges(G,nodePos)
#And show the final result
pylab.show()
最终结果如下所示:
希望这对您有所帮助。
这里与之前的 post(A_A)略有不同。我的使用了很多相同的东西,只放了一条画线并包含了一些标签,并显示了一个二分图。它可能对互联网上的其他人有用,所以我把它放在这里。enter image description here
import networkx as nx
% matplotlib inline
from networkx.algorithms import bipartite
B = nx.Graph()
B.add_nodes_from(['$x_1$','$x_2$','$x_3$'], s='o', bipartite=0) # Add the node attribute 'bipartite'
B.add_nodes_from(['$f_a$','$f_b$','$f_c$','$f_d$'], s='s', bipartite=1)
B.add_edges_from([('$x_1$','$f_a$'),('$x_1$','$f_b$'),('$x_2$','$f_a$'),('$x_2$','$f_b$'),('$x_2$','$f_c$'),('$x_3$','$f_c$'),('$x_3$','$f_d$')])
pos = dict()
X, Y = bipartite.sets(B)
pos.update((n, (i,1)) for i, n in enumerate(X))
pos.update((n, (i+0.5,2)) for i, n in enumerate(Y))
nodeShapes = set((aShape[1]["s"] for aShape in B.nodes(data=True)))
for aShape in nodeShapes:
nx.draw(
B,
pos,
with_labels=True,
node_shape = aShape,
node_color = '0.95',
node_size=1000,
nodelist = [
sNode[0] for sNode in filter(lambda x: x[1]["s"]==aShape, B.nodes(data=True))
]
)
plt.savefig("img/15_Graphical_Models_12b.png") # save as png