Having the following code:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
G.add_nodes_from(range(1, 10))
G.add_edges_from([(1, 3), (2, 4), (3, 4), (2,6), (1, 2), (4, 9), (9, 1)])
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True)
plt.show()
G.add_node(10)
nx.draw(G, pos, with_labels=True) # this gives the error
plt.show()
How can I add node 10 to the graph at a random position?
The error I'm actually getting is:
NetworkXError: Node 10 has no position.
How can I include the newly created node to the graph already built spring_layout?
The problem (as already noted by others) is that pos is a dict which assigns a position to each node. But when you've added a node, it doesn't update pos.
The following will find a good position for new node 10 given the existing position of all the other nodes. Basically, it calls spring_layout again, but holds all of the existing nodes in place. I've got node 10 connected to node 9.
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
G.add_nodes_from(range(1, 10))
G.add_edges_from([(1, 3), (2, 4), (3, 4), (2,6), (1, 2), (4, 9), (9, 1)])
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True)
plt.show()
G.add_node(10)
G.add_edge(9,10) #So node 10 should be close to node 9
oldnodes = list(G.nodes())
oldnodes.remove(10)
pos = nx.spring_layout(G, pos=pos, fixed=oldnodes)
nx.draw(G, pos, with_labels=True)
plt.show()
The output from spring layout is a dictionary mapping nodes to positions
{nodeid:[x,y]}. To place the new node randomly, you have to give it a random position in the pos dictionary.
Here is an example that finds the bounding box and then picks a random point somewhere inside.
import numpy as np
bounds = np.zeros((2,2)) # xy min, xymax
for pt in pos.values():
bounds[0] = np.min([bounds[0],pt], axis=0) # compare point to bounds and take the lower value
bounds[1] = np.max([bounds[1],pt], axis=0) # compare point to bounds and take the highest value
pos[10] = (bounds[1] - bounds[0]) * np.random.random(2) + bounds[0]
Related
What I Want?
I have a Graph with a lot of vertices and a lot of edges. The vertices are coordinated.
I am tring to check the planarity of the graph and I always get True as an answer.
Exmple
Here is a small exmple:
pos = {1: (0, 0), 2: (0, 1), 3: (1, 1), 4: (1, 0)}
G = nx.Graph().to_undirected()
G.add_nodes_from(pos)
G.add_edge(1, 3, weight=1)
G.add_edge(2, 4, weight=1)
G.add_edge(2, 3, weight=1)
print(nx.check_planarity(G, False))
nx.draw_networkx(G, with_labels=True, pos=pos)
plt.show()
the output is:
(True, <networkx.algorithms.planarity.PlanarEmbedding object at 0x07CD3E30>)
As you can see clearly the graph is not planarity, however the result is still True
What am I doing worng?
Note that a graph is planar if it can be drawn in the Euclidean plane without any edge intersections.
In your case your graph is planar, as it is enough to swap nodes 1 and 4 to avoid edge intersections.
However, if you consider a complete graph (a complete graph Kn is planar only for n ≤ 4) you can see the difference.
>>> K4 = nx.complete_graph(4)
>>> nx.check_planarity(K4)
(True, <networkx.algorithms.planarity.PlanarEmbedding object at 0x1035df1d0>)
>>> K5 = nx.complete_graph(5)
>>> nx.check_planarity(K5)
(False, None)
You may use the answer of check_planarity to draw a possible planar layout.
import networkx as nx
import matplotlib.pyplot as plt
pos = {1: (0, 0), 2: (0, 1), 3: (1, 1), 4: (1, 0)}
G = nx.Graph().to_undirected()
G.add_nodes_from(pos)
G.add_edge(1, 3, weight=1)
G.add_edge(2, 4, weight=1)
G.add_edge(2, 3, weight=1)
is_planar, G2 = nx.check_planarity(G, False)
print(is_planar)
# plotting
fig = plt.figure()
ax = fig.add_subplot(121)
ax = plt.gca()
ax.margins(0.20)
nx.draw_networkx(G, with_labels=True, pos=pos)
ax = fig.add_subplot(122)
ax = plt.gca()
ax.margins(0.20)
nx.draw_networkx(G2, with_labels=True)
plt.show()
I generated a graph using networkx
import networkx as nx
G = nx.grid_graph(dim=[5,5])
nx.draw(G);
Then I compute the minimal path between two nodes using the astar algorithm
def dist(a, b):
(x1, y1) = a
(x2, y2) = b
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
nodes = list(G.nodes)
tmp = nx.astar_path(G,nodes[3],nodes[14],dist)
Now I would like to to modify the color and the size of the edges of the path between the nodes, where the nodes are defined by tmp
tmp
[(0, 3), (1, 3), (2, 3), (2, 4)]
You need to plot each of the network's components with its own commands. Here is a working code that demonstrates how to achieve such a plot.
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
# only relevant part is treated here
G = nx.grid_graph(dim=[5,5])
node_list = [(0, 3), (1, 3), (2, 3), (2, 4)]
edge_list = [[(0, 3), (1, 3)], [(1, 3), (2, 3)], [(2, 3), (2, 4)]]
pos = nx.spring_layout(G)
nx.draw(G, pos=pos, with_labels=True)
# draw selected nodes in green with triangle shape
nx.draw_networkx_nodes(G, pos=pos, nodelist=node_list, node_size=300, node_color='g', node_shape='^')
# draw selected edges in blue with solid line
nx.draw_networkx_edges(G, pos=pos, edgelist=edge_list, width=3.0, edge_color='blue', style='solid')
The output plot:
I am using NetworkX to create a multi-edge graph in Python,
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
Nodes = [0, 1]
G.add_nodes_from(Nodes)
Edges = [(0,1)]
#Edges =[(0, 1, 0), (0, 1, 1), (0, 1, 2)]
G.add_edges_from(Edges)
nx.draw(G)
plt.savefig("path.png")
For a simple graph , defining Edges = [(0,1)] allows me to use G.add_edges_from. But, when multiple edges are defined between the nodes 0 and 1 Edges =[(0, 1, 0), (0, 1, 1), (0, 1, 2)] I couldn't use G.add_edges_from to add edges.
I would like to ask for suggestions on how to create a graph with multi-edges.
Changing G = nx.Graph() to G = nx.MultiGraph() helps in resolving the error.
I have a complete graph (all nodes are directly connected by an edge), and I want to color a subset of nodes and edges over the same graph. The complete graph for N=5 is this.
N=5 COMPLETE GRAPH
Now I want to color, for example, the next subset of edges: [(0, 3), (1, 0), (2, 1), (3, 4), (4, 2)] in blue. How can I do that over the same graph?.
Thanks in advance.
If you use the draw_networkx_* functions to separately draw each part of the graph (nodes, node labels, edges, edge labels), you have fine control of what is rendered. The main trick is to produce the positions dictionary and then reuse it for each drawing function.
import networkx as nx
import itertools
import matplotlib.pyplot as plt
# produce a degree-5 complete directed graph
G = nx.DiGraph()
edges = itertools.permutations(xrange(5), 2) # see https://stackoverflow.com/a/10651524/1643946
G.add_edges_from(edges)
# specific path to highlight
elist = [(0, 3), (1, 0), (2, 1), (3, 4), (4, 2)]
# set up layout
pos = nx.circular_layout(G)
# draw it
nx.draw_networkx_nodes(G, pos)
nx.draw_networkx_labels(G, pos)
nx.draw_networkx_edges(G, pos, edge_color='k', width=0.5) # show all edges, thin lines
nx.draw_networkx_edges(G, pos, edgelist=elist, edge_color='b', width=2) # highlight elist
# turn off axis markings
plt.axis('off')
Produces a graph like this:
I have a polygon comprising of 5 edges. Each edge has its own width, which is randomly generated between 0.2 and 0.5 here for illustration purpose.
Code
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.path import Path
import math as mt
import random
def buildRectPath(edge, width):
theta = mt.atan((edge[1][1]-edge[0][1]) / (edge[1][0]-edge[0][0]+0.0000001)) # avoid ZeroDivisionError
x_left_top = edge[0][0] - mt.sin(theta) * width
y_left_top = edge[0][1] + mt.cos(theta) * width
x_left_bottom = edge[0][0]
y_left_bottom = edge[0][1]
x_right_top = edge[1][0] - mt.sin(theta) * width
y_right_top = edge[1][1] + mt.cos(theta) * width
x_right_bottom = edge[1][0]
y_right_bottom = edge[1][1]
verts = [(x_left_bottom, y_left_bottom), # left, bottom
(x_left_top, y_left_top), # left, top
(x_right_top, y_right_top), # right, top
(x_right_bottom, y_right_bottom), # right, bottom
(x_left_bottom, y_left_bottom),] # ignored
codes = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,]
path = Path(verts, codes)
return path
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])
axes.axis('equal')
poly = [(1, 1), (2, 4), (4, 6), (6, 6), (8, 3), (1, 1)] # construct a random polygon
# expand each edge of the polygon (to different widths)
edges = [[(1, 1), (2, 4)], [(2, 4), (4, 6)], [(4, 6), (6, 6)], [(6, 6), (8, 3)], [(8, 3), (1, 1)]]
widths = [random.uniform(0.2, 0.5) for cnt in xrange(5)] # generate random widths for the 5 edges
for i, edge in enumerate(edges):
axes.plot([edge[0][0], edge[1][0]], [edge[0][1], edge[1][1]], color='b')
rectPath = buildRectPath(edge, widths[i])
rectPatch = patches.PathPatch(rectPath, facecolor='yellow', alpha=0.5)
axes.add_patch(rectPatch)
Output
Goal
I want to get a smooth contour of the shape. Basically, I am expecting two curves, one for inner loop and the other for the outer loop.
Note that
Since the widths of the lines are different, the contour that I am looking for is kind of like a fitting line that considers all the widths.
Currently there exist gaps between the rectangles. The contour should be a continuous curve that is gap-free.