Rotate k-partite graph in Network - python-3.x

I would like to rotate the following k-partite graph vertically or at 45 degrees. I want to show the following plot in a hierarchical way where red nodes are at the top and green node-set are at the bottom
Documentation of networks only have a rotate option for shell_layout and for edges labels networkx.drawing.nx_pylab.draw_networkx_edge_labels
Here is the program code:
G = nx.Graph()
G.add_nodes_from(emc["entity"], bipartite=0)
G.add_nodes_from(set(EMM_unique["keys"]).symmetric_difference(set(emc["entity"])), bipartite=1)
G.add_nodes_from(EMM["id"], bipartite=2)
G.add_edges_from(list(emc.itertuples(index=False)))
G.add_edges_from(list(EMM.itertuples(index=False)))
nodes = G.nodes()
# for each of the parts create a set
nodes_0 = set([n for n in nodes if G.nodes[n]['bipartite']==0])
nodes_1 = set([n for n in nodes if G.nodes[n]['bipartite']==1])
nodes_2 = set([n for n in nodes if G.nodes[n]['bipartite']==2])
# set the location of the nodes for each set
pos = dict()
pos.update( (n, (1, i)) for i, n in enumerate(nodes_0) ) # put nodes from X at x=1
pos.update( (n, (2, i)) for i, n in enumerate(nodes_1) ) # put nodes from Y at x=2
pos.update( (n, (3, i)) for i, n in enumerate(nodes_2) ) # put nodes from X at x=1
color_map = []
for node in G:
if node in emc["entity"].values:
color_map.append("red")
elif node in EMM["id"].values:
color_map.append("green")
else:
color_map.append("blue")
nx.draw(G, pos, node_color=color_map, width= 2, with_labels=True, with_arrows=True)
This solution is only good to flip the position and is not useful for rotation. As I am not adding the nodes one by one therefore, this solution is not very helpful as well.

Instead of flipping the graph, have you looked into using pygraphviz or the hierarchical_pos solution as in the answer below?
Can one get hierarchical graphs from networkx with python 3?
the hierarchy_pos solution worked well to some extent for me:
## Converting the graph to an oriented tree through depth first search or breadth first search
tree_g = nx.dfs_tree(g, <starting_node>)
## attempt to draw it like a tree
pos = hierarchy_pos(tree_g)
nx.draw(tree_g, pos=pos,....)
https://networkx.github.io/documentation/networkx-1.10/reference/generated/networkx.algorithms.traversal.depth_first_search.dfs_tree.html

