python-igraph manual

For using igraph from Python

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

Source Code for Module igraph.utils

  1  # vim:ts=4:sw=4:sts=4:et 
  2  # -*- coding: utf-8 -*- 
  3  """Utility functions that cannot be categorised anywhere else. 
  4   
  5  @undocumented: _is_running_in_ipython 
  6  """ 
  7   
  8  from contextlib import contextmanager 
  9  from collections import MutableMapping 
 10  from itertools import chain 
 11   
 12  import os 
 13  import tempfile 
 14   
 15  __all__ = ["dbl_epsilon", "multidict", "named_temporary_file", "rescale", \ 
 16          "safemin", "safemax"] 
 17  __docformat__ = "restructuredtext en" 
 18  __license__ = u"""\ 
 19  Copyright (C) 2006-2012  Tamás Nepusz <ntamas@gmail.com> 
 20  Pázmány Péter sétány 1/a, 1117 Budapest, Hungary 
 21   
 22  This program is free software; you can redistribute it and/or modify 
 23  it under the terms of the GNU General Public License as published by 
 24  the Free Software Foundation; either version 2 of the License, or 
 25  (at your option) any later version. 
 26   
 27  This program is distributed in the hope that it will be useful, 
 28  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 29  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 30  GNU General Public License for more details. 
 31   
 32  You should have received a copy of the GNU General Public License 
 33  along with this program; if not, write to the Free Software 
 34  Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA 
 35  02110-1301 USA 
 36  """ 
