beyondbeneath / bezier-curved-edges-networkx Goto Github PK
View Code? Open in Web Editor NEWFunction to produce Bezier curves for the edges in a NetworkX graph
License: MIT License
Function to produce Bezier curves for the edges in a NetworkX graph
License: MIT License
Hi,
Thanks for publishing this useful code!
When I run this code, I get the following error:
Traceback (most recent call last):
File "bezier-curved-edges-networkx/run.py", line 14, in <module>
curves = curved_edges(G, positions)
File "bezier-curved-edges-networkx/curved_edges.py", line 58, in curved_edges
curveplots.append(bezier.Curve(nodes, degree=2).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
File "/lib/python3.9/site-packages/bezier/curve.py", line 101, in __init__
self._verify_degree(verify)
File "/lib/python3.9/site-packages/bezier/curve.py", line 161, in _verify_degree
raise ValueError(msg)
ValueError: A degree 2 curve should have 3 nodes, not 4.
It looks like this is due to a release of the bezier package adding the verify
argument to the Curve
constructor (this release: https://bezier.readthedocs.io/en/stable/releases/0.11.0.html).
So when I set verify=False
in line 58:
curveplots.append(bezier.Curve(nodes, degree=2, verify=False).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
it works!
Or instead, I can change the degree:
curveplots.append(bezier.Curve(nodes, degree=3).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
and this works too.
Hi,
I'm using your curved_edges.py, it is very useful.
I've found a problem when I tried to use it with a MultiGraph or MultiDiGraph. This is what I found and what I changed to get it work.
If you are using G as MultiDiGraph, edges = np.array(G.edges())
causes this problem:
in curved_edges(G, pos, dist_ratio, bezier_precision, polarity)
6 # Get nodes into np array
7 edges = np.array(G.edges())
----> 8 l = edges.shape[0]
9
10 if polarity == 'random':
IndexError: tuple index out of range
I changed it to support MultiDiGraph edges: (a, b, c)
edges = np.array([edge for edge in G.edges()])
The next issue is to not use a fixed degree=2
, In my use case, I notice the degree can change so I found a better option in bezier.Curve.from_nodes(nodes)
. Since it just return the Curve computing the degree itself.
So, if I run:
curveplots.append(bezier.Curve(nodes, degree=2).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
I get this:
<ipython-input-10-53b971525f16> in curved_edges(G, pos, dist_ratio, bezier_precision, polarity)
56 for i in range(l):
57 nodes = node_matrix[:,i,:].T
---> 58 curveplots.append(bezier.Curve(nodes, degree=2).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
59
60 # Return an array of these curves
~/py3.6/lib/python3.6/site-packages/bezier/curve.py in __init__(self, nodes, degree, copy, verify)
102 super(Curve, self).__init__(nodes, copy=copy)
103 self._degree = degree
--> 104 self._verify_degree(verify)
105
106 @classmethod
~/py3.6/lib/python3.6/site-packages/bezier/curve.py in _verify_degree(self, verify)
162 f"{expected_nodes} nodes, not {num_nodes}."
163 )
--> 164 raise ValueError(msg)
165
166 @property
ValueError: A degree 2 curve should have 3 nodes, not 4.
So I changed it to:
curveplots.append(bezier.Curve.from_nodes(nodes).evaluate_multi(np.linspace(0,1,bezier_precision)).T)
Lastly, would you consider to publish your module in pypi?
hi:
it is so beautiful graph via networkx.
Would you mind telling me where the "curved_edges" is from?
thank you very much!
best regards,
rawen
[email protected]
`
-- #1 Imports
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from fa2 import ForceAtlas2
--# 1 Load the graph edges and compute the node positions using ForceAtlas2
G = nx.read_edgelist('facebook_combined.txt')
forceatlas2 = ForceAtlas2()
positions = forceatlas2.forceatlas2_networkx_layout(G, pos=None, iterations=50)
-- #1 Produce the curves
curves = curved_edges(G, positions)
lc = LineCollection(curves, color='w', alpha=0.05)
-- #1 Plot
plt.figure(figsize=(20,20))
nx.draw_networkx_nodes(G, positions, node_size=5, node_color='w', alpha=0.4)
plt.gca().add_collection(lc)
plt.tick_params(axis='both',which='both',bottom=False,left=False,labelbottom=False,labelleft=False)
plt.show()
`
Hello,
First, I want to thank you for creating this and sharing it. I've been working on adding color to the graph based on spectral clustering. I mostly got the nodes to be colored by group and have been working on the edges. My plan was to create separate LineCollections
per group and plot them individually with different colors. My approach was:
n
groupspositions
dictionary from ForceAtlasn
group of nodespositions
dictionary for each n
groupI've been able to do this, but I'm having problems with the curved_edges
function. It's this step that is causing problems:
coords = np.array([pos[x] for x in u]).reshape([edges.shape[0], 2, edges.shape[1]])
The resulting coords
array just as the same x, y combo repeating over and over again. Could you tell me what this step is doing? Particularly the pos[x]
part... can't figure that out.
Below is my full code, which should reproduce the issue. Thanks for your help!
import sys
import curved_edges
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from fa2 import ForceAtlas2
from sklearn.cluster import SpectralClustering
import pandas as pd
import numpy as np
# Importing network as Pandas dataframe
network = pd.read_csv(r'/path/',sep=" ",header=None, names=['from','to'])
#network = network.rename(columns={"0":"from","1":"to"})
# Creating initial graph
G = nx.from_pandas_edgelist(network,'from','to',create_using=nx.Graph())
# Performing spectral clustering
matrix = nx.to_numpy_matrix(G)
sc = SpectralClustering(7, affinity='precomputed', n_init=100,assign_labels='discretize')
sc.fit(matrix)
clusters = pd.DataFrame({'group':sc.labels_})
# Rearraging graph for coloring
clusters = clusters.reindex(G.nodes())
# Running Force Atlas
forceatlas2 = ForceAtlas2()
positions = forceatlas2.forceatlas2_networkx_layout(G,pos=None,iterations=50)
# Making a new network based on selected cluster
network_sub = pd.merge(network,clusters[clusters['group'] ==3],left_on='to',right_index=True,how='inner').drop(['group'],axis=1).reset_index(drop=True)
# Making a list that has the nodes we want to keep
node_list = list(dict.fromkeys(network_sub['to'].tolist() + network_sub['from'].tolist()))
# Getting the subset of the Atlast positions dict
positions_sub = {k:v for k, v in positions.items() for k in node_list}
# Loading a new network based on the subset
G_sub = nx.from_pandas_edgelist(network_sub,'from','to',create_using=nx.Graph())
print(G_sub.number_of_nodes())
curves = curved_edges(G_sub,positions_sub)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.