File: pattern-graph.html

package info (click to toggle)
python-pattern 2.6%2Bgit20150109-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 78,672 kB
  • sloc: python: 53,865; xml: 11,965; ansic: 2,318; makefile: 94
file content (431 lines) | stat: -rw-r--r-- 33,013 bytes parent folder | download | duplicates (5)
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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <title>pattern-graph</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link type="text/css" rel="stylesheet" href="../clips.css" />
    <style>
        /* Small fixes because we omit the online layout.css. */
        h3 { line-height: 1.3em; }
        #page { margin-left: auto; margin-right: auto; }
        #header, #header-inner { height: 175px; }
        #header { border-bottom: 1px solid #C6D4DD;  }
        table { border-collapse: collapse; }
        #checksum { display: none; }
    </style>
    <link href="../js/shCore.css" rel="stylesheet" type="text/css" />
    <link href="../js/shThemeDefault.css" rel="stylesheet" type="text/css" />
    <script language="javascript" src="../js/shCore.js"></script>
    <script language="javascript" src="../js/shBrushXml.js"></script>
    <script language="javascript" src="../js/shBrushJScript.js"></script>
    <script language="javascript" src="../js/shBrushPython.js"></script>
</head>
<body class="node-type-page one-sidebar sidebar-right section-pages">
    <div id="page">
    <div id="page-inner">
    <div id="header"><div id="header-inner"></div></div>
    <div id="content">
    <div id="content-inner">
    <div class="node node-type-page"
        <div class="node-inner">
        <div class="breadcrumb">View online at: <a href="http://www.clips.ua.ac.be/pages/pattern-graph" class="noexternal" target="_blank">http://www.clips.ua.ac.be/pages/pattern-graph</a></div>
        <h1>pattern.graph</h1>
        <!-- Parsed from the online documentation. -->
        <div id="node-1392" class="node node-type-page"><div class="node-inner">