I tried to change the coordinates at the position(pos) variable and it worked. The part of the code that is different from what I posted above and has a solution is here
# set the location of the nodes for each set
pos = dict()
pos.update( (n, (i, -1)) for i, n in enumerate(nodes_0) )
pos.update( (n, (i, -2) for i, n in enumerate(nodes_1) )
pos.update( (n, (i, -3)) for i, n in enumerate(nodes_2) )

Related

Why shortest path not always found for Leetcode 1129 challenge?

I am trying to solve LeetCode problem 1129. Shortest Path with Alternating Colors:
You are given an integer n, the number of nodes in a directed graph where the nodes are labeled from 0 to n - 1. Each edge is red or blue in this graph, and there could be self-edges and parallel edges.
You are given two arrays redEdges and blueEdges where:
redEdges[i] = [aᵢ, bᵢ] indicates that there is a directed red edge from node aᵢ to node bᵢ in the graph, and
blueEdges[j] = [uⱼ, vⱼ] indicates that there is a directed blue edge from node uⱼ to node vⱼ in the graph.
Return an array answer of length n, where each answer[x] is the length of the shortest path from node 0 to node x such that the edge colors alternate along the path, or -1 if such a path does not exist.
Example 1:
Input: n = 3, redEdges = [[0,1],[1,2]], blueEdges = []
Output: [0,1,-1]
Here is my code for that problem:
class Solution:
def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]:
res = [0] + [-1]*(n-1)
Red = defaultdict(list)
Blue = defaultdict(list)
for x,y in redEdges:
if x!=0 or y!=0:
Red[x].append(y)
for x,y in blueEdges:
if x!=0 or y!=0:
Blue[x].append(y)
def dfs(vertex,color,cost):
if color == "red":
for x in Red[vertex]:
if res[x] != -1:
res[x] = min(cost,res[x])
else:
res[x] = cost
if vertex in Red.keys():
del Red[vertex]
dfs(x,"blue",cost+1)
else:
for x in Blue[vertex]:
if res[x] != -1:
res[x] = min(cost,res[x])
else:
res[x] = cost
if vertex in Blue.keys():
del Blue[vertex]
dfs(x,"red",cost+1)
dfs(0,"red",1)
dfs(0,"blue",1)
return res
But for the following input:
redEdges=[[2,2],[0,1],[0,3],[0,0],[0,4],[2,1],[2,0],[1,4],[3,4]]
blueEdges=[[1,3],[0,0],[0,3],[4,2],[1,0]]
...my output is:
[0,1,4,1,1]
But the correct solution is:
[0,1,2,1,1]
...because there is a path from node 0 to node 2 like this:
red blue
0 -----> 4 -----> 2
I have no idea why my code doesn't give 2 as this path should be found via my DFS algorithm.
I thought that it might be something with the [0,0] edge, but it seems that it doesn't have an impact on a solution.
What is wrong in my code?
The problem is that your code deletes the vertex it has visited, but doesn't restore it when backtracking. There is a possibility that there is another path from vertex 0 to the one you just deleted that still needs to be traversed and is a shorter path.
Here is example input that demonstrates the problem:
redEdges = [[0,1],[2,3],[0,3]]
blueEdges = [[1,2],[3,4]]
Your code will correctly create the following adjacency lists:
Red = {0: [1, 3], 2: [3]}
Blue = {1: [2], 3: [4]}
With dfs the path 0, 1, 2, 3, 4 will be visited and during this traversal all the keys in these dictionaries will be deleted. As the loop over the outgoing edges from 0 is still active, dfs will still follow the red edge from 0 to 3, but there it finds no blue edges as the key 3 is not there anymore. And so the algorithm doesn't see the shorter path from 0 to 4, which is 0, 3, 4.
Not your question, but BFS is more suitable for finding shortest paths. I would suggest you rework the algorithm and use BFS instead.
Just to have a complete answer, here is a spoiler solution using BFS:
class Solution:
def shortestAlternatingPaths(self, n, redEdges, blueEdges):
# Build a separate adjacency list for each color
adj = [[[] for _ in range(n)], [[] for _ in range(n)]]
for i, edges in enumerate((redEdges, blueEdges)):
for x, y in edges:
if x or y:
adj[i][x].append(y)
# Collect shortest distances for each color separately
res = [[0] + [-1] * (n-1), [0] + [-1] * (n-1)]
# Start BFS at node 0, traversing with either color
frontier = [(0, 0), (0, 1)]
distance = 1
while frontier: # BFS loop
nextfrontier = []
for node, color in frontier:
for neighbor in adj[color][node]:
# If not yet visited with this color...
if res[color][neighbor] == -1:
res[color][neighbor] = distance
nextfrontier.append((neighbor, 1-color))
frontier = nextfrontier
distance += 1
# Get the minimum distance per node from the two color alternatives
return [min(a, b) if min(a, b) > -1 else max(a, b)
for a, b in zip(*res)]

Parking problem -pickup and delivery with ordering

I am trying to solve an optimization problem, using the CP-Sat solver of Ortools, that is very similar to a standard Pickup and Delivery example but with a twist that I cannot figure out how to solve. A simplified version of my problem would be:
I have some containers that needs to be picked up, by a single vehicle, and moved to another area with pre-allocated "parking-lots". The task is to find the minimal travel distance of the vehicle. Each pickup can be dropped off on any of the parking lots in the other area.
I have so far managed to solve this by utilizing AddCircuit, on a graph with a start node with edges going out to all pickup nodes, and with each pickup node having edges going out to all parking nodes and modelling the possible edges as booleans.
Example: start node (0), two pickups (1,2) and two parking lots (3,4). See figure.
A twist to the problem that I cannot figure out how solve, is that there should be an ordering of the parkings. Imagine the parking lot is a tunnel with one open end. I.e. I cannot park at the bottom of the tunnel if a container has already been parked in beginning of the tunnel. For the example attached, I cannot park a container on node 4 if node 3 has already had a container parked. In this case the attached minimal path solution (0->1->3->2->4) is not valid but should rather be 0->2->4->1->3->0 (also being the only feasible path for this simple example).
I would appreciate any help I could get on this.
A solution to the example without the ordering of the parkings are shown below:
import numpy as np
from ortools.sat.python import cp_model
model = cp_model.CpModel()
solver = cp_model.CpSolver()
start_node = (0, 0)
pickup_nodes = [(-1, 1), (1, 3)]
drop_off_nodes = [(-1, 2), (1, 4)]
all_nodes = [start_node] + pickup_nodes + drop_off_nodes
pickup_indices = [1, 2]
drop_off_indices = [3, 4]
scale = 100 # scale to solve rounding problem
# using euclidean distance
distances = [
[int(scale * np.sqrt((n1[0] - n2[0]) ** 2 + (n1[1] - n2[1]) ** 2)) for n2 in all_nodes]
for n1 in all_nodes
]
literals = {}
all_arcs = []
# start-> pickup
for i in pickup_indices:
literals[0, i] = model.NewBoolVar(f"{0} -> {i}") # start arc
all_arcs.append((0, i, literals[0, i]))
# pickup -> drop off
for i in pickup_indices:
for j in drop_off_indices:
literals[i, j] = model.NewBoolVar(f"{i} -> {j}")
all_arcs.append((i, j, literals[i, j]))
# drop off -> pickup
for i in drop_off_indices:
for j in pickup_indices:
literals[i, j] = model.NewBoolVar(f"{i} -> {j}")
all_arcs.append((i, j, literals[i, j]))
# drop off -> start
for i in drop_off_indices:
literals[i, 0] = model.NewBoolVar(f"{i} -> {0}")
all_arcs.append((i, 0, literals[i, 0]))
model.AddCircuit(all_arcs)
model.Minimize(sum(literals[i, j] * distances[i][j] for i, j in literals))
solver.Solve(model)
print(f"Travel distance: {solver.ObjectiveValue()}")
# print path
start_node = 0
node_idx = 0
print(node_idx, end="")
full_circuit = False
while not full_circuit:
for i, pos in enumerate(all_nodes):
if (node_idx, i) in literals and solver.Value(literals[(node_idx, i)]):
print(f" -> {i}", end="")
node_idx = i
break
if node_idx == start_node:
full_circuit = True
N.B: This question has also been posted on https://groups.google.com/g/or-tools-discuss/c/xazcgayBUok

