Ignore non-connected nodes in NetworkX Graph - python

I have a network diagram where a node is connected to another node which in-turn is connected to another node, worked through a logic to ignore when there is only one neighbour but that is still leaving few bits back. The attached diagram does a better job explaining it
I need to only keep where a red-node is connected to a blue-node or another red-node through a green node. Data used
for u, v in CA_new.edges:
if len(list(CA_new.neighbors(v))) == 1 and len(list(CA_new.neighbors(u))) == 1:
removeNodeslist.append(v)
removeNodeslist.append(u)
else:
keepNodeslist.append(v)
keepNodeslist.append(u)
CA_new.remove_nodes_from(removeNodeslist)

From your comments, it sounds like you’re looking for the connected components that contain at least two parent nodes, and at least one of those parents has a colored edge. With that in mind, you can do something like the following:
import numpy as np
import networkx as nx
import pandas as pd
data = {
'Parent': list("EEABEHDILGKCDBLLFBCCJ"),
'Child': ["X1","X2","Y1","Y1","Y1","M1","N3","N4","N5","N7","N8","M1","M2",
"M3","M4","M5","M6","M7","M8","M9","P7"],
'Colour': list("NNNNYYNYNNNYNNNNYNNNN")
}
df = pd.DataFrame(data)
G = nx.from_pandas_edgelist(df, source = 'Parent', target = 'Child')
parent_set = set(df['Parent'])
colored_parent_set = set(df.loc[df['Colour']=='Y','Parent'])
node_set = set()
for comp in nx.connected_components(G):
if (len(comp & parent_set) >= 2 and
comp & colored_parent_set):
node_set |= comp
H = G.subgraph(node_set)
colors = ['limegreen']*len(H)
for i,n in enumerate(H.nodes):
if n in colored_parent_set:
colors[i] = "red"
elif n in parent_set:
colors[i] = "deepskyblue"
nx.draw(H, node_color = colors, with_labels = True)
Here's the result that I get:

Related

pyviz to visualize multiple separate graphs into one and filter by graph

I am generating a graph to visualize the association's rules and using pyviz to get an interactive visualization. Currently, I saved data in one graph but I would like to save different data into separate graphs and represent it all in one network graph, then set a drop-down menu to filter the graph and only show that part of the whole network graph.
I would like to have, graph_1,graph_2, and graph_3 saved in one general graph and do post filtering where I can choose which to focus.
I am using the below code to generate and visualize one graph:
import networkx as nx
from pyvis.network import Network
def draw_graph(rules, saveName):
rules_to_show = len(rules)
G1 = nx.DiGraph()
color_map=[]
N = 50
colors = np.random.rand(N)
strs=[]
mydic={}
median = rules['confidence'].median()
for i in range (rules_to_show):
conf = rules.iloc[i]['confidence']
strs.append(str('R')+str(i))
G1.add_nodes_from(["R"+str(i)])
for a in rules.iloc[i]['antecedents']:
G1.add_nodes_from([a])
if conf > median:
G1.add_edge(a, "R"+str(i), color='lightgrey' , value = conf*0.01)
else:
G1.add_edge(a, "R"+str(i), color='orange' , value = conf*0.01)
for c in rules.iloc[i]['consequents']:
G1.add_nodes_from([a])
if conf > median:
G1.add_edge("R"+str(i), c, color='lightgrey', value = conf*0.01)
else:
G1.add_edge("R"+str(i), c, color='orange', value = conf*0.01)
for node in G1:
# print(node)
found_a_string = False
for item in strs:
# print(item)
if node==item:
found_a_string = True
if found_a_string:
color_map.append("lightblue")
else:
color_map.append("lightgreen")
for index,row in dataset.iterrows():
mydic.update({row["items"]:(row['support'])})
x={}
for node in G1:
if node in mydic:
x.update({node:mydic.get(node)})
else:
x.setdefault(node, 0.0001)
nodes, values = zip(*x.items())
nt= Network(notebook=True,
cdn_resources="remote",
bgcolor="#222222",
font_color="white",
height="750px",
width="100%",
select_menu=True,
filter_menu=True)
nt.add_nodes(list(nodes), value=[int(v*10000) for v in values], color=color_map)
nt.from_nx(G1)
nt.repulsion(node_distance=100, spring_length=500)
nt.show_buttons(filter_=['physics'])
nt.show(str(saveName)+'.html')
draw_graph (update_df, 'test')

How to create a colormap with the distance of routes

