Beispiel #1
0
total_nodes = 10
adjacency_matrix = np.random.rand(total_nodes, total_nodes) < 0.25
weight_matrix = np.random.randn(total_frames, total_nodes, total_nodes)

# Normalise the weights, such that they are on the interval [0, 1].
# They can then be passed directly to matplotlib colormaps (which expect floats on that interval).
vmin, vmax = -2, 2
weight_matrix[weight_matrix < vmin] = vmin
weight_matrix[weight_matrix > vmax] = vmax
weight_matrix -= vmin
weight_matrix /= vmax - vmin

cmap = plt.cm.RdGy

fig, ax = plt.subplots()
g = Graph(adjacency_matrix, edge_cmap=cmap, arrows=True, ax=ax)


def update(ii):
    artists = []
    for jj, kk in zip(*np.where(adjacency_matrix)):
        w = weight_matrix[ii, jj, kk]
        artist = g.edge_artists[(jj, kk)]
        artist.set_facecolor(cmap(w))
        artist.update_width(
            0.03 * np.abs(w - 0.5)
        )  # np.abs(w-0.5) so that large negative edges are also wide
        artists.append(artist)
    return artists

- :code:`edge_color` : edge face colour
- :code:`edge_alpha` : edge transparency
- :code:`edge_zorder` : node zorder; artists with higher z-order occlude artists with lower z-order
- :code:`arrows` : boolean flag that turn the drawing of arrow heads on or off

All node and edge artist properties can be specified in three ways:
"""

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

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:

import numpy as np
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])
#!/usr/bin/env python
"""
Default Design
==============

Default visualisation for an unweighted graph.
"""

import matplotlib.pyplot as plt

from netgraph import Graph

cube = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4),
        (2, 6), (1, 5), (3, 7)]

Graph(cube)
plt.show()
===============

"""


import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph

# create a random geometric graph and plot it
g = nx.random_geometric_graph(100, 0.15, seed=42)
node_positions = nx.get_node_attributes(g, 'pos')
plot_instance = Graph(g,
                      node_layout=node_positions,
                      node_size=1,
                      node_edge_width=0.1,
                      edge_width=0.1)

# select a random path in the network and plot it
path = nx.shortest_path(g, 33, 66)

for node in path:
    plot_instance.node_artists[node].radius = 1.5 * 1e-2
    plot_instance.node_artists[node].set_color('orange')

for ii, node_1 in enumerate(path[:-1]):
    node_2 = path[ii+1]
    if (node_1, node_2) in plot_instance.edges:
        edge = (node_1, node_2)
    else: # the edge is specified in reverse node order
Beispiel #5
0
#!/usr/bin/env python
"""
Curved Edges
============

Curved edges are repelled by nodes and other edges. This reduces node/edge and edge/edge occlusions.
"""

import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph

Graph(nx.wheel_graph(7), edge_layout='curved')
plt.show()
#!/usr/bin/env python
"""
Dot and radial node layouts
===========================

Plot a tree or other directed, acyclic graph with the :code:`'dot'` or :code:`'radial'` node layout.
Netgraph uses an implementation of the Sugiyama algorithm provided by the grandalf_ library
(and thus does not require Graphviz to be installed).

.. _grandalf: https://github.com/bdcht/grandalf
"""

import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph

unbalanced_tree = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (2, 6), (3, 7),
                   (3, 8), (4, 9), (4, 10), (4, 11), (5, 12), (5, 13), (5, 14),
                   (5, 15)]

balanced_tree = nx.balanced_tree(3, 3)

