python-igraph manual

For using igraph from Python

   Home       Trees       Indices       Help   
Package igraph :: Package remote :: Module gephi
[hide private]

Source Code for Module igraph.remote.gephi

  1  # vim:ts=4:sw=4:sts=4:et 
  2  # -*- coding: utf-8 -*- 
  3  """Classes that help igraph communicate with Gephi (http://www.gephi.org).""" 
  4   
  5  from igraph.compat import property 
  6  import urllib2 
  7   
  8  try: 
  9      # JSON is optional so we don't blow up with Python < 2.6 
 10      import json 
 11  except ImportError: 
 12      try: 
 13          # Try with simplejson for Python < 2.6 
 14          import simplejson as json 
 15      except ImportError: 
 16          # No simplejson either 
 17          from igraph.drawing.utils import FakeModule 
 18          json = FakeModule() 
 19   
 20  __all__ = ["GephiConnection", "GephiGraphStreamer", "GephiGraphStreamingAPIFormat"] 
 21  __docformat__ = "restructuredtext en" 
 22  __license__ = u"""\ 
 23  Copyright (C) 2006-2012  Tamás Nepusz <ntamas@gmail.com> 
 24  Pázmány Péter sétány 1/a, 1117 Budapest, Hungary 
 25   
 26  This program is free software; you can redistribute it and/or modify 
 27  it under the terms of the GNU General Public License as published by 
 28  the Free Software Foundation; either version 2 of the License, or 
 29  (at your option) any later version. 
 30   
 31  This program is distributed in the hope that it will be useful, 
 32  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 33  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 34  GNU General Public License for more details. 
 35   
 36  You should have received a copy of the GNU General Public License 
 37  along with this program; if not, write to the Free Software 
 38  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA  
 39  02110-1301 USA 
 40  """ 
