I have a graph with nodes and edges. The code colors the array Edges with the array Weights as shown in the current output. Is it possible to put arrows on the array elements in Edges as displayed in the expected output? I want arrows on specific edges according to Edges, not all.
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.cm import ScalarMappable
N = 1
def pos():
x, y = 1, N + 3 - 1
for _ in range(2 * N * (N + 1)):
yield (x, y)
y -= (x + 2) // (N + 3)
x = (x + 2) % (N + 3)
G = nx.Graph()
it_pos = pos()
for u in range(2 * N * (N + 1)):
G.add_node(u + 1, pos=next(it_pos))
if u % (2 * N + 1) < N:
for v in (u - 2 * N - 1, u - N - 1, u - N):
if G.has_node(v + 1):
G.add_edge(u + 1, v + 1)
elif u % (2 * N + 1) == N:
G.add_edge(u + 1, u - N + 1)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N - 1, u - N):
G.add_edge(u + 1, v + 1)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u + 1, v + 1)
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold')
Edges=np.array([[1,2],[1,3],[1,4]])
Weights=np.array([[1.7],[2.9],[8.6]])
flat_weights = Weights.flatten()
weights_normalized = [x / max(flat_weights) for x in flat_weights]
edge_weight_map = dict(zip([tuple(e) for e in Edges.tolist()],weights_normalized))
my_cmap = plt.cm.get_cmap('Oranges')
colors = my_cmap([edge_weight_map.get(tuple(e), 0) for e in Edges.tolist()])
pos = nx.get_node_attributes(G, 'pos')
sm = ScalarMappable(cmap=my_cmap, norm=plt.Normalize(0,max(flat_weights)))
nx.draw_networkx_edges(G, pos, edge_color=colors,
edgelist=[tuple(e) for e in Edges.tolist()],
width=5);
plt.colorbar(sm)
The current output is
The expected output is
You are almost there.
First, you will need to create a directed graph instead of an undirected graph:
G = nx.DiGraph()
Second, DiGraph objects are plotted with arrow heads by default, so you need to specify arrows=False in the call to nx.draw(...).
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold', arrows=False)
If you now plot your selected edges separately, they come with arrow heads (per default).
Related
I have a network with nodes and vertices and the following numbering scheme. I want to generate an adjacency matrix A for the nodes 0,1 as shown below. I tried to do using networkx. I present the current and expected outputs.
import networkx as nx
N=2
def pos():
x, y = 1, N + 3 - 1
for _ in range(N):
yield (x, y)
y -= (x + 2) // (N+1 )
x = (x + 2) % (N+1)
G = nx.Graph()
it_pos = pos()
for u in range(N):
G.add_node(u+1, pos=next(it_pos))
if u % (2 * N) < N:
for v in (u - 2 * N, u - N, u - N):
if G.has_node(v + 1):
G.add_edge(u + 2, v + 2)
elif u % (2 * N) == N:
G.add_edge(u + 1, u - N + 1)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N, u - N):
G.add_edge(u + 1, v + 1)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u + 1, v + 1)
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold')
Nodes=len(G.nodes)
A=nx.adjacency_matrix(G).todense()
The current output is
A=matrix([[0., 0.],
[0., 0.]])
The expected output is
You want the adjacency matrix between node and its edges, but the function you are using looks for neighbouring nodes.
In order to build your network and get your matrix, you could do the following:
import networkx as nx
import numpy as np
import pandas as pd
# build the network with relevant edges
G = nx.Graph()
points = {
0: (1, 1), 1: (2, 1),
'a':(1, 2), 'b':(2, 2),
'c':(0, 1), 'd':(3, 1),
'e':(1, 0), 'f':(2, 0)
}
for key, pos in points.items():
G.add_node(key, pos=pos)
G.add_edge('a', 0, name=0)
G.add_edge('b', 1, name=1)
G.add_edge('c', 0, name=2)
G.add_edge(0, 1, name=3)
G.add_edge(1, 'd', name=4)
G.add_edge(0, 'e', name=5)
G.add_edge(1, 'f', name=6)
# find connected edges to nodes 0 and 1
my_nodes = [0, 1] # could be more here
edges = {
node: [G.get_edge_data(*edge)['name'] for edge in G.edges(node)]
for node in my_nodes
}
# build matirx
mat = np.zeros((len(my_nodes), 7), dtype=np.uint8)
for i, node in enumerate(my_nodes)):
mat[i, edges[node]] = 1
mat[i, edges[node]] = 1
A = pd.DataFrame(mat)
A
Edit: generalize the connection search.
You can implement the matrix in Python using a nested list:
A = [[1, 0, 1, 1, 0, 1, 0], [0, 1, 0, 1, 1, 0, 1]]
I am generating an adjacency matrix using networkx. For N=10, the elapsed time is 0.1 seconds. Is there a more efficient way to do it? I present the current and expected outputs of elapsed times.
import networkx as nx
import time
N=10
def TicTocGenerator():
# Generator that returns time differences
ti = 0 # initial time
tf = time.time() # final time
while True:
ti = tf
tf = time.time()
yield tf-ti # returns the time difference
TicToc = TicTocGenerator() # create an instance of the TicTocGen generator
# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
# Prints the time difference yielded by generator instance TicToc
tempTimeInterval = next(TicToc)
if tempBool:
print( "Elapsed time: %f seconds.\n" %tempTimeInterval )
def tic():
# Records a time in TicToc, marks the beginning of a time interval
toc(False)
t = time.time()
tic()
################################################################
def pos():
x, y = 1, N + 3 - 1
for _ in range(2 * N * (N + 1)):
yield (x, y)
y -= (x + 2) // (N + 3)
x = (x + 2) % (N + 3)
G = nx.Graph()
it_pos = pos()
for u in range(2 * N * (N + 1)):
G.add_node(u+1, pos=next(it_pos))
if u % (2 * N + 1) < N:
for v in (u - 2 * N - 1, u - N - 1, u - N):
if G.has_node(v + 1):
G.add_edge(u + 1, v + 1)
elif u % (2 * N + 1) == N:
G.add_edge(u + 1, u - N + 1)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N - 1, u - N):
G.add_edge(u + 1, v + 1)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u + 1, v + 1)
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold')
################################################################
toc()
The current output is
Elapsed time: 0.10 seconds.
The expected output is
Elapsed time: 0.000001 seconds.
The following code generate adjacency matrix of a specific network. However, I want the node numbering to occur in a certain way and remain fixed and not fluctuate with every run. I present the current and expected output.
import matplotlib.pyplot as plt
import networkx as nx
N = 2
G = nx.Graph()
for u in range(2 * N * (N + 1)):
if u % (2 * N + 1) < N:
for v in (u - 2 * N - 1, u - N - 1, u - N):
if G.has_node(v):
G.add_edge(u, v)
elif u % (2 * N + 1) == N:
G.add_edge(u, u - N)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N - 1, u - N):
G.add_edge(u, v)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u, v)
A=nx.adjacency_matrix(G).todense()
print([A])
nx.draw(G,with_labels=True, font_weight='bold')
The current output is
The expected output is
Here is a possible solution:
import networkx as nx
N = 2
def pos():
x, y = 1, N + 3 - 1
for _ in range(2 * N * (N + 1)):
yield (x, y)
y -= (x + 2) // (N + 3)
x = (x + 2) % (N + 3)
G = nx.Graph()
it_pos = pos()
for u in range(2 * N * (N + 1)):
G.add_node(u + 1, pos=next(it_pos))
if u % (2 * N + 1) < N:
for v in (u - 2 * N - 1, u - N - 1, u - N):
if G.has_node(v + 1):
G.add_edge(u + 1, v + 1)
elif u % (2 * N + 1) == N:
G.add_edge(u + 1, u - N + 1)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N - 1, u - N):
G.add_edge(u + 1, v + 1)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u + 1, v + 1)
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold')
This is the result of the code above:
Here I've used the pos() function to generate each node position. These positions are saved as tuples (x, y) within each node as a label. And they're eventually used to draw the graph.
I am generating a graph with 12 nodes and the adjacency matrix. However, with every run, I see a different orientation though the adjacency matrix is the same. I want to have the same orientation (with the same adjacency matrix ofcourse!) in every run. I present the current and expected output.
import networkx as nx
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
N = 2
def pos():
x, y = 1, N + 3 - 1
for _ in range(2 * N * (N + 1)):
yield (x, y)
y -= (x + 2) // (N + 3)
x = (x + 2) % (N + 3)
G = nx.Graph()
it_pos = pos()
for u in range(2 * N * (N + 1)):
G.add_node(u + 1, pos=next(it_pos))
if u % (2 * N + 1) < N:
for v in (u - 2 * N - 1, u - N - 1, u - N):
if G.has_node(v + 1):
G.add_edge(u + 1, v + 1)
elif u % (2 * N + 1) == N:
G.add_edge(u + 1, u - N + 1)
elif u % (2 * N + 1) < 2 * N:
for v in (u - 1, u - N - 1, u - N):
G.add_edge(u + 1, v + 1)
else:
for v in (u - 1, u - N - 1):
G.add_edge(u + 1, v + 1)
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold')
D=len(G.nodes)
print(D)
fig, ax = plt.subplots(1, 1)
P=np.array([[1.00000000e-04, 1.90053824e-05, 3.70041863e-05, 5.50029902e-05,
7.30017941e-05, 8.20011961e-05, 1.00059804e-05, 9.10005980e-05,
2.80047843e-05, 1.00657843e-06, 4.60035882e-05, 1.01000000e-04]])
D=nx.draw(G, with_labels=True, node_color=[P], node_size=1000, cmap='Blues')
# -------------------------------------
norm = matplotlib.colors.Normalize(vmin=np.min(P), vmax=np.max(P))
sm = plt.cm.ScalarMappable(cmap='Blues', norm=norm)
sm.set_array([])
clb=fig.colorbar(sm)
clb.set_label('r (m)',labelpad=-50, y=1.1, rotation=0)
# -------------------------------------
plt.show()
The current output is
The expected output is
You are plotting twice with nx.draw, the first time with the node positions specified (correctly), the second time without specifying the node positions.
Presumably, you are only saving (and hence seeing) the second plot.
Delete the first call to nx.draw and substitute the second call (D=nx.draw(...)) with:
nx.draw(G, nx.get_node_attributes(G, 'pos'), with_labels=True, font_weight='bold', node_color=[P], cmap='Blues')
My function returns 2 different values which I want to utilise in 2 different graphs using Matplotlib. How can I achieve it?
def option_value_european_put(T, m, r, sigma, mu, E):
cost_value_at_initial_t_put = []
portfolio_payoff_put = []
for e in E:
delta_t = T / m
u = (1 + (sigma * math.sqrt(delta_t)) * (math.sqrt(1 + ((mu ** 2) * delta_t) / math.pow(sigma, 2))))
v = 2 - u
option_stock_price_matrix_put = np.zeros((m + 1, m + 1))
sum = 0
k = m
start = m
for i in range(m + 1):
option_stock_price_matrix_put[i][start] = max(
(e - stock_price_binomial_model(
mu, sigma, T, m,
S
)[i][start], 0)
)
for j in range(m - 1, -1, -1):
for i in range(0, j + 1):
v_plus = option_stock_price_matrix_put[i][j + 1]
v_minus = option_stock_price_matrix_put[i + 1][j + 1]
v_t = ((((v_plus - v_minus) / (u - v)) * (1 + r * delta_t)) + (u * v_minus - v * v_plus) / (u - v)) / (
1 + r * delta_t)
option_stock_price_matrix_put[i][j] = v_t
cost_value_at_initial_t_put.append(option_stock_price_matrix_put[0][0])
for i in range(0, m+1):
sum = sum + option_stock_price_matrix_put[k][i]
portfolio_return_average = math.average(sum)
portfolio_payoff_put.append(portfolio_return_average-option_stock_price_matrix_put[0][0] )
return cost_value_at_initial_t_put, portfolio_payoff_put
I want to use cost_value_at_initial_t_put in 1 Matplotlib plot and the other value in another plot. How can I use it?
Supposing that cost_value_at_initial_t_put and portfolio_payoff_cut are both lists you can create subplots:
import matplotlib.pyplot as plt
fig, (ax_cost, ax_payoff) = plt.subplots(nrows=2)
ax_cost.plot(cost_value_at_initial_t_put)
ax_payoff.plot(portfolio_payoff_cut)