I am trying to run the following code to plot networkx graph but it gives me type error: list indices must be integers or slices, not str. May you help me with that?
pos = [[6.886709112999999, 50.50618938]]
nodes = ['866','144']
edges = [['866', '144']]
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
nx.draw_networkx(G, pos)
plt.show()
If you want to specify the positions for draw_networkx you should supply a dictionary of positions (x,y):
pos (dictionary, optional) – A dictionary with nodes as keys and positions as values. If not specified a spring layout positioning will be computed. See networkx.drawing.layout for functions that compute node positions.
You can take a look here (how to plot a networkx graph using the (x,y) coordinates of the points list?) for a recent example.
Or with your small example:
import networkx as nx
import matplotlib.pylab as plt
pos = {'866':[6.886709112999999, 0], '144': [50.50618938, 0]}
nodes = ['866','144']
edges = [['866', '144']]
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
nx.draw_networkx(G, pos)
plt.show()
The type error you observed, is probably caused by networks trying to call your pos list with the nodes as index, e.g. pos['866'].
Related
I'm trying to create a visualization for a tree graph using networkx.
How can I choose the root node? i.e. the first one from the top.
Running this code:
import networkx as nx
import pydot
import matplotlib.pyplot as plt
from networkx.drawing.nx_pydot import *
G = nx.Graph()
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(2,4)
G.add_edge(4,5)
G.add_edge(4,6)
G.add_edge(5,7)
pos = pydot_layout(G, prog="dot", root=4)
nx.draw(G, pos, with_labels=True)
plt.show()
Gives this output:
Note that I used root=4 to create the layout but still the root in the picture is node 1.
How can I decide which node is chosen as first/top one?
With other prog options such as "twopi" it does react to what I set as root.
I found a solution if G is a tree. Create an auxiliary (directed / nx.DiGraph) graph where the direction of each edge (v,w) is determined by the order in wich v and w are explored in a BFS starting at the root.
Then get the layout pos out of the directed graph aux_G and plot G with it
aux_G = my_func_directed_bfs(G, root=4)
pos = pydot_layout(aux_G , prog="dot")
nx.draw(G, pos, with_labels=True)
plt.show()
NOTE: Networkx visualization always returns a plot random to the nodes.
Just because node 1 is appearing on the top of chart DOESN'T MEAN it is the root node! Since you may be using PyCharm (or whatever editor), the case may be every time you run your script, it stores some cache so you can get same output but I assure you the node visualization is created on the go.
Since you want to differentiate betweeen root node and other nodes, I recommend you to use node_color parameter of nx.draw().
Create a list of colors for each node and pass it to node_color
Here the full modified code you can use :-
G = nx.Graph()
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(2,4)
G.add_edge(4,5)
G.add_edge(4,6)
G.add_edge(5,7)
pos = pydot_layout(G, prog="dot", root=4)
colors = []
for node in G:
if node == 4:
colors.append('red')
else:
colors.append('blue')
pos = pydot_layout(G, prog="dot", root=4)
nx.draw(G, pos,node_color=colos,with_labels=True)
plt.show()
Unfortunately, since the networkx visualization is integrated with highly denser visualization libraries like seaborn and matplotlib, it is not possible to decide the orientation of each node.
So I am trying to generate a hexagonal lattice using NetworkX in Python. After using code:
G = nx.hexagonal_lattice_graph(m=2, n=2, periodic=False, with_positions=True, create_using=None)
plt.subplot(111)
nx.draw(G, with_labels=True, font_weight='bold')
plt.show()
I am getting a hexagonal lattice which looks like this:
lattice
As you can see, this lattice is formed from irregular hexagons and everytime the code is ran the shape changes. Is there a way to generate a perfect hexagonal lattice using NetworkX, i.e this, but with only X number of hexagons?
Thanks!
You need to use the with_postion attribute in the hexagonal_lattic_graph function and set it to True. This will store the positions of the nodes in an attribute called pos inside the Graph G itself. You can read more about from the documentation here:
with_positions (bool (default: True)) – Store the coordinates of each node in the graph node attribute ‘pos’. The coordinates provide a lattice with vertical columns of hexagons offset to interleave and cover the plane. Periodic positions shift the nodes vertically in a nonlinear way so the edges don’t overlap so much.
So, you just need to extract the positions from the graph itself, like this:
pos = nx.get_node_attributes(G, 'pos')
Then, pass this with pos while drawing your graph
import networkx as nx
import matplotlib.pyplot as plt
# create the graph and set with_positions=True
G = nx.hexagonal_lattice_graph(m=2, n=2, periodic=False, with_positions=True, create_using=None)
plt.subplot(111)
# Extract the positions
pos = nx.get_node_attributes(G, 'pos')
# Pass the positions while drawing
nx.draw(G, pos=pos, with_labels=True, font_weight='bold')
plt.show()
Imagine you have a network of 10 nodes and the nodes value is values = [i for i in range(len(10))]
Now I want to color this network however, I only want a color map of the nodes that have a value less than 5. How do I do this?
Thank you in advance.
For that, you can simply not include (filte out) those nodes you want to avoid when plotting in nx.draw. If you do want to include them, though just without a colormap (perhaps a constant color), just use a constant color rather than removing those nodes. Here's an example using a random graph:
import networkx as nx
import matplotlib as mpl
from matplotlib import pyplot as plt
G = nx.barabasi_albert_graph(10, 1)
# defines a colormap lookup table
nodes = sorted(list(G.nodes()))
low, *_, high = sorted(values)
norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)
To include all nodes, but have those <5 without any colormap:
plt.subplots(figsize=(10,6))
nx.draw(G,
nodelist=values,
node_size=500,
node_color=[mapper.to_rgba(i) if i>5 else 'lightblue'
for i in values],
with_labels=True)
plt.show()
To directly remove them:
plt.subplots(figsize=(10,6))
pos = nx.spring_layout(G)
nx.draw_networkx_edges(G, pos=pos)
nx.draw_networkx_nodes(G, pos=pos,
nodelist=[i for i in values if i>5],
node_color=[mapper.to_rgba(i)
for i in nodes if i>5])
nx.draw_networkx_labels(G, pos=pos,
labels={node:node for node in nodes if node>5})
I have a DiGraph() in NetworkX and would like to set edge color for each edge in an CircosPlot. I'm using the following syntax (this is just an example):
import networkx as nx
G = nx.DiGraph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(2,3,color='b',weight=4)
pos = nx.circular_layout(G)
edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]
weights = [G[u][v]['weight'] for u,v in edges]
a = CircosPlot(G, figsize=(15,15), edge_color=colors)
a.draw()
plt.show()
This results in the following error:
TypeError: unhashable type: 'list'
Any ideas how to get the edge color working on CircosPlot? (Note that the same code with nx.draw instead of CircosPlot works)
I took the liberty of adding a few more nodes to he graph so nodes in the CircosPlot are a bit smaller (big nodes make it harder to see the edges).
I also increased the edge weights so the color is easier to see.
G = nx.DiGraph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
G.add_node(6)
G.add_edge(1,2,color='r',weight=6)
G.add_edge(2,3,color='b',weight=6)
G.add_edge(3,1,color='b',weight=6)
a = nxv.CircosPlot(G, node_labels='gender',
edge_color='color', edge_width='weight')
a.draw()
You have to specify the attribute name for the graph properties instead of a list. The API is similar to the seaborn package.
This answer demonstrates how to draw a graph with custom colors and edge thickness using the following code:
import networkx as nx
G = nx.Graph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(2,3,color='b',weight=4)
G.add_edge(3,4,color='g',weight=6)
pos = nx.circular_layout(G)
edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]
weights = [G[u][v]['weight'] for u,v in edges]
nx.draw(G, pos, edges=edges, edge_color=colors, width=weights)
Suppose however, that I want to graph a multi graph like:
G = nx.MultiGraph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(1,2,color='b',weight=3)
G.add_edge(2,3,color='r',weight=4)
G.add_edge(2,3,color='b',weight=6)
Calling something like draw should result in a total of three points. Point 1 and 2 should have both a red and blue line between them, similarly 2 and 3 should have both a red and blue line between them as well.
This fails to work for multigraphs because the multiple edges requires a different storage technique. Is there a relatively easy way around this?
Also, I believe this question and answer does not apply. The questioner uses the MultiGraph object, however, the actual graph is not a multigraph. The solution, is to chose the first (and, in his case, only) edge. In this case, however, both edges are needed in the drawing phase.
Is there a way to graph the multiple edges with different colors and weights in networkx?
You just need to access the edges of a multigraph in a different way
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
G = nx.MultiGraph()
G.add_edge(1,2,color='r',weight=8)
G.add_edge(1,2,color='b',weight=3)
G.add_edge(2,3,color='r',weight=4)
G.add_edge(2,3,color='c',weight=6)
pos = nx.circular_layout(G)
edges = G.edges()
colors = []
weight = []
for (u,v,attrib_dict) in list(G.edges.data()):
colors.append(attrib_dict['color'])
weight.append(attrib_dict['weight'])
nx.draw(G, pos, edges=edges, edge_color=colors, width=weight, )
plt.show()
Here is another combination of edges
G = nx.MultiGraph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(1,2,color='b',weight=3)
G.add_edge(2,3,color='r',weight=4)
G.add_edge(2,3,color='b',weight=6)
You can read more about accessing multigraph edges here.