Visualizing agents using Mesa & Networkx - graph

I'm current doing a multi agent path finding using Mesa and Networkx. The nodes represent location where only 1 agent can reside at one point of time. The edges represent distance between the nodes. How do I visualize the moving of agents along the edges at each time step? For example at time step = 4, Agent A is in the middle of edge connecting node 1 and 2.

I guess you want to plot some agent traversing between the nodes using networkx and matplotlib.
import matplotlib.pyplot as plt
import networkx as nx
import matplotlib.animation as animation
import matplotlib
import numpy as np
matplotlib.use('TkAgg')
plt.ion()
H = nx.octahedral_graph() # generate a random graph
pos = nx.spring_layout(H, iterations=200) # find good positions for nodes
In order to do that, first we need to know the position of the agent in each step or frame while traversing. If we assume that there are 50 steps between each node (or on each edge), we can write a generator to update the agent's position in each frame:
def traverse(graph, start, end, steps_between_nodes=50):
"""Generate the new position of the agent.
:param graph: the graph you want to put your agent to traverse on.
:param start: the node to start from.
:param end: the node to end at.
:param steps_between_nodes: number of steps on each edge.
"""
steps = np.linspace(0, 1, steps_between_nodes)
# find the best path from start to end
path = nx.shortest_path(graph, source=start, target=end)
stops = np.empty((0, 2))
for i, j in zip(path[1:], path):
# get the position of the agent at each step
new_stops = steps[..., None] * pos[i] + (1 - steps[..., None]) * pos[j]
stops = np.vstack((stops, new_stops))
for s in stops:
yield s
Then we can animate it as follows:
agent_pos = traverse(H, 1, 4) # make an agent traversing from 1 to 4
def update_position(n):
plt.cla()
nx.draw(H, pos, node_size=700, with_labels=True, node_color='green')
c = plt.Circle(next(agent_pos), 0.05, color='purple', zorder=2, alpha=0.7)
plt.gca().add_patch(c)
ani = animation.FuncAnimation(plt.gcf(), update_position, interval=30, repeat=False)
plt.ioff()
plt.show()
Finally we will have something like this:

Related

How to get the length of lines representing edges in the plot of graph after layout out using networkx

For a graph in networkx, I have made a layout to draw a network graph using code below:
data = pd.read_csv('data\\email-dept3.csv')
edges = [edge for edge in zip(data['source'],data['target'])]
print(len(edges))
G = nx.Graph()
G.add_edges_from(edges)
node_pos = nx.kamada_kawai_layout(G)
#I want to get the edge length as one attributes, but I don't know how to code this function
edge_length = calculate_edge_length()
nx.draw_networkx_nodes(G,node_pos,**options)#draw nodes
[nx.draw_networkx_edges(G,node_pos,edgelist=[key],alpha=np.amin([1,value*100]),width=2) for key,value in cent.items()]
plt.show()
And the result is:
What I want to do is get the every edge's length in this graph. Because after layout, every node has a position in screen, and the edge has its length according to its two nodes' position. But in networkx's API, I can't find the method to get the edge's length. And I also don't know how to calculate this value.
If you need more information, please contact me.
I am trying all kinds of methods to adjust the transparency of edges. The length of line is one of my consideration.
Interesting idea! Seems like a worthwhile experiment; I'll let you decide if it works well or not. :-)
But in networkx's API, I can't find the method to get the edge's length
I think you have to compute them yourself. Fortunately, that's not too hard. Here's an example.
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (10,10)
def example_graph():
"""
Return the classic Karate Club network, but give text labels to the nodes.
"""
labels = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJZKLMNOPQRSTUVWXYZ'
kg = nx.karate_club_graph()
edges = [(labels[i], labels[j]) for i,j in kg.edges()]
G = nx.Graph()
G.add_edges_from(edges)
return G
# Test network
G = example_graph()
# Determine layout node positions
node_pos = nx.kamada_kawai_layout(G)
# Determine edge distances (from the node positions)
node_pos_df = pd.DataFrame(node_pos.values(), columns=['x', 'y'], index=node_pos.keys())
node_pos_df = node_pos_df.rename_axis('label').sort_index()
edges = np.array(G.edges())
u_pos = node_pos_df.loc[edges[:, 0]].values
v_pos = node_pos_df.loc[edges[:, 1]].values
distances = np.linalg.norm(u_pos - v_pos, axis=1)
## Optional: Add the distances as edge attributes
#edge_distances = {(u,v): d for (u,v), d in zip(G.edges(), distances)}
#nx.set_edge_attributes(G, edge_distances, "layout_distance")
# Compute alpha: Set 0.15 as minimum alpha, 1.0 as maximum alpha
d_min, d_max = distances.min(), distances.max()
alphas = 1.0 - 0.85 * (distances - d_min) / (d_max - d_min)
# Draw graph
nx.draw_networkx_nodes(G, node_pos)
nx.draw_networkx_edges(G, node_pos, edgelist=G.edges(), alpha=alphas, width=2)
plt.show()