39 """Internal function that determines whether igraph is running inside 40 IPython or not.""" 41 try: 42 # get_ipython is injected into the Python builtins by IPython so 43 # this should succeed in IPython but throw a NameError otherwise 44 get_ipython 45 return True 46 except NameError: 47 return False 48
49 50 @contextmanager 51 -def named_temporary_file(*args, **kwds):
52 """Context manager that creates a named temporary file and 53 returns its name. 54 55 All parameters are passed on to ``tempfile.mkstemp``, see 56 its documentation for more info. 57 """ 58 handle, tmpfile = tempfile.mkstemp(*args, **kwds) 59 os.close(handle) 60 try: 61 yield tmpfile 62 finally: 63 os.unlink(tmpfile) 64
65 -def rescale(values, out_range = (0., 1.), in_range = None, clamp = False, 66 scale = None):
67 """Rescales a list of numbers into a given range. 68 69 `out_range` gives the range of the output values; by default, the minimum 70 of the original numbers in the list will be mapped to the first element 71 in the output range and the maximum will be mapped to the second element. 72 Elements between the minimum and maximum values in the input list will be 73 interpolated linearly between the first and second values of the output 74 range. 75 76 `in_range` may be used to override which numbers are mapped to the first 77 and second values of the output range. This must also be a tuple, where 78 the first element will be mapped to the first element of the output range 79 and the second element to the second. 80 81 If `clamp` is ``True``, elements which are outside the given `out_range` 82 after rescaling are clamped to the output range to ensure that no number 83 will be outside `out_range` in the result. 84 85 If `scale` is not ``None``, it will be called for every element of `values` 86 and the rescaling will take place on the results instead. This can be used, 87 for instance, to transform the logarithm of the original values instead of 88 the actual values. A typical use-case is to map a range of values to color 89 identifiers on a logarithmic scale. Scaling also applies to the `in_range` 90 parameter if present. 91 92 Examples: 93 94 >>> rescale(range(5), (0, 8)) 95 [0.0, 2.0, 4.0, 6.0, 8.0] 96 >>> rescale(range(5), (2, 10)) 97 [2.0, 4.0, 6.0, 8.0, 10.0] 98 >>> rescale(range(5), (0, 4), (1, 3)) 99 [-2.0, 0.0, 2.0, 4.0, 6.0] 100 >>> rescale(range(5), (0, 4), (1, 3), clamp=True) 101 [0.0, 0.0, 2.0, 4.0, 4.0] 102 >>> rescale([0]*5, (1, 3)) 103 [2.0, 2.0, 2.0, 2.0, 2.0] 104 >>> from math import log10 105 >>> rescale([1, 10, 100, 1000, 10000], (0, 8), scale=log10) 106 [0.0, 2.0, 4.0, 6.0, 8.0] 107 >>> rescale([1, 10, 100, 1000, 10000], (0, 4), (10, 1000), scale=log10) 108 [-2.0, 0.0, 2.0, 4.0, 6.0] 109 """ 110 if scale is not None: 111 values = [scale(value) for value in values] 112 113 if in_range is None: 114 mi, ma = min(values), max(values) 115 else: 116 mi, ma = in_range 117 if scale is not None: 118 mi, ma = scale(mi), scale(ma) 119 120 ratio = float(ma - mi) 121 if not ratio: 122 return [(out_range[0] + out_range[1]) / 2.] * len(values) 123 124 min_out, max_out = map(float, out_range) 125 ratio = (max_out - min_out) / ratio 126 result = [(x - mi) * ratio + min_out for x in values] 127 128 if clamp: 129 return [max(min(x, max_out), min_out) for x in result] 130 else: 131 return result 132
133 -def str_to_orientation(value, reversed_horizontal=False, reversed_vertical=False):
134 """Tries to interpret a string as an orientation value. 135 136 The following basic values are understood: ``left-right``, ``bottom-top``, 137 ``right-left``, ``top-bottom``. Possible aliases are: 138 139 - ``horizontal``, ``horiz``, ``h`` and ``lr`` for ``left-right`` 140 141 - ``vertical``, ``vert``, ``v`` and ``tb`` for top-bottom. 142 143 - ``lr`` for ``left-right``. 144 145 - ``rl`` for ``right-left``. 146 147 ``reversed_horizontal`` reverses the meaning of ``horizontal``, ``horiz`` 148 and ``h`` to ``rl`` (instead of ``lr``); similarly, ``reversed_vertical`` 149 reverses the meaning of ``vertical``, ``vert`` and ``v`` to ``bt`` 150 (instead of ``tb``). 151 152 Returns one of ``lr``, ``rl``, ``tb`` or ``bt``, or throws ``ValueError`` 153 if the string cannot be interpreted as an orientation. 154 """ 155 156 aliases = {"left-right": "lr", "right-left": "rl", "top-bottom": "tb", 157 "bottom-top": "bt", "top-down": "tb", "bottom-up": "bt", 158 "top-bottom": "tb", "bottom-top": "bt", "td": "tb", "bu": "bt"} 159 160 dir = ["lr", "rl"][reversed_horizontal] 161 aliases.update(horizontal=dir, horiz=dir, h=dir) 162 163 dir = ["tb", "bt"][reversed_vertical] 164 aliases.update(vertical=dir, vert=dir, v=dir) 165 166 result = aliases.get(value, value) 167 if result not in ("lr", "rl", "tb", "bt"): 168 raise ValueError("unknown orientation: %s" % result) 169 return result 170
171 172 -def consecutive_pairs(iterable, circular=False):
173 """Returns consecutive pairs of items from the given iterable. 174 175 When `circular` is ``True``, the pair consisting of the last 176 and first elements is also returned. 177 178 Example: 179 180 >>> list(consecutive_pairs(range(5))) 181 [(0, 1), (1, 2), (2, 3), (3, 4)] 182 >>> list(consecutive_pairs(range(5), circular=True)) 183 [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] 184 >>> list(consecutive_pairs([])) 185 [] 186 >>> list(consecutive_pairs([], circular=True)) 187 [] 188 >>> list(consecutive_pairs([0])) 189 [] 190 >>> list(consecutive_pairs([0], circular=True)) 191 [(0, 0)] 192 """ 193 it = iter(iterable) 194 195 try: 196 prev = it.next() 197 except StopIteration: 198 return 199 first = prev 200 201 for item in it: 202 yield prev, item 203 prev = item 204 205 if circular: 206 try: 207 yield item, first 208 except UnboundLocalError: 209 yield first, first 210
211 -class multidict(MutableMapping):
212 """A dictionary-like object that is customized to deal with multiple 213 values for the same key. 214 215 Each value in this dictionary will be a list. Methods which emulate 216 the methods of a standard Python `dict` object will return or manipulate 217 the first items of the lists only. Special methods are provided to 218 deal with keys having multiple values. 219 """ 220
221 - def __init__(self, *args, **kwds):
222 self._dict = {} 223 if len(args) > 1: 224 raise ValueError("%r expected at most 1 argument, got %d" % \ 225 (self.__class__.__name__, len(args))) 226 if args: 227 args = args[0] 228 self.update(args) 229 self.update(kwds) 230
231 - def __contains__(self, key):
232 """Returns whether there are any items associated to the given `key`.""" 233 try: 234 return len(self._dict[key]) > 0 235 except KeyError: 236 return False 237
238 - def __delitem__(self, key):
239 """Removes all the items associated to the given `key`.""" 240 del self._dict[key] 241
242 - def __getitem__(self, key):
243 """Returns an arbitrary item associated to the given key. Raises ``KeyError`` 244 if no such key exists. 245 246 Example: 247 248 >>> d = multidict([("spam", "eggs"), ("spam", "bacon")]) 249 >>> d["spam"] 250 'eggs' 251 """ 252 try: 253 return self._dict[key][0] 254 except IndexError: 255 raise KeyError(key) 256
257 - def __iter__(self):
258 """Iterates over the keys of the multidict.""" 259 return iter(self._dict) 260
261 - def __len__(self):
262 """Returns the number of distinct keys in this multidict.""" 263 return len(self._dict) 264
265 - def __setitem__(self, key, value):
266 """Sets the item associated to the given `key`. Any values associated to the 267 key will be erased and replaced by `value`. 268 269 Example: 270 271 >>> d = multidict([("spam", "eggs"), ("spam", "bacon")]) 272 >>> d["spam"] = "ham" 273 >>> d["spam"] 274 'ham' 275 """ 276 self._dict[key] = [value] 277
278 - def add(self, key, value):
279 """Adds `value` to the list of items associated to `key`. 280 281 Example: 282 283 >>> d = multidict() 284 >>> d.add("spam", "ham") 285 >>> d["spam"] 286 'ham' 287 >>> d.add("spam", "eggs") 288 >>> d.getlist("spam") 289 ['ham', 'eggs'] 290 """ 291 try: 292 self._dict[key].append(value) 293 except KeyError: 294 self._dict[key] = [value] 295
296 - def clear(self):
297 """Removes all the items from the multidict.""" 298 self._dict.clear() 299
300 - def get(self, key, default=None):
301 """Returns an arbitrary item associated to the given `key`. If `key` 302 does not exist or has zero associated items, `default` will be 303 returned.""" 304 try: 305 items = self._dict[key] 306 return items[0] 307 except (KeyError, IndexError): 308 return default 309
310 - def getlist(self, key):
311 """Returns the list of values for the given `key`. An empty list will 312 be returned if there is no such key.""" 313 try: 314 return self._dict[key] 315 except KeyError: 316 return [] 317
318 - def iterlists(self):
319 """Iterates over ``(key, values)`` pairs where ``values`` is the list 320 of values associated with ``key``.""" 321 return self._dict.iteritems() 322
323 - def lists(self):
324 """Returns a list of ``(key, values)`` pairs where ``values`` is the list 325 of values associated with ``key``.""" 326 return self._dict.items() 327
328 - def update(self, arg, **kwds):
329 if hasattr(arg, "keys") and callable(arg.keys): 330 for key in arg.keys(): 331 self.add(key, arg[key]) 332 else: 333 for key, value in arg: 334 self.add(key, value) 335 for key, value in kwds.iteritems(): 336 self.add(key, value)
337
338 -def safemax(iterable, default=0):
339 """Safer variant of ``max()`` that returns a default value if the iterable 340 is empty. 341 342 Example: 343 344 >>> safemax([-5, 6, 4]) 345 6 346 >>> safemax([]) 347 0 348 >>> safemax((), 2) 349 2 350 """ 351 it = iter(iterable) 352 try: 353 first = it.next() 354 except StopIteration: 355 return default 356 else: 357 return max(chain([first], it)) 358
359 -def safemin(iterable, default=0):
360 """Safer variant of ``min()`` that returns a default value if the iterable 361 is empty. 362 363 Example: 364 365 >>> safemin([-5, 6, 4]) 366 -5 367 >>> safemin([]) 368 0 369 >>> safemin((), 2) 370 2 371 """ 372 it = iter(iterable) 373 try: 374 first = it.next() 375 except StopIteration: 376 return default 377 else: 378 return min(chain([first], it)) 379
380 -def dbl_epsilon():
381 """Approximates the machine epsilon value for doubles.""" 382 epsilon = 1.0 383 while 1.0 + epsilon / 2.0 != 1.0: 384 epsilon /= 2 385 return epsilon 386 387 dbl_epsilon = dbl_epsilon() 388

   Home       Trees       Indices       Help