fig, (ax1, ax2) = plt.subplots(1, 2)
Graph(unbalanced_tree, node_layout='dot', ax=ax1)
Graph(balanced_tree, node_layout='radial', ax=ax2)
plt.show()
"""

import numpy as np
import matplotlib.pyplot as plt

from netgraph import Graph

weighted_cube = [
    (0, 1, -0.1),
    (1, 2, -0.2),
    (2, 3, -0.4),
    (3, 2,  0.0),
    (3, 0, -0.2),
    (4, 5,  0.7),
    (5, 6,  0.9),
    (6, 5, -0.2),
    (6, 7,  0.5),
    (7, 4,  0.1),
    (0, 4,  0.5),
    (1, 5, -0.3),
    (5, 1, -0.4),
    (2, 6,  0.8),
    (3, 7,  0.4)
]

edge_width = {(u, v) : 3 * np.abs(w) for (u, v, w) in weighted_cube}
edge_color = {(u, v) : 'blue' if w <=0 else 'red' for (u, v, w) in weighted_cube}
Graph(weighted_cube, edge_width=edge_width, edge_color=edge_color, arrows=True)

plt.show()
def plot_reduced_network_topology(ax, network_type, A_reduced, m, color,
                                  color_bias, node_size_bias, title_letter):
    """TODO: Docstring for plot_network_topology.

    :ax: TODO
    :A_unit: TODO
    :returns: TODO

    """
    ax.annotate(title_letter,
                xy=(-0.2, 1.03),
                xycoords="axes fraction",
                size=labelsize * 0.7)
    cmap = sns.color_palette(color, as_cmap=True)

    G = nx.from_numpy_array(A_reduced)
    k = np.sum(A_reduced, 1)

    node_size = np.log(k + node_size_bias)
    node_size_dict = {u: v for u, v in zip(np.arange(len(k)), node_size)}
    node_color_dict = {
        u: cmap(k_i / k.max() + color_bias)
        for u, k_i in zip(np.arange(len(k)), k)
    }
    edgelists = [(ni, nj) for ni in range(m) for nj in range(m)
                 if A_reduced[ni, nj]]
    if m == 1:
        node_layout = {0: (0.7, 0.5)}
        node_size_dict = {0: 15}
        radius = 0.2
        edge_width = 5
        node_edge_width = 3
        ax.set_xlim(0, 1)
        ax.set_ylim(0, 1)
    else:
        node_layout = 'spring'
        node_sizes = np.log(k + 1) / m**0.3 * 2.5
        node_size_dict = {u: node_sizes[u] for u in np.arange(len(k))}
        radius = 0.07 / m**0.25
        widths = np.log(A_reduced / A_reduced.max() + 1.3) * 2
        widths = np.log(A_reduced / A_reduced.max() + 1) * 80 / m**1.5
        edge_width = {(u, v): widths[v, u] * 1 if u == v else widths[v, u]
                      for (u, v) in edgelists}
        node_edge_width = 1

    if m == 3:
        node_layout = {0: (0.3, 0.2), 1: (0.7, 0.2), 2: (0.5, 0.6)}
        node_layout = {
            key: (x * (np.random.random() * 0.1 + 1),
                  y * (np.random.random() * 0.1 + 1))
            for key, (x, y) in node_layout.items()
        }
        node_sizes = np.log(k + 1) * 2
        node_size_dict = {u: node_sizes[u] for u in np.arange(len(k))}
        radius = 0.08
        widths = np.log(A_reduced / A_reduced.max() + 1.5) * 10
        edge_width = {(u, v): widths[v, u] * 0.5 if u == v else widths[v, u]
                      for (u, v) in edgelists}

    elif m == 5:
        if network_type == 'SF':
            node_layout = {
                0: (0.5, 0.45),
                1: (0.2, 0.25),
                2: (0.6, 0.2),
                3: (0.6, 0.75),
                4: (0.3, 0.55)
            }
        else:
            node_layout = {
                0: (0.3, 0.4),
                1: (0.7, 0.4),
                2: (0.5, 0.6),
                3: (0.4, 0.2),
                4: (0.6, 0.2)
            }
        node_layout = {
            key: (x * (np.random.random() * 0.1 + 1),
                  y * (np.random.random() * 0.1 + 1))
            for key, (x, y) in node_layout.items()
        }
        #node_layout=nx.spring_layout(G)
        node_sizes = np.log(k + 3) * 1.8
        node_size_dict = {u: node_sizes[u] for u in np.arange(len(k))}
        radius = 0.06
        widths = np.log(A_reduced / A_reduced.max() + 1.3) * 5
        edge_width = {(u, v): widths[v, u] * 0.5 if u == v else widths[v, u]
                      for (u, v) in edgelists}

    g = Graph(edgelists,
              edge_width=edge_width,
              arrows=True,
              node_layout=node_layout,
              node_size=node_size_dict,
              edge_layout='straight',
              node_color=node_color_dict,
              node_alpha=0.8,
              edge_color='tab:grey',
              edge_alp=0.5,
              ax=ax,
              edge_layout_kwargs={'selfloop_radius': radius})
    xy_position = np.vstack((g.node_positions.values()))
    x_max, x_min = xy_position[:, 0].max() + radius * 2, xy_position[:, 0].min(
    ) - radius * 2.0
    y_max, y_min = xy_position[:, 1].max() + radius * 2, xy_position[:, 1].min(
    ) - radius * 2.0
from matplotlib.animation import FuncAnimation
from netgraph import Graph

# Simulate a dynamic network with
# - 5 frames / different node states,
# - with 10 nodes at each time point, and
# - an expected edge density of 25%.
total_frames = 5
total_nodes = 10
adjacency_matrix = np.random.rand(total_nodes, total_nodes) < 0.25
node_values = np.random.rand(total_frames, total_nodes)

cmap = plt.cm.viridis

fig, ax = plt.subplots()
g = Graph(adjacency_matrix, edge_width=1.5, arrows=True, ax=ax)
ax.axis([0, 1, 0, 1])


def update(ii):
    for node, artist in g.node_artists.items():
        value = node_values[ii, node]
        artist.set_facecolor(cmap(value))
        artist.set_edgecolor(cmap(value))
        # The default node size is 3., which is rescaled internally
        # to 0.03 to yield layouts comparable to networkx and igraph.
        # As the expectation of `value` is 0.5, we multiply `value` by 6 * 0.01,
        # and thus match the default node size on average.
        artist.radius = 6 * 0.01 * value
    return g.node_artists.values()
Beispiel #10
0
from matplotlib.animation import FuncAnimation
from netgraph import Graph

# Simulate a dynamic network with
# - 5 frames / network states,
# - with 10 nodes at each time point,
# - an expected edge density of 25% at each time point
total_frames = 5
total_nodes = 10
adjacency_matrix = np.random.rand(total_frames, total_nodes,
                                  total_nodes) < 0.25

fig, ax = plt.subplots()
g = Graph(np.ones((total_nodes, total_nodes)),
          edge_width=1.5,
          arrows=True,
          ax=ax)  # initialise with fully connected graph


def update(ii):
    for (jj, kk), artist in g.edge_artists.items():
        # turn visibility of edge artists on or off, depending on the adjacency
        if adjacency_matrix[ii, jj, kk]:
            artist.set_visible(True)
        else:
            artist.set_visible(False)
    return g.edge_artists.values()


animation = FuncAnimation(fig,
                          update,
def plot_network_topology(ax, network_type, N, A_unit, color, color_bias,
                          node_size_bias, title_letter):
    """TODO: Docstring for plot_network_topology.

    :ax: TODO
    :A_unit: TODO
    :returns: TODO

    """
    simpleaxis(ax)
    ax.annotate(title_letter,
                xy=(-0.2, 1.03),
                xycoords="axes fraction",
                size=labelsize * 0.7)
    cmap = sns.color_palette(color, as_cmap=True)
    N_actual = len(A_unit)
    k = np.sum(A_unit > 0, 0)

    if network_type == 'SF':
        edge_width = 1.0
        node_size = k**0.25 * 2.1
    elif network_type == 'ER':
        edge_width = 0.2
        node_size = k**0.2 * 2
    else:
        node_size = k**0.2 * 2
        edge_width = 2.5
    node_size_dict = {u: v for u, v in zip(np.arange(len(k)), node_size)}
    node_color_dict = {
        u: cmap(k_i / k.max() + color_bias)
        for u, k_i in zip(np.arange(len(k)), k)
    }
    G = nx.from_numpy_array(A_unit)
    if network_type == 'SBM_ER':
        space = 'linear'
        feature = feature_from_network_topology(A_unit,
                                                G,
                                                space,
                                                tradeoff_para=0.5,
                                                method='degree')
        group_index = group_index_from_feature_Kmeans(feature, len(N))
        groups_dict = {
            node_i: group_i
            for group_i, nodes in enumerate(group_index) for node_i in nodes
        }
        g = Graph(A_unit,
                  edge_width=edge_width,
                  arrows=True,
                  node_size=node_size_dict,
                  edge_layout='straight',
                  node_layout='community',
                  node_layout_kwargs={'node_to_community': groups_dict},
                  node_color=node_color_dict,
                  node_alpha=0.8,
                  edge_color='tab:grey',
                  edge_alp=0.8,
                  ax=ax,
                  edge_zorder=1)
    else:
        g = Graph(A_unit,
                  edge_width=edge_width,
                  arrows=True,
                  node_size=node_size_dict,
                  edge_layout='straight',
                  node_layout=nx.spring_layout(G),
                  node_color=node_color_dict,
                  node_alpha=0.8,
                  edge_color='tab:grey',
                  edge_alp=0.8,
                  ax=ax,
                  edge_zorder=1)
Beispiel #12
0
import matplotlib.pyplot as plt

from netgraph import Graph

partitions = [
    list(range(3)),
    list(range(3, 9)),
    list(range(9, 21))
]

edges = list(zip(np.repeat(partitions[0], 2), partitions[1])) \
      + list(zip(np.repeat(partitions[0], 2), partitions[1][1:])) \
      + list(zip(np.repeat(partitions[1], 2), partitions[2])) \
      + list(zip(np.repeat(partitions[1], 2), partitions[2][1:]))

Graph(edges, node_layout='multipartite', node_layout_kwargs=dict(layers=partitions, reduce_edge_crossings=True), node_labels=True)

plt.show()

################################################################################
# To change the layout from the left-right orientation to a bottom-up orientation,
# call the layout function directly and swap x and y coordinates of the node positions.

import numpy as np
import matplotlib.pyplot as plt

from netgraph import Graph, get_multipartite_layout

partitions = [
    list(range(3)),
    list(range(3, 9)),
Beispiel #13
0
===================

Default visualisation for a weighted graph.
"""