Reduce number of nodes/edges of a Graph in nedworkx

I have a Graph with many nodes of degree 2 (derived from a LineString). In order to simplify the Graph I would like to reduce it to just the nodes with a degree not equal to 2 but still containig the same overall connections. You can find an example of what I mean in the picture below.
So if there are multiple nodes mit degree=2 between two nodes with the degree of 3, all the nodes and edges in the middle should be deleted and a single connection between the two deg=3 nodes should be established with the same weight as the sum of the omitted edges.
Example Picture of reduced Graph
You can identify chains by 1) inducing a subgraph only containing nodes with degree 2, and 2) then identifying the individual components in the induced subgraph. Then it is a simple matter of summing the weights in each chain and creating a new edge with that weight between the nodes connecting to the end points of the chain.
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
def contract(g):
"""
Contract chains of neighbouring vertices with degree 2 into a single edge.
Arguments:
----------
g -- networkx.Graph or networkx.DiGraph instance
Returns:
--------
h -- networkx.Graph or networkx.DiGraph instance
the contracted graph
"""
# create subgraph of all nodes with degree 2
is_chain = [node for node, degree in g.degree() if degree == 2]
chains = g.subgraph(is_chain)
# contract connected components (which should be chains of variable length) into single node
components = list(nx.components.connected_component_subgraphs(chains))
hyper_edges = []
for component in components:
end_points = [node for node, degree in component.degree() if degree < 2]
candidates = set([neighbor for node in end_points for neighbor in g.neighbors(node)])
connectors = candidates - set(list(component.nodes()))
hyper_edge = list(connectors)
weights = [component.get_edge_data(*edge)['weight'] for edge in component.edges()]
hyper_edges.append((hyper_edge, np.sum(weights)))
# initialise new graph with all other nodes
not_chain = [node for node in g.nodes() if not node in is_chain]
h = g.subgraph(not_chain).copy()
for hyper_edge, weight in hyper_edges:
h.add_edge(*hyper_edge, weight=weight)
return h
# create weighted graph
edges = np.random.randint(0, 20, size=(int(400*0.2), 2))
weights = np.random.rand(len(edges))
g = nx.Graph()
for edge, weight in zip(edges, weights):
g.add_edge(*edge, weight=weight)
h = nx.algorithms.minimum_spanning_tree(g)
# contract
i = contract(h)
# plot
pos = nx.spring_layout(h)
fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True)
nx.draw(h, pos=pos, ax=ax1)
nx.draw(i, pos=pos, ax=ax2)
plt.show()
nx.component.connected_component_subgraphs has been deprecated. components can now be defined as:
components = [chains.subgraph(c) for c in nx.components.connected_components(chains)]
https://networkx.org/documentation/networkx-2.1/reference/algorithms/generated/networkx.algorithms.components.connected_component_subgraphs.html

Periodic and Aperiodic directed graphs

I am a bit confused on how to distinguish a directed graph to be aperiodic or periodic. Wikipedia says this about aperiodic graphs:
'In the mathematical area of graph theory, a directed graph is said to be aperiodic if there is no integer k > 1 that divides the length of every cycle of the graph.'
For example is the graph below aperiodic or periodic. I believe the graph is not periodic but by wikipedia's definition it is periodic since integer k = 2 divides all cycles in the graph (AC and ACDB)
It would be great if someone could provide a method to distinguish if a graph is aperiodic or periodic. Maybe provide some examples of periodic and aperiodic graphs to help explain.
Thank you.
Here's a short python implementation based on Networkx, for finding wether a graph is periodic:
import networkx as nx
from math import gcd
from functools import reduce
G = nx.DiGraph()
G.add_edges_from([('A', 'C'), ('C', 'D'), ('D', 'B'), ('B', 'A'), ('C', 'A')])
cycles = list(nx.algorithms.cycles.simple_cycles(G))
cycles_sizes = [len(c) for c in cycles]
cycles_gcd = reduce(gcd, cycles_sizes)
is_periodic = cycles_gcd > 1
print("is_periodic: {}".format(is_periodic))
The code does the following:
Build the graph from your example (by specifying the edges).
List all cycles (AC and ACDB).
List all cycles sizes [2, 4].
Find greatest common denominator (GCD).
If GCD is 1 it means the graph is aperiodic, otherwise it's periodic by definition.
The graph you have given above in not aperiodic as it has the period of 2. (i.e. every node can return to itself in multiples of 2 steps)
You can play with different examples to get better intuition, and also visualize your graph by adding:
import matplotlib.pyplot as plt
nx.draw_networkx(G, with_labels=True)
plt.show()

