Related
does anyone know how to make a multidirected graph in NetworkX? My problem is, that the node 3 here does not return to node 2 as I wrote in the edgelist... Here is my code:
import networkx as nx
G = nx.MultiDiGraph(directed = True)
G.add_nodes_from(range(1, 11))
edgelist = [(1, 2), (2, 3), (3, 2), (3, 9), (9, 4), (4, 5), (5, 7), (7, 6), (6, 4), (7, 8), (7, 10), (10, 11), (11, 5)]
G = nx.from_edgelist(edgelist)
nx.draw_networkx(G,
with_labels = True,
arrows = True,
arrowstyle = '-|>',
node_size = 100,
node_color = 'yellow',
edge_color = 'black',
width = 3,
arrowsize = 10)
This is the image I get from this code. There should be two edges on node 2 and 3, but there is just one
The G = nx.from_edgelist(edgelist) line uses a constructor that replaces the original object, so it's drawing a standard Graph instead of a multidigraph (but still mimics the arrows since forced in the draw-call).
Try replacing that line with G = nx.from_edgelist(edgelist, create_using = nx.MultiDiGraph()) and you should at least get two arrows drawn on the desired edge. You can also check the output of nx.info(G) to verify the graph type in case you're unsure if it worked.
You also don't need the initial variables as the constructor handles that as well. Minimal code to get this working:
import networkx as nx
edgelist = [(1, 2), (2, 3), (3, 2), (3, 9), (9, 4), (4, 5), (5, 7), (7, 6), (6, 4), (7, 8), (7, 10), (10, 11), (11, 5)]
G = nx.from_edgelist(edgelist, create_using = nx.MultiDiGraph())
nx.draw_networkx(G,
with_labels = True,
arrows = True,
arrowstyle = '-|>',
node_size = 100,
node_color = 'yellow',
edge_color = 'black',
width = 3,
arrowsize = 10)
I have created 2 small graphs using python dictionaries and Networkx.
Now I want to assign and display an attribute (capacity) to the nodes and the edges. I failed in doing this when a graph was created using the dictionary. My code is:
#VNFGraph
Nf = {'VNF1', 'VNF2', 'VNF3', 'VNF4', 'VNF5'}
Lf = {('VNF1', 'VNF2'),('VNF2', 'VNF3'),('VNF3', 'VNF4'), ('VNF2', 'VNF5'),('VNF5', 'VNF3')}
# SERVERGraph
Ns = {'S1', 'S2', 'S3', 'S4', 'S5'}
Ls = {('S1', 'S2'),('S1', 'S4'),('S2', 'S4'),('S2', 'S3'),('S4', 'S3'),('S4', 'S5'),('S3', 'S5')}
graph1 = nx.DiGraph()
graph1.add_nodes_from(list(Nf))
graph1.add_edges_from(list(Lf))
graph2 = nx.Graph()
graph2.add_nodes_from(list(Ns))
graph2.add_edges_from(list(Ls))
graph2.add_edge("S1", "S2", weight=4.7)
pos1 = ({'VNF1': (0, 6), 'VNF2': (2, 6), 'VNF3': (4, 6), 'VNF4': (6, 6), 'VNF5': (3, 4)})
pos = ({'S1': (0, 1), 'S2': (2, 2), 'S3': (4, 2), 'S4': (3, 1), 'S5': (6, 1)})
fig1, ax1 = plt.subplots(figsize=(7, 7))
nx.draw_networkx_nodes(graph1, pos=pos1, ax=ax1, edgecolors='black', node_size=1100)
nx.draw_networkx_labels(graph1, pos=pos1, ax=ax1, labels=dict(zip(Nf, Nf)), font_size=7)
nx.draw_networkx_edges(graph1, pos=pos1, ax=ax1, node_size=900, arrowsize=25)
nx.draw_networkx_nodes(graph2, pos=pos, ax=ax1, edgecolors='black', node_size=800)
nx.draw_networkx_labels(graph2, pos=pos, ax=ax1, labels=dict(zip(Ns, Ns)), font_size=8)
nx.draw_networkx_edges(graph2, pos=pos, ax=ax1, node_size=900, arrowsize=25)
plt.axis('on')
plt.show()
I want to assign values (capacity attribute) to each node and link and display that too.
You need to pass the capacity to the nx.draw_commands as a list of values (which are in the same order as the nodes/edges of your graph). My usual approach is to write the attributes to the graph and then read them out and pass them to the draw commands:
import networkx as nx
import matplotlib.pyplot as plt
from random import randint
Nf = {'VNF1', 'VNF2', 'VNF3', 'VNF4', 'VNF5'}
Lf = {('VNF1', 'VNF2'),('VNF2', 'VNF3'),('VNF3', 'VNF4'), ('VNF2', 'VNF5'),('VNF5', 'VNF3')}
graph1 = nx.DiGraph()
graph1.add_nodes_from(list(Nf))
graph1.add_edges_from(list(Lf))
pos1 = ({'VNF1': (0, 6), 'VNF2': (2, 6), 'VNF3': (4, 6), 'VNF4': (6, 6), 'VNF5': (3, 4)})
'''
Create a dict of node and edge weights:
Dict has to have following form: {node_label: {attribute1: value1, attribute2: value2 ...}}
'''
node_weight = {n:{'weight':randint(100, 1000)} for n in graph1.nodes()}
edge_weight = {e:{'weight':randint(1, 5)} for e in graph1.edges()}
'''
Write attributes to graph
'''
nx.set_node_attributes(graph1, node_weight)
nx.set_edge_attributes(graph1, edge_weight)
'''
Get attributes from graph; returns dict: {node_label: value (of specified attribtue)}
In order to pass them to nx.draw you need a list, so unpack the values of the dict
This way you avoid messing up the order of the nodes
'''
node_size = list(nx.get_node_attributes(graph1, 'weight').values())
edge_size = list(nx.get_edge_attributes(graph1, 'weight').values())
fig1, ax1 = plt.subplots(figsize=(7, 7))
nx.draw_networkx_nodes(graph1, pos=pos1, ax=ax1, edgecolors='black', node_size=node_size)
nx.draw_networkx_labels(graph1, pos=pos1, ax=ax1, labels=dict(zip(Nf, Nf)), font_size=7)
nx.draw_networkx_edges(graph1, pos=pos1, ax=ax1, width = edge_size, arrowsize=25)
plt.axis('on')
plt.show()
These codes produce a chart
import numpy as np
import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
menStd = (2, 3, 4, 1, 2)
womenStd = (3, 5, 2, 3, 3)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
p1 = plt.bar(ind, menMeans, width, yerr=menStd)
p2 = plt.bar(ind, womenMeans, width,
bottom=menMeans, yerr=womenStd)
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0], p2[0]), ('Men', 'Women'))
Jupyter notebook automatically print the chart, even I didn't call plt.show(). I don't want to show the chart in the same cell with the code but the next cell by running a really short code such as plt.show(). In order to keep the cell as concise as possible.
Just enclose all your plot-related statements inside a function called plot_and_show(). Then you can call the function when you are ready.
import matplotlib.pyplot as plt
import numpy as np
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
menStd = (2, 3, 4, 1, 2)
womenStd = (3, 5, 2, 3, 3)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars: can also be len(x) sequence
def plot_and_show():
p1 = plt.bar(ind, menMeans, width, yerr=menStd)
p2 = plt.bar(ind, womenMeans, width,
bottom=menMeans, yerr=womenStd)
plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0], p2[0]), ('Men', 'Women'))
plot_and_show()
import numpy as np
import pandas as pd
import matplotlib
# matplotlib.use("Agg")
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import cnames
from matplotlib import animation
t_start = 2 #start frame
t_end = 1711 #end frame
data = pd.read_csv('Sub6_cylinder0009_index_flex_processed.csv')
df = data.loc[t_start:t_end,'FT1X':'CMC5Z']
df_minmax = pd.DataFrame(index=list('xyz'),columns=range(2))
for i in list('xyz'):
c_max = df.max().max()
c_min = df.min().min()
df_minmax.loc[i] = np.array([c_min,c_max])
df_minmax = 3.3*df_minmax
df.columns = np.repeat(range(22),3)
N_tag = int(df.shape[1]/3) # nr of tags used (all)
N_trajectories = N_tag
t = np.linspace(0,data.Time[t_end],df.shape[0])
x_t = np.zeros(shape=(N_tag,df.shape[0],3))
for tag in range(22):
x_t[tag,:,:] = df[tag]
x_t = x_t[:, :, [0, 2, 1]]
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')
ax.axis('on')
#choose a different color for each trajectory
colors = plt.cm.jet(np.linspace(0, 1, N_trajectories))
# set up trajectory lines
lines = sum([ax.plot([], [], [], '-', c=c) for c in colors], [])
# set up points
pts = sum([ax.plot([], [], [], 'o', c=c) for c in colors], [])
#set up lines which create the stick figures
stick_defines = [
(0, 13),
(13, 14),
(14, 19),
(1, 5),
(2, 6),
(3, 7),
(4, 8),
(5, 9),
(6, 10),
(7, 11),
(8, 12),
(9, 15),
(10, 16),
(11, 17),
(12, 18),
(18, 21),
(15, 20)
]
stick_lines = [ax.plot([], [], [], 'k-')[0] for _ in stick_defines]
print(stick_lines)
ax.set_xlim3d([np.nanmin(x_t[:, :, 0]), np.nanmax(x_t[:, :, 0])])
ax.set_ylim3d([np.nanmin(x_t[:, :, 1])-400, np.nanmax(x_t[:, :, 1])+400])
ax.set_zlim3d([np.nanmin(x_t[:, :, 2]), np.nanmax(x_t[:, :, 2])])
ax.set_xlabel('X [mm]')
ax.set_ylabel('Y [mm]')
ax.set_zlabel('Z [mm]')
# set point-of-view: specified by (altitude degrees, azimuth degrees)
#ax.view_init(30, 25)
# initialization function: plot the background of each frame
def init():
for line, pt in zip(lines, pts):
line.set_data(np.array([]), np.array([]))
line.set_3d_properties(np.array([]))
pt.set_data(np.array([]),np.array([]))
pt.set_3d_properties(np.array([]))
return lines + pts
# animation function. This will be called sequentially with the frame number
def animate(i):
i = (5 * i) % x_t.shape[1]
for pt, xi in zip(pts, x_t):
x, y, z = xi[:i].T
pt.set_data(x[-1:], y[-1:])
pt.set_3d_properties(z[-1:])
for stick_line, (sp, ep) in zip(stick_lines, stick_defines):
stick_line._verts3d = x_t[[sp,ep], i, :].T.tolist()
#ax.view_init(30, 0.3 * i)
fig.canvas.draw()
return lines + pts + stick_lines
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=500, interval=30, blit=True, repeat=False)
# Save as mp4. This requires mplayer or ffmpeg to be installed
#anim.save('animation.mp4', progress_callback=lambda i, n: print(f'Saving frame {i} of {n}'))
plt.show()
anim.save('test.mp4', writer='ffmpeg')
This does not save animation. However,
anim.save('animation.mp4', progress_callback=lambda i, n: print(f'Saving frame {i} of {n}'))
Does save the animation but the rendering is not really sharp and quite blurry. How do I change that ?
The other points are:
How do I change all the scatter points to a single color ?eg dark grey or black
How do I change the index finger only to a different color? eg Index finger color red
best wishes,
PS: Attached is the animation
import numpy as np
import pandas as pd
import matplotlib
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.colors import cnames
from matplotlib import animation
#=============================================================================================
t_start = 2# start frame
t_end = 1711# end frame
data = pd.read_csv('Sub6_cylinder0009_index_flex_processed.csv') # only coordinate data
df = data.loc[t_start:t_end,'FT1X':'CMC5Z']
# Find max and min values for animation ranges
df_minmax = pd.DataFrame(index=list('xyz'),columns=range(2))
for i in list('xyz'):
c_max = df.max().max()
c_min = df.min().min()
df_minmax.loc[i] = np.array([c_min,c_max])
df_minmax = 3.3*df_minmax # increase by 30% to make animation look better
df.columns = np.repeat(range(22),3) # store cols like this for simplicity
print(df.columns)
N_tag = int(df.shape[1]/3) # nr of tags used (all)
N_trajectories = N_tag
t = np.linspace(0,data.Time[t_end],df.shape[0]) # pseudo time-vector for first walking activity
x_t = np.zeros(shape=(N_tag,df.shape[0],3)) # empty animation array (3D)
for tag in range(22):
# # store data in numpy 3D array: (tag,time-stamp,xyz-coordinates)
x_t[tag,:,:] = df[tag]
x_t = x_t[:, :, [0, 2, 1]]
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1], projection='3d')
ax.axis('on')
#choose a different color for each trajectory
#colors1 = plt.cm.Reds(np.linspace(0, 1, N_trajectories))
#colors2 = plt.cm.gray(np.linspace(0, 1, N_trajectories))
# set up trajectory lines
#lines = sum([ax.plot([], [], [], '-', c=c) for c in colors1], [])
# set up points
#pts = sum([ax.plot([], [], [], 'o--', c=c) for c in colors2], [])
#pts = ax.plot([], [], [], 'o', c=colors2[0])
#pts = ax.plot([], [], [], 'o-', c=colors2[8])
#set up lines which create the stick figures
stick_defines = [
(0, 13), # Thumb Tip
(13, 14),
(14, 19),
(1, 5), #Index Tip
(2, 6), # Middle Tip
(3, 7), # Ring Tip
(4, 8), # Pinky Tip
(5, 9),
(6, 10),
(7, 11),
(8, 12),
(9, 15),
(10, 16),
(11, 17),
(12, 18),
(18, 21),
(15, 20)
# (22, 23),
# (23, 24),
# (22, 26),
# (25,26)
]
stick_defines1 = [
# (0, 13), # Thumb Tip
# (13, 14),
# (14, 19),
(1, 5), #Index Tip
# (2, 6), # Middle Tip
# (3, 7), # Ring Tip
# (4, 8), # Pinky Tip
(5, 9),
# (6, 10),
# (7, 11),
# (8, 12),
(9, 15),
# (10, 16),
# (11, 17),
# (12, 18),
# (18, 21),
(15, 20)
# (22, 23),
# (23, 24),
# (22, 26),
# (25,26)
]
stick_lines = [ax.plot([], [], [], 'ko--', alpha=0.5)[0] for _ in stick_defines]
stick_lines1 = [ax.plot([], [], [], 'ro-')[0] for _ in stick_defines1]
print(stick_lines)
ax.set_xlim3d([np.nanmin(x_t[:, :, 0]), np.nanmax(x_t[:, :, 0])])
ax.set_ylim3d([np.nanmin(x_t[:, :, 1])-400, np.nanmax(x_t[:, :, 1])+400])
ax.set_zlim3d([np.nanmin(x_t[:, :, 2]), np.nanmax(x_t[:, :, 2])])
ax.set_xlabel('X [mm]')
ax.set_ylabel('Y [mm]')
ax.set_zlabel('Z [mm]')
# set point-of-view: specified by (altitude degrees, azimuth degrees)
#ax.view_init(30, 25)
# initialization function: plot the background of each frame
# def init():
# for pt in pts:#zip(pts):
# # line.set_data(np.array([]), np.array([]))
# # line.set_3d_properties(np.array([]))
# pt.set_data(np.array([]), np.array([]))
# pt.set_3d_properties(np.array([]))
# return pts
# animation function. This will be called sequentially with the frame number
def animate(i):
# we'll step two time-steps per frame. This leads to nice results.
i = (5 * i) % x_t.shape[1]
pts = []
for pt, xi in zip(pts, x_t):
x, y, z = xi[:i].T # note ordering of points to line up with true exogenous registration (x,z,y)
pt.set_data(x[-1:], y[-1:])
pt.set_3d_properties(z[-1:])
for stick_line, (sp, ep) in zip(stick_lines, stick_defines):
stick_line._verts3d = x_t[[sp,ep], i, :].T.tolist()
for stick_line1, (sp, ep) in zip(stick_lines1, stick_defines1):
stick_line1._verts3d = x_t[[sp,ep], i, :].T.tolist()
#ax.view_init(30, 0.3 * i)
fig.canvas.draw()
return pts + stick_lines+stick_lines1
# instantiate the animator.
anim = animation.FuncAnimation(fig, animate, frames=500, interval=30, blit=True, repeat=False)
plt.show()
# Save as mp4. This requires mplayer or ffmpeg to be installed
anim.save('animation.mp4', progress_callback=lambda i, n: print(f'Saving frame {i} of {n}'))
#anim.save('test.mp4', writer='ffmpeg')
I have managed to answer my questions, however, the saving of the animation still remains a problem, the current version works but the video is blurry and is not particularly sharp. The last line of code which is commented out simply does not work for unknown reasons.
If you have a better way to have save the animation with better resolution please let me know.
Attached is the animation.
best wishes,
So far I calculate the euclidean distance between the neighbors manually. But I need help on our to calculate the distance automatically in the code. My code so far is:
import networkx as nx
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
G = nx.Graph()
list_edges = [(0,1,3.8), (0,2,3.6), (1,3,2.5), (2,4,3.5), (3,5,4.6), (3,6,4.0), (3,7,2.8), (4,8,2.9),
(4,9,2.7), (4,10,4.1), (7,8,2.2), (5,6,3.1), (6,7,3.2), (8,9,3.6), (9,10,3.4)]
G.add_weighted_edges_from(list_edges)
G.add_node(0, pos = (8.5,10.5))
G.add_node(1, pos = (5,9))
G.add_node(2, pos = (11.5,8.5))
G.add_node(3, pos = (5,6.5))
G.add_node(4, pos = (11.5,5))
G.add_node(5, pos = (1.5,3.5))
G.add_node(6, pos = (4.5,2.5))
G.add_node(7, pos = (7,4.5))
G.add_node(8, pos = (9,3.5))
G.add_node(9, pos = (12.5,2.5))
G.add_node(10, pos = (15.5,4))
T = nx.minimum_spanning_tree(G, algorithm='kruskal')
#print(G.adj.items())
#print(T.edges())
#node_list = G.nodes()
#print(node_list)
#print(nx.get_node_attributes(G,'pos'))
node_pos=nx.get_node_attributes(G,'pos')
edge_weight=nx.get_edge_attributes(G,'weight')
red_edges = T.edges()
node_col = ['white']
# If the edge is in the shortest path set it to red, else set it to white color
edge_col = ['black' if not edge in red_edges else 'red' for edge in G.edges()]
# Draw the nodes
nx.draw_networkx(G, node_pos,node_color= node_col, node_size=450)
# Draw the node labels
nx.draw_networkx_labels(G, node_pos,node_color= node_col)
# Draw the edges
nx.draw_networkx_edges(G, node_pos,edge_color= edge_col)
# Draw the edge labels
nx.draw_networkx_edge_labels(G, node_pos,edge_color= edge_col, edge_labels=edge_weight)
# Remove the axis
plt.axis('off')
# Show the plot
plt.show()
Any help will be appreciated
You are probably looking for scipy.spatial.distance.pdist, which calculates all pairwise distances. If you need only few distances, you could also calculate them with scipy.spatial.distane.euclidean.
The following code reproduces your results without the requirement of given distances:
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial.distance import pdist, squareform
import seaborn as sns
sns.set()
G = nx.Graph()
# list_edges = [(0, 1, 3.8), (0, 2, 3.6), (1, 3, 2.5), (2, 4, 3.5), (3, 5, 4.6), (3, 6, 4.0), (3, 7, 2.8), (4, 8, 2.9),
# (4, 9, 2.7), (4, 10, 4.1), (7, 8, 2.2), (5, 6, 3.1), (6, 7, 3.2), (8, 9, 3.6), (9, 10, 3.4)]
# G.add_weighted_edges_from(list_edges)
list_unweighted_edges = [(0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (3, 6), (3, 7), (4, 8),
(4, 9), (4, 10), (7, 8), (5, 6), (6, 7), (8, 9), (9, 10)]
G.add_node(0, pos=(8.5, 10.5))
G.add_node(1, pos=(5, 9))
G.add_node(2, pos=(11.5, 8.5))
G.add_node(3, pos=(5, 6.5))
G.add_node(4, pos=(11.5, 5))
G.add_node(5, pos=(1.5, 3.5))
G.add_node(6, pos=(4.5, 2.5))
G.add_node(7, pos=(7, 4.5))
G.add_node(8, pos=(9, 3.5))
G.add_node(9, pos=(12.5, 2.5))
G.add_node(10, pos=(15.5, 4))
position_array = []
for node in sorted(G):
position_array.append(G.nodes[node]["pos"])
print(position_array)
distances = squareform(pdist(np.array(position_array)))
for u, v in list_unweighted_edges:
G.add_edge(u, v, weight=np.round(distances[u][v],decimals=1))
T = nx.minimum_spanning_tree(G, algorithm='kruskal')
node_pos = nx.get_node_attributes(G, 'pos')
edge_weight = nx.get_edge_attributes(G, 'weight')
red_edges = T.edges()
node_col = ['white']
# If the edge is in the shortest path set it to red, else set it to white color
edge_col = ['black' if not edge in red_edges else 'red' for edge in G.edges()]
# Draw the nodes
nx.draw_networkx(G, node_pos, node_color=node_col, node_size=450)
# Draw the node labels
nx.draw_networkx_labels(G, node_pos, node_color=node_col)
# Draw the edges
nx.draw_networkx_edges(G, node_pos, edge_color=edge_col)
# Draw the edge labels
nx.draw_networkx_edge_labels(G, node_pos, edge_color=edge_col, edge_labels=edge_weight)
# Remove the axis
plt.axis('off')
# Show the plot
plt.show()