import matplotlib.pyplot as plt

from netgraph import Graph

weighted_cube = [(0, 1, -0.1), (1, 2, -0.2), (2, 3, -0.4), (3, 2, 0.0),
                 (3, 0, -0.2), (4, 5, 0.7), (5, 6, 0.9), (6, 5, -0.2),
                 (6, 7, 0.5), (7, 4, 0.1), (0, 4, 0.5), (1, 5, -0.3),
                 (5, 1, -0.4), (2, 6, 0.8), (3, 7, 0.4)]

cmap = 'RdGy'
Graph(weighted_cube, edge_cmap=cmap, edge_width=2., arrows=True)
plt.show()

################################################################################
# By default, different edge weights are represented by different colors.
# The default colormap is :code:`'RdGy'` but any diverging matplotlib colormap can be used:
#
# - :code:`'PiYG'`
# - :code:`'PRGn'`
# - :code:`'BrBG'`
# - :code:`'PuOr'`
# - :code:`'RdGy'` (default)
# - :code:`'RdBu'`
# - :code:`'RdYlBu'`
# - :code:`'RdYlGn'`
# - :code:`'Spectral'`
Beispiel #14
0
#!/usr/bin/env python
"""
Custom Node Positions and Edge Paths
====================================

Node positions can be set explicitly by using a dictionary that maps
node IDs to (x, y) coordinates as the :code:`node_layout` keyword argument.

Analogously, edge paths can be set explicitly by using a dictionary that maps
edge IDs to ndarray of (x, y) coordinates as the :code:`edge_layout` keyword argument.
"""