How to refer the center of a giant component to an external coordinate system?

I am working in Python (package: NetworkX) with a network of, say, 100 nodes. I create it and then fragment it by removing a fraction of its nodes (removal), as shown below. The script computes the length of the largest component and its center node(s).
import networkx as nx
import matplotlib.pyplot as plt
import numpy
N = 10
G=nx.grid_2d_graph(N,N)
pos = dict( (n, n) for n in G.nodes() )
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
nx.relabel_nodes(G,labels,False)
pos = {y:x for x,y in labels.iteritems()}
nx.draw_networkx(G, pos=pos, with_labels=True, node_size = 300)
plt.axis('off')
plt.show()
plt.close()
removal=numpy.array([1,5,18,23,54,8,36,95,41,75,77,56,29,39,81,76,27,34,52,50,53,64,45,85])
G.remove_nodes_from(removal)
nx.draw_networkx(G, pos=pos, with_labels=True, node_size = 300)
plt.axis('off')
plt.show()
giant = max(nx.connected_component_subgraphs(G), key=len) #The largest component
center_nodes = nx.center(giant) #The center node(s)
print len(giant)
print center_nodes
This gives me:
len(giant)=29 and center_nodes=[12,13].
What the network looks like after removal:
My network is embedded in a 2D grid which measures (N+1)x(N+1), and has its own coordinate system. Every node of the network is to be seen as if it was placed at the intersection of each cell in the grid below:
My problem: How can I "translate" the result given by center_nodes=[12,13] into the location of cell A in the grid? In this case, I would like to have center_nodes=[12,13] -> center_coord=13.
PS: if I change removal, len(center_nodes) changes, as does the shape of the connected subgraphs. Thus, cell A will not be in the same position as above. To account for this, I would like to be able to always get the grid coordinates of the cell at the top left corner of the center_nodes cluster, regardless of its shape and location within the network.

trajectory of bullet, when there is a drag force

i tried to express the trajectory of bullet when there is a drag force.
however, i am not able to express the graph precisely.
how to depict trajectory from ode equation?.
this is my graph. this graph does not plausible. although i struggled setting different sign of vydot value, this is not working correctly.
from pylab import*
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import numpy as np
g=10
m=1
k=0.01
y=zeros([2])
vy0=0
vydot=200
vx0=0
vxdot=200
y[0]=vy0
y[1]=vydot
x=zeros([2])
x[0]=vx0
x[1]=vxdot
t=linspace(0,1000,5000)
def fy(y,t):
g0=y[1]
g1=-k*y[1]
return array([g0,g1])
def fx(z,t):
g0=-x[1]
g1=-k*(x[1])-g
return array([g0,g1])
ans1=odeint(fy,y,t)
ans2=odeint(fx,x,t)
ydata=(ans1[:,])
xdata=(ans2[:,])
plt.plot(ydata,xdata)
show()"""
In air, as opposed to liquids, the bullet not only displaces the volume along its path, but also increases the impulse of the displaced air molecules proportional to the velocity. Thus the drag force is
vn=sqrt(vx²+vy²)
dragx = -k*vn*vx
dragy = -k*vn*vy
Thus use
def f(z,t):
x,y,vx,vy = z
vn = sqrt(vx*vx+vy*vy)
return array([vx, vy, -k*vn*vx, -k*vn*vy-g ])
For a first overview, consider the problem without drag. Then the solution is
x(t) = vx*t = 200m/s*t
y(t) = vy*t-g/2*t² = 200m/s*t - 5m/s²*t²
y(t)=0 is again met for t=2*vy/g at the x coordinate 2*vx*vy/g = 8000m. Maximum height is reached for t=vy/g at height vy²/(2g)=2000m.

Resources