How to convert a bipartite graph into no bipartite - python-3.x

I've been trying to do this for a long time without success, so I'd better ask you.
First of all, I'm working on python 3 and networkx.
I have a bipartite graph as the image A, in which there are two types of nodes according to their 'group' attribute (group='R' and group='X'). Also, some relationships are reversible, as R4, and some are not (so I guess we would have to unfold the node in those cases).
What I need is to leave only the nodes of the R group and eliminate the X ones, but keeping the relations between them. That is, convert the green nodes into edges and keep a graph of only blue nodes.
Ohhh please!!, Can someone give me a hand?
Any help would be very welcome.
Thank you in advance wholeheartedly!
GRAPH IMAGE HERE:
https://media.springernature.com/full/springer-static/image/art%3A10.1038%2Fs41540-018-0067-y/MediaObjects/41540_2018_67_Fig1_HTML.png

Go over nodes of the graph, if the node is green add an edge between all its neighbours (which will only be blue). At the end remove all the green nodes.
to_remove = []
for node in G.nodes(data = True):
if node[1]["type"] == "Green": ## check if the node is green
to_remove.append(node[0])
## go over all neighbours of the node and add an edge between them
neighbours = list(G.neighbors(node[0]))
for i in range(0, len(neighbours)-1):
for j in range(i+1, len(neighbours)):
G.add_edge(neighbours[i],neighbours[j])
## remove the green nodes
G.remove_nodes_from(to_remove)

Related

Creating random directed edges between nodes in nodejs

Say I have a graph with several nodes. I need to design an algorithm which randomly creates directed edges between nodes while satisfying the following conditions:
each node has exactly one edge pointing to it
each node has exactly one edge pointing away from it
no node points to itself
For example, say my graph had three nodes, the following scenarios would be acceptable:
Node A points to B, B points to C, C points to A
Node A points to C, C points to B, B points to A
Does anyone know what the most efficient way of doing this would be? I'm using nodejs btw. For argument's sake, we can say that I am starting with an array containing the names of the nodes.
Thanks
lets define you have array of vertex: V = {v}; |V| = N, now we can shuffle array of vertex by using any random shuffle algorithm.
V = [v_1, v_2, v_3,..,v_n]
Now we can define N-1 edges E, where e[i] = (v[i] to v[i + 1]), and the last vertex will be (v[N-1] to v[0])

Converting Matplotlib and Networkx/Pygraphviz units to a common unit