Compact graph-vizualization using pydot

I would like to visualize a "linear" directed graph with the layout like that:
All the in- and out-degrees are 1 (except the first and last, of course). The length of the labels are different, so I can't calculate easily, how many nodes will fit in one row or the other. The code I have so far is this.
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
G = nx.DiGraph()
G.add_node("XYZ 1.0")
for i in range(1, 20):
G.add_node(f'XYZ 1.{i}', style='filled', fillcolor='skyblue')
G.add_edge(f'XYZ 1.{i-1}', f'XYZ 1.{i}')
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
prog = 'dot'
file_name = f'nx_graph_{prog}.png'
pydt.write(file_name, prog=prog, format="png")
So far I use networkx in a project that needs to be run in a Python docker container, so I would like to use pydot and Networkx, if it is possible.
In some of the graphviz programs I can set coordinates if I understand correctly, but for setting coordinates I should know the widths of the boxes to avoid overlapping boxes.
I managed to find a way to do this with pydot. We can create a dot file with the coordinates with the write_dot function. Reading it back, we can get the coordinates that dot program created (and also the widths, heights). We can somehow calculate the new coordinates and modify them in the networkx Digraph. Converting again to pydot.Dot object, and at the end, we can use neato with the -n option to create the graph, that way we use the coordinates we have set. A working code can be seen below.
import networkx as nx
from networkx.drawing.nx_pydot import to_pydot
import pydot
from typing import List
G = nx.DiGraph()
G.add_node(0, label="XYZ 1.0")
for i in range(1, 20):
G.add_node(i, label=f'XYZ 1.{i}')
G.add_edge(i - 1, i)
# set defaults
G.graph['graph'] = {'rankdir': 'LR'}
G.graph['node'] = {'shape': 'rectangle'}
G.graph['edges'] = {'arrowsize': '4.0'}
pydt = to_pydot(G)
dot_data = pydt.create_dot()
pydt2 = pydot.graph_from_dot_data(dot_data.decode('utf-8'))[0]
def get_position(node):
pydot_node = pydt2.get_node(str(node))[0]
return [float(i) for i in pydot_node.get_attributes().get("pos")[1:-1].split(',')]
def fix_position(position: List, w: float = 1000, shift: float = 80):
x_orig, y_orig = position
n = int(x_orig / w)
y = y_orig - n * shift
remain_x = x_orig - n * w
if n % 2 == 0:
x = remain_x
else:
x = w - remain_x
return x, y
def refresh_coordinates_using_x():
for node in G.nodes:
position = get_position(node)
x, y = fix_position(position)
pos = f'"{x},{y}!"'
G.nodes[node]['pos'] = pos
refresh_coordinates_using_x()
pydt3 = to_pydot(G)
file_name = f'nx_graph_neato.png'
pydt3.write(file_name, prog=["neato", "-n"], format="png")
If you want to calculate the position of the nodes based on the widths, you need to know, that while the coordinates are in points, the widths are in inches. 1 inch is 72 points.
The result will be similar to this one.

