Python networkx edge and node labeling problem - python

I'm new to Python and I wanted to draw a incidence graph, but with changed labels. I want them to start labeling nodes from '1', not from '0'. Also I want to label edges like this: if It's between node '1' and '2', label It as '12' or '1:2'. Thanks in advance :)
im = np.array([[1, 1, 0, 0, 0, 0], [1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 1, 0], [0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 1]])
am = (np.dot(im, im.T) > 0).astype(int)
np.fill_diagonal(am, 0)
K = nx.from_numpy_matrix(am)
pos = nx.spring_layout(K)
print(pos)
x=1
nx.relabel_nodes(K, lambda x: x + + 1)
nx.draw(K, pos, with_labels=True)
edge_labels = dict(((u, v), d) for u, v, d in K.edges(data=True))
nx.draw_networkx_edge_labels(K, pos, edge_labels = edge_labels, label_pos=0.5)
plt.show()

Then build the label you want, just as you've done so far. I'll break this down to basic opeartions; you can build it up again as you wish:
edge_labels = dict(((u, v),
str(u+1) +":"+ str(v+1) +" "+ str(d))
for u, v, d in K.edges(data=True))

Related

Python variable and data structure scope

if matrix[row][col] == 0:
continue # continue if it is a water cell
matrix[row][col] = 0 # mark the cell visited by making it a water cell
This is a snippet from the program below. My question is how you are able to update countIslandsBFS()'s matrix from a function call to visitIslandBFS()
In general, I had thought only global variables could be changed with a function call. The visitIslandBFS() function they wrote returns nothing - so how is it possible to update the matrix passed in by countIslandBFS()?
from collections import deque
def countIslandsBFS(matrix):
rows = len(matrix)
cols = len(matrix[0])
totalIslands = 0
for i in range(rows):
for j in range(cols):
if (matrix[i][j] == 1): # only if the cell is a land
# we have found an island
totalIslands += 1
visitIslandBFS(matrix, i, j)
return totalIslands
def visitIslandBFS(matrix, x, y):
neighbors = deque([(x, y)])
while neighbors:
row, col = neighbors.popleft()
if row < 0 or row >= len(matrix) or col < 0 or col >= len(matrix[0]):
continue # continue, if it is not a valid cell
if matrix[row][col] == 0:
continue # continue if it is a water cell
matrix[row][col] = 0 # mark the cell visited by making it a water cell
# insert all neighboring cells to the queue for BFS
neighbors.extend([(row + 1, col)]) # lower cell
neighbors.extend([(row - 1, col)]) # upper cell
neighbors.extend([(row, col + 1)]) # right cell
neighbors.extend([(row, col - 1)]) # left cell
def main():
print(countIslandsBFS([[0, 1, 1, 1, 0], [0, 0, 0, 1, 1], [
0, 1, 1, 1, 0], [0, 1, 1, 0, 0], [0, 0, 0, 0, 0]]))
print(countIslandsBFS([[1, 1, 1, 0, 0], [0, 1, 0, 0, 1], [
0, 0, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0]]))
main()

Python Matrix check for diagonals and horizontals correctly to win a game