<div class="content">
<p class="big"><span style="font-size: 16px;">The pattern.graph module has tools for graph analysis (shortest path, centrality) and graph visualization in the browser. A graph is a network of nodes connected by edges. It can be used for example to study social networks or to model semantic relationships between concepts.</span></p>
<p>It can be used by itself or with other <a href="pattern.html">pattern</a> modules: <a href="pattern-web.html">web</a> | <a href="pattern-db.html">db</a> | <a href="pattern-en.html">en</a> | <a href="pattern-search.html">search</a> | <a href="pattern-vector.html">vector</a> | graph.</p>
<p><img style="border: 0px initial initial;" src="../g/pattern_schema.gif" alt="" width="620" height="180" /></p>
<hr />
<h2>Documentation</h2>
<ul>
<li><a href="#node">Node</a></li>
<li><a href="#edge">Edge</a></li>
<li><a href="#graph">Graph</a></li>
<li><a href="#layout">Graph layout</a></li>
<li><a href="#utility">Graph adjacency</a></li>
<li><a href="#canvas">Visualization</a>&nbsp;<span class="link-maintenance">(</span><a class="link-maintenance" href="#canvas"><span class="smallcaps link-maintenance">export</span></a><span class="link-maintenance">)</span></li>
<li><a href="#javascript">graph.js</a></li>
</ul>
<p>&nbsp;</p>
<hr />
<h2><a name="node"></a>Node</h2>
<p>A <span class="inline_code">Node</span> is an element with a unique id (a string or <span class="inline_code">int</span>) in a graph. A graph is a network of nodes and edges (connections between nodes). For example, the World Wide Web (WWW) can be represented as a vast graph with websites as nodes, website URLs as node id's, and hyperlinks as edges. Graph analysis can then be used to find important nodes (i.e., popular websites) and the shortest path between them.</p>
<p>A <span class="inline_code">Node</span> takes a number of optional parameters used to style the graph <a class="link-maintenance" href="#canvas">visualization</a> of the graph: <span class="inline_code">radius</span> (node size), <span class="inline_code">text</span>, <span class="inline_code">fill</span> and <span class="inline_code">stroke</span> (colors; each a tuple of <a href="http://en.wikipedia.org/wiki/RGBA">RGBA</a> values between <span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>), <span class="inline_code">strokewidth</span>, <span class="inline_code">font</span>, <span class="inline_code">fontsize</span> and <span class="inline_code">fontweight</span>.</p>
<pre class="brush:python; gutter:false; light:true;">node = Node(id="", **kwargs)</pre><pre class="brush:python; gutter:false; light:true;">node.graph                     # Parent Graph.
node.id                        # Unique string or int.
node.links                     # List of Node objects. 
node.edges                     # List of Edge objects.
node.edge(node, reverse=False)  
</pre><pre class="brush:python; gutter:false; light:true;">node.weight                    # Eigenvector centrality (0.0-1.0).
node.centrality                # Betweenness centrality (0.0-1.0).
node.degree                    # Degree centrality (0.0-1.0).  </pre><pre class="brush:python; gutter:false; light:true;">node.x                         # 2D horizontal offset.
node.y                         # 2D vertical offset.
node.force                     # 2D Vector, updated by Graph.layout.
node.radius                    # Default: 5
node.fill                      # Default: None
node.stroke                    # Default: (0,0,0,1)
node.strokewidth               # Default: 1 
node.text                      # Text object, or None.</pre><pre class="brush:python; gutter:false; light:true;">node.flatten(depth=1, traversable=lambda node, edge: True)
</pre><ul>
<li><span class="inline_code">Node.edge(node)</span> returns the <span class="inline_code">Edge</span> from this node to the given <span class="inline_code">node</span>, or <span class="inline_code">None</span>.</li>
<li><span class="inline_code">Node.flatten()</span> returns a list with the node itself (<span class="inline_code">depth=0</span>), directly connected nodes (<span class="inline_code">depth=1</span>), nodes connected to those nodes (<span class="inline_code">depth=2</span>), and so on.</li>
</ul>
<p><span class="smallcaps">node weight and centrality</span></p>
<p>A well-known task in graph analysis is measuring how important or <em>central</em> each node in the graph is. The pattern.graph module has three centrality measurements, adopted from <a href="http://networkx.lanl.gov/">NetworkX</a>.</p>
<p><span class="inline_code">Node.weight</span> is the node's <em>eigenvector</em> centrality (= incoming traffic) as a value between <span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>. Nodes with more (indirect) incoming edges have a higher weight. For example, in the WWW, popular websites are those that are often linked to, where the popularity of the referring websites is taken into account.</p>
<p><span class="inline_code">Node.centrality</span> is the node's <em>betweenness</em> centrality (= passing traffic) as a value between <span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>. Nodes that occur more frequently in paths between other nodes have a higher betweenness. They are often found at the intersection of different clusters of nodes (e.g., like a broker or a bridge).</p>
<p><span class="inline_code">Node.degree</span> is the node's <em>degree</em> centrality (= local traffic) as a value between <span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>. Nodes with more edges have a higher degree.</p>
<p>&nbsp;</p>
<hr />
<h2><a name="edge"></a>Edge</h2>
<p>An <span class="inline_code">Edge</span> is a connection between two nodes. Its <span class="inline_code">weight</span> defines the importance of the connection. Edges with a higher weight are preferred when traversing the path between two (indirectly) connected nodes.</p>
<p>An <span class="inline_code">Edge</span> takes optional parameters <span class="inline_code">stroke</span> (a tuple of <a href="http://en.wikipedia.org/wiki/RGBA">RGBA</a> values between <span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>) and <span class="inline_code">strokewidth</span>, which can be used to style the graph&nbsp;<a class="link-maintenance" href="#canvas">visualization</a>.</p>
<pre class="brush:python; gutter:false; light:true;">edge = Edge(node1, node2, weight=0.0, length=1.0, type=None, **kwargs)</pre><pre class="brush:python; gutter:false; light:true;">edge.node1                     # Node (sender).
edge.node2                     # Node (receiver). 
edge.weight                    # Connection strength.
edge.length                    # Length modifier for the visualization.
edge.type                      # Useful in semantic networks.
edge.stroke                    # Default: (0,0,0,1)
edge.strokewidth               # Default: 1 </pre><p class="smallcaps"><br />directed graph</p>
<p>An edge can be traversed in both directions: from <span class="inline_code">node1</span> → <span class="inline_code">node2</span>, and from <span class="inline_code">node2</span> → <span class="inline_code">node1</span>. The <span class="inline_code">Graph.shortest_path()</span> and <span class="inline_code">Graph.betweenness_centrality()</span> methods have a <span class="inline_code">directed</span> parameter which can be set to <span class="inline_code">True</span>, so that edges are only traversed from <span class="inline_code">node1</span> → <span class="inline_code">node2</span>. This is called a directed graph. Evidently, it produces different shortest paths and node weights.</p>
<p>Two nodes can be connected by at most two edges (one in each direction). Otherwise, <span class="inline_code">Graph.add_edge()</span> simply returns the edge that already exists between the given nodes.</p>
<p>&nbsp;</p>
<hr />
<h2><a name="graph"></a>Graph</h2>
<p>A <span class="inline_code">Graph</span> is a network of nodes connected by edges, with methods for finding paths between (indirectly) connected nodes.</p>
<pre class="brush:python; gutter:false; light:true;">graph = Graph(layout=SPRING, distance=10.0)</pre><pre class="brush:python; gutter:false; light:true;">graph[id]                      # Node with given id (Graph is a subclass of dict).
graph.nodes                    # List of Node objects.
graph.edges                    # List of Edge objects.
graph.density                  # &lt; 0.35 =&gt; sparse, &gt; 0.65 =&gt; dense
graph.layout                   # GraphSpringLayout. 
graph.distance                 # GraphSpringLayout spacing.
</pre><pre class="brush:python; gutter:false; light:true;">graph.add_node(id)             # Creates + returns new Node.
graph.add_edge(id1, id2)       # Creates + returns new Edge.
graph.remove(node)             # Removes given Node + edges.
graph.remove(edge)             # Removes given Edge.
graph.prune(depth=0)           # Removes nodes + edges if len(node.links) &lt;= depth.
graph.node(id)                 # Returns node with given id.
graph.edge(id1, id2)           # Returns edge connecting the given nodes.
graph.copy(nodes=ALL)          # Returns a new Graph.
graph.split()                  # Returns a list of (unconnected) graphs.
</pre><pre class="brush:python; gutter:false; light:true;">graph.eigenvector_centrality() # Updates all Node.weight values.
graph.betweenness_centrality() # Updates all Node.centrality values. </pre><pre class="brush:python; gutter:false; light:true;">graph.shortest_path(node1, node2, heuristic=None, directed=False)
graph.shortest_paths(node, heuristic=None, directed=False)
graph.paths(node1, node2, length=4)
graph.fringe(depth=0, traversable=lambda node, edge: True)
</pre><pre class="brush:python; gutter:false; light:true;">graph.update(iterations=10, weight=10, limit=0.5)</pre><ul>
<li><span class="inline_code"><span><span class="inline_code">Graph.add_node()</span></span></span> takes an id + any optional parameter of <span><span class="inline_code">Node</span></span>.</li>
<li><span class="inline_code">Graph.add_edge()</span> takes two id's + any optional parameter of <span class="inline_code">Edge</span>.<br />Both methods have an optional <span class="inline_code">base</span> parameter that defines the subclass of <span class="inline_code">Node</span> or <span class="inline_code">Edge</span> to use.</li>
</ul>
<ul>
<li><span class="inline_code">Graph.prune()</span> removes all nodes with less or equal (undirected) connections than <span class="inline_code">depth</span>.</li>
<li><span class="inline_code">Graph.copy()</span> returns a new <span class="inline_code">Graph</span> from the given list of nodes.</li>
<li><span class="inline_code">Graph.split()</span> return a list of unconnected subgraphs.</li>
</ul>
<ul>
<li><span class="inline_code"><span><span class="inline_code">Graph.paths()</span></span></span> returns all paths (each a list of nodes) &lt;= <span class="inline_code">length</span> connecting two given nodes.</li>
<li><span class="inline_code"><span><span class="inline_code">Graph.shortest_path()</span></span></span> returns a list of nodes connecting the two given nodes<span class="inline_code"><span>.</span><br /></span></li>
<li><span class="inline_code">Graph.shortest_paths()</span> returns a dictionary of node <span style="line-height: normal;">→</span> shortest path.<br />The optional <span class="inline_code">heuristic</span> function takes two node id's and returns a penalty (<span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>) for traversing their edges. With <span class="inline_code">directed=True</span>, edges are only traversable in one direction.</li>
</ul>
<ul>
<li><span class="inline_code">Graph.fringe()</span> returns a list of <em>leaf</em> nodes.<br />With <span class="inline_code">depth=0</span>, returns the nodes with one edge.<br />With <span class="inline_code">depth=1</span>, returns the nodes with one edge + the connected nodes, etc.</li>
</ul>
<p>For example:</p>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.graph import Graph
&gt;&gt;&gt; 
&gt;&gt;&gt; g = Graph()
&gt;&gt;&gt; for n1, n2 in (
&gt;&gt;&gt;   ('cat', 'tail'), ('cat', 'purr'), ('purr', 'sound'),
&gt;&gt;&gt;   ('dog', 'tail'), ('dog', 'bark'), ('bark', 'sound')):
&gt;&gt;&gt;     g.add_node(n1)
&gt;&gt;&gt;     g.add_node(n2)
&gt;&gt;&gt;     g.add_edge(n1, n2, weight=0.0, type='is-related-to')
&gt;&gt;&gt;
&gt;&gt;&gt; for n in sorted(g.nodes, key=lambda n: n.weight):
&gt;&gt;&gt;     print '%.2f' % n.weight, n