Currently I have a plot that shows all the shortest paths between all the nodes in my network and my target:
Now I would like to make a cmap, where I would color the origin nodes and the edges based on the distance of the shortest path. Can anyone help me?
Here is what I have:
import networkx as nx
import matplotlib.pyplot as plt
import osmnx as ox
import pandas as pd
import geopandas as gpd
from shapely.wkt import loads as load_wkt
ox.config(log_console=True, use_cache=True)
place = {'city': 'Lisbon', 'country': 'Portugal'}
G = ox.graph_from_place(place, network_type='drive')
G = ox.project_graph(G)
hospitals = ox.pois_from_place(place, amenities=['hospital'])
hosp_1 = hospitals.iloc[21]['geometry'] # Hospital Santa Maria (Polygon)
def poly_centroide(polygon):
# Gives me the coordinates of the center point of the Polygon
p1 = load_wkt(polygon)
centroide = p1.centroid.wkt
return centroide
polygon_1 = str(hosp_1)
coord_1_str = poly_centroide(polygon_1)
coord_1 = (38.74817825481225, -9.160815118526642) # Coordinates Hospital Santa Maria
target_1 = ox.get_nearest_node(G, coord_1)
routes = []
for node in G.nodes:
try:
route = nx.shortest_path(G, node, target_1)
routes.append(route)
except nx.exception.NetworkXNoPath:
continue
fig, ax = ox.plot_graph_routes(G, routes, edge_linewidth=0.2, node_size=5, route_linewidth=1)
plt.show()
Now I would like to know how to create the cmap where the colors of the nodes and edges are based on the distance of the shortest path.
I suspect it could be done with nx.dra() but I have no idea how...
Thank you in advance.
I have slightly added to your code. This will help in colouring the nodes based on their topological distance (since you did not pass any specific weight while calculating the shortest path, the shortest path is calculated based on the number of edges needed to be traversed to reach the destination as each edge is assigned a weight of 1).
I start after target_1 = ox.get_nearest_node(G, coord_1)
Obtain the nodes and edges geodataframes from the graph. We need the nodes geodataframe for this purpose.
nodes, edges = ox.graph_to_gdfs(G, nodes=True, edges=True)
We then calculate the shortest path, the shortest path length, and assign the latter to a new column in the nodes geodataframe.
nodes['shortest_route_length_to_target'] = 0
routes = []
route_lengths = []
i = 0
for node in G.nodes:
try:
route = nx.shortest_path(G, node, target_1)
route_length = nx.shortest_path_length(G, node, target_1)
routes.append(route)
route_lengths.append(route_length)
nodes['shortest_route_length_to_target'][node] = route_length
except nx.exception.NetworkXNoPath:
continue
Now we define the following functions. You will notice that these functions are the ones already existing in the file plot.py but are slightly modified for this purpose.
import numpy as np
import matplotlib.cm as cm
def get_colors(n, cmap='viridis', start=0., stop=1., alpha=1.,):
colors = [cm.get_cmap(cmap)(x) for x in np.linspace(start, stop, n)]
colors = [(r, g, b, alpha) for r, g, b, _ in colors]
return colors
def get_node_colors_by_attr(G, attr, num_bins=None, cmap='viridis', start=0, stop=1, na_color='none'):
if num_bins is None:
num_bins=len(G.nodes())
bin_labels = range(num_bins)
# attr_values = pd.Series([data[attr] for node, data in G.nodes(data=True)])
attr_values = pd.Series(nodes[attr].values)
cats = pd.qcut(x=attr_values, q=num_bins, labels=bin_labels)
colors = get_colors(num_bins, cmap, start, stop)
node_colors = [colors[int(cat)] if pd.notnull(cat) else na_color for cat in cats]
return node_colors
Now the following lines of code will give you your desired output.
nc = get_node_colors_by_attr(G, attr = 'shortest_route_length_to_target', num_bins=20,)
fig, ax = ox.plot_graph(G, node_color = nc, fig_height=20,)
You could vary the colormap (cmap) or the number of bins (num_bins) you wish to discretise the route_lengths values into.

Networkx: Network with parallel edges