I'm building a game like Connect4 the user can connect any number. I am having a problem checking the horizontal and diagonals lines:
def WinningSequenceCheck(board,piece,row_count):
#Horizontal Check
piecePlayer1=0
piecePlayer2=0
win_sequence=board[0]["TamanhoSequĂȘncia"]
width=board[0]["CumpGrelha"]
height=row_count
for c in range(height+1):
for r in range(width):
if board[0]["Tabuleiro"][c][r]==1:
piecePlayer1+=1
if piecePlayer1==win_sequence:
return True
if board[0]["Tabuleiro"][c][r]==2:
pecasPlayer2+=1
if pecasPlayer2==win_sequence:
return True
#For diagonals i did this:
diag1=0
diag2=0
a=0
b=height
d=0
for c in range(width):
for l in range(height+1):
if board[0]["Tabuleiro"][b-l][l+a]==1:
diag1+=1
if diag1==win_sequence:
return True
if board[0]["Tabuleiro"][b-l][l+a]==2:
diag2+=1
if diag2==win_sequence:
return True
if (b-l<height):
b=height
if l<=l-1:
a=a
elif(a+l<width-1):
a+=1
elif(a+l<=width-1):
return
else:
break
The problem with diagonals is that it goes from left to right but it's not checking properly if there is a line of a winning sequence of 1s or 2s
If it finds it should return true because im incrementing each time he finds 1 or 2
Im i doing the horizontal check properly?
Is there a better way to check in diagonals ?
The expected result from the horizontal is that if it finds the number 1 it adds to the variable piecePlayer1 (for the player 1)
If the piecePlayer1 is equal to Victory sequence ( example victory sequence is 5) the game returns true because in one of the lines he found 5 one's .
Winning Sequence=5
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 1, 0, 0, 0, 0, 0] ---> Win
The same is for the diagonal check:
Winning Sequence =4
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0] Diagonal WIN
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
#Stunna, here is simple sample code to check the diagonal values, you can try it and modify to suit your main module:
def winner(board, length):
"""Returns the 'mark' of the winning player"""
W = range(len(board)) # width
H = range(len(board[0])) # height
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
for dx, dy in directions:
edges = []
if dx > 0:
edges += [(0, y) for y in H]
if dy > 0: # scanning down
edges += [(x, 0) for x in W]
if dy < 0: # scanning up
edges += [(x, H[-1]) for x in W]
for ex, ey in edges:
row = 0; mark = None
x, y = ex, ey
while x in W and y in H:
if board[x][y] == mark:
row += 1
else:
mark = board[x][y]
row = 1
if mark is not None and row >= length:
return mark
x, y = x + dx, y + dy
return None
print(winner([
['X', 'O', 'O', 'O'],
['O', 'X', 'O', 'X'],
['O', 'O', 'X', 'O'],
['O', 'X', 'X', 'X'] ], 4)) # X

I have a problem understanding the A* Algorithm (Python)