I am attempting to autoscale a networkx graph based on the number of nodes and whether there are nodes that overlap in the horizontal direction or the vertical direction (ie. if all nodes were on the same line, they would intersect). To do this, I look at the position of each node and check whether the position plus the node size is between any other nodes coordinates plus the node size. To get the node positions, I am using networkx.nx_agraph.graphviz_layout. The issue is that the positions and the node size are not of the same unit.
Networkx calls pyplot.scatter underneath the hood (source: https://networkx.github.io/documentation/networkx-1.10/_modules/networkx/drawing/nx_pylab.html#draw_networkx_nodes), which takes the node size as an area in pixels (source: https://stackoverflow.com/questions/14827650/pyplot-scatter-plot-marker-size).
Networkx draws the graph with circle nodes, so based on this it would make sense that to convert the node size to inches, I would do node_size * 4 / (math.pi * DPI) where DPI is the DPI used by Matplotlib. In my code this does not seem to work. I have also tried taking the square root of the node size and dividing it by the DPI but that doesn't seem to work either.
Currently the issue is that I am not able to detect what nodes are overlapping.
In summary: If I am plotting a networkx graph with circle nodes, how can I convert the node size and/or the Pygraphviz positions to a common unit?
It could also be that my code is wrong, so here is a short reproducible example:
NODE_SIZE = 300
DPI = 100
mpl.rcParams['figure.dpi'] = DPI
G = nx.gnp_random_graph(50, 0)
pos = nx.nx_agraph.graphviz_layout(G)
tmp_pos = sorted(pos.items(), key=lambda x: x[1][0]) # Sort it by x value so you only have to check to the right of the node in the list of positions
node_size_inches = NODE_SIZE * 4 / (math.pi * DPI) # This is my attempt at getting the height/width of the nodes
i = 0
for key, xy in tmp_pos:
x = xy[0]
overlapping = []
# Since list is sorted by x, you only need to check nodes to the right
for k, xyt in tmp_pos[i+1:]:
xt = xyt[0]
# Check for overlapping nodes to the right
if x <= xt <= x + node_size_inches:
overlapping.append(k)
# Since list is sorted by x, if the previous condition fails, nothing after can be applicable
else:
break
if overlapping: print("{}:{}".format(key, overlapping))
i += 1
nx.draw(G, pos=pos, with_labels=True)

NetworkX bipartite graph issues

Here's the set up: I have a data frame, df, with columns labeled A,B,...,K. Each entry of column A is unique and will make up one of the two sets of vertices, call it X, in a bipartite graph, G. The entries of columns B,...,K (not all unique) make up the other set of vertices, call it Y, in the bipartite graph. We draw an edge from vertex y in Y to vertex x in X if y is in the same row as x.
Using this answer from another post, I have the following code which creates a bipartite graph with vertex sets given by the entries of column A (positioned on the right) and B (positioned on the left)
G = nx.Graph()
G.add_nodes_from(df['A'], bipartite=0)
G.add_nodes_from(df['B'], bipartite=1)
G.add_weighted_edges_from(
[(row['B'], row['A'], 1) for idx, row in df.iterrows()],
weight='weight')
pos = {node:[0, i] for i,node in enumerate(df['B'])}
pos.update({node:[1, i] for i,node in enumerate(df['A'])})
nx.draw(G, pos, with_labels = True)
plt.show()
I'm seeking advice/help with a few problems:
The number of vertices is large enough so that the vertices appear very bunched up. Is there a way of spreading out the vertices in each of the two vertex sets?
As I mentioned, this code makes a bipartite graph connecting some entries of B with some entries of A (again, based on row matching). How can I do this for each of the other columns (i.e. connecting elements of C,...,K with A in the same way)? I know there is a way to union graphs together with union(G1,G2) but I imagine there's a better way to achieve this.
I'd like to create some kind of edge coloring based on the degree of vertices in Y. I imagine the coloring will be implemented using the G.degree(), but I'm not sure how that works.
Please let me know if you have any suggestions for my problems. Thanks in advance!

Finding neighbours of neighbours of a node - Python

The following is a graph that I'm using to find neighbours of green nodes.
Green nodes are in a different set called new = [12,13,14,15,16,17,18,19,20,21,22,23,24,25].
When I access the first green node 12; it has it has two neighbours 15 and 21.But 21 has another green neighbours and hence I need them to be in my list of neighbours of node 12.This should be repeated until green nodes meet the red ones. So ultimately, the set of neighbours of node 12 should be [0,15,21,14,16,134,23,19,3]. can someone please help me to find this?
Pseudo-code since you didn’t at all specify how your graph works:
def findNeighbors (node, greens, visited = None):
if visited is None:
visited = set()
for n in node.directNeighbors:
# visit node if it’s new
if n not in visited:
visited.add(n)
# go recursively if the new node is green
if n in greens:
findNeighbors(n, greens, visited)
return visited
greenNodes = set(new)
twelve = findNodeByValue(12)
result = findNeighbors(twelve, greenNodes)

igraph half circle layout in R

I am trying various visualizations for an Igraph in R (version.3.3.1).
Currently my visualizing is as shown as below, 2 nodes (blue and green) in circular layout.
Circular Layout
visNetwork(data$nodes,data$edges) %>% visIgraphLayout(layout="layout_in_circle")
Now I want to have a semicircle structure instead of a full circle as in the pic. All blue nodes form a semicircle, green nodes another semicircle. Each semicircle separated by a small distance as well. How can i achieve this. I found grid package has an option for semicircle, but i couldnt make it work with igraph. Please provide some pointers.
The layout argument accepts an arbitrary matrix with two columns and N rows if your graph has N vertices; all you need to do is to create a list of coordinates that correspond to a semicircle. You can make use of the fact that a vertex at angle alpha around a circle with radius r centered at (0, 0) is to be found at (r * cos(alpha), r * sin(alpha)). Since you are using R, alpha should be specified in radians, spaced evenly between 0 and pi (which corresponds to 180 degrees).

Resources