I am practicing working with custom node/edge attributes in NetworkX, for a NetworkX <-> neo4j interaction package I'm writing. For the purposes of testing and for mimicking neo4j's display principles, I want to label & color my nodes and edges based on these custom properties.
I wrote the following code to label nodes based on their ['data']['label']
attribute, to color nodes based on their ['data']['color']
attribute, and to label edges based on their ['label']
attribute. Only the edges are being labeled as expected.
Surprisingly, my label and color dictionaries print out as expected and in the format required by NetworkX documentation. But the graph drawing is not as expected. What am I doing wrong here?
import networkx as nx
import matplotlib.pyplot as plt
def draw_labeled_net(G: nx.DiGraph):
plt.figure(figsize = (12,12))
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, node_color = get_node_colors(G))
nx.draw_networkx_labels(G, pos, labels = get_node_labels(G), font_size = 12)
nx.draw_networkx_edges(G, pos, edge_color = 'tab:red')
nx.draw_networkx_edge_labels(G, pos, edge_labels = get_edge_labels(G))
plt.show()
def get_node_labels(G: nx.DiGraph):
labels = {}
for i in range(len(G.nodes)):
try:
labels[i] = G.nodes[i]['data']['label']
except KeyError as e:
labels[i] = 'None'
print()
print('Node labels:')
print(labels)
def get_edge_labels(G: nx.DiGraph):
edge_labels = {}
for edge in list(G.edges):
try:
edge_labels[edge] = G.get_edge_data(*edge)['label']
except KeyError as e:
edge_labels[edge] = 'None'
def get_node_colors(G: nx.DiGraph):
colors = {}
for i in range(len(G.nodes)):
try:
colors[i] = f"tab:{G.nodes[i]['data']['color']}"
except KeyError as e:
colors[i] = 'tab:red'
print()
print('Node colors:')
print(colors)
G = nx.DiGraph()
G.add_node(0, data = {'color': 'green', 'label': 'Person'})
G.nodes[0]
G.add_edge(0, 1, label = 'hitBy')
draw_labeled_net(G)
CodePudding user response:
There are a couple of things here that are causing the issue. The main thing is that you are not actually returning anything from your functions, so for example calling get_node_colors(G)
returns None
, which you are passing as arguments to the different drawing functions.
What probably may have confused you and drawn your attention away from the actual problem was the fact that the edge label was displayed correctly. I am not intricately familiar with networkx
, but you can notice that if you remove the edge_labels
argument from the draw_networkx_edge_labels
function then the edge labels are still printed correctly. So the draw function must be using the label you assigned when adding the edge to your graph, and might make you unaware that your get_edge_labels
function is actually returning None
.
Note also that from the documentation, node_color
should be an array of colors that match the length of the number of nodes, so I have changed your get_node_colors
function to return an array instead of a dictionary.
The following code should get you what you want:
import networkx as nx
import matplotlib.pyplot as plt
def draw_labeled_net(G: nx.DiGraph):
plt.figure(figsize = (12,12))
pos = nx.spring_layout(G)
nx.draw_networkx_nodes(G, pos, node_color = get_node_colors(G))
nx.draw_networkx_labels(G, pos, labels = get_node_labels(G), font_size = 12)
nx.draw_networkx_edges(G, pos, edge_color = 'tab:red')
nx.draw_networkx_edge_labels(G, pos)
plt.show()
def get_node_labels(G: nx.DiGraph):
labels = {}
for i in range(len(G.nodes)):
try:
labels[i] = G.nodes[i]['data']['label']
except KeyError as e:
labels[i] = 'None'
print()
print('Node labels:')
print(labels)
return labels
def get_edge_labels(G: nx.DiGraph):
edge_labels = {}
for edge in list(G.edges):
try:
edge_labels[edge] = G.get_edge_data(*edge)['label']
except KeyError as e:
edge_labels[edge] = 'None'
return edge_labels
def get_node_colors(G: nx.DiGraph):
colors = []
for i in range(len(G.nodes)):
try:
colors.append(f"tab:{G.nodes[i]['data']['color']}")
except KeyError as e:
colors.append('tab:red')
print()
print('Node colors:')
print(colors)
return colors
G = nx.DiGraph()
G.add_node(0, data = {'color': 'green', 'label': 'Person'})
G.nodes[0]
G.add_edge(0, 1, label = 'hitBy')
draw_labeled_net(G)