I'm trying to look into the A* Algorithm but I'm kind of having a hard time understanding a specific part. So the A* Algorithm Python Code with the example is this:
class Node():
"""A node class for A* Pathfinding"""
def __init__(self, parent=None, position=None):
self.parent = parent
self.position = position
self.g = 0
self.h = 0
self.f = 0
def __eq__(self, other):
return self.position == other.position
def astar(maze, start, end):
"""Returns a list of tuples as a path from the given start to the given end in the given maze"""
# Create start and end node
start_node = Node(None, start)
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end)
end_node.g = end_node.h = end_node.f = 0
# Initialize both open and closed list
open_list = []
closed_list = []
# Add the start node
open_list.append(start_node)
# Loop until you find the end
while len(open_list) > 0:
# Get the current node
current_node = open_list[0]
current_index = 0
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
# Pop current off open list, add to closed list
open_list.pop(current_index)
closed_list.append(current_node)
# Found the goal
if current_node == end_node:
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return path[::-1] # Return reversed path
# Generate children
children = []
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]: # Adjacent squares
# Get node position
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])
# Make sure within range
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0:
continue
# Make sure walkable terrain
if maze[node_position[0]][node_position[1]] != 0:
continue
# Create new node
new_node = Node(current_node, node_position)
# Append
children.append(new_node)
# Loop through children
for child in children:
# Child is on the closed list
for closed_child in closed_list:
if child == closed_child:
continue
# Create the f, g, and h values
child.g = current_node.g + 1
child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2)
child.f = child.g + child.h
# Child is already in the open list
for open_node in open_list:
if child == open_node and child.g > open_node.g:
continue
# Add the child to the open list
open_list.append(child)
def main():
maze = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
start = (4, 3)
end = (4, 5)
path = astar(maze, start, end)
print(path)
if __name__ == '__main__':
main()
In the
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
I don't get how the current_node can be defined as the item in the maze I've given above. In the example I've given above, the start = (4,3) and end = (4,5), giving the only possible shortest distance would be as something like the following:
maze = [[0, 0, 0, 0, *, 0, 0, 0, 0, 0],
[0, 0, 0, *, 1, *, 0, 0, 0, 0],
[0, 0, 0, *, 1, *, 0, 0, 0, 0],
[0, 0, 0, *, 1, *, 0, 0, 0, 0],
[0, 0, 0, s, 1, e, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
with the s being the start_node and e being the end_node.
However, in the code of the A* Algorithm, the current_node becomes the item only if the item.f is smaller than the current_node.f. In the example I've given here, I can't see that the first * would have an f value smaller than the f value of the start_node - I mean, in the code, we already have described the start_node.f = 0 haven't we? And we defined the first current_node as the start_node... so no item in the open_list would have an item.f value smaller than zero..
How is this possible?? Or am I missing something here??
I think the clue is that you have to take into account the two lines above this for loop as well:
# Get the current node
current_node = open_list[0]
current_index = 0
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
What happens:
In the first iteration of your while loop:
There is only one item in the open_list, being the start_node where indeed f=0
So after the above code block, this start node becomes the current_node
Right after the above loop the start_node is removed from the open_list: open_list.pop(current_index)
The open_list is then populated by the valid neighbouring locations (by walking its children)
In the second iteration of your while loop:
The above code block looks for the item in the open_list with the lowest f value
because of the first line current_node = open_list[0], you will be sure that the new current_node is always one from the open_list.
as the start_node has been removed from the open_list, it will for sure be replaced here

Python: Boundary points of a non-convex grid

I have the following situation as shown in the Figure below:
I want to find out the grid points that surround the red points. The red points are trajectories of moving agents. So in many situations we have a bunch of points, therefore the solution should be as fast as possible.
The grid is plotted as points.
First step, I managed to reduce the number of grid points as shown below (plotted as x):
This is my code:
step = .5
gridX, gridY = np.meshgrid(np.arange(xmin-step, xmax+step, step), np.arange(ymin-step, ymax+step, step))
mask = False * np.empty_like(gridX, dtype=bool)
threshold = 0.5
for (x,y) in zip(df_traj['X'], df_traj['Y']):
pX = x * np.ones_like(gridX)
pY = y * np.ones_like(gridY)
distX = (pX - gridX)**2
distY = (pY - gridY)**2
dist = np.sqrt(distX + distY)
condition = (dist < threshold)
mask = mask | condition
gX = gridX*mask
gY = gridY*mask
Second step, and this is where I need a little help:
How can I efficiently filter out the inner points of the grid and keep only the "x-points" outside the "red area"?
EDIT
In this special case I have 92450 red points.
I think if you just walk around the edge, since its a evenly spaced grid, it should work. No need for far more complicated non-convex-hull to handle pnts that can be anywhere. This isn't adapted to your code and I cheat with my data structures to make the code easy so youll have to handle that but it think as psuedocode it should work.
pnts = <<lists of points>>
edge_pnts = []
fpnt = pnt_with_min_x_then_min_y
cpnt = fpnt
npnt = None
while npnt != fpnt:
if (cpnt[0] + 1, cpnt[1] ) in pnts: npnt = (cpnt[0] + 1, cpnt[1] )
elif (cpnt[0] + 1, cpnt[1] + 1) in pnts: npnt = (cpnt[0] + 1, cpnt[1] + 1)
elif (cpnt[0], cpnt[1] + 1) in pnts: npnt = (cpnt[0] , cpnt[1] + 1)
elif (cpnt[0] - 1, cpnt[1] + 1) in pnts: npnt = (cpnt[0] - 1, cpnt[1] + 1)
elif (cpnt[0] - 1, cpnt[1] ) in pnts: npnt = (cpnt[0] - 1, cpnt[1] )
elif (cpnt[0] - 1, cpnt[1] - 1) in pnts: npnt = (cpnt[0] - 1, cpnt[1] - 1)
elif (cpnt[0] , cpnt[1] - 1) in pnts: npnt = (cpnt[0] , cpnt[1] - 1)
elif (cpnt[0] + 1, cpnt[1] - 1) in pnts: npnt = (cpnt[0] + 1, cpnt[1] - 1)
else: raise ValueError("Oh no!")
edge_pnts.append(npnt)
cpnt = npnt
For non convex polygons, like your example, convex hull is not a solution. My recommendation is that, given you already have a discrete grid, that you simply attribute the value False to a bool grid cell when a sample occurs inside. Something like this:
import numpy as np
import matplotlib.pyplot as plt
# Generic data production
X, Y = np.random.normal(0, 1, 100000), np.random.normal(0, 1, 100000)
ind = np.where((X > 0) & (Y > 0))
X[ind] = 0
Y[ind] = 0
# Generic grid definition
step = 0.5
xmin, xmax = X.min(), X.max()
ymin, ymax = Y.min(), Y.max()
firstx = xmin-step/2
firsty = ymin-step/2
lastx = xmax+2*step/2
lasty = ymax+2*step/2
gridX, gridY = np.meshgrid(np.arange(firstx, lastx, step), np.arange(firsty, lasty, step))
# This is the actual code that computes inside or outside
bool_grid = np.ones(gridX.shape, dtype="bool")
bool_grid[np.int_(0.5+(Y-firsty)/step), np.int_(0.5+(X-firstx)/step)] = False
# Plot code
plt.scatter(gridX.flatten(), gridY.flatten(), marker="+", color="black", alpha=0.3)
plt.scatter(gridX[bool_grid].flatten(), gridY[bool_grid].flatten(), marker="+", s=90, color="green")
plt.scatter(X, Y, s=10, color="red")
plt.show()
, which results in the following (green crosses are True values):
NOTE: This is very fast but it has some limitations. If your data is not compact you'll have True values inside the shape (so holes are possible). It's possible to process the image to remove the holes however (a flood fill or a moving window based algorithm for example). Another possibility is to play with the resolution of the grid.
You just need to pick a point you know is on the hull (let's take the leftmost point among the topmost points), and assume you "got to it" from above (as we know there is no points above it).
now while the next point is not in your list:
Try going CCW from the direction you came from.
The code looks like that:
matrix = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
# Find the leftmost topmost point
first_point = None
for i in range(len(matrix)):
if first_point:
break
for j in range(len(matrix[0])):
if matrix[i][j]:
first_point = [i, j]
break
next_point = first_point
prev_direction = 'up'
next_direction_dict = {'up': 'left', 'left': 'down', 'down': 'right', 'right': 'up'}
opposite_direction = {'up': 'down', 'left': 'right', 'down': 'up', 'right': 'left'}
hull_points = []
def go_direction(point, direction):
# Find the point to a given direction of a given point
i = point[0]
j = point[1]
if direction == 'right':
j += 1
elif direction == 'up':
i -= 1
elif direction == 'left':
j -= 1
elif direction == 'down':
i += 1
else:
raise ValueError
return [i, j]
def find_next_point(matrix, point, prev_direction):
next_direction = next_direction_dict[prev_direction]
next_point = go_direction(point, next_direction)
prev_direction = next_direction
while not matrix[next_point[0]][next_point[1]]:
next_direction = next_direction_dict[prev_direction]
next_point = go_direction(point, next_direction)
prev_direction = next_direction
from_direction = opposite_direction[prev_direction]
return next_point, from_direction
next_point, prev_direction = find_next_point(matrix, next_point, prev_direction)
while next_point != first_point:
if next_point not in hull_points:
hull_points.append(next_point)
next_point, prev_direction = find_next_point(matrix, next_point, prev_direction)
Edit:
Now also handles single point 'tentacles' by iterating until returning to the first point
Heres another though that came to my mind --
A flood fill of the space:
pnts = <<lists of points>>
seen = set()
edges = []
stack = (0,0)
while stack:
ele = stack.pop()
if ele in pnts:
edges.append(ele)
else:
seen.add(ele)
if (ele[0] + 1, ele[1]) not in seen:
stack.append(ele[0] + 1, ele[1])
if (ele[0] - 1, ele[1]) not in seen:
stack.append(ele[0] - 1, ele[1])
if (ele[0], ele[1] + 1) not in seen:
stack.append(ele[0], ele[1] + 1)
if (ele[0], ele[1] - 1) not in seen:
stack.append(ele[0], ele[1] - 1)
Then you need to sort the points which shouldn't be too hard.

Prim's Algorithm input parameter (values) in Python

I have looked at the following prim's algorithm (in order to create a minimum spanning tree) and I am unsure as to what the input value s in the following code is, I think the G of course would be the graph sent (adjacency matrix or list graphs) and I think the value s is where the start should be? Also if it is the start then in what way would you send a starting value to the following algorithm?:
from heapq import heappop, heappush
def prim(self, G, s):
P, Q = {}, [(0, None, s)]
while Q:
_, p, u = heappop(Q)
if u in P: continue
P[u] = p
for v, w in G[u].items():
heappush(Q, (w, u, v))
return P
Any help will be much appreciated, thank you!
Here you are:
#A = adjacency matrix, u = vertex u, v = vertex v
def weight(A, u, v):
return A[u][v]
#A = adjacency matrix, u = vertex u
def adjacent(A, u):
L = []
for x in range(len(A)):
if A[u][x] > 0 and x <> u:
L.insert(0,x)
return L
#Q = min queue
def extractMin(Q):
q = Q[0]
Q.remove(Q[0])
return q
#Q = min queue, V = vertex list
def decreaseKey(Q, K):
for i in range(len(Q)):
for j in range(len(Q)):
if K[Q[i]] < K[Q[j]]:
s = Q[i]
Q[i] = Q[j]
Q[j] = s
#V = vertex list, A = adjacency list, r = root
def prim(V, A, r):
u = 0
v = 0
# initialize and set each value of the array P (pi) to none
# pi holds the parent of u, so P(v)=u means u is the parent of v
P=[None]*len(V)
# initialize and set each value of the array K (key) to some large number (simulate infinity)
K = [999999]*len(V)
# initialize the min queue and fill it with all vertices in V
Q=[0]*len(V)
for u in range(len(Q)):
Q[u] = V[u]
# set the key of the root to 0
K[r] = 0
decreaseKey(Q, K) # maintain the min queue
# loop while the min queue is not empty
while len(Q) > 0:
u = extractMin(Q) # pop the first vertex off the min queue
# loop through the vertices adjacent to u
Adj = adjacent(A, u)
for v in Adj:
w = weight(A, u, v) # get the weight of the edge uv
# proceed if v is in Q and the weight of uv is less than v's key
if Q.count(v)>0 and w < K[v]:
# set v's parent to u
P[v] = u
# v's key to the weight of uv
K[v] = w
decreaseKey(Q, K) # maintain the min queue
return P
A = [ [0, 4, 0, 0, 0, 0, 0, 8, 0],
[4, 0, 8, 0, 0, 0, 0, 11, 0],
[0, 8, 0, 7, 0, 4, 0, 0, 2],
[0, 0, 7, 0, 9, 14, 0, 0, 0],
[0, 0, 0, 9, 0, 10, 0, 0, 0],
[0, 0, 4, 14, 10, 0, 2, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 1, 6],
[8, 11, 0, 0, 0, 0, 1, 0, 7],
[0, 0, 2, 0, 0, 0, 6, 7, 0]]
V = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
P = prim(V, A, 0)
print P
[None, 0, 5, 2, 3, 6, 7, 0, 2]
G is the graph or the adjacency matrix and s is any random starting node which u can give , it does not matter which of the node you choose

Categories