import numpy as np
import matplotlib.pyplot as plt

from netgraph import Graph

edge_list = [(0, 1)]
node_positions = {0: (0.2, 0.4), 1: (0.8, 0.6)}
edge_paths = {
    (0, 1):
    np.array([(0.2, 0.4), (0.2, 0.8), (0.5, 0.8), (0.5, 0.2), (0.8, 0.2),
              (0.8, 0.6)])
}

Graph(edge_list, node_layout=node_positions, edge_layout=edge_paths)
plt.show()
Directed Graphs
===============

Default visualisation for a directed graph.
"""

import matplotlib.pyplot as plt

from netgraph import Graph

cube = [
    (0, 1),
    (1, 2),
    (2, 3),  # <- bidirectional edges
    (3, 2),  # <-
    (3, 0),
    (4, 5),
    (5, 6),  # <-
    (6, 5),  # <-
    (6, 7),
    (0, 4),
    (7, 4),
    (5, 1),  # <-
    (1, 5),  # <-
    (2, 6),
    (3, 7)
]

Graph(cube, edge_width=2., arrows=True)
plt.show()
Beispiel #16
0
#!/usr/bin/env python
"""
Circular node layout
====================

The circular node layout routine in netgraph uses the Baur-Brandes algorithm to reduce edge crossings.
"""

import matplotlib.pyplot as plt

from netgraph import Graph

unbalanced_tree = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (2, 6), (3, 7),
                   (3, 8), (4, 9), (4, 10), (4, 11), (5, 12), (5, 13), (5, 14),
                   (5, 15)]

Graph(unbalanced_tree, node_layout='circular')

plt.show()
.. __ : https://github.com/Penlect/rectangle-packer
"""

import matplotlib.pyplot as plt

from itertools import combinations
from netgraph import Graph

edge_list = []

# add 15 2-node components
edge_list.extend([(ii, ii + 1) for ii in range(30, 60, 2)])

# add 10 3-node components
for ii in range(60, 90, 3):
    edge_list.extend([(ii, ii + 1), (ii, ii + 2), (ii + 1, ii + 2)])

# add a couple of larger components
n = 90
for ii in [10, 20, 30]:
    edge_list.extend(list(combinations(range(n, n + ii), 2)))
    n += ii

nodes = list(range(n))
Graph(edge_list,
      nodes=nodes,
      node_size=1,
      edge_width=0.3,
      node_layout='circular')
plt.show()
Beispiel #18
0
community_to_color = {
    0: 'tab:blue',
    1: 'tab:orange',
    2: 'tab:green',
    3: 'tab:red',
}
node_color = {
    node: community_to_color[community_id]
    for node, community_id in node_to_community.items()
}

Graph(
    g,
    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()

################################################################################
# Alternatively, the best partition into communities can be inferred, for example
# using the Louvain algorithm (:code:`pip install python-louvain`):

from community import community_louvain
node_to_community = community_louvain.best_partition(g)