Please help with the simplest way to generate a complete random weighted undirected graph given size N, so that weights form a metric space (obey triangle inequality). I know there is networkx library but not sure how to do this.
Although #SvenMarnach is correct, I thought I would mention that it is pretty easy to initialize a graph from a distance matrix in networkx:
import numpy as np
import networkx as nx
V = 100 # number of nodes
D = 2 # dimensionality
positions = np.random.rand(V, D)
differences = positions[:, None, :] - positions[None, :, :]
distances = np.sqrt(np.sum(differences**2, axis=-1)) # euclidean
# create a weighted, directed graph in networkx
graph = nx.from_numpy_matrix(distances, create_using=nx.DiGraph())
Related
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()
I have a dataframe with some columns. I've created a Networkx undirected graph and I want to draw the corresponding network. I need also to change the color of the edges based on the weights of those edges, so I used a LinearColorMap. This is the code:
#my other stuff
cmap = LinearSegmentedColormap.from_list('RwG',['red','white','green'])
nx.draw(G, poss, node_size=1500, node_color='lightgrey', edgelist=edges,edge_color=weights,
width=list(map(lambda number: number * 16 / m, x)), edge_cmap=cmap)
However, I need to normalize my color map so that the white color is centered on a specific value (e.g. -76). The weights are in the [-60,-100] range.
How can I achieve that ?
Visually:
If you pass in a matplotlib colormap to networkx, networkx will normalize your numerical color argument linearly between the minimum and maximum value.
Personally, I think this is a somewhat shortsighted design decision but it is what it is: your non-linear mapping of weights to color is simply not possible.
You can, however, pre-compute the colors and pass those in instead (similarly how you are precomputing edge widths):
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
def weight_to_color(w, threshold):
if w < threshold:
return 'green'
elif np.isclose(w , threshold):
return 'white'
else: # x > threshold
return 'red'
weight_matrix = 40 * np.random.rand(10, 10) - 100
g = nx.from_numpy_array(weight_matrix)
weights = [g.edges[edge]['weight'] for edge in g.edges]
nx.draw(g, node_color='lightgray', edgelist=g.edges, edge_color=[weight_to_color(w, -76) for w in weights])
plt.show()
I have a list of networkX graphs gSet that are of varying sizes. I want to add isolated nodes to all of them such that they all have the same number of nodes thereby padding their adjacency matrices on the right and bottom with 0's. This is what I have tried thus far, maxNodes is the number of nodes in the largest graph from the list:
for i in range(0, len( gSet )):
numOfNodes = nx.to_numpy_array( gSet[i] ).shape[0]
for j in range(maxNodes - numOfNodes, maxNodes ):
gSet[i].add_node(j)
This doesn't seem to change all the graphs to be the same size however.
# collection of dummy graphs:
gSet = []
for _ in range(10):
size = np.random.randint(1,8)
G = nx.from_numpy_array(np.random.rand(size,size)>0.8)
gSet.append(G)
# check number of nodes in each graph:
print('before:')
for g in gSet:
print(len(g))
# find number of nodes in graph with most nodes:
max_nodes = max([len(g) for g in gSet])
# networkx numbers nodes from 0 to the number of nodes -1 (=length of the graph -1)
# so len(g) gives the smallest positive integer that can be used as a node name.
for g in gSet:
while len(g) < max_nodes:
g.add_node(len(g))
# check number of nodes in each graph:
print('after:')
for g in gSet:
print(len(g))
gSet.add_node(j)
This looks to be incorrect. You want to add the extra node to ONE of the graphs in gSet.
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()
I built a graph using bnlearn:hc using the following steps:
bootstrap 500 bns using hc algorithm
calculated the best threshold
extract the best arcs with threshold > "best threshold calculated" and direction > 0.5
So if I try to bootstrap with 1 bn, to be more fast in small tests, sometimes I have some undirected arcs.
In bnlearn how I can know what are the undirected arcs from a bn object (a learned structure) and remove it? This would be the best solution ?
Tks
When there are many nodes it can be hard to pick out the undirected arcs in a graph. In this case you can use undirected.arcs() to find them.
Usage is as follows:
boot = boot.strength(data = df, R=500, algorithm = 'hc',
algorithm.args = list(score = 'bde'))
boot.avg = averaged.network(boot)
undirected.arcs(boot.avg)
You can check the scores of each arc direction to make sure one isn't greater than the other:
score(set.arc(boot.avg, from="A", to="B", df)
score(set.arc(boot.avg, from="B", to="A", df)
And then finally you will want to set a direction like so:
boot.avg = set.arc(boot.avg, from="A", to="B")
If you want to remove the arc entirely you can do so with:
boot.avg = drop.arc(boot.avg, from="A", to="B")
To see which arcs are undirected you can plot the network. Use plot(network) or, if you have the package Rgraphviz, you can use graphviz.plot(network).