You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
32 KiB
HTML
431 lines
32 KiB
HTML
<!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> <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> </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> </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 <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> </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 # < 0.35 => sparse, > 0.65 => 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) <= 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) <= <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;">>>> from pattern.graph import Graph
|
|
>>>
|
|
>>> g = Graph()
|
|
>>> for n1, n2 in (
|
|
>>> ('cat', 'tail'), ('cat', 'purr'), ('purr', 'sound'),
|
|
>>> ('dog', 'tail'), ('dog', 'bark'), ('bark', 'sound')):
|
|
>>> g.add_node(n1)
|
|
>>> g.add_node(n2)
|
|
>>> g.add_edge(n1, n2, weight=0.0, type='is-related-to')
|
|
>>>
|
|
>>> for n in sorted(g.nodes, key=lambda n: n.weight):
|
|
>>> 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;">>>> for n in g.shortest_path('purr', 'bark'):
|
|
>>> 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> </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. & Hoover, D. (2006). http://ajaxian.com/archives/new-javascriptcanvas-graph-library</span></p>
|
|
<p> </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 <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> 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 <span class="inline_code">{id1:</span> <span class="inline_code">{id2:</span> <span class="inline_code">weight}}</span> dictionary with <span class="inline_code">Node.id</span>'s as keys, where each value is a dictionary of connected <span class="inline_code">Node.id</span>'s <span style="line-height: 18px;">→</span> <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>. 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. </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 <span class="inline_code">visit</span> 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 <span class="inline_code">traversable</span> function takes the visited <span class="inline_code">Node</span> and an <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; ">>>> def directed(node, edge):
|
|
>>> return node.id == edge.node1.id
|
|
>>>
|
|
>>> dfs(g, traversable=directed) </pre></div>
|
|
<p> </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 HTML <canvas> element. The HTML <canvas> element allows dynamic, scriptable rendering of 2D shapes and bitmap images (see also Pattern's <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> with an index.html (the visualization), a style.css, graphs.js and canvas.js. The optional parameter <span class="inline_code">javascript</span> 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;">>>> from pattern.graph import Graph
|
|
>>>
|
|
>>> g = Graph()
|
|
>>> for n1, n2 in (
|
|
>>> ('cat', 'tail'), ('cat', 'purr'), ('purr', 'sound'),
|
|
>>> ('dog', 'tail'), ('dog', 'bark'), ('bark', 'sound')):
|
|
>>> g.add_node(n1)
|
|
>>> g.add_node(n2)
|
|
>>> g.add_edge(n1, n2, weight=0.0, type='is-related-to')
|
|
>>>
|
|
>>> 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> 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 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, <span class="inline_code">DEFAULT</span> (generates style.css), <span class="inline_code">None</span> or path.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="inline_code">title</span></td>
|
|
<td><span class="inline_code">'Graph'</span></td>
|
|
<td>HTML <span class="inline_code"><span><span class="inline_code"><title>Graph</title></span>.</span></span></td>
|
|
</tr>
|
|
<tr>
|
|
<td><span class="inline_code">id</span></td>
|
|
<td><span class="inline_code">'graph'</span></td>
|
|
<td>HTML <span class="inline_code"><div</span> <span class="inline_code">id="graph"></span> contains the <span class="inline_code"><canvas></span>.</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="border: 0; font-size: 0.5em;"> </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"><canvas></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;"> </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;"> </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;"> </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> => 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> => 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 /> </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. With <span class="inline_code">type=CANVAS</span>, it returns a HTML string with a <span class="inline_code"><div</span> <span class="inline_code">id="graph"></span> that contains the canvas.js animation. With <span class="inline_code">type=DATA</span>, it returns a Javascript string that initializes the <span class="inline_code">Graph</span> in variable <span class="inline_code">g</span> (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; ">>>> import cherrypy
|
|
>>>
|
|
>>> class Visualization(object):
|
|
>>> def index(self):
|
|
>>> return (
|
|
>>> '<html>'
|
|
>>> '<head>'
|
|
>>> '<script src="canvas.js"></script>'
|
|
>>> '<script src="graph.js"></script>'
|
|
>>> '</head>'
|
|
>>> '<body>' + g.serialize(CANVAS, directed=True) +
|
|
>>> '</body>'
|
|
>>> '</html>'
|
|
>>> )
|
|
>>> index.exposed = True
|
|
>>>
|
|
>>> cherrypy.quickstart(Visualization())</pre></div>
|
|
<p> </p>
|
|
<hr />
|
|
<h2><a name="javascript"></a>graph.js</h2>
|
|
<p>Below is a standalone demonstration of graph.js, without using <span class="inline_code">export()</span> or canvas.js. The <span class="inline_code">Graph.loop()</span> method fires the spring layout algorithm (<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;"><!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<style>
|
|
#graph { display: block; position: relative; overflow: hidden; }
|
|
#graph .node-label { font: 11px sans-serif; }
|
|
</style>
|
|
<script src="graph.js"></script>
|
|
<script>
|
|
</pre></div>
|
|
<div class="example">
|
|
<pre class="brush: jscript;gutter: false; light: true; fontsize: 100; first-line: 1; "> function spring() {
|
|
SHADOW = 0.65 // slow...
|
|
g = new Graph(document.getElementById("_ctx"));
|
|
// Random nodes.
|
|
for (var i=0; i < 50; i++) {
|
|
g.addNode(i+1);
|
|
}
|
|
// Random edges.
|
|
for (var j=0; j < 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;"> </script>
|
|
</head>
|
|
<body onload="spring();">
|
|
<div id="graph" style="width:700px; height:500px;">
|
|
<canvas id="_ctx" width="700" height="500"></canvas>
|
|
</div>
|
|
</body>
|
|
</html> </pre></div>
|
|
<p> </p>
|
|
<hr />
|
|
<h2>See also</h2>
|
|
<ul>
|
|
<li><a href="http://gephi.org/" target="_blank">Gephi</a> (GPL): ne<span>twork analysis & 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> |