Spaces:
Running
Running
File size: 17,950 Bytes
b9a0f21 |
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 30 31 32 33 34 35 36 37 38 39 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
The hvPlot NetworkX plotting API is meant as a drop-in replacement for the ``networkx.draw`` methods. In most cases the existing code will work as is or with minor modifications, returning a HoloViews object rendering an interactive bokeh plot, equivalent to the matplotlib plot the standard API constructs. First let us import the plotting interface and give it the canonical name ``hvnx``:
```python
import hvplot.networkx as hvnx
import networkx as nx
import holoviews as hv
```
In this user guide we will follow along with many of the examples in the [NetworkX tutorial](https://networkx.github.io/documentation/stable/tutorial.html#drawing-graphs) on drawing graphs.
The ``hxnx`` namespace provides all the same plotting functions as ``nx``, this means in most cases one can simply be swapped for the other. This also includes most keywords used to customize the plots. The main difference is in the way multiple plots are composited, like all other hvPlot APIs the networkX functions returns HoloViews objects which can be composited using ``+`` and ``*`` operations:
```python
G = nx.petersen_graph()
spring = hvnx.draw(G, with_labels=True)
shell = hvnx.draw_shell(G, nlist=[range(5, 10), range(5)], with_labels=True, font_weight='bold')
spring + shell
```
```python
H = nx.triangular_lattice_graph(1, 20)
hvnx.draw_planar(H, node_color='green', edge_color='brown')
```
The most common ``layout`` functions have dedicated drawing methods such as the ``draw_shell`` function above, which automatically computes the node positions.
However layout algorithms are not necessarily deterministic, so if we want to plot and overlay subsets of either the nodes or edges using the ``nodelist`` and ``edgelist`` keywords the node positions should be computed ahead of time and passed in explicitly:
```python
pos = nx.layout.spring_layout(G)
hvnx.draw(G, pos, nodelist=[0, 1, 2, 3, 4], node_color='blue') *\
hvnx.draw_networkx_nodes(G, pos, nodelist=[5, 6, 7, 8, 9], node_color='green')
```
The ``hvnx`` namespace also makes ``save`` and ``show utilities available to save the plot to HTML or PNG files or display it in a separate browser window when working in a standard Python interpreter.
```python
G = nx.dodecahedral_graph()
shells = [[2, 3, 4, 5, 6], [8, 1, 0, 19, 18, 17, 16, 15, 14, 7], [9, 10, 11, 12, 13]]
shell = hvnx.draw_shell(G, nlist=shells)
pos = nx.nx_agraph.graphviz_layout(G)
graphviz = hvnx.draw(G, pos=pos)
layout = shell + graphviz
hvnx.save(layout, 'graph_layout.png')
```
#### Styling Graphs
The full set of options which are inherited from networkx's API are listed in the ``hxnx.draw()`` docstring. Using these the more common styling of nodes and edges can easily be altered through the common set of options that are inherited from networkx. In addition common HoloViews options to control the size of the plots, axes and styling are also supported. Finally, some ``layout`` functions also accept special keyword arguments such as the ``nlist`` argument for the shell layout which specifies the shells.
```python
options = {
'node_color': 'black',
'node_size': 100,
'edge_width': 3,
'width': 300,
'height': 300
}
random = hvnx.draw_random(G, **options)
circular = hvnx.draw_circular(G, **options)
spectral = hvnx.draw_spectral(G, **options)
shell = hvnx.draw_shell(G, nlist=[range(5,10), range(5)], **options)
(random + circular + spectral + shell).cols(2)
```
In addition to being able to set scalar style values hvPlot also supports the HoloViews concept of [style mapping](https://holoviews.org/user_guide/Style_Mapping.html#styling-mapping), which uses so called ``dim`` transforms to map attributes of the graph nodes and edges to vary the visual attributes of the plot. For example we might construct a graph with edge weights and node sizes as attributes. The plotting function will extract these attributes which means they can be used to scale visual properties of the plot such as the ``edge_width``, ``edge_color`` or ``node_size``:
```python
G = nx.Graph()
G.add_edge('a', 'b', weight=0.6)
G.add_edge('a', 'c', weight=0.2)
G.add_edge('c', 'd', weight=0.1)
G.add_edge('c', 'e', weight=0.7)
G.add_edge('c', 'f', weight=0.9)
G.add_edge('a', 'd', weight=0.3)
G.add_node('a', size=20)
G.add_node('b', size=10)
G.add_node('c', size=12)
G.add_node('d', size=5)
G.add_node('e', size=8)
G.add_node('f', size=3)
pos = nx.spring_layout(G) # positions for all nodes
hvnx.draw(G, pos, edge_color='weight', edge_cmap='viridis',
edge_width=hv.dim('weight')*10, node_size=hv.dim('size')*20)
```
The full set of options that are supported can be accessed on the ``hvnx.draw`` function (note this does not include some bokeh specific option to control the styling of selection, nonselection and hover nodes and edges which may also be supplied and follow a pattern like ``hover_node_fill_color`` or ``selection_edge_line_alpha``).
For reference here is the docstring listing the main supported option:
```python
print(hvnx.draw.__doc__)
```
The main difference to the networkx.draw API are a few options which are not supported (such as `font_weight` and `arrowsize`) and the renaming of `width` (which controls the edge line width) to ``edge_width`` since `width` and `height` are reserved for defining the screen dimensions of the plot.
## Examples
To demonstrate that the API works almost identically this section reproduces various examples from the NetworkX documentation.
### Plot properties
Compute some network properties for the lollipop graph.
URL: https://networkx.github.io/documentation/stable/auto_examples/basic/plot_properties.html
```python
# Copyright (C) 2004-2018 by
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
# BSD license.
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
G = nx.lollipop_graph(4, 6)
pathlengths = []
print("source vertex {target:length, }")
for v in G.nodes():
spl = dict(nx.single_source_shortest_path_length(G, v))
print('{} {} '.format(v, spl))
for p in spl:
pathlengths.append(spl[p])
print('')
print("average shortest path length %s" % (sum(pathlengths) / len(pathlengths)))
# histogram of path lengths
dist = {}
for p in pathlengths:
if p in dist:
dist[p] += 1
else:
dist[p] = 1
print('')
print("length #paths")
verts = dist.keys()
for d in sorted(verts):
print('%s %d' % (d, dist[d]))
print("radius: %d" % nx.radius(G))
print("diameter: %d" % nx.diameter(G))
print("eccentricity: %s" % nx.eccentricity(G))
print("center: %s" % nx.center(G))
print("periphery: %s" % nx.periphery(G))
print("density: %s" % nx.density(G))
hvnx.draw(G, with_labels=True)
```
### Simple Path
Draw a graph with hvPlot.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_simple_path.html
```python
G = nx.path_graph(8)
hvnx.draw(G)
```
### Node colormap
Draw a graph with hvPlot, color by degree.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_node_colormap.html
```python
# Author: Aric Hagberg (hagberg@lanl.gov)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
G = nx.cycle_graph(24)
pos = nx.spring_layout(G, iterations=200)
# Preferred API
# hvnx.draw(G, pos, node_color='index', node_size=500, cmap='Blues')
# Original code
hvnx.draw(G, pos, node_color=range(24), node_size=500, cmap='Blues')
```
### Edge Colormap
Draw a graph with hvPlot, color edges.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_edge_colormap.html
```python
# Author: Aric Hagberg (hagberg@lanl.gov)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
G = nx.star_graph(20)
pos = nx.spring_layout(G)
colors = range(20)
hvnx.draw(G, pos, node_color='#A0CBE2', edge_color=colors,
edge_width=4, edge_cmap='Blues', with_labels=False)
```
### House With Colors
Draw a graph with hvPlot.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_house_with_colors.html
```python
# Author: Aric Hagberg (hagberg@lanl.gov)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
G = nx.house_graph()
# explicitly set positions
pos = {0: (0, 0),
1: (1, 0),
2: (0, 1),
3: (1, 1),
4: (0.5, 2.0)}
hvnx.draw_networkx_nodes(G, pos, node_size=2000, nodelist=[4], padding=0.2) *\
hvnx.draw_networkx_nodes(G, pos, node_size=3000, nodelist=[0, 1, 2, 3], node_color='black') *\
hvnx.draw_networkx_edges(G, pos, alpha=0.5, width=6, xaxis=None, yaxis=None)
```
### Circular Tree
URL: https://networkx.org/documentation/stable/auto_examples/graphviz_layout/plot_circular_tree.html
```python
try:
import pygraphviz # noqa
from networkx.drawing.nx_agraph import graphviz_layout
except ImportError:
try:
import pydot # noqa
from networkx.drawing.nx_pydot import graphviz_layout
except ImportError:
raise ImportError("This example needs Graphviz and either "
"PyGraphviz or pydot")
G = nx.balanced_tree(3, 5)
pos = graphviz_layout(G, prog='twopi', args='')
hvnx.draw(G, pos, node_size=20, alpha=0.5, node_color="blue", with_labels=False, width=600, height=600)
```
### Spectral Embedding
The spectral layout positions the nodes of the graph based on the eigenvectors of the graph Laplacian L=D−A, where A is the adjacency matrix and D is the degree matrix of the graph. By default, the spectral layout will embed the graph in two dimensions (you can embed your graph in other dimensions using the dim argument to either draw_spectral() or spectral_layout()).
When the edges of the graph represent similarity between the incident nodes, the spectral embedding will place highly similar nodes closer to one another than nodes which are less similar.
This is particularly striking when you spectrally embed a grid graph. In the full grid graph, the nodes in the center of the graph are pulled apart more than nodes on the periphery. As you remove internal nodes, this effect increases.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_spectral_grid.html
```python
options = {
'node_size': 100,
'width': 250, 'height': 250
}
G = nx.grid_2d_graph(6, 6)
spectral1 = hvnx.draw_spectral(G, **options)
G.remove_edge((2, 2), (2, 3))
spectral2 = hvnx.draw_spectral(G, **options)
G.remove_edge((3, 2), (3, 3))
spectral3 = hvnx.draw_spectral(G, **options)
G.remove_edge((2, 2), (3, 2))
spectral4 = hvnx.draw_spectral(G, **options)
G.remove_edge((2, 3), (3, 3))
spectral5 = hvnx.draw_spectral(G, **options)
G.remove_edge((1, 2), (1, 3))
spectral6 = hvnx.draw_spectral(G, **options)
G.remove_edge((4, 2), (4, 3))
spectral7 = hvnx.draw_spectral(G, **options)
(hv.Empty() + spectral1 + hv.Empty() +
spectral2 + spectral3 + spectral4 +
spectral5 + spectral6 + spectral7).cols(3)
```
### Plot four grids
Draw a graph with hvPlot.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_four_grids.html
```python
# Author: Aric Hagberg (hagberg@lanl.gov)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
# Copyright (C) 2004-2018
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
# BSD license.
G = nx.grid_2d_graph(4, 4) # 4x4 grid
pos = nx.spring_layout(G, iterations=100)
g1 = hvnx.draw(G, pos, font_size=8)
g2 = hvnx.draw(G, pos, node_color='black', node_size=0, with_labels=False)
g3 = hvnx.draw(G, pos, node_color='green', node_size=250, with_labels=False, edge_width=6)
H = G.to_directed()
g4 = hvnx.draw(H, pos, node_color='blue', node_size=20, with_labels=False)
(g1 + g2 + g3 + g4).cols(2)
```
### Ego Graph
Example using the NetworkX ego_graph() function to return the main egonet of the largest hub in a Barabási-Albert network.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_ego_graph.html
```python
# Author: Drew Conway (drew.conway@nyu.edu)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
from operator import itemgetter
# Create a BA model graph
n = 1000
m = 2
G = nx.generators.barabasi_albert_graph(n, m)
# find node with largest degree
node_and_degree = G.degree()
(largest_hub, degree) = sorted(node_and_degree, key=itemgetter(1))[-1]
# Create ego graph of main hub
hub_ego = nx.ego_graph(G, largest_hub)
# Draw graph
pos = nx.spring_layout(hub_ego)
g = hvnx.draw(hub_ego, pos, node_color='blue', node_size=50, with_labels=False)
# Draw ego as large and red
gnodes = hvnx.draw_networkx_nodes(hub_ego, pos, nodelist=[largest_hub], node_size=300, node_color='red')
g * gnodes
```
### Random Geometric Graph
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_random_geometric_graph.html
```python
G = nx.random_geometric_graph(200, 0.125)
# position is stored as node attribute data for random_geometric_graph
pos = nx.get_node_attributes(G, 'pos')
# find node near center (0.5,0.5)
dmin = 1
ncenter = 0
for n in pos:
x, y = pos[n]
d = (x - 0.5)**2 + (y - 0.5)**2
if d < dmin:
ncenter = n
dmin = d
# color by path length from node near center
p = nx.single_source_shortest_path_length(G, ncenter)
hvnx.draw_networkx_edges(G, pos, nodelist=[ncenter], alpha=0.4, width=600, height=600) *\
hvnx.draw_networkx_nodes(G, pos, nodelist=list(p.keys()),
node_size=80,
node_color=list(p.values()),
cmap='Reds_r')
```
### Weighted Graph
An example using Graph as a weighted network.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_weighted_graph.html
```python
# Author: Aric Hagberg (hagberg@lanl.gov)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
import networkx as nx
G = nx.Graph()
G.add_edge('a', 'b', weight=0.6)
G.add_edge('a', 'c', weight=0.2)
G.add_edge('c', 'd', weight=0.1)
G.add_edge('c', 'e', weight=0.7)
G.add_edge('c', 'f', weight=0.9)
G.add_edge('a', 'd', weight=0.3)
elarge = [(u, v) for (u, v, attr) in G.edges(data=True) if attr['weight'] > 0.5]
esmall = [(u, v) for (u, v, attr) in G.edges(data=True) if attr['weight'] <= 0.5]
pos = nx.spring_layout(G) # positions for all nodes
# nodes
nodes = hvnx.draw_networkx_nodes(G, pos, node_size=700)
# edges
edges1 = hvnx.draw_networkx_edges(
G, pos, edgelist=elarge, edge_width=6)
edges2 = hvnx.draw_networkx_edges(
G, pos, edgelist=esmall, edge_width=6, alpha=0.5, edge_color='blue', style='dashed')
labels = hvnx.draw_networkx_labels(G, pos, font_size=20, font_family='sans-serif')
edges1 * edges2 * nodes * labels
```
### Directed Graph
Draw a graph with directed edges using a colormap and different node sizes.
Edges have different colors and alphas (opacity). Drawn using matplotlib.
URL: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_directed.html
```python
# Author: Rodrigo Dorantes-Gilardi (rodgdor@gmail.com)
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
G = nx.generators.directed.random_k_out_graph(10, 3, 0.5)
pos = nx.layout.spring_layout(G)
node_sizes = [3 + 10 * i for i in range(len(G))]
M = G.number_of_edges()
edge_colors = range(2, M + 2)
edge_alphas = [(5 + i) / (M + 4) for i in range(M)]
nodes = hvnx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color='blue')
edges = hvnx.draw_networkx_edges(G, pos, node_size=node_sizes, arrowstyle='->',
arrowsize=10, edge_color=edge_colors,
edge_cmap='Blues', edge_width=2, colorbar=True)
nodes * edges
```
### Giant Component
This example illustrates the sudden appearance of a giant connected component in a binomial random graph.
https://networkx.org/documentation/stable/auto_examples/graphviz_layout/plot_giant_component.html
```python
# Copyright (C) 2006-2018
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
# BSD license.
# Adapted by Philipp Rudiger <prudiger@anaconda.com>
import math
try:
import pygraphviz # noqa
from networkx.drawing.nx_agraph import graphviz_layout
layout = graphviz_layout
except ImportError:
try:
import pydot # noqa
from networkx.drawing.nx_pydot import graphviz_layout
layout = graphviz_layout
except ImportError:
print("PyGraphviz and pydot not found;\n"
"drawing with spring layout;\n"
"will be slow.")
layout = nx.spring_layout
n = 150 # 150 nodes
# p value at which giant component (of size log(n) nodes) is expected
p_giant = 1.0 / (n - 1)
# p value at which graph is expected to become completely connected
p_conn = math.log(n) / float(n)
# the following range of p values should be close to the threshold
pvals = [0.003, 0.006, 0.008, 0.015]
region = 220 # for pylab 2x2 subplot layout
plots = []
for p in pvals:
G = nx.binomial_graph(n, p)
pos = layout(G)
region += 1
g = hvnx.draw(G, pos, with_labels=False, node_size=15)
# identify largest connected component
Gcc = sorted([G.subgraph(c) for c in nx.connected_components(G)], key=len, reverse=True)
G0 = Gcc[0]
edges = hvnx.draw_networkx_edges(
G0, pos, with_labels=False, edge_color='red', edge_width=6.0)
# show other connected components
other_edges = []
for Gi in Gcc[1:]:
if len(Gi) > 1:
edge = hvnx.draw_networkx_edges(Gi, pos,
with_labels=False,
edge_color='red',
alpha=0.3,
edge_width=5.0
)
other_edges.append(edge)
plots.append((g*edges*hv.Overlay(other_edges)).relabel("p = %6.3f" % (p)))
hv.Layout(plots).cols(2)
```
|