0.00 Node(id='cat')
0.00 Node(id='dog')
0.07 Node(id='purr')
0.07 Node(id='bark')
0.15 Node(id='tail') 
1.00 Node(id='sound') 
</pre></div>
<div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; for n in g.shortest_path('purr', 'bark'):
&gt;&gt;&gt;     print n    

Node(id='purr')
Node(id='sound')
Node(id='bark')
</pre></div>
<table border="0">
<tbody>
<tr>
<td>
<p>When sorted by <span class="inline_code">Node.weight</span> (i.e., eigenvector centrality), <em>sound</em> is the most important node in the network. This can be explained by observing the visualization on the right. Most nodes (indirectly) connect to <em>sound</em> or <em>tail</em>. No nodes connect to <em>dog</em> or <em>cat</em>, so these are the least important in the network (weight <span class="inline_code">0.0</span>).</p>
<p>By default, nodes with a higher height will have a larger radius in the visualization.</p>
</td>
<td><img src="../g/pattern_graph3.jpg" alt="" width="170" height="155" /></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<hr />
<h2><a name="layout"></a>Graph layout</h2>
<p>A <span class="inline_code">GraphLayout</span> updates node positions (<span class="inline_code">Node.x</span>, <span class="inline_code">Node.y</span>) iteratively each time <span class="inline_code">GraphLayout.update()</span> is called. The pattern.graph module currently has one implementation: <span class="inline_code">GraphSpringLayout</span>, which uses a force-based algorithm where edges are regarded as springs. Connected nodes are pulled closer together (attraction) while other nodes are pushed further apart (repulsion).</p>
<pre class="brush:python; gutter:false; light:true;">layout = GraphSpringLayout(graph)</pre><pre class="brush:python; gutter:false; light:true;">layout.graph                    # Graph owner.
layout.iterations               # Starts at 0, +1 each update().
layout.bounds                   # (x, y, width, height)-tuple.</pre><pre class="brush:python; gutter:false; light:true;">layout.k                        # Force constant   (4.0)
layout.force                    # Force multiplier (0.01) 
layout.repulsion                # Maximum repulsion radius (50)</pre><pre class="brush:python; gutter:false; light:true;">layout.update(weight=10.0, limit=0.5) # weight = Edge.weight multiplier.
layout.reset()
layout.copy(graph)</pre><p><span class="small"><span style="text-decoration: underline;">Reference</span>: Hellesoy, A. &amp; Hoover, D. (2006). http://ajaxian.com/archives/new-javascriptcanvas-graph-library</span></p>
<p>&nbsp;</p>
<hr />
<h2><a name="utility"></a>Graph adjacency</h2>
<p>The pattern.graph has a number of functions that can be used to modify graph edges:</p>
<pre class="brush:python; gutter:false; light:true;">unlink(graph, node1, node2=None)</pre><pre class="brush:python; gutter:false; light:true;">redirect(graph, node1, node2)</pre><pre class="brush:python; gutter:false; light:true;">cut(graph, node)</pre><pre class="brush:python; gutter:false; light:true;">insert(graph, node, a, b)</pre><ul>
<li style="margin-bottom: 0.3em;"><span class="inline_code">unlink()</span> removes the edge between <span class="inline_code">node1</span> and <span class="inline_code">node2</span>. <br />If only <span class="inline_code">node1</span> is given, removes all edges to + from it. This does not remove <span class="inline_code">node1</span> from the graph.</li>
<li style="margin-bottom: 0.3em;"><span class="inline_code">redirect()</span> connects <span class="inline_code">node1</span>'s edges to <span class="inline_code">node2</span> and removes&nbsp;<span class="inline_code">node1</span>.<br />If <span class="inline_code">A</span>, <span class="inline_code">B</span>, <span class="inline_code">C</span>, <span class="inline_code">D</span> are nodes and <span class="inline_code">A</span> → <span class="inline_code">B</span> and <span class="inline_code">C</span> → <span class="inline_code">D</span>, and we redirect <span class="inline_code">A</span> to <span class="inline_code">C</span>, then <span class="inline_code">C</span> → <span class="inline_code">B</span> and <span class="inline_code">C</span> → <span class="inline_code">D</span>.</li>
<li style="margin-bottom: 0.3em;"><span class="inline_code">cut()</span> removes the given <span class="inline_code">node</span>&nbsp;and connects the surrounding nodes. <br />If <span class="inline_code">A</span>, <span class="inline_code">B</span>, <span class="inline_code">C</span>, <span class="inline_code">D</span> are nodes and <span class="inline_code">A</span> <span>→</span> <span class="inline_code">B</span> and <span class="inline_code">B</span> <span>→</span> <span class="inline_code">C</span> and <span class="inline_code">B</span> <span>→</span> <span class="inline_code">D</span>, and we cut <span class="inline_code">B</span>, then <span class="inline_code">A</span> <span>→</span> <span class="inline_code">C</span> and <span class="inline_code">A</span> <span>→</span> <span class="inline_code">D</span>.</li>
<li><span class="inline_code">insert()</span> inserts the given <span class="inline_code">node</span> between node <span class="inline_code">a</span> and node <span class="inline_code">b</span>. <br />If <span class="inline_code">A</span>, <span class="inline_code">B</span>, <span class="inline_code">C</span> are nodes and <span class="inline_code">A</span> <span>→</span> <span class="inline_code">B</span>, and we insert <span class="inline_code">C</span>, then <span class="inline_code">A</span> <span>→</span> <span class="inline_code">C</span> and <span class="inline_code">C</span> <span>→</span> <span class="inline_code">B</span>.</li>
</ul>
<h3>Edge adjacency map</h3>
<p><span style="font-variant: normal;">The <span class="inline_code">adjacency()</span> function returns a map of linked nodes:</span><span class="smallcaps"><br /></span></p>
<pre class="brush:python; gutter:false; light:true;">adjacency(graph, 
      directed = False, 
      reversed = False, 
    stochastic = False, 
     heuristic = lambda node1, node2: 0)</pre><p>The return value is an&nbsp;<span class="inline_code">{id1:</span> <span class="inline_code">{id2:</span> <span class="inline_code">weight}}</span>&nbsp;dictionary with <span class="inline_code">Node.id</span>'s as keys, where each value is a dictionary of connected&nbsp;<span class="inline_code">Node.id</span>'s&nbsp;<span style="line-height: 18px;">→</span>&nbsp;<span class="inline_code">Edge.weight</span>.</p>