41 42 43 -class GephiConnection(object):
44 """Object that represents a connection to a Gephi master server.""" 45
46 - def __init__(self, url=None, host="127.0.0.1", port=8080, workspace=0):
47 """Constructs a connection to a Gephi master server. 48 49 The connection object can be constructed either by specifying the `url` 50 directly, or by specifying the `host`, `port` and `workspace` arguments. 51 The latter three are evaluated only if `url` is None; otherwise the 52 `url` will take precedence. 53 54 The `url` argument does not have to include the operation (e.g., 55 ``?operation=updateGraph``); the connection will take care of it. 56 E.g., if you wish to connect to workspace 2 in a local Gephi instance on 57 port 7341, the correct form to use for the `url` is as follows:: 58 59 http://localhost:7341/workspace0 60 """ 61 self._pending_operations = [] 62 self._autoflush_threshold = 1024 63 64 self.url = url or self._construct_default_url(host, port, workspace) 65
66 - def __del__(self):
67 try: 68 self.close() 69 except urllib2.URLError: 70 # Happens when Gephi is closed before the connection is destroyed 71 pass 72
73 - def _construct_default_url(self, host, port, workspace):
74 return "http://%s:%d/workspace%d" % (host, port, workspace) 75
76 - def close(self):
77 """Flushes all the pending operations to the Gephi master server in a 78 single request.""" 79 self.flush() 80
81 - def flush(self):
82 """Flushes all the pending operations to the Gephi master server in a 83 single request.""" 84 data = "".join(self._pending_operations) 85 self._pending_operations = [] 86 conn = urllib2.urlopen(self._update_url, data=data) 87 return conn.read() 88 89 @property
90 - def url(self):
91 """The URL of the Gephi workspace where the data will be sent.""" 92 return self._url_root 93 94 @url.setter
95 - def url(self, value):
96 self._url_root = value 97 self._get_url = self._url_root + "?operation=getGraph" 98 self._update_url = self._url_root + "?operation=updateGraph" 99
100 - def write(self, data):
101 """Sends the given raw data to the Gephi streaming master server in an HTTP 102 POST request.""" 103 self._pending_operations.append(data) 104 if len(self._pending_operations) >= self._autoflush_threshold: 105 self.flush() 106
107 - def __repr__(self):
108 return "%s(url=%r)" % (self.__class__.__name__, self.url)
109
110 111 -class GephiGraphStreamingAPIFormat(object):
112 """Object that implements the Gephi graph streaming API format and returns 113 Python objects corresponding to the events defined in the API. 114 """ 115
116 - def get_add_node_event(self, identifier, attributes={}):
117 """Generates a Python object corresponding to the event that adds a node 118 with the given identifier and attributes in the Gephi graph streaming API. 119 120 Example:: 121 122 >>> api = GephiGraphStreamingAPIFormat() 123 >>> api.get_add_node_event("spam") 124 {'an': {'spam': {}}} 125 >>> api.get_add_node_event("spam", dict(ham="eggs")) 126 {'an': {'spam': {'ham': 'eggs'}}} 127 """ 128 return {"an": {identifier: attributes}} 129
130 - def get_add_edge_event(self, identifier, source, target, directed, attributes={}):
131 """Generates a Python object corresponding to the event that adds an edge 132 with the given source, target, directednessr and attributes in the Gephi 133 graph streaming API. 134 """ 135 result = dict(attributes) 136 result["source"] = source 137 result["target"] = target 138 result["directed"] = bool(directed) 139 return {"ae": {identifier: result}} 140
141 - def get_change_node_event(self, identifier, attributes):
142 """Generates a Python object corresponding to the event that changes the 143 attributes of some node in the Gephi graph streaming API. The given attributes 144 are merged into the existing ones; use C{None} as the attribute value to 145 delete a given attribute. 146 147 Example:: 148 149 >>> api = GephiGraphStreamingAPIFormat() 150 >>> api.get_change_node_event("spam", dict(ham="eggs")) 151 {'cn': {'spam': {'ham': 'eggs'}}} 152 >>> api.get_change_node_event("spam", dict(ham=None)) 153 {'cn': {'spam': {'ham': None}}} 154 """ 155 return {"cn": {identifier: attributes}} 156
157 - def get_change_edge_event(self, identifier, attributes):
158 """Generates a Python object corresponding to the event that changes the 159 attributes of some edge in the Gephi graph streaming API. The given attributes 160 are merged into the existing ones; use C{None} as the attribute value to 161 delete a given attribute. 162 163 Example:: 164 165 >>> api = GephiGraphStreamingAPIFormat() 166 >>> api.get_change_edge_event("spam", dict(ham="eggs")) 167 {'ce': {'spam': {'ham': 'eggs'}}} 168 >>> api.get_change_edge_event("spam", dict(ham=None)) 169 {'ce': {'spam': {'ham': None}}} 170 """ 171 return {"ce": {identifier: attributes}} 172
173 - def get_delete_node_event(self, identifier):
174 """Generates a Python object corresponding to the event that deletes a 175 node with the given identifier in the Gephi graph streaming API. 176 177 Example:: 178 179 >>> api = GephiGraphStreamingAPIFormat() 180 >>> api.get_delete_node_event("spam") 181 {'dn': {'spam': {}}} 182 """ 183 return {"dn": {identifier: {}}} 184
185 - def get_delete_edge_event(self, identifier):
186 """Generates a Python object corresponding to the event that deletes an 187 edge with the given identifier in the Gephi graph streaming API. 188 189 Example:: 190 191 >>> api = GephiGraphStreamingAPIFormat() 192 >>> api.get_delete_edge_event("spam:ham") 193 {'de': {'spam:ham': {}}} 194 """ 195 return {"de": {identifier: {}}}
196
197 198 -class GephiGraphStreamer(object):
199 """Class that produces JSON event objects that stream an igraph graph to 200 Gephi using the Gephi Graph Streaming API. 201 202 The Gephi graph streaming format is a simple JSON-based format that can be used 203 to post mutations to a graph (i.e. node and edge additions, removals and updates) 204 to a remote component. For instance, one can open up Gephi (http://www.gephi.org}), 205 install the Gephi graph streaming plugin and then send a graph from igraph 206 straight into the Gephi window by using `GephiGraphStreamer` with the 207 appropriate URL where Gephi is listening. 208 209 Example:: 210 211 >>> from cStringIO import StringIO 212 >>> from igraph import Graph 213 >>> buf = StringIO() 214 >>> streamer = GephiGraphStreamer() 215 >>> graph = Graph.Formula("A --> B, B --> C") 216 >>> streamer.post(graph, buf) 217 >>> print buf.getvalue() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE 218 {"an": {"igraph:...:v:0": {"name": "A"}}} 219 {"an": {"igraph:...:v:1": {"name": "B"}}} 220 {"an": {"igraph:...:v:2": {"name": "C"}}} 221 {"ae": {"igraph:...:e:0:1": {...}}} 222 {"ae": {"igraph:...:e:1:2": {...}}} 223 <BLANKLINE> 224 225 """ 226
227 - def __init__(self, encoder=None):
228 """Constructs a Gephi graph streamer that will post graphs to a 229 given file-like object or a Gephi connection. 230 231 `encoder` must either be ``None`` or an instance of ``json.JSONEncoder`` 232 and it must contain the JSON encoder to be used when posting JSON objects. 233 """ 234 self.encoder = encoder or json.JSONEncoder(ensure_ascii=True) 235 self.format = GephiGraphStreamingAPIFormat() 236
237 - def iterjsonobj(self, graph):
238 """Iterates over the JSON objects that build up the graph using the Gephi 239 graph streaming API. The objects returned from this function are Python 240 objects; they must be formatted with ``json.dumps`` before sending them 241 to the destination.""" 242 243 # Construct a unique ID prefix 244 id_prefix = "igraph:%s" % (hex(id(graph)), ) 245 246 # Add the vertices 247 add_node = self.format.get_add_node_event 248 for vertex in graph.vs: 249 yield add_node("%s:v:%d" % (id_prefix, vertex.index), vertex.attributes()) 250 251 # Add the edges 252 add_edge = self.format.get_add_edge_event 253 directed = graph.is_directed() 254 for edge in graph.es: 255 yield add_edge("%s:e:%d:%d" % (id_prefix, edge.source, edge.target), 256 "%s:v:%d" % (id_prefix, edge.source), 257 "%s:v:%d" % (id_prefix, edge.target), 258 directed, edge.attributes()) 259
260 - def post(self, graph, destination, encoder=None):
261 """Posts the given graph to the destination of the streamer using the 262 given JSON encoder. When `encoder` is ``None``, it falls back to the default 263 JSON encoder of the streamer in the `encoder` property. 264 265 `destination` must be a file-like object or an instance of `GephiConnection`. 266 """ 267 encoder = encoder or self.encoder 268 for jsonobj in self.iterjsonobj(graph): 269 self.send_event(jsonobj, destination, encoder=encoder, flush=False) 270 destination.flush() 271
272 - def send_event(self, event, destination, encoder=None, flush=True):
273 """Sends a single JSON event to the given destination using the given 274 JSON encoder. When `encoder` is ``None``, it falls back to the default 275 JSON encoder of the streamer in the `encoder` property. 276 277 `destination` must be a file-like object or an instance of `GephiConnection`. 278 279 The method flushes the destination after sending the event. If you want to 280 avoid this (e.g., because you are sending many events), set `flush` to 281 ``False``. 282 """ 283 encoder = encoder or self.encoder 284 destination.write(encoder.encode(event)) 285 destination.write("\r\n") 286 if flush: 287 destination.flush()
288

   Home       Trees       Indices       Help