Skip to content

Commit

Permalink
Merge branch 'master' into joss
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbrodersen committed Jul 12, 2023
2 parents bc6ed3a + e8f2cd6 commit 2975e76
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 272 deletions.
228 changes: 20 additions & 208 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
# netgraph
# Netgraph

[![Downloads](https://pepy.tech/badge/netgraph)](https://pepy.tech/project/netgraph)
*Publication-quality network visualisations in python*

Netgraph is a python library for creating publication quality plots of networks.
Netgraph is compatible with a variety of network data formats, including `networkx` and `igraph` `Graph` objects.
[![Downloads](https://pepy.tech/badge/netgraph)](https://pepy.tech/project/netgraph)

Netgraph is a python library that aims to complement existing network analysis libraries such as such as [networkx](https://networkx.org/), [igraph](https://igraph.org/), and [graph-tool](https://graph-tool.skewed.de/) with publication-quality visualisations within the python ecosystem. To facilitate a seamless integration, netgraph supports a variety of input formats, including networkx, igraph, and graph-tool `Graph` objects. Netgraph implements numerous node layout algorithms and several edge routing routines. Uniquely among python alternatives, it handles networks with multiple components gracefully (which otherwise break most node layout routines), and it post-processes the output of the node layout and edge routing algorithms with several heuristics to increase the interpretability of the visualisation (reduction of overlaps between nodes, edges, and labels; edge crossing minimisation and edge unbundling where applicable). The highly customisable plots are created using [matplotlib](https://matplotlib.org/), and the resulting matplotlib objects are exposed in an easily queryable format such that they can be further manipulated and/or animated using standard matplotlib syntax. Finally, netgraph also supports interactive changes: with the `InteractiveGraph` class, nodes and edges can be positioned using the mouse, and the `EditableGraph` class additionally supports insertion and deletion of nodes and edges as well as their (re-)labelling through standard text-entry.

## Installation

Install the current release of `netgraph` with:
Install the current release of `netgraph` from PyPI:

``` shell
pip install netgraph
```

If you are using (Ana-)conda (or mamba), you can also obtain netgraph from conda-forge:

``` shell
conda install -c conda-forge netgraph
```

## Documentation

The documentation of the full API, as well as numerous code examples can be found on [ReadTheDocs](https://netgraph.readthedocs.io/en/latest/index.html).
Numerous tutorials, code examples, and a complete documentation of the API can be found on [ReadTheDocs](https://netgraph.readthedocs.io/en/latest/index.html).


## Quickstart
Expand Down Expand Up @@ -92,215 +97,22 @@ help(EditableGraph)
```


## Reasons why you might want to use netgraph
## Examples


### Better layouts

![Example visualisations](./figures/gallery_portrait.png)


### Interactivity

Algorithmically finding a visually pleasing graph layout is hard.
This is demonstrated by the plethora of different algorithms in use
(if graph layout was a solved problem, there would only be one
algorithm). To ameliorate this problem, this module contains an
`InteractiveGraph` class, which allows node positions to be tweaked
with the mouse after an initial draw.

- Individual nodes and edges can be selected using the left-click.
- Multiple nodes and or edges can be selected by holding `control`
while clicking, or by using the rectangle/window selector.
- Selected plot elements can be dragged around by holding left-click
on a selected artist.

![Demo of selecting, dragging, and hovering](https://media.giphy.com/media/yEysQUUTndLT6mI9cN/giphy.gif)


``` python
import matplotlib.pyplot as plt
import networkx as nx
from netgraph import InteractiveGraph

g = nx.house_x_graph()

edge_color = dict()
for ii, edge in enumerate(g.edges):
edge_color[edge] = 'tab:gray' if ii%2 else 'tab:orange'

node_color = dict()
for node in g.nodes:
node_color[node] = 'tab:red' if node%2 else 'tab:blue'

plot_instance = InteractiveGraph(
g, node_size=5, node_color=node_color,
node_labels=True, node_label_offset=0.1, node_label_fontdict=dict(size=20),
edge_color=edge_color, edge_width=2,
arrows=True, ax=ax)

plt.show()
```

There is also some experimental support for editing the graph
elements interactively using the `EditableGraph` class.

- Pressing `insert` or `+` will add a new node to the graph.
- Double clicking on two nodes successively will create an edge between them.
- Pressing `delete` or `-` will remove selected nodes and edges.
- Pressing `@` will reverse the direction of selected edges.

When adding a new node, the properties of the last selected node will
be used to style the node artist. Ditto for edges. If no node or edge
has been previously selected, the first created node or edge artist
will be used.

![Demo of interactive editing](https://media.giphy.com/media/TyiS2Pl1z9CFqYMYe7/giphy.gif)

Finally, elements of the graph can be labeled and annotated. Labels
remain always visible, whereas annotations can be toggled on and off by
clicking on the corresponding node or edge.

- To create or edit a node or edge label, select the node (or edge)
artist, press the `enter` key, and type.
- To create or edit an annotation, select the node (or edge) artist,
press `alt + enter`, and type.
- Terminate either action by pressing `enter` or `alt + enter` a
second time.

![Demo of interactive labeling](https://media.giphy.com/media/OofBM1xtwfSpK7DPSU/giphy.gif)

``` python
import matplotlib.pyplot as plt
import networkx as nx
from netgraph import EditableGraph

g = nx.house_x_graph()

edge_color = dict()
for ii, (source, target) in enumerate(g.edges):
edge_color[(source, target)] = 'tab:gray' if ii%2 else 'tab:orange'

node_color = dict()
for node in g.nodes:
node_color[node] = 'tab:red' if node%2 else 'tab:blue'

annotations = {
4 : 'This is the representation of a node.',
(0, 1) : dict(s='This is not a node.', color='red')
}


fig, ax = plt.subplots(figsize=(10, 10))

plot_instance = EditableGraph(
g, node_color=node_color, node_size=5,
node_labels=True, node_label_offset=0.1, node_label_fontdict=dict(size=20),
edge_color=edge_color, edge_width=2,
annotations=annotations, annotation_fontdict = dict(color='blue', fontsize=15),
arrows=True, ax=ax)

plt.show()
```

### Fine control over plot elements

High quality figures require fine control over plot elements.
To that end, all node artist and edge artist properties can be specified in three ways:

1. Using a single scalar or string that will be applied to all artists.

``` python
import matplotlib.pyplot as plt
from netgraph import Graph

edges = [(0, 1), (1, 1)]
Graph(edges, node_color='red', node_size=4.)
plt.show()
```

2. Using a dictionary mapping individual nodes or individual edges to a property:

``` python
import matplotlib.pyplot as plt
from netgraph import Graph

Graph([(0, 1), (1, 2), (2, 0)],
edge_color={(0, 1) : 'g', (1, 2) : 'lightblue', (2, 0) : np.array([1, 0, 0])},
node_size={0 : 20, 1 : 4.2, 2 : np.pi},
)
plt.show()
```

3. By directly manipulating the node and edge artists (which are derived from matplotlib PathPatch artists):

``` python
import matplotlib.pyplot as plt; plt.ion()
from netgraph import Graph

fig, ax = plt.subplots()
g = Graph([(0, 1), (1, 2), (2, 0)], ax=ax)

# make some changes
g.edge_artists[(0, 1)].set_facecolor('red')
g.edge_artists[(1, 2)].set_facecolor('lightblue')

# force redraw to display changes
fig.canvas.draw()
```

Similarly, node and edge labels are just matplotlib text objects.
Their properties can also be specified using a single value that is applied to all of them:

``` python
import matplotlib.pyplot as plt
from netgraph import Graph

Graph([(0, 1)],
node_size=20,
node_labels={0 : 'Lorem', 1 : 'ipsum'},
node_label_fontdict=dict(size=18, fontfamily='Arial', fontweight='bold'),
edge_labels={(0, 1) : 'dolor sit'},
# blue bounding box with red edge:
edge_label_fontdict=dict(bbox=dict(boxstyle='round',
ec=(1.0, 0.0, 0.0),
fc=(0.5, 0.5, 1.0))),
)
plt.show()
```

Alternatively, their properties can be manipulated individually after an initial draw:

``` python
import matplotlib.pyplot as plt
from netgraph import Graph

fig, ax = plt.subplots()
g = Graph([(0, 1)],
node_size=20,
node_labels={0 : 'Lorem', 1 : 'ipsum'},
edge_labels={(0, 1) : 'dolor sit'},
ax=ax
)

# make some changes
g.node_label_artists[1].set_color('hotpink')
g.edge_label_artists[(0, 1)].set_style('italic')

# force redraw to display changes
fig.canvas.draw()
plt.show()
```

For a full list of available arguments, please consult the docstrings
of the `Graph` or `InteractiveGraph` class:

```python
from netgraph import Graph; help(Graph)
```

## Recent changes

- 4.12.12 Expanded the documentation to cover installation of optional dependencies, automated testing, and troubleshooting issues with matplotlib event handling (issue #69).
- 4.12.11 Mitigated a bug in `EditableGraph` that occurred when deleting a node while hovering over an edge incident to that node (issue #66).
- 4.12.10 Fixed a bug with automatic node label rescaling if the node label fontsize was specified using the `fontsize` keyword argument (instead of just `size`).
- 4.12.9 Fixed a bug that occurred when the distance argument to `_shorten_line_by` was equal or smaller than zero.
- 4.12.8 Fixed a bug that occurred with recent numpy versions when using multi-partite or shell layouts with un-equal numbers of nodes in each layer (issue #65).
- 4.12.7 Fixed a bug that occurred with recent matplotlib versions when using the rectangle selector in `InteractiveGraph`.
- 4.12.6 Added support for graphs with nodes but no edges to `EditableGraph` (issue #62).
- 4.12.5 Added support for empty graphs in `EditableGraph` (issue #62).
- 4.12.4 Turned off clipping of self-loop paths.
- 4.12.3 Bugfix: stopped overwriting `step` parameter in `get_community_layout`.
- 4.12.2 Improved node positions rescaling for some layouts & standardised node position padding across all layouts.
Expand Down
20 changes: 17 additions & 3 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,33 @@
Netgraph
========

*Publication-quality network visualisations in python*

.. image:: https://pepy.tech/badge/netgraph

Netgraph is a python library for creating publication quality plots of networks.
Netgraph is compatible with a variety of network data formats, including :code:`networkx`, :code:`igraph`, and :code:`graph_tool` :code:`Graph` objects.
Netgraph is a python library that aims to complement existing network analysis libraries such as such as networkx_, igraph_, and graph-tool_ with publication-quality visualisations within the python ecosystem. To facilitate a seamless integration, netgraph supports a variety of input formats, including networkx, igraph, and graph-tool :code:`Graph` objects. Netgraph implements numerous node layout algorithms and several edge routing routines. Uniquely among python alternatives, it handles networks with multiple components gracefully (which otherwise break most node layout routines), and it post-processes the output of the node layout and edge routing algorithms with several heuristics to increase the interpretability of the visualisation (reduction of overlaps between nodes, edges, and labels; edge crossing minimisation and edge unbundling where applicable). The highly customisable plots are created using matplotlib_, and the resulting matplotlib objects are exposed in an easily queryable format such that they can be further manipulated and/or animated using standard matplotlib syntax. Finally, netgraph also supports interactive changes: with the :code:`InteractiveGraph` class, nodes and edges can be positioned using the mouse, and the :code:`EditableGraph` class additionally supports insertion and deletion of nodes and edges as well as their (re-)labelling through standard text-entry.

.. _networkx: https://networkx.org/
.. _igraph: https://igraph.org/
.. _graph-tool: https://graph-tool.skewed.de/
.. _matplotlib: https://matplotlib.org/


Installation
------------

From PyPI:

.. code-block:: shell
pip install netgraph
From conda-forge:

.. code-block::
conda install -c conda-forge netgraph
Contributing & Support
----------------------
Expand All @@ -37,7 +51,7 @@ cool feature, I will probably worship the ground you walk on for the
rest of the week. Probably.

.. _GitHub: /~https://github.com/paulbrodersen/netgraph
.. _StackOverflow: https://stackoverflow.com/
.. _StackOverflow: https://stackoverflow.com/questions/tagged/netgraph
__ https://stackoverflow.com/help/minimal-reproducible-example


Expand Down
34 changes: 29 additions & 5 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
.. _installation:

Installation
============
Installation & Testing
======================

Install the current release of `netgraph` with:
Install the current release of Netgraph with:

.. code-block:: shell
pip install netgraph
To upgrade to a newer version, use the `--upgrade` flag:
To upgrade to a newer version, use the :code:`--upgrade` flag:

.. code-block::
pip install --upgrade netgraph
If you do not have permission to install software systemwide, you can install into your user directory using the --user flag:
If you do not have permission to install software systemwide, you can install into your user directory using the :code:`--user` flag:

.. code-block::
pip install --user netgraph
If you are using (Ana-)conda (or mamba), you can also obtain netgraph from conda-forge:

.. code-block::
conda install -c conda-forge netgraph
Alternatively, you can manually download netgraph from GitHub_ or PyPI_.
To install one of these versions, unpack it and run the following from the top-level source directory using the terminal:

Expand All @@ -36,3 +42,21 @@ Or without pip:
.. code-block::
python setup.py install
Some of the examples in the documentation use additional libraries. These can be installed with:

.. code-block::
pip install netgraph[docs]
For automated testing, install the additional dependencies required for testing using:

.. code-block::
pip install netgraph[tests]
The full test suite can then be executed by running the following from the top-level source directory using the terminal:

.. code-block::
pytest
Loading

0 comments on commit 2975e76

Please sign in to comment.