paulbrodersen / netgraph Goto Github PK
View Code? Open in Web Editor NEWPublication-quality network visualisations in python
License: GNU General Public License v3.0
Publication-quality network visualisations in python
License: GNU General Public License v3.0
I'm developing some software for Mac using python, tkinter, and pyinstaller. As I add more features, I check to make sure the result can be successfully notarized by Apple. Now notarization fails, and the error log is making reference to QtDesigner, QtWebView, QtBluetooth, and a few other executables starting with Qt. My software was not written using QtDesigner, and I've never seen any of the names before. Are they associated with netgraph, the only new module I've installed since my last successful notarization? If so, are they necessary for use of the Graph class, which is all I really need right now from netgraph for purposes of creating static plots of network communities.
If the above executables aren't really necessary for using the Graph class, I will probably delete them from my software package's contents.
Thanks
Paul
Hello,
When running the following code, netgraph doesn't draw arrows on edges.
Doesn't netgraph recognize the following G as a directed graph?
import matplotlib.pyplot as plt
import netgraph
import networkx as nx
n = 5
G = nx.DiGraph()
G.add_nodes_from(range(n))
G.add_edges_from([(i, (i+1)%n) for i in range(n)]) # directed cycle
plt.subplots(1,1)
netgraph.draw(G, directed=True) # doesn't draw arrows
plt.show()
Reproducing Example:
import networkx as nx
import matplotlib.pyplot as plt
from netgraph import Graph
G = nx.DiGraph()
G.add_nodes_from([0, 1, 2, 3, 4])
G.add_edges_from([(0, 1),
(1, 2),
(0, 2),
(1, 3),
(3, 4)])
Graph(graph=G, arrows=True, node_layout='dot', node_labels=True,
node_label_fontdict={'size':14}, node_label_offset=0.1)
plt.show()
This results in error:
AttributeError: 'DummyVertex' object has no attribute 'data'
My package versions are:
networkx=2.6.2
netgraph=4.0.4
grandalf=0.7
Possible fix:
_node_layout.py:588
# extract node positions
node_positions = dict()
for v in graph.C[0].sV:
node_positions[v.data] = v.view.xy
# for layer in layout.layers:
# for vertex in layer:
# node_positions[vertex.data] = vertex.view.xy
Is it somehow possible to start the interactive Graph with previously serialized node_positions?
I have successfuly used the interactive graph to define my layout but now I would like to edit it when a new node is added.
I tried overwritting it directly but that only breaks everything.
interGraph = netgraph.InteractiveGraph(graph)
interGraph.node_positions = new_positions
I'm trying to use this to accomplish a Process Status Monitoring:
Hi, I ran into an issue when using InteractivelyConstructDestroyGraph
where deleting nodes would not delete the node from the dictionary node_positions. Adding del self.node_positions[node]
to the method _delete_node(self, node)
in _interactive_invariants.py resolved the issue for me.
I am also having an issue where newly added nodes sometimes can not be used (deleted, moved, adding edges to other nodes) until another node has been selected and the initial node has been reselected.
To reproduce it keep adding and deleting one node at the time. Eventually the node won't be deletable. The error that pops up is the following
Traceback (most recent call last):
File "C:\...\matplotlib\cbook\__init__.py", line 196, in process
func(*args, **kwargs)
File "C:\...\netgraph\_interactive_variants.py", line 462, in _on_key_add_or_destroy
self._delete_nodes()
File "C:\...\netgraph\_interactive_variants.py", line 511, in _delete_nodes
nodes = [self._draggable_artist_to_node[artist] for artist in self._selected_artists]
File "C:\...\netgraph\_interactive_variants.py", line 511, in <listcomp>
nodes = [self._draggable_artist_to_node[artist] for artist in self._selected_artists]
KeyError: <matplotlib.patches.Circle object at 0x00000207CE248708>
The issue is minor since it does not break anything but slightly annoying.
For something completely different. I also found it very useful to uncomment the line for adding bidirectional edges in _add_edges(self)
, moving it to a new separate method _add_bidirectional_edges(self)
and adding a hotkey.
Hi,
I have been trying to plot multigraphs using netgraph but it seems it is not supported. Here is a minimal example and error message:
# Simple example of a graph with two nodes and two parallel edges between them
G = nx.MultiDiGraph()
G.add_nodes_from(range(2))
G.add_edge(0, 1, key=0, weight=1)
G.add_edge(0, 1, key=1, weight=1)
# plot the graph using netgraph
Graph(G,node_labels={0:'a',1:'b'},edge_layout='curved',arrows=True)
Error Trace:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/var/folders/8t/nc0dxp394llg8dc047hmbqsh0000gn/T/ipykernel_54472/3976304237.py in <module>
5 G.add_edge(0, 1, key=1, weight=1)
6 # plot the graph using netgraph
----> 7 Graph(G,node_labels={0:'a',1:'b'},edge_layout='curved',arrows=True)
/opt/anaconda3/lib/python3.9/site-packages/netgraph/_main.py in __init__(self, graph, edge_cmap, *args, **kwargs)
1352 kwargs.setdefault('node_zorder', node_zorder)
1353
-> 1354 super().__init__(edges, *args, **kwargs)
1355
1356
/opt/anaconda3/lib/python3.9/site-packages/netgraph/_main.py in __init__(self, edges, nodes, node_layout, node_layout_kwargs, node_shape, node_size, node_edge_width, node_color, node_edge_color, node_alpha, node_zorder, node_labels, node_label_offset, node_label_fontdict, edge_width, edge_color, edge_alpha, edge_zorder, arrows, edge_layout, edge_layout_kwargs, edge_labels, edge_label_position, edge_label_rotate, edge_label_fontdict, origin, scale, prettify, ax, *args, **kwargs)
267 *args, **kwargs
268 ):
--> 269 self.edges = _parse_edge_list(edges)
270
271 self.nodes = self._initialize_nodes(nodes)
/opt/anaconda3/lib/python3.9/site-packages/netgraph/_parser.py in _parse_edge_list(edges)
138 """Ensures that the type of edges is a list, and each edge is a 2-tuple."""
139 # Edge list may be an array, or a list of lists. We want a list of tuples.
--> 140 return [(source, target) for (source, target) in edges]
141
142
/opt/anaconda3/lib/python3.9/site-packages/netgraph/_parser.py in <listcomp>(.0)
138 """Ensures that the type of edges is a list, and each edge is a 2-tuple."""
139 # Edge list may be an array, or a list of lists. We want a list of tuples.
--> 140 return [(source, target) for (source, target) in edges]
141
142
ValueError: too many values to unpack (expected 2)
I tried to install netgraph in my project, and this problem appeared;
DEPRECATION: netgraph is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at https://github.com/pypa/pip/issues/8559
Would it be possible to update netgraph to match these new installation settings?
Code example:
import networkx as nx
import netgraph as ng
import matplotlib.pyplot as plt
graph = nx.Graph([(0, 1)])
ng.Graph(graph, node_layout='community', node_layout_kwargs={'node_to_community': {0: 0, 1: 1}})
plt.show()
Error trace:
Traceback (most recent call last):
File "D:\Projects\PycharmProjects\CommunityDetection\netgraph_bug.py", line 7, in <module>
ng.Graph(graph, node_layout='community', node_layout_kwargs={'node_to_community': {0: 0, 1: 1}})
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_main.py", line 1306, in __init__
super().__init__(edges, *args, **kwargs)
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_main.py", line 286, in __init__
self.node_positions = self._initialize_node_layout(
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_main.py", line 426, in _initialize_node_layout
return self._get_node_positions(node_layout, node_layout_kwargs, origin, scale)
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_main.py", line 441, in _get_node_positions
node_positions = get_community_layout(
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_node_layout.py", line 62, in wrapped_layout_function
return layout_function(edges, *args, **kwargs)
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_node_layout.py", line 870, in get_community_layout
relative_node_positions = _get_node_positions(edges, node_to_community)
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_node_layout.py", line 931, in _get_node_positions
subgraph_node_positions = get_fruchterman_reingold_layout(
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_node_layout.py", line 62, in wrapped_layout_function
return layout_function(edges, *args, **kwargs)
File "C:\ProgramData\Miniconda3\envs\CommunityDetection\lib\site-packages\netgraph\_node_layout.py", line 257, in get_fruchterman_reingold_layout
assert len(edges) > 0, "The list of edges has to be non-empty."
AssertionError: The list of edges has to be non-empty.
Package versions:
networkx=2.6.3
netgraph=4.6.1
I created a graph with networkx 2.1. Then, I used netgraph 3.1.2 to display my graph in Jupiter Notebook (using Python 3.5) as an Interactive graph, when I want to use a different shape for different nodes, the nodes aren't moving unless they are circles.
I tried both changing all nodes to different shapes, and having some circles and some different shapes. The selection (multiple nodes) functionality is no longer functional when I change shapes too. (I'm guessing it has something to do with the node creation that is being somehow altered)
I am working on a visualization of a network that includes moveable nodes with edge labels that are updated by streaming data. Currently I am using randint to update a pandas dataframe while I work on the plotting.
The current code can generate the nodes and allows them to move and also updates the edge labels, but it feels "clunky" and every once in a while the plot flashes the axes (which I do not want to see). I believe this is just an artifact of clearing and regenerating the plot. I can't seem to find a good hook in netgraph to simply refresh graph without doing a clear and redraw which will inevitably get worse as the network grows. Any ideas on how to make this smoother?
Here is the current code:
import pandas as pd
import matplotlib.pyplot as plt
#plt.ion()
import networkx as nx
import random as r
import netgraph
import numpy as np
#Graph creation:
G=nx.Graph(type="")
#edges automatically create nodes
df=pd.read_csv('diyNodeSet.csv')
G = nx.from_pandas_edgelist(df, source='sdr', target='rxr', \
create_using=nx.DiGraph)
#Create edge list from dataframe
df['xy']=list(zip(df.sdr,df.rxr))
ed=list(zip(df.br,df.pct))
el=dict(zip(df.xy,ed))
pos = nx.layout.circular_layout(G) ##initial node placement
# drag nodes around #########
plot_instance = netgraph.InteractiveGraph(G, node_positions=pos, node_color='red', edge_labels=el)
#update the edge labels with random data
import threading
interval = 3
def updatePlot(oldPlot):
nodePos=oldPlot.node_positions
new_pct=pd.Series([r.randint(1, 100),r.randint(1, 100),r.randint(1, 100),r.randint(1, 100)], name='pct', index=[0,1,2,3])
df.update(new_pct)
ed=list(zip(df.br,df.pct))
el=dict(zip(df.xy,ed))
oldPlot.fig.clear()
global plot_instance
plot_instance = netgraph.InteractiveGraph(G, node_positions=nodePos, node_color='red', edge_labels=el)
#call update each interval
def startTimer():
threading.Timer(interval, startTimer).start()
updatePlot(plot_instance)
startTimer()
Hi Paul,
I'm having trouble using the plot community functionality. The graph I'm constructing is a simple stochastic block model with two uneven sized communities. For some reason, I keep getting an error that reads "The list of edges has to be non-empty", even through the graph object g
has 24 nodes and a variable, but certainly non-zero number of edges. I've tried passing in the Networks graph object as an adjacency matrix, edge list, and others forms but for some reason the Graph
class isn't recognizing the edges in g
. Do you have any advice? I've pasted the example below. Essentially the only part of the code that I've changed from the tutorial is the generative graph model (stochastic block model).
For clarity, networkx
version is 2.6.3
and netgraph
version is 4.4.1
from netgraph import Graph
# create a modular graph
partition_sizes = np.asarray([4,20])
probs = np.asarray([[0.0, 0.75], [0.75, 0.0]])
g = nx.stochastic_block_model(sizes, probs, seed=0)
# create a dictionary that maps nodes to the community they belong to
node_to_community = dict()
node = 0
for community_id, size in enumerate(partition_sizes):
for _ in range(size):
node_to_community[node] = community_id
node += 1
community_to_color = {
0 : 'tab:blue',
1 : 'tab:orange'
}
node_color = {node: community_to_color[community_id] for node, community_id in node_to_community.items()}
Graph(nx.adjacency_matrix(g).todense(),
node_color=node_color, node_edge_width=0, edge_alpha=0.1,
node_layout='community', node_layout_kwargs=dict(node_to_community=node_to_community),
edge_layout='bundled', edge_layout_kwargs=dict(k=2000),
)
plt.show()
Hi, first of all, I'm really glad you made this... it produces really nice plots for weighted graphs, which is something I've missing!
There are however some small problems when using Matplotlib 2:
My plot (1200 dpi, white border cropped):
My plot (Matplotlib default dpi, uncropped):
Also, these warnings are thrown:
/Users/allan/src/netgraph/netgraph.py:129: RuntimeWarning: invalid value encountered in less
weights[weights<edge_vmin] = edge_vmin
/Users/allan/src/netgraph/netgraph.py:130: RuntimeWarning: invalid value encountered in greater
weights[weights>edge_vmax] = edge_vmax
/Users/allan/homeInstalled/miniconda3/envs/py36/lib/python3.6/site-packages/matplotlib/colors.py:494: RuntimeWarning: invalid value encountered in less
cbook._putmask(xa, xa < 0.0, -1)
/Users/allan/src/netgraph/netgraph.py:612: RuntimeWarning: invalid value encountered in true_divide
v = v / np.linalg.norm(v) # unit
/Users/allan/src/netgraph/netgraph.py:620: RuntimeWarning: divide by zero encountered in double_scalars
dx *= (r-offset)/r
/Users/allan/src/netgraph/netgraph.py:620: RuntimeWarning: invalid value encountered in double_scalars
dx *= (r-offset)/r
/Users/allan/src/netgraph/netgraph.py:621: RuntimeWarning: divide by zero encountered in double_scalars
dy *= (r-offset)/r
/Users/allan/src/netgraph/netgraph.py:621: RuntimeWarning: invalid value encountered in double_scalars
dy *= (r-offset)/r
Hey,
I'm currently using the library on a project and have a usecase for linking to a URL based on node attributes. I have the annotation showing on node click, but realized that the link is not selectable or clickable. Would it be possible to do either of those (hyperlinks would be preferred but selectable text is good too)?
Thanks
Hi it's me again :)
Just caught a small bug and the fix is very simple (see below).
When trying to supply a dict for the node_shape argument (so that different nodes can have different shapes) it currently throws an exception:
_main.py", line 1167, in _check_types
raise TypeError(msg)
TypeError: Item 0 in node_shape is of the wrong type.
Expected type: <class 'str'>
Actual type: <class 'int'>
The first arg that currently is sent to the _check types function is str_or_dict which then gets iterated over as "for item in items". So it it's a dict, it's the keys which get iterated over rather than the values .
The first arg that is sent to the **_check type**s function should be str_or_dict.values() instead of the current str_or_dict (as it correctly is in _normalize_numeric_argument)
Hi,
Excellent job for the Interactivity drawing network.
In my case, I'll draw rectangles after each node to represent their attributions. So I wonder if there is a way to get node position so I can refresh the matplotlib drawing?
Like this example, I wanna move the rectangles together with nodes.
Here is my code in jupyterlab
%matplotlib widget
import matplotlib
import numpy as np
import matplotlib.pyplot as plt; plt.ion()
import networkx as nx
import netgraph
fig, axs = plt.subplots(figsize = (10,10))
nodes = np.array(['A', 'B', 'C', 'D', 'E', 'F', 'G'])
edges = np.array([['A', 'B'], ['A', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'F'], ['C', 'G']])
pos_ = np.array([[0, 0], [-2, 1], [2, 1], [-3, 2], [-1, 2], [1, 2], [3, 2]])
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
x_move = 0
y_move = 0
block_size = 0.5
for pos in pos_:
rect1 = matplotlib.patches.Rectangle((pos[0]+x_move,pos[1]+y_move), 0.85*block_size, 0.75*block_size, facecolor='red', edgecolor=None)
axs.add_patch(rect1)
I = netgraph.InteractiveGraph(G,
node_positions=dict(zip(nodes, pos_)),
node_labels=dict(zip(nodes,nodes)),
node_label_bbox=dict(fc="lightgreen", ec="black", boxstyle="square", lw=3),
node_size=12,
)
When I execute a netgraph example as a Python script, the plot window appears and disappears almost instantly. However, when I execute each line of code in the Python prompt, the plot window stays.
An MWE:
import numpy as np
import matplotlib.pyplot as plt; plt.ion()
import netgraph
graph = [
(0, 1),
(1, 2),
(2, 0)
]
netgraph.draw(graph, node_labels={0: '0', 1: '1', 2: '2'})
The same problem occurs with networkx directed graphs as well.
Hello,
We have an application with PyQt, and we would like to use netgraph to our solution.
However, we are not being able to make the graphs interactive, apparently the Qt does not bypass the click events to the plot.
Any idea how we could solve it?
Here is an example:
import sys
import matplotlib
import matplotlib.pyplot as plt
from netgraph import InteractiveGraph
from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT
from matplotlib.figure import Figure
import networkx as nx
matplotlib.use('Qt5Agg')
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
g = nx.house_x_graph()
fig, ax = plt.subplots(figsize=(10, 10))
plot_instance = InteractiveGraph(g)
super(MplCanvas, self).__init__(fig)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
sc = MplCanvas(self, width=5, height=4, dpi=100)
toolbar = NavigationToolbar2QT(sc, self)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(toolbar)
layout.addWidget(sc)
widget = QtWidgets.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()
Hello,
I have encountered the same error several times and I finally took some time to check that it indeed comes from the package. Here is a reproducible example :
import numpy
from netgraph import Graph
n_nodes = 2730
A = np.random.binomial(n =1, p = 0.002, size = (n_nodes ,n_nodes ))
clusters = np.random.randint(5, size=n_nodes )
G = nx.from_numpy_array(A, create_using=nx.DiGraph)
print('Is the graph weakly connected ? : {}'.format(nx.is_weakly_connected(G)))
print('Is the graph strongly connected ? : {}'.format(nx.is_weakly_connected(G)))
G_netgraph = Graph(G;
node_layout="community",
edge_layout='straight',
node_layout_kwargs=dict(node_to_community = {node:clusters[node] for node in G.nodes} )
)
I get the following error : KeyError: 13
The key changes with the graphs.
If you have a hint of what's happening, I would really appreciate it. I would love to use the package on large graph. The plots are really beautiful.
Thanks
Rémi
I apologize for posting this here, as it is not a bug or issue but instead a question regarding the adjustment of node label font sizes, one that I doubt would yield a response on StackOverflow.
At https://netgraph.readthedocs.io/en/latest/graph_classes.html
it states that node_label_fontdict
consists of keyword arguments passed to matplotlib.text.Text. I'm looking at matplotlib.text.Text right now and see the familiar keyword argument fontsize
. It's not clear what an example dictionary, node_label_fontdict
would look like if I merely wanted to change my label font size.
BTW, this package is really nice. I plan to use it for community detection in the context of EEG signal analysis.
I have two models both of which can output a value from fixed set of values (say ["A", "B", "C"]). For example, model_1 = ["A", "B", "C"], model_1 = ["A", "B", "C"]
I want to create a flowchart with starting nodes as model_1 and model_2 to show the following logic -
if output_model_1 = "A" and output_model_2 = "A":
final_output = "A"
elif output_model_1 = "B" and output_model_2 = "B":
final_output = "B"
elif output_model_1 = "C" and output_model_2 = "C":
final_output = "C"
elif (output_model_1 = "A" and output_model_2 = "B") or (output_model_1 = "B" and output_model_2 = "A"):
final_output = "C"
elif (output_model_1 = "A" and output_model_2 = "C") or (output_model_1 = "C" and output_model_2 = "A"):
final_output = "A"
elif (output_model_1 = "B" and output_model_2 = "C") or (output_model_1 = "C" and output_model_2 = "B"):
final_output = "B"
Can you please help? Many thanks!
Should the setup.py
include networkx
as a dependency?
I propose a nicer arrowhead shape fo netgraph as follows.
How do you think about.
from matplotlib import pyplot as plt
from shapely.geometry.polygon import Polygon
from descartes import PolygonPatch
poly = Polygon([[-3,1], [0,9], [3,1], [0,3], [-3,1]])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-5, 5)
ax.set_ylim(0, 10)
ax.set_aspect(1)
ax.add_patch(PolygonPatch(poly))
plt.show()
Hi,
Thanks a lot for the library!
I wanted to draw a directed graph in interactive format.
import matplotlib.pyplot as plt
import netgraph
import networkx as nx
n = 5
G = nx.DiGraph()
G.add_nodes_from(range(n))
G.add_edges_from([(i, (i+1)%n) for i in range(n)]) # directed cycle
plot_instance = netgraph.InteractiveGraph(G, draw_arrows=True, directed=True,node_labels=True)
#netgraph.draw(G, draw_arrows=True) # doesn't draw arrows
plt.show()
The intended graph should look like this: (contains arrow)
But the code above generates a graph like this: (has no arrow)
How can I include arrow in interactive graphs?
Thank you!
Hi! I am using Networkx to draw several graphs in a figure. Each graph is represented in a circular layout and may have an edge with another circle. The issue is that I can't use Networkx's union function, otherwise I'll end up with a single graph if two individual ones have an edge between them. What I wanted was to just join them with an edge but still retain their individual references, since it may be that I there is a link between one of the graphs mentiones earlier and another one in the future. The reference is important to me because I still want to be able to plot them individually in a circle layout, rather than plotting them together in a circle layout.
Cheers!
First, sorry if raising an issue is not the proper way to log my question.
I have a PyQt app where I draw graphs with various number of nodes.
After determining the nodes positions (in my case using nx.shell_layout(G)), I draw an InteractiveGraph (thanks to your advice on a SO question I opened a few days ago) and it works fine.
However, I can see that the graph is not "adjusted" to the matplotlib canvas it is attached to. It seems to me that netgraph (or networkx) auto determines a "frame" depending on the number of nodes it has to display. So when you click/move the nodes, they are not "displayed" if you moved outside of this frame, which is smaller than my overall matplotlib size.
So I would like to know if there is a way to adjust this frame (or box) so that its limits fit the one of my matplotlib canvas?
When I create a class that simply inherits a networkx Graph, the plotter won't work. For example, this works fine:
g = networkx.Graph([(1,2)])
netgraph.Graph(g)
However if I do a simple inheritance I get an error.
class NewGraph(networkx.Graph):
pass
g = NewGraph([(1,2)])
netgraph.Graph(g)
NotImplementedError: Input graph must be one of:
list
tuple
set
networkx.Graph
igraph.Graph
Currently, type(graph) = <class '__main__.NewGraph'>
Instead of checking the graph objects with isinstance
, it's doing a string check of the class name in _parser.py. Per the code's comments, this is to avoid importing (potentially slow or non-existent) modules just for type checking. However this prevents any possibility of extending code.
Is it possible to allow importing for type checking? What's the standard way to do this in python? I'm assume it's a try-except for the module imports and keeping track of which are loaded. Are igraph and networkx so slow to import that this can't be done?
In the meantime I need this capability badly enough that I've monkey patched my way around it.
Trying to create a community network graph but fails with the error:
*ValueError: zero-size array to reduction operation minimum which has no identity*
Everything works using networksx, but since netgraph allows for edge bundling and prettier graphs I would love for it to work.
The only code needed to reproduce would be the one below (links_filtered is a pandas edgelist).
G=nx.from_pandas_edgelist(links_filtered, 'from', 'to')
node_to_community = community.community_louvain.best_partition(G)
Graph(G, node_layout='community', node_layout_kwargs=dict(node_to_community=node_to_community))
Hi Paul,
I am having a problem with the scale parameter of the Graph class.
First of all, I am not assigning any value to it and I leave it as the default (1.0 1.0).
Debugging a bit, I figure out that that value is changed internally by the function "get_layout_for_multiple_components" to (0.67, 1). In this way I always get an error saying that some of the nodes are outside the origin-scale area.
I tried with the spring, circular and multipartite layout and all of them produce the same error.
Am I setting something wrong?
Graph(G,
node_layout = 'circular',
node_size = 8,
node_color = node_color,
node_labels = node_label,
node_edge_width = border,
node_label_fontdict = dict(size=font_size),
node_edge_color = edge_color,
node_label_offset = 0.15,
node_alpha = 1,
arrows = True,
edge_layout = 'curved',
edge_label = show_edge_labels,
edge_labels = edge_label,
edge_label_fontdict = dict(size=font_size),
edge_color = edge_color,
edge_width = edge_width,
edge_label_position = 0.35)
netgraph
doesn't support enclosing text labels in nodes and directing edges to the bounding boxes of text labels. At the current version nodes could be regular polygons or circles only. BaseGraph.draw_edges
method instantiates edge_artist
that supports offset that is constant:
edge_artist = EdgeArtist(
...
offset = node_size[target],
...
)
node_size[target]
is a constant value. Hovewer, while creating bounding boxes of text labels, it would be nice to have a support for rectangular nodes that encloses text labels [1]. Also, netgraph
lacks support for dynamic recomputation of the offset
while dragging source nodes in order to point arrows of edges to exact positions of bounding boxes of rectangles ot text labels (it should remain unique for each edge that points to the same node)[2]. Currently, it is able to point arrows only to specific offsets of each node that remains constant. I'm able to write code for both [1] and [2] and I can share it but I'm not sure if it's possible to allow each node artist to have attributes responsible for different height and width, not node_size
only.
I copied the code below from the README, and changed 'InteractiveGraph' with 'InteractivelyConstructDestroyGraph'.
When I try the keystrokes as indicated in the source code (e.g. "Pressing 'A' will add a node to the graph", "Pressing 'D' will remove a selected node") I get the following exceptions:
File "/usr/local/lib/python3.7/site-packages/netgraph/_interactive_variants.py", line 458, in _on_key_add_or_destroy
self._add_node(event)
File "/usr/local/lib/python3.7/site-packages/netgraph/_interactive_variants.py", line 485, in _add_node
self.draw_nodes({node:pos}, **self.kwargs)
AttributeError: 'InteractivelyConstructDestroyGraph' object has no attribute 'kwargs'
File "/usr/local/lib/python3.7/site-packages/netgraph/_interactive_variants.py", line 462, in _on_key_add_or_destroy
self._delete_nodes()
File "/usr/local/lib/python3.7/site-packages/netgraph/_interactive_variants.py", line 514, in _delete_nodes
edges = [(source, target) for (source, target) in self.edge_list if ((source in nodes) or (target in nodes))]
AttributeError: 'InteractivelyConstructDestroyGraph' object has no attribute 'edge_list'
import matplotlib.pyplot as plt
import networkx as nx
from netgraph import InteractiveGraph
from netgraph._interactive_variants import InteractivelyConstructDestroyGraph
g = nx.house_x_graph()
node_data = {
4 : dict(s = 'Additional annotations can be revealed\nby clicking on the corresponding plot element.', fontsize=20, backgroundcolor='white')
}
edge_data = {
(0, 1) : dict(s='Clicking on the same plot element\na second time hides the annotation again.', fontsize=20, backgroundcolor='white')
}
fig, ax = plt.subplots(figsize=(10, 10))
plot_instance = InteractivelyConstructDestroyGraph(g, node_size=5, edge_width=3,
node_labels=True, node_label_offset=0.08, node_label_fontdict=dict(size=20),
node_data=node_data, edge_data=edge_data, ax=ax)
plt.show()
Traceback (most recent call last):
File "test.py", line 12, in <module>
plot_instance = netgraph.InteractivelyCreateDestroyGraph(graph, draw_arrows=True, ax=ax)
AttributeError: module 'netgraph' has no attribute 'InteractivelyCreateDestroyGraph'
The plots generated by your examples in the readme quickly open and then crash/close. No error message is shown. Thus, I believe it's some sort problem either Pycharm IDE or compatibility issues with the latest version matplotlib.
python version: 3.8.10
netgraph version: 4.1.0
I'm trying to use the get_fruchterman_reingold_layout
function to get node positions for plotting. When used on edges/nodes from a small graph, it fails, raising ValueError: Some given node positions are not within the data range specified by origin and scale!
and showing different scale values than the ones that were actually provided.
Below is a minimal example: using the smaller list of edges results in error, while the second, bigger one, is fine.
#! /usr/bin/env python3
import netgraph
import warnings
warnings.filterwarnings("ignore")
nodes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
# not enough edges
edges = [(0, 5), (0, 8), (0, 21), (0, 27), (1, 6),]
# enough edges
#edges = [(0, 5), (0, 8), (0, 21), (0, 27), (1, 6), (1, 7), (1, 10), (1, 11), (1, 16), (1, 27), (2, 3), (2, 8), (2, 9), (2, 14), ]
selected_node = 0
plot_x, plot_y = 1.7786, 1
pos = netgraph.get_fruchterman_reingold_layout(
edges=edges,
nodes=nodes,
origin=(0,0),
scale=(plot_x,plot_y),
node_size=0,
node_positions={selected_node:(plot_x/2,plot_y/2)},
fixed_nodes=[selected_node],
)
print(pos)
Would it be possible to pass a Graph
object from networkx into draw
?
Hi, when I run the 'InteractivelyConstructDestroyGraph' example code from the README.md I get the following error when trying to add new nodes using the hotkey 'A',
AttributeError: 'dict_values' object has no attribute 'append'.
It directs to _interactive_variants.py line 489, in _add_node, self._draggable_artists.append(node_artist)
I am using version 3.1.6 of Netgraph with Python 3.7
On another note I am wondering if there is a way to draw a background image underneath the graph?
Getting the following error when drawing a networkx Digraph().
networkx version: 2.0
netgraph version: 3.1.2
python 3
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-63-2bd83e0b2753> in <module>()
----> 1 netgraph.draw(G, draw_arrows=True)
/anaconda3/lib/python3.6/site-packages/netgraph/_main.py in draw(graph, node_positions, node_labels, edge_labels, edge_cmap, ax, **kwargs)
77 # but if the variance in weights is large, this typically results in less
78 # visually pleasing results.
---> 79 edge_color = get_color(edge_weight, cmap=edge_cmap)
80 kwargs.setdefault('edge_color', edge_color)
81
/anaconda3/lib/python3.6/site-packages/netgraph/_main.py in get_color(mydict, cmap, vmin, vmax)
313 # - the colormap midpoint is at zero-value, and
314 # - negative and positive values have comparable intensity values
--> 315 values /= np.nanmax([np.nanmax(np.abs(values)), abs(vmax), abs(vmin)]) # [-1, 1]
316 values += 1. # [0, 2]
317 values /= 2. # [0, 1]
TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'l') according to the casting rule ''same_kind''
Hello,
I can generate a directed graph using the code in the readme file, but when it displays in Jupyter notebook it is not interactive. Is there something I need to enable in Jupyter Notebooks to make the image interactive? I do not see any other guidance in your documentation.
Here is my code:
import networkx as nx
import matplotlib.pyplot as plt
import netgraph
edgls = [(1,2),(2,6),(1,2),(2,6),(2,12),(3,2),(3,9),(3,7),(3,8),(4,15),
(4,12),(5,16),(5,18),(6,24),(7,25),(8,25),(8,15),(9,15),(9,19),
(9,12),(10,14),(11,10),(12,13),(13,14),(13,19),(14,10),(15,6),
(15,10),(16,14),(16,20),(16,22),(17,14),(17,26),(18,17),(19,11),
(20,6),(21,22),(21,15),(23,6),(25,21),(26,9)]
sdmodel = nx.DiGraph()
sdmodel.add_edges_from(edgls)
plt.figure(figsize=(11,11))
netgraph.draw(sdmodel)
plot_instance = netgraph.InteractiveGraph(sdmodel)
Thank you!
Hello!
I am trying to embed Netgraph's plots inside my PyQt application, however I am not being able to make the figure occupy the entire window nor scale with it. The graphs keep touching only one of the borders of the figure, and I can't make the figure in only one direction (x or y).
It's been a while since I started to try to make this right, looking into MatPlotLib's documentations. I have even written a few questions at StackOverflow about it, however without any success.(Scalable MatPlotLib Figure with PyQt window and FigureCanvas not entirely filing PyQt Window)
The behavior I face can be seen in the image:
It is possible to see that the graph can't touch the horizontal borders of the Window, doesn't matter how I scale it. I also keep receiving this Warnings whenever I touch the blank space between the border of the Figure and the border of the Window.
What I want is for the graph to always touch the border of the window.
Could you help me somehow? At this point I don't know if this could be something related to the Netgraph library itself.
Here is the code I am using for testing:
import sys
import matplotlib; matplotlib.use("Qt5Agg")
from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
import matplotlib.pyplot as plt
from netgraph import EditableGraph
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None):
figure = plt.figure()
figure.set_figheight(8)
figure.set_figwidth(6)
plt.tight_layout()
figure.patch.set_visible(False)
super(MplCanvas, self).__init__(figure)
self.setParent(parent)
self.ax = plt.axes([0,0,1,1], frameon=False)
self.ax.axis('off')
self.ax.get_xaxis().set_visible(False)
self.ax.get_yaxis().set_visible(False)
self.graph = EditableGraph([(0, 1)], ax=self.ax)
plt.autoscale(axis='both', tight=True)
self.updateGeometry()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.canvas = MplCanvas(self)
self.lbl = QtWidgets.QLabel(self)
self.setCentralWidget(self.canvas)
def main():
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
if __name__ == "__main__":
main()
Is there any way to render the network graph with orthogonal layout?
Hi Paul!
First, thank you for netgraph! I find it really useful to visualize parts of my work and I love the InteractiveGraphs!
Now to the issue I came across. I use netgraph to visualize computational graphs I build and reconfigure, i.e., mostly to check that whatever I configured is connected correctly. The sugiyama layout works sufficiently well for this purpose, but sometimes my graph is split into multiple components. For small sub-graphs, the sugiyama layout vertically aligns the nodes, which creates a problem when rescaling the layout to fit into the bounding box. Basically, I run into a division by zero at the following line:
netgraph/netgraph/_node_layout.py
Line 574 in f8f950c
Here is a minimal reproducible example that triggers this case:
import networkx as nx
import netgraph as ng
G = nx.DiGraph()
G.add_node('A')
G.add_node('B')
G.add_edge('A', 'B')
edge_list = [edge for edge in G.edges]
node_layout = ng.get_sugiyama_layout(edge_list)
The result is that the node positions contain nan
values:
node_layout
{'A': array([nan, 1.]), 'B': array([nan, -0.])}
I understand that you are quite busy, so I'll leave here my suggested fix. For my cases, it seems that simply not normalizing when the nodes are aligned, should do the trick:
np.divide(node_positions, np.max(node_positions, axis=0), where=np.max(node_positions, axis=0) != 0, out=node_positions)
instead of
node_positions /= np.max(node_positions, axis=0)
Best,
Pablo
I just created a fresh install from this conda environment file:
name: myNewEnv
channels:
- conda-forge
dependencies:
- python=3.8
- jupyterlab=3
- ipympl
- matplotlib
- networkx
- pip
- pip:
- netgraph
Then I wanted to just import the libraries, i.e.:
import networkx
import netgraph
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
But here was was stopped with the following exception:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
~\Anaconda3\envs\myNewEnv\lib\site-packages\netgraph\_main.py in RegularPolygon()
605 try: # seems deprecated for newer versions of matplotlib
--> 606 center = property(matplotlib.patches.RegularPolygon._get_xy,
607 matplotlib.patches.RegularPolygon._set_xy)
AttributeError: type object 'RegularPolygon' has no attribute '_get_xy'
During handling of the above exception, another exception occurred:
AttributeError Traceback (most recent call last)
<ipython-input-1-8690930b5b60> in <module>
1 import networkx
----> 2 import netgraph
3 import matplotlib.pyplot as plt
4 import matplotlib.image as mpimg
~\Anaconda3\envs\myNewEnv\lib\site-packages\netgraph\__init__.py in <module>
79 __email__ = "[email protected]"
80
---> 81 from ._main import (draw,
82 draw_nodes,
83 draw_node_labels,
~\Anaconda3\envs\myNewEnv\lib\site-packages\netgraph\_main.py in <module>
597
598
--> 599 class RegularPolygon(matplotlib.patches.RegularPolygon):
600 """
601 The API for matplotlib.patches.Circle and matplotlib.patches.RegularPolygon in matplotlib differ substantially.
~\Anaconda3\envs\myNewEnv\lib\site-packages\netgraph\_main.py in RegularPolygon()
607 matplotlib.patches.RegularPolygon._set_xy)
608 except AttributeError:
--> 609 center = matplotlib.patches.RegularPolygon.xy
610
611
AttributeError: type object 'RegularPolygon' has no attribute 'xy'
The execution of the code import matplotlib; print(matplotlib.__version__)
results in 3.4.1
.
I have a large network which for which I would like to visualize communities and multiple components.
I can load it in Cytoscape and do it there but I was looking for pythonic solution as it is much easier to export publication quality plot from matplotlib than Cytoscape.
However, it fails with RecursionError: maximum recursion depth exceeded while calling a Python object.
Is there a way to override this? I am working on a computer cluster and have enough RAM and memory for handling this
The arrowhead scales with the width of the arrow, bu so much that it might disappear:
And shouldn't one of the arrows from the mutually connected nodes be even wider, considering it's weight relative to the other connections?
Figure is produces with the following code:
#!/usr/bin/env python
# -*- coding: utf8 -*-
import matplotlib as mpl
mpl.use('Qt5Agg')
import matplotlib.pyplot as plt
import numpy as np
import netgraph
import networkx as nx
mat = np.array([[ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.09025436, 0.01328399], # noqa
[ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ], # noqa
[ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ], # noqa
[ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ], # noqa
[ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ], # noqa
[ 0.0 , 0.0 , 0.0 , 0.0 , 0.05444029, 0.0 , 0.0 ], # noqa
[ 0.08 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ]]) # noqa
mat[mat == 0.0] = np.NaN
# Create networkx graph in order to use networkx layout engines
g = nx.from_numpy_matrix(mat, create_using=nx.DiGraph())
pos = nx.drawing.layout.circular_layout(g)
node_positions = list(pos.values())
# Create figure
fig, ax = plt.subplots()
netgraph.draw_nodes(node_positions, node_size=3)
netgraph.draw_edges(mat, node_positions, node_size=3, edge_width=15*mat+0.4)
# Adjust axis limits
npArr = np.array(node_positions)
maxX, maxY = 1.3*np.max(node_positions, axis=0)
minX, minY = 1.3*np.min(node_positions, axis=0)
ax.set_ylim(minY, maxY)
ax.set_xlim(minX, maxX)
plt.show()
Based on this problem it would be nice to have an option of highlighting a collection of nodes depending on some input dictionary when I mouse over some key node.
My example code so far:
import matplotlib.pyplot as plt
import networkx as nx
from netgraph import Graph # pip install netgraph
node_labels = {1: 'p→q', 2: '¬q', 3: '¬ (¬p)', 4: '¬p', 5: '¬p∧ ¬ (¬p)', 6: 'p', 7: 'q', 8: 'q∧ ¬q', 9: '¬p'}
color_map = {1: 'red', 2: 'red', 3: 'red', 4: 'red', 5: 'lightblue', 6: 'lightblue', 7: 'lightblue', 8: 'lightblue', 9: 'blue'}
edge_labels = {(3, 5): '∧I', (4, 5): '∧I', (4, 6): '¬E', (5, 6): '¬E', (1, 7): '→E', (6, 7): '→E', (2, 8): '∧I', (7, 8): '∧I', (8, 9): '¬E', (3, 9): '¬E'}
highlight = {1: {1}, 2: {2}, 3: {3}, 4: {4}, 5: {3, 4, 5}, 6: {3, 6}, 7: {1, 3, 7}, 8: {1, 2, 3, 8}, 9: {1, 2, 9}}
graph = nx.from_edgelist(edge_labels, nx.DiGraph())
Graph(graph, node_layout='dot',
node_labels=node_labels, node_label_fontdict=dict(size=21),
edge_labels=edge_labels, edge_label_fontdict=dict(size=14), edge_label_rotate=False,
node_color=color_map, node_edge_color=color_map, arrows=True
)
plt.show()
The dictionary highlight
could be a possible input parameter. The functionality could be similar to that one of the interactive graphs.
If I mouse over some key node from the dictionary highlight
int the example code, the functionality would highlight all the value nodes. For example, mouse over node 9
would highlight nodes 1, 2, 9
, because of the following shape of highlight = ... **9: {1, 2, 9}**}
I need this to highlight the origin assumptions of some the propositions in proof graphs like the one in the example above. The most simple approach for me so far is this library at moment and so it would be nice to have this functionality in it too. Thank you!
Fixing the previous bug about true_division
in numpy here #10, it would be nice to support self-loops.
/anaconda3/lib/python3.6/site-packages/netgraph/_main.py:848: UserWarning: Plotting of self-loops not supported. Ignoring edge (X, Y).
warnings.warn("Plotting of self-loops not supported. Ignoring edge ({}, {}).".format(source, target))
Hi there! Very nice library, trying to leverage the ArcDiagram plot and running into an issue. I'm creating a graph where the nodes represent percentages (string labels '0' to '100') and the edges are all from '0' to whatever the percentage is for the datapoint (e.g. '55'). I would like to render the arc diagram with the nodes arranged 0-100 in a linear fashion, and am passing in the ordered list of nodes to the ArcDiagram constructor's node_order param as ['0', '1', '2',...'99', '100'] but the graph rendering appears to be ignoring this.
Am I using node_order incorrectly or is it not being applied for some reason?
Thanks!
I'm trying to replicate the approach for the community node layout described at https://netgraph.readthedocs.io/en/latest/sphinx_gallery_output/plot_10_community_layout.html#sphx-glr-sphinx-gallery-output-plot-10-community-layout-py
Here's my example, where my graph is undirected with no self-loops. The communities are detected using networkx louvain method:
XKCD_COLORS = {
'cloudy blue': '#acc2d9',
'dark pastel green': '#56ae57',
'dust': '#b2996e',
'electric lime': '#a8ff04',
'fresh green': '#69d84f'}
colors=list(XKCD_COLORS.values())
import networkx as nx
import networkx.algorithms.community as nc
from netgraph import Graph
import numpy as np
from matplotlib import pyplot as plt
A=np.random.randn(8,8) # adjacency matrix: eight nodes; undirected; no self-loops
np.fill_diagonal(A, 0)
A=A+A.T
G=nx.from_numpy_matrix(A)
channels=['A','B','C','D','E','F','G','H']
Nc=len(channels)
labels_dict={i:channels[i] for i in range(Nc)}
nodes=range(Nc)
clusters=nc.louvain_communities(G) # returns communities as a list of sets, each set forming a cluster.
node_to_community = dict() # use clusters above to create node_to_community dictionary;
for i in range(Nc):
for j in range(len(clusters)):
if nodes[i] in clusters[j]:
node_to_community.update({i:j})
community_to_color = {i: colors[i] for i in range(len(clusters))}
node_color = {node: community_to_color[community_id] for node, community_id in node_to_community.items()}
Graph(G,node_color=node_color, node_labels=labels_dict,node_edge_width=0, edge_alpha=0.1, node_layout='community', node_layout_kwargs=dict(node_to_community=node_to_community),
edge_layout='bundled', edge_layout_kwargs=dict(k=2000))
plt.show()
I obtain a correct graph, but accompanying it is the following error message:
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/netgraph/_edge_layout.py", line 761
displacement = compatibility * delta / distance_squared[..., None]
RuntimeWarning: invalid value encountered in true_divide
flake8 testing of https://github.com/paulbrodersen/netgraph on Python 2.7.14
$ flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
./netgraph/_main.py:820:64: F821 undefined name 'shape'
raise ValueError("Got unknown shape: %s" % shape)
^
Python version: 3.10.6
netgraph version: 4.10.2
I have a network g
, and I have created a pos
dict using a networkx layout function. The output for the list of nodes and pos print are:
print(list(g.nodes))
gives ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
print(pos)
gives
{0: array([1.0000000e+00, 1.4702742e-08]),
1: array([0.809017 , 0.58778526]),
2: array([0.30901698, 0.95105655]),
3: array([-0.30901702, 0.95105649]),
4: array([-0.80901699, 0.58778526]),
5: array([-9.99999988e-01, -7.27200340e-08]),
6: array([-0.80901693, -0.58778529]),
7: array([-0.30901711, -0.95105646]),
8: array([ 0.30901713, -0.95105646]),
9: array([ 0.80901694, -0.58778529])}
When I try to plot the network using netgraph, I get the following error:
Graph(g, node_layout=pos, node_edge_width=1, edge_alpha=1, edge_width=1)
ValueError: node_layout is incomplete. The following elements are missing:
-4
-2
-8
-1
-6
-3
-7
-9
-0
-5
I don't understand the problem. My pos dict has all node positions.
Edit: I found the reason when this happens. It happens when the network is taken from a gml file. i have reproduced the issue here: https://colab.research.google.com/drive/1zhe68opt4NlF4BPVc8L1GcdRVdCCbH--
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.