Colormapping the Mandelbrot set by iterations in python

I am using np.ogrid to create the x and y grid from which I am drawing my values. I have tried a number of different ways to color the scheme according to the iterations required for |z| >= 2 but nothing seems to work. Even when iterating 10,000 times just to be sure that I have a clear picture when zooming, I cannot figure out how to color the set according to iteration ranges. Here is the code I am using, some of the structure was borrowed from a tutorial. Any suggestions?
#I found this function and searched in numpy for best usage for this type of density plot
x_val, y_val = np.ogrid[-2:2:2000j, -2:2:2000j]
#Creating the values to work with during the iterations
c = x_val + 1j*y_val
z = 0
iter_num = int(input("Please enter the number of iterations:"))
for n in range(iter_num):
z = z**2 + c
if n%10 == 0:
print("Iterations left: ",iter_num - n)
#Creates the mask to filter out values of |z| > 2
z_mask = abs(z) < 2
proper_z_mask = z_mask - 255 #switches current black/white pallette
#Creating the figure and sizing for optimal viewing on a small laptop screen
plt.figure(1, figsize=(8,8))
plt.imshow(z_mask.T, extent=[-2, 2, -2, 2])
plt.gray()
plt.show()

How to detect objects shape from images using python3?

i want to write a code in python3 that detects objects shapes from images.
I want to choose a pixel from an object in the given image and find the neighbours pixels.
If they have the same RGB value that means that they are part of the object.
When neighbour pixel changes the RGB value with an ajustable difference from original pixel the algorithm should stop searching for neighbours. I think that this will work unless the backgroud and object have the same color.
I have found a way to put the pixels with same color in an rectangle,but this will not help me. I want to save just the shape of the object and put it in a different image.
For example,
If i want to start my algorithm from the middle of an object, let's
say a black table with a white background,the algorithm will find
pixels with the same color in any direction. When the neighbour pixel
RGB values will change with more than 30 units in one direction,the
algorithm will stop going in that direction,and will start going in
another direction untill I have the shape of the table.
I found a code on another post that help me to determinate regions of pixels with a shared value using PIL
Thanks!
from collections import defaultdict
from PIL import Image, ImageDraw
def connected_components(edges):
"""
Given a graph represented by edges (i.e. pairs of nodes), generate its
connected components as sets of nodes.
Time complexity is linear with respect to the number of edges.
"""
neighbors = defaultdict(set)
for a, b in edges:
neighbors[a].add(b)
neighbors[b].add(a)
seen = set()
def component(node, neighbors=neighbors, seen=seen, see=seen.add):
unseen = set([node])
next_unseen = unseen.pop
while unseen:
node = next_unseen()
see(node)
unseen |= neighbors[node] - seen
yield node
return (set(component(node)) for node in neighbors if node not in seen)
def matching_pixels(image, test):
"""
Generate all pixel coordinates where pixel satisfies test.
"""
width, height = image.size
pixels = image.load()
for x in xrange(width):
for y in xrange(height):
if test(pixels[x, y]):
yield x, y
def make_edges(coordinates):
"""
Generate all pairs of neighboring pixel coordinates.
"""
coordinates = set(coordinates)
for x, y in coordinates:
if (x - 1, y - 1) in coordinates:
yield (x, y), (x - 1, y - 1)
if (x, y - 1) in coordinates:
yield (x, y), (x, y - 1)
if (x + 1, y - 1) in coordinates:
yield (x, y), (x + 1, y - 1)
if (x - 1, y) in coordinates:
yield (x, y), (x - 1, y)
yield (x, y), (x, y)
def boundingbox(coordinates):
"""
Return the bounding box of all coordinates.
"""
xs, ys = zip(*coordinates)
return min(xs), min(ys), max(xs), max(ys)
def disjoint_areas(image, test):
"""
Return the bounding boxes of all non-consecutive areas
who's pixels satisfy test.
"""
for each in connected_components(make_edges(matching_pixels(image, test))):
yield boundingbox(each)
def is_black_enough(pixel):
r, g, b = pixel
return r < 10 and g < 10 and b < 10
if __name__ == '__main__':
image = Image.open('some_image.jpg')
draw = ImageDraw.Draw(image)
for rect in disjoint_areas(image, is_black_enough):
draw.rectangle(rect, outline=(255, 0, 0))
image.show()
Try using opencv with Python.
With opencv you can make advanced image analysis and there are many tutorials to use it.
http://www.pyimagesearch.com/2014/04/21/building-pokedex-python-finding-game-boy-screen-step-4-6/

Resources