I need to develop a bipartite network where nodes come from the 'id_emp' and 'name_dep' columns of the dataframe below:
import networkx as nx
import pandas as pd
df = pd.DataFrame({'id_emp':[13524791000109, 12053850000137, 4707821000113, 4707821000114],
'name_emp':['Cristiano', 'Gaúcho', 'Fenômeno','Angelin'],
'name_dep': ['Ronaldo','Ronaldo', 'Ronaldo', 'Ronaldo'],
'peso': [8,9,10,11]})
On the edges:
1 - They have weight, determined by the 'weight' column;
2 - They must be directed;
3 - In orgininal work must demonstrate a relation of exchange, then between two nodes, there must be two parallel edges;
I am trying with the following code:
G = nx.MultiDiGraph()
G.add_nodes_from(df['id_emp'], bipartite = 0)
deputados = [v for v in G.nodes if G.nodes[v]['bipartite'] == 0]
G.add_nodes_from(df['name_dep'], bipartite = 1)
empresa = [v for v in G.nodes if G.nodes[v]['bipartite'] == 1]
G.add_weighted_edges_from(df[['id_emp', 'name_dep', 'peso']].values)
edge_width = [a[2]['weight']//2 for a in G.edges(data=True)]
deputado = "Ronaldo"
lista_subset_graph = list(df[df["name_dep"] == deputado]["id_emp"]) + [deputado]
H = G.subgraph(lista_subset_graph)
nx.draw_networkx_nodes(H, pos = nx.spring_layout(H), nodelist = deputados, node_color='#bfbf7f', node_shape="h", node_size=3000, with_labels = True)
nx.draw_networkx_nodes(H, pos = nx.spring_layout(H), nodelist = empresa, node_color='#9f9fff', node_size=3000, with_labels = True)
nx.draw_networkx_edges(H, pos = nx.spring_layout(H),width=edge_width, alpha=0.2)
#nx.draw(H, style = "solid", with_labels = True)
plt.figure(figsize=(7.5, 7.5))
plt.show()
Output:
When I comment the lines started by nx.draw_networkx_nodes and nx.draw_networkx_edges and uncomment the line started by nx.draw the output is as follows:
I would like to keep a preview as the first image that meets the specs for the edges.

recursive function to return a list of all connected nodes, given a certain node from network graph using python

I'm trying to write a function that will return a list of all the connected nodes in a sub-network, given a starting node from subgraph:
for example the following graph has two sub-networks, one red and one green, as shown in the following image:
using python's package called networkx, I've ran the following code:
import networkx as nx
import pandas as pd
import numpy as np
G=nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_node(4)
G.add_node(5)
G.add_node(6)
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(1,5)
G.add_edge(4,6)
def recurse(G, z , node):
z.append(node)
n = list(set(G.neighbors(node)) - set(z))
if len(n) == 0:
return []
else:
for i in n:
if i not in z:
z.extend(recurse(G, z, i))
return z
z = []
f = recurse(G,z,1)
print(f)
The function is supposed to return the sub-group -> [1,2,3,5] when given (1) as starting node but it returns [1,2,3,1,2,3]
Any ideas how I can perform this task by tweaking the code or maybe using another method?
Thanks!
In case you're not interested about the order the nodes are visited you could just do DFS and collect visited nodes to set:
def recurse(G, z, node):
z.add(node)
for i in G.neighbors(node):
if i not in z:
recurse(G, z, i)
z = set()
recurse(G,z,1)
print(z) # {1, 2, 3, 5}

Drawing multiplex graphs with networkx?

I'm trying to visualize a few graphs whose nodes represent different objects. I want to create an image that looks like the one here:
Basically, I need a 3D plot and the ability to draw edges between nodes on the same level or nodes on different levels.
This answer below may not be a complete solution, but is a working demo for rendering 3D graphs using networkx.
networkx as such cannot render 3D graphs. We will have to install mayavi for that to happen.
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
from mayavi import mlab
import random
def draw_graph3d(graph, graph_colormap='winter', bgcolor = (1, 1, 1),
node_size=0.03,
edge_color=(0.8, 0.8, 0.8), edge_size=0.002,
text_size=0.008, text_color=(0, 0, 0)):
H=nx.Graph()
# add edges
for node, edges in graph.items():
for edge, val in edges.items():
if val == 1:
H.add_edge(node, edge)
G=nx.convert_node_labels_to_integers(H)
graph_pos=nx.spring_layout(G, dim=3)
# numpy array of x,y,z positions in sorted node order
xyz=np.array([graph_pos[v] for v in sorted(G)])
# scalar colors
scalars=np.array(G.nodes())+5
mlab.figure(1, bgcolor=bgcolor)
mlab.clf()
#----------------------------------------------------------------------------
# the x,y, and z co-ordinates are here
# manipulate them to obtain the desired projection perspective
pts = mlab.points3d(xyz[:,0], xyz[:,1], xyz[:,2],
scalars,
scale_factor=node_size,
scale_mode='none',
colormap=graph_colormap,
resolution=20)
#----------------------------------------------------------------------------
for i, (x, y, z) in enumerate(xyz):
label = mlab.text(x, y, str(i), z=z,
width=text_size, name=str(i), color=text_color)
label.property.shadow = True
pts.mlab_source.dataset.lines = np.array(G.edges())
tube = mlab.pipeline.tube(pts, tube_radius=edge_size)
mlab.pipeline.surface(tube, color=edge_color)
mlab.show() # interactive window
# create tangled hypercube
def make_graph(nodes):
def make_link(graph, i1, i2):
graph[i1][i2] = 1
graph[i2][i1] = 1
n = len(nodes)
if n == 1: return {nodes[0]:{}}
nodes1 = nodes[0:n/2]
nodes2 = nodes[n/2:]
G1 = make_graph(nodes1)
G2 = make_graph(nodes2)
# merge G1 and G2 into a single graph
G = dict(G1.items() + G2.items())
# link G1 and G2
random.shuffle(nodes1)
random.shuffle(nodes2)
for i in range(len(nodes1)):
make_link(G, nodes1[i], nodes2[i])
return G
# graph example
nodes = range(10)
graph = make_graph(nodes)
draw_graph3d(graph)
This code was modified from one of the examples here.
Please post the code in this case, when you succeed in reaching the objective.

Categories

Resources