<p>If <span class="inline_code">directed=True</span>, edges are only traversable in one direction. If <span class="inline_code">stochastic=True</span>, the edge weights for all neighbors of a given node sum to <span class="inline_code">1.0</span>.&nbsp;The optional <span class="inline_code">heuristic</span> function takes two node id's and returns an additional cost (<span class="inline_code">0.0</span>-<span class="inline_code">1.0</span>) for traversing their edges.&nbsp;</p>
<h3>Edge traversal</h3>
<p>The <span class="inline_code">bfs()</span> function (breadth-first search) visits all nodes connected to the given <span class="inline_code">node</span>. <br />The <span class="inline_code">dfs()</span> function (depth-first search) visits all nodes connected to the given <span class="inline_code">node</span> depth-first, i.e., as far as possible along each path before backtracking.</p>
<pre class="brush:python; gutter:false; light:true;">bfs(node, visit=lambda node: False, traversable=lambda node, edge: True)</pre><pre class="brush:python; gutter:false; light:true;">dfs(node, visit=lambda node: False, traversable=lambda node, edge: True)
</pre><p>The given&nbsp;<span class="inline_code">visit</span>&nbsp;function is called with each visited node. Traversal will stop if it returns <span class="inline_code">True</span>, and subsequently <span class="inline_code">bfs()</span> or <span class="inline_code">dfs()</span> will return <span class="inline_code">True</span>.</p>
<p>The given&nbsp;<span class="inline_code">traversable</span> function takes the visited&nbsp;<span class="inline_code">Node</span> and an&nbsp;<span class="inline_code">Edge</span> and returns <span class="inline_code">True</span> if we are allowed to follow this connection to the next node. For example, the traversable for directed edges:</p>
<div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; def directed(node, edge):
&gt;&gt;&gt;     return node.id == edge.node1.id
&gt;&gt;&gt;
&gt;&gt;&gt; dfs(g, traversable=directed)   </pre></div>
<p>&nbsp;</p>
<hr />
<h2><a name="canvas"></a>Visualization</h2>
<p>The pattern.graph module has a JavaScript counterpart (graph.js) that can be used to visualize a graph in a web page, as a&nbsp;HTML&nbsp;&lt;canvas&gt; element. The HTML &lt;canvas&gt; element allows dynamic, scriptable rendering of 2D shapes and bitmap images (see also Pattern's&nbsp;<a class="link-maintenance" href="pattern-canvas.html">canvas.js</a>).</p>
<p><span class="inline_code">Graph.export(</span>) creates a new file folder at the given <span class="inline_code">path</span>&nbsp;with an index.html (the visualization), a style.css, graphs.js and canvas.js. The optional parameter <span class="inline_code">javascript</span>&nbsp;defines the URL path to graph.js and canvas.js (which will not be included in this case).</p>
<pre class="brush:python; gutter:false; light:true;">graph.export(path, encoding='utf-8', **kwargs)</pre><div class="example">
<pre class="brush:python; gutter:false; light:true;">&gt;&gt;&gt; from pattern.graph import Graph
&gt;&gt;&gt;  
&gt;&gt;&gt; g = Graph()
&gt;&gt;&gt; for n1, n2 in (
&gt;&gt;&gt;   ('cat', 'tail'), ('cat', 'purr'), ('purr', 'sound'),
&gt;&gt;&gt;   ('dog', 'tail'), ('dog', 'bark'), ('bark', 'sound')):
&gt;&gt;&gt;     g.add_node(n1)
&gt;&gt;&gt;     g.add_node(n2)
&gt;&gt;&gt;     g.add_edge(n1, n2, weight=0.0, type='is-related-to')
&gt;&gt;&gt;  
&gt;&gt;&gt; g.export('sound', directed=True)</pre></div>
<p>Nodes and edges will be styled according to their <span class="inline_code">fill</span>, <span class="inline_code">stroke</span>, and <span class="inline_code">strokewidth</span>&nbsp;properties.</p>
<p>The following parameters can be used to customize the visualization:</p>
<table class="border">
<tbody>
<tr>
<td><span class="smallcaps">Parameter</span></td>
<td><span class="smallcaps">Default</span></td>
<td><span class="smallcaps">Description</span></td>
</tr>
<tr>
<td><span class="inline_code">javascript</span></td>
<td><span class="inline_code">''</span></td>
<td>Path to canvas.js&nbsp;and graph.js.</td>
</tr>
<tr>
<td><span class="inline_code">stylesheet</span></td>
<td class="inline_code"><span class="inline_code">INLINE</span></td>
<td>Path to CSS: INLINE,&nbsp;<span class="inline_code">DEFAULT</span>&nbsp;(generates style.css),&nbsp;<span class="inline_code">None</span>&nbsp;or path.</td>
</tr>
<tr>
<td><span class="inline_code">title</span></td>
<td><span class="inline_code">'Graph'</span></td>
<td>HTML&nbsp;<span class="inline_code"><span><span class="inline_code">&lt;title&gt;Graph&lt;/title&gt;</span>.</span></span></td>
</tr>
<tr>
<td><span class="inline_code">id</span></td>
<td><span class="inline_code">'graph'</span></td>
<td>HTML&nbsp;<span class="inline_code">&lt;div</span> <span class="inline_code">id="graph"&gt;</span>&nbsp;contains the&nbsp;<span class="inline_code">&lt;canvas&gt;</span>.</td>
</tr>
<tr>
<td style="border: 0; font-size: 0.5em;">&nbsp;</td>
</tr>
<tr>
<td><span class="inline_code">ctx</span></td>
<td><span class="inline_code">'canvas.element'</span></td>
<td>HTML <span class="inline_code">&lt;canvas&gt;</span> element to use for drawing.</td>
</tr>
<tr>
<td><span class="inline_code">width</span></td>
<td><span class="inline_code">700</span></td>
<td>Canvas width in pixels.</td>
</tr>
<tr>
<td><span class="inline_code">height</span></td>
<td><span class="inline_code">500</span></td>
<td>Canvas height in pixels.</td>
</tr>
<tr>
<td><span class="inline_code">frames</span></td>
<td><span class="inline_code">500</span></td>
<td>Number of frames of animation.</td>
</tr>
<tr>
<td><span class="inline_code">ipf</span></td>
<td><span class="inline_code">2</span></td>
<td><span class="inline_code">GraphLayout.update()</span> iterations per frame.</td>
</tr>
<tr>
<td style="border: 0; font-size: 0.5em;">&nbsp;</td>
</tr>
<tr>
<td><span class="inline_code">directed</span></td>
<td><span class="inline_code">False</span></td>
<td>Visualize eigenvector centrality as an edge arrow?</td>
</tr>
<tr>
<td><span class="inline_code">weighted</span></td>
<td><span class="inline_code">False</span></td>
<td>Visualize betweenness centrality as a node shadow?</td>
</tr>
<tr>
<td><span class="inline_code">pack</span></td>
<td><span class="inline_code">True</span></td>
<td>Shorten leaf edges + add node weight to node radius.</td>
</tr>
<tr>
<td style="border: 0; font-size: 0.5em;">&nbsp;</td>
</tr>
<tr>
<td><span class="inline_code">distance</span></td>
<td><span class="inline_code">graph.distance</span></td>
<td>Average edge length.</td>
</tr>
<tr>
<td><span class="inline_code">k</span></td>
<td><span class="inline_code">graph.k</span></td>
<td>Force constant.</td>
</tr>
<tr>
<td><span class="inline_code">force</span></td>
<td><span class="inline_code">graph.force</span></td>
<td>Force dampener.</td>
</tr>
<tr>
<td><span class="inline_code">repulsion</span></td>
<td><span class="inline_code">graph.repulsion</span></td>
<td>Force radius.</td>
</tr>
<tr>
<td style="border: 0; font-size: 0.5em;">&nbsp;</td>
</tr>
<tr>
<td><span class="inline_code">href</span></td>
<td><span class="inline_code">{}</span></td>
<td>Dictionary of <span class="inline_code">Node.id</span> =&gt; URL.</td>
</tr>
<tr>
<td><span class="inline_code">css</span></td>
<td><span class="inline_code">{}</span></td>
<td>Dictionary of <span class="inline_code">Node.id</span> =&gt; CSS classname.</td>
</tr>
</tbody>
</table>
<p>To export a static visualization, use <span class="inline_code">frames=1</span> and <span class="inline_code">ipf=0</span>.<br />&nbsp;</p>
<p class="smallcaps">Server-side scripting</p>
<p><span class="inline_code">Graph.serialize()</span> returns a string with (a portion of) the HTML, CSS and JavaScript source code of the visualization. It can be used to serve a dynamic web page.&nbsp;With <span class="inline_code">type=CANVAS</span>, it returns a HTML string with a <span class="inline_code">&lt;div</span> <span class="inline_code">id="graph"&gt;</span>&nbsp;that contains the canvas.js animation.&nbsp;With <span class="inline_code">type=DATA</span>, it returns a Javascript string that initializes the <span class="inline_code">Graph</span> in variable&nbsp;<span class="inline_code">g</span>&nbsp;(which will draw to <span class="inline_code">ctx</span>).</p>
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">graph.serialize(type=HTML, **kwargs) # HTML | CSS | CANVAS | DATA</pre><div class="example">
<pre class="brush: python;gutter: false; light: true; fontsize: 100; first-line: 1; ">&gt;&gt;&gt; import cherrypy
&gt;&gt;&gt; 
&gt;&gt;&gt; class Visualization(object):
&gt;&gt;&gt;     def index(self):
&gt;&gt;&gt;         return (
&gt;&gt;&gt;             '&lt;html&gt;'
&gt;&gt;&gt;             '&lt;head&gt;'
&gt;&gt;&gt;             '&lt;script src="canvas.js"&gt;&lt;/script&gt;'
&gt;&gt;&gt;             '&lt;script src="graph.js"&gt;&lt;/script&gt;'
&gt;&gt;&gt;             '&lt;/head&gt;'
&gt;&gt;&gt;             '&lt;body&gt;' + g.serialize(CANVAS, directed=True) +
&gt;&gt;&gt;             '&lt;/body&gt;'
&gt;&gt;&gt;             '&lt;/html&gt;'
&gt;&gt;&gt;         )
&gt;&gt;&gt;     index.exposed = True 
&gt;&gt;&gt; 
&gt;&gt;&gt; cherrypy.quickstart(Visualization())</pre></div>
<p>&nbsp;</p>
<hr />
<h2><a name="javascript"></a>graph.js</h2>
<p>Below is a standalone demonstration of graph.js, without using&nbsp;<span class="inline_code">export()</span> or canvas.js. The <span class="inline_code">Graph.loop()</span> method fires the spring layout algorithm&nbsp;(<span class="link-maintenance"><a href="http://www.clips.ua.ac.be/media/pattern-graph/random" target="_blank">view live demo</a></span>).</p>
<p><img class="border" src="../g/pattern_graph4.jpg" alt="" width="610" height="390" /></p>
<div class="example">
<pre class="brush:xml; gutter:false; light:true;">&lt;!doctype html&gt; 
&lt;html&gt;
&lt;head&gt; 
    &lt;meta charset="utf-8"&gt;
    &lt;style&gt;
        #graph { display: block; position: relative; overflow: hidden; }
        #graph .node-label { font: 11px sans-serif; }
    &lt;/style&gt;
    &lt;script src="graph.js"&gt;&lt;/script&gt;
    &lt;script&gt;  
</pre></div>
<div class="example">
<pre class="brush: jscript;gutter: false; light: true; fontsize: 100; first-line: 1; ">&nbsp;&nbsp;&nbsp;&nbsp;function spring() {
        SHADOW = 0.65 // slow... 
        g = new Graph(document.getElementById("_ctx"));
        // Random nodes. 
        for (var i=0; i &lt; 50; i++) { 
            g.addNode(i+1);
        }
        // Random edges. 
        for (var j=0; j &lt; 75; j++) { 
            var n1 = choice(g.nodes);
            var n2 = choice(g.nodes);
            g.addEdge(n1, n2, {weight: Math.random()});
        }
        g.prune(0);
        g.betweennessCentrality();
        g.eigenvectorCentrality();
        g.loop({frames:500, fps:30, ipf:2, weighted:0.5, directed:true});
    }
</pre></div>
<div class="example">
<pre class="brush:xml; gutter:false; light:true;">    &lt;/script&gt;
&lt;/head&gt;
&lt;body onload="spring();"&gt; 
    &lt;div id="graph" style="width:700px; height:500px;"&gt;
        &lt;canvas id="_ctx" width="700" height="500"&gt;&lt;/canvas&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt; </pre></div>
<p>&nbsp;</p>
<hr />
<h2>See also</h2>
<ul>
<li><a href="http://gephi.org/" target="_blank">Gephi</a> (GPL): ne<span>twork analysis &amp; visualization GUI.</span></li>
<li><a href="http://networkx.lanl.gov/" target="_blank">NetworkX</a> (BSD): <span>network analysis toolkit for Python + NumPy.</span></li>
<li><a href="http://www.cityinabottle.org/nodebox/" target="_blank">NodeBox</a> (BSD): g<span>raphics toolkit for Python + OpenGL.</span></li>
</ul>
</div>
</div></div>
        </div>
    </div>
    </div>
    </div>
    </div>
    </div>
    <script>
        SyntaxHighlighter.all();
    </script>
</body>
</html>