netgraph: publication quality network drawings on top of Matplotlib
Publication-quality network visualisations in python
At a glance
- What is it?
- netgraph is a Python drawing library that takes graphs from networkx, igraph or graph-tool and turns them into Matplotlib based, publication ready figures, with layout heuristics that keep disconnected graphs readable. Its newest tagged release is from July 2023, while the repository itself keeps receiving commits.
- Who is it for?
- netgraph is worth adopting for a paper figure or a report graphic when the analysis is already done in networkx, igraph or graph-tool and the drawing is the part that needs work, because it keeps the graph object you have and returns Matplotlib objects you can restyle. It is the wrong tool when you need a new layout algorithm or a feature the library does not implement, since the release line stopped at 4.13.1 in 2023 even though commits continue.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 45 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A drawing layer, not another analysis library
netgraph is a Python library for publication quality network visualisations, and its position in the ecosystem is deliberate. It complements the existing analysis libraries, networkx, igraph and graph-tool, rather than replacing any of them. You keep the library that computed your communities or your centrality, and netgraph takes the resulting graph and draws it.
The input formats make that boundary concrete. A graph can be given as an edge list, as an edge list with weights, as a full rank matrix, as a networkx `Graph` or `DiGraph`, as an `igraph.Graph`, or as a `graph_tool.Graph`. MultiGraph objects from networkx are explicitly not supported yet, which is the kind of small gap that only shows up after you have already committed to the library.
The output is a Matplotlib figure. Node and edge artists are derived from `matplotlib.patches.PathPatch` and labels are `matplotlib.text.Text` instances, so once the plot exists it is a Matplotlib object and standard Matplotlib syntax applies to it. That is the design decision that makes the library usable in a scientific workflow: the figure can be saved at print resolution, animated, or restyled without leaving the ecosystem the reader of the paper already uses.
The package is licensed under GPLv3, it is published on PyPI as `netgraph` and on conda-forge, and the full API documentation lives on Read the Docs.
Disconnected graphs, the case other layout routines break on
The capability the project singles out as its distinguishing one is handling networks with multiple components. The claim is that other Python alternatives break on such networks, and that netgraph handles them gracefully. A disconnected network is not an edge case in practice: a co-authorship graph usually has one large component and a long tail of single papers, a citation graph is full of small components, and a microbiome or a transport network can be entirely fragmented.
When a layout algorithm assumes connectivity, that assumption shows up as a picture that looks wrong rather than as an error. Nodes pile up in a corner, a component collapses to a point, or the whole drawing is scaled to a bounding box that one huge component dominates. The result is a figure that survives review badly, because the reader cannot tell whether the structure is missing or merely misplaced.
The repository's example set includes a file named `plot_12_multicomponent_graphs.py` alongside the single component examples, and the change log shows work in this area, with a fix for multi-partite and shell layouts with un-equal numbers of nodes in each layer, and a later standardisation of node position padding across all layouts. Padding is the unglamorous part of layout work and it is where inconsistency usually shows.
The layout roster itself is broad. The examples cover a default layout, a directed network, weighted graphs, a dot layout, a circular layout, a community layout, a curved edge layout, an arcdiagram, bipartite and multipartite layouts, a geometric layout and a custom layout, so the algorithm choice is a parameter rather than a fork.
Heuristics that run after the layout algorithm
Netgraph does not stop when the layout algorithm returns node positions. It post-processes that output with several heuristics to increase the interpretability of the visualisation, and the three named in the description are the ones that matter in practice.
The first is the reduction of overlaps between nodes, edges and labels. Layout algorithms optimise a force or a packing objective, and they routinely place a label on top of a node or run an edge straight through one. The second is edge crossing minimisation, which matters because the number of crossings is what a reader perceives as complexity in a dense graph. The third is edge unbundling where applicable, which separates edges that share a route so that a bundle of parallel links can be read as several links rather than one thick band.
This stage is where the visual quality of a publication figure is won, and it is also where the cost sits. Each heuristic is extra computation on a graph that may already be large, and the result is layout that no longer strictly satisfies the objective the algorithm optimised. That is an acceptable trade for a static figure and a bad one if you plan to animate the layout, where stability across frames matters as much as the final picture.
The change log shows this area getting attention for small correctness issues rather than new features, including a fix for a bug that occurred when the distance argument to `_shorten_line_by` was equal or smaller than zero, and a fix for automatic node label rescaling when the label font size was given with the `fontsize` keyword instead of `size`.
InteractiveGraph and EditableGraph for layouts a human has to fix
Some figures cannot be fixed by an algorithm, and netgraph ships two classes for that case. `InteractiveGraph` lets you position nodes and edges with the mouse. `EditableGraph` goes further and supports insertion and deletion of nodes and edges, and the creation, editing and deletion of labels and annotations through standard text entry.
Both build on the same graph data, so the workflow is to let the algorithm produce a first pass and then correct it by hand. For a paper with a handful of labels that keep colliding, that is faster and better than any heuristic.
There is a trap in the quickstart worth repeating, because it costs an afternoon. The plot instance must be retained, otherwise it is garbage collected after the initial draw and the elements can no longer be moved. The documentation also notes that under PyCharm the code has to be executed in a console rather than in the editor, for related reasons.
import matplotlib.pyplot as plt
from netgraph import Graph, InteractiveGraph, EditableGraph
plot_instance = InteractiveGraph(graph_data)
plt.show()plot_instance = EditableGraph(graph_data)
plt.show()The editable class has also picked up several fixes for empty and edge-free graphs in recent versions, including support for graphs with nodes but no edges and support for empty graphs, plus a fix for a bug that occurred when deleting a node while hovering over an edge incident to that node.
The plot is a queryable Matplotlib object
Because the drawing is built from Matplotlib artists, the result can be inspected and modified after the fact rather than only through constructor arguments. The quickstart shows a plot created directly on an existing axis, then individual artists addressed by index and by edge tuple.
plot_instance = Graph([(0, 1)], node_labels=True, edge_labels=True, ax=ax)
plot_instance.node_artists[0].set_alpha(0.2)
plot_instance.edge_artists[(0, 1)].set_facecolor('red')
plot_instance.edge_label_artists[(0, 1)].set_style('italic')
plot_instance.node_label_artists[1].set_size(10)So a node can be made transparent, an edge recoloured, a label italicised and a label resized, each addressed precisely. That is a real advantage for a figure that has to match a house style or a journal template, because it means the styling loop is a normal Python editing loop rather than a search through keyword arguments.
Saving follows the same path, since the figure is a Matplotlib figure, and the example writes a PDF at 300 dpi.
fig.savefig('test.pdf', dpi=300)The example set in the repository follows that structure too, with separate files for node and edge artist customisation, labels, legends, highlighting paths, hyperlinks and a PyQt example, which tells you which use cases the author expected.
Install from PyPI or conda-forge, read the docs on Read the Docs
Installation is a one line operation from either of the two usual sources, PyPI and conda-forge.
pip install netgraphconda install -c conda-forge netgraphThe runtime dependencies are small and well known: numpy, scipy, matplotlib, rectangle-packer and grandalf. The last two are the ones a reader might not recognise. rectangle-packer handles the node packing and overlap reduction, and grandalf is the graph layout library that does the actual algorithm work. Python 3.6 or newer is required, and the package declares itself operating system independent.
There are two optional dependency groups. The tests group pulls in pytest and pytest-mpl, the latter for image comparison testing of rendered figures, which is a good sign about how the project treats visual regressions. The docs group pulls in sphinx with the read the docs theme, numpydoc, sphinx-gallery, Pillow and networkx, so the documentation build, including the gallery of rendered examples, is reproducible.
The tutorials, code examples and the complete API reference are on Read the Docs, and the project publishes a figure gallery in the repository under `figures/`.
A release line that stopped in 2023 while commits continue
The maintenance picture here needs two dates, not one. The most recent tagged releases are 4.13.1 and 4.13.0, both published on 2023-07-12, and the version in the setup script is 4.13.2, which is one patch ahead of the newest tag. The last push to the repository was on 2026-09-08.
So the code keeps moving while the released version does not, and the gap is more than three years wide. For a library whose main risk is breakage from new Matplotlib or numpy releases, that gap is the thing to test, and the change log shows exactly that kind of churn: a fix for multi-partite and shell layouts with recent numpy versions, a fix for the rectangle selector in `InteractiveGraph` with recent Matplotlib versions, and a further fix in the same series.
The project is not closed, though. It was published in the Journal of Open Source Software, with the paper describing it as Netgraph, Publication-quality Network Visualisations in Python, and the README asks that citations point to that paper if the library is used in a scientific publication. The repository also carries a `publication/` directory with the draft.
The licence deserves attention in a commercial context. The library is GPLv3, which is copyleft, and that is a different choice from the permissive licences most of the Python plotting stack uses. It governs the library, not the data you draw with it, but for a company embedding netgraph inside a proprietary tool the distinction is the whole question.
Where drawing by hand in Matplotlib differs
The alternative is to skip the network specific layer and draw the figure directly with Matplotlib, which is what netgraph itself produces. Scatter plots for nodes, line collections or patches for edges, text calls for labels and a layout computed with scipy or with a force directed routine of your own. It is entirely feasible, it gives you complete control, and for a small graph with ten nodes it is often faster than learning a new library.
The difference shows up at two points. The first is the layout step, where a general purpose library gives you a set of algorithms and a set of post-processing heuristics that exist because the naive output is not publishable. Rolling your own means reproducing that work, and the component of it that is genuinely hard is the part that keeps a disconnected graph from collapsing. The second is the graph specific plumbing, where a network library knows that an edge is a pair of nodes, that a label belongs to an artist, and that deleting a node means updating every incident edge, something that `EditableGraph` had to have fixed for a specific hovering bug.
There is a middle path worth considering, which the project supports directly. Because the output is a Matplotlib object, you can let netgraph do the layout and the readability heuristics and then restyle the result in plain Matplotlib, which keeps the difficult part and drops the library specific styling.
The practical decision comes down to how much of your figure pipeline is about the graph. If the graph is the subject, the layout library earns its place. If the graph is a small inset in a larger chart, going straight to Matplotlib is usually the shorter path.
Editorial conclusion
netgraph is worth adopting for a paper figure or a report graphic when the analysis is already done in networkx, igraph or graph-tool and the drawing is the part that needs work, because it keeps the graph object you have and returns Matplotlib objects you can restyle. It is the wrong tool when you need a new layout algorithm or a feature the library does not implement, since the release line stopped at 4.13.1 in 2023 even though commits continue. Before adopting it, check that the layout you want is among the ones it implements, read the changelog entries for the fixes on your Matplotlib and numpy versions, and plan for the GPLv3 licence, which is copyleft and not the default choice inside a proprietary codebase.
Frequently asked questions
How do I install netgraph?
Install the current release from PyPI with `pip install netgraph`, or take it from conda-forge with `conda install -c conda-forge netgraph`. The runtime dependencies are numpy, scipy, matplotlib, rectangle-packer and grandalf, and Python 3.6 or newer is required.
Which graph libraries can netgraph draw?
Netgraph accepts edge lists, edge lists with weights, full rank matrices, networkx Graph and DiGraph objects, igraph.Graph objects and graph_tool.Graph objects. networkx MultiGraph objects are not supported yet.
What is the difference between InteractiveGraph and EditableGraph?
With InteractiveGraph, nodes and edges can be positioned using the mouse. The EditableGraph class additionally supports insertion and deletion of nodes and edges, and labels and annotations can be created, edited or deleted through standard text entry.
Can I style a netgraph figure after it is created?
Yes. Node and edge artists are derived from matplotlib.patches.PathPatch and labels are matplotlib.text.Text instances, and the resulting objects are exposed in a queryable format. The quickstart shows addressing node_artists by index and edge_artists by edge tuple and then calling Matplotlib setters on them.
What is the latest released version of netgraph?
The newest GitHub tags are 4.13.1 and 4.13.0, both published on 2023-07-12, while the version in the setup script is 4.13.2. The last push to the repository was on 2026-09-08, so commits continue after the newest tag.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/paulbrodersen-netgraph)Was this useful?