PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/nubox/src/nubox/util.py

https://code.google.com/p/nubox/
Python | 394 lines | 261 code | 8 blank | 125 comment | 3 complexity | 96983e34e954fd794f76febc7596cdf6 MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. """
  3. :mod:`nubox.util`
  4. =================
  5. Provides utility functions used within ``nubox``.
  6. """
  7. from __future__ import (division, with_statement, absolute_import, generators,
  8. nested_scopes)
  9. from math import floor
  10. from .shim import (xrange, product, izip, bytes)
  11. from .const import (TYPE_TO_TYPECODE, TYPECODES, ARRAY_TYPECODES, INT_TYPECODES,
  12. FLOAT_TYPECODES, UNICODE_TYPECODES, OBJECT_TYPECODES)
  13. def gettype(item):
  14. """
  15. Determines the ``type`` and typecode of an **item**. Returns a ``tuple``
  16. with a Python ``type`` or ``class`` and itemcode ``str``.
  17. Arguments:
  18. - item(``object``) an **item** to be placed in an ``NdArray``
  19. """
  20. item_type = type(item)
  21. try:
  22. item_typecode = TYPE_TO_TYPECODE[item_type]
  23. except KeyError:
  24. item_typecode = OBJECT_TYPECODES[0]
  25. return (item_type, item_typecode)
  26. def compatypecodes(typecodes):
  27. """
  28. Determines if an iterable of typecodes is represents the same Python
  29. ``type``. Returns a ``bool``. Typecodes that resolve to the same ``type``
  30. are "compatible" and generally can be stored in the same array without loss.
  31. Arguments:
  32. - typecodes(sequence) a sequence of typecodes from most likely from
  33. ``nubox.const.TYPECODES``
  34. """
  35. all_tc = len(typecodes)
  36. for cls in (INT_TYPECODES, FLOAT_TYPECODES, UNICODE_TYPECODES,
  37. OBJECT_TYPECODES):
  38. if len([tc for tc in typecodes if tc in cls]) == all_tc:
  39. return True
  40. return False
  41. def checktypecode(typecode):
  42. """
  43. Determines ``bool`` values of typecode properties returns a ``tuple`` of
  44. ``(istc, isatc, isutc, isotc, isftc, isitc)``, where:
  45. - ``istc`` is any valid typecode
  46. - ``isatc`` is an ``array`` typecode (valid for ``array.array`` instances)
  47. - ``isutc`` is an ``unicode`` typecode
  48. - ``isotc`` is an ``object`` typecode
  49. - ``isftc`` is a ``float`` typecode
  50. - ``isitc`` is an ``int`` or ``long`` typecode
  51. Arguments:
  52. - typecode(``str``) A single character identifying the typecode most
  53. likely one of ``nubox.const.TYPECODES``
  54. """
  55. istc = typecode in TYPECODES
  56. isatc = typecode in ARRAY_TYPECODES
  57. isutc = typecode in UNICODE_TYPECODES
  58. isotc = typecode in OBJECT_TYPECODES
  59. isftc = typecode in FLOAT_TYPECODES
  60. isitc = typecode in INT_TYPECODES
  61. return (istc, isatc, isutc, isotc, isftc, isitc)
  62. def checkitem(item):
  63. """
  64. Determines **item** properties and returns ``bool`` values. Returns a
  65. ``tuple`` of ``(isiterable, isarray, isarrayitem, islistitem)``, where:
  66. - ``isatomic`` is ``True`` if **item** is atomic i.e. not a container
  67. - ``isiterable`` is ``True`` if **item** is an iterable
  68. - ``isarray`` is ``True`` if **item** is an ``array.array`` instance
  69. - ``isarrayitem`` is ``True`` if **item** can be an ``array.array``
  70. **item**
  71. - ``islistitem`` is ``True`` if **item** can be a ``list`` **item**
  72. Arguments:
  73. - item(``object``) an **item** to be placed in an ``NdArray``
  74. """
  75. item_type, item_typecode = gettype(item)
  76. try:
  77. iter(item)
  78. isiterable = True
  79. if (item_type in (bytes, unicode)) and (len(item) == 1): # str or unicode
  80. isatomic = True
  81. else:
  82. isatomic = False
  83. except TypeError:
  84. isiterable = False
  85. isatomic = True
  86. isarray = hasattr(item_type, '_kwargs') and hasattr(item_type, 'data')
  87. if item_typecode in ARRAY_TYPECODES:
  88. isarrayitem = True
  89. islistitem = True
  90. elif item_typecode in TYPECODES:
  91. isarrayitem = False
  92. islistitem = True
  93. else:
  94. isarrayitem = False
  95. islistitem = False
  96. return (isatomic, isiterable, isarray, isarrayitem, islistitem)
  97. def flatten(l):
  98. """
  99. Flattens a ``list`` or ``tuple``. Returns a ``list`` with all elements.
  100. Arguments:
  101. - l(sequence) A possibly nested ``list`` or ``tuple`` of elements
  102. """
  103. if isinstance(l, (list, tuple)):
  104. return sum(map(flatten, l), [])
  105. else:
  106. return [l]
  107. def unnest(l):
  108. """
  109. For a given iterable of iterables returns a ``list``, which contains all
  110. sub-sequences in a depth-first manner. For example given a nested iterable:
  111. ``[(1, 2, 3), (3, (4, 5))]`` it returns: ``[[(1, 2, 3), (3, (4, 5))],
  112. (1, 2, 3), 1, 2, 3, (3, (4, 5)), 3, (4, 5), 4, 5]``.
  113. Arguments:
  114. - l(sequence) A possibly nested ``list`` or ``tuple`` of elements
  115. """
  116. u = []
  117. u.append(l)
  118. if isinstance(l, (list, tuple)):
  119. for e in l:
  120. u.extend(unnest(e))
  121. return u
  122. def slices_shape2indices_shape(slices, shape):
  123. """
  124. Translates and iterable of ``slice`` instances and the corresponding "shape"
  125. i.e. lengths of each dimension into a ``tuple`` of indices and a new shape.
  126. This function de facto implements an nD-slice.
  127. Arguments:
  128. - slices(iterable of ``slice``) a sequence of ``slice`` instances
  129. - shape(``tuple``) a sequence of dimensions i.e. lengths for each of the
  130. ``slices``.
  131. """
  132. if len(slices) != len(shape):
  133. raise ValueError("number of slices must match shape")
  134. nd_indices = []
  135. nd_shape = []
  136. for dim, slice in izip(shape, slices):
  137. sss = slice.indices(dim) # start,stop,step obeying len
  138. indices = range(*sss) # this -> [] if sss is an empty slice
  139. dim = len(indices)
  140. nd_indices.append(indices)
  141. nd_shape.append(dim)
  142. nd_indices = tuple(product(*nd_indices))
  143. nd_shape = tuple(nd_shape) if nd_indices else () # at least on 0 in nd_shape
  144. return (nd_indices, tuple(nd_shape))
  145. def hex_to_rgb(value):
  146. """
  147. Converts a hex ``string`` into a RGB ``tuple``.
  148. Arguments:
  149. - value(``str``) A ``string`` representation of a hexadecimal
  150. number.
  151. """
  152. value = value.lstrip('#')
  153. lv = len(value)
  154. return tuple(int(value[i:i + int(lv / 3)], 16) for i in range(0, lv, int(lv / 3)))
  155. def rgb_to_hex(rgb):
  156. """
  157. Converts a RGB ``sequence`` into a hex ``string``.
  158. Arguments:
  159. - rgb(sequence) A sequence of ``int`` in the 0-255 range.
  160. """
  161. return '#%02x%02x%02x' % rgb
  162. def make_colors(breakpoints, length=240):
  163. """
  164. Creates a linear color map given RGB "breakpoints". Returns an array of
  165. colors of specified "length". A breakpoint is any RGB color-tuple. By
  166. default returns an array valid for ``hijack_colors``.
  167. Arguments:
  168. - breakpoints (sequence) A sequence of ``tuples`` of RGB values
  169. each RGB value is a floating point number from ``0.`` to ``1.``.
  170. - length(``int``) [default: ``240``] The number of colors in the returned
  171. ``list``
  172. """
  173. ln = len(breakpoints)
  174. rng = floor(length / (ln - 1)) #
  175. if ln < 2:
  176. raise ValueError('at least 2 breakpoints required')
  177. breakids = []
  178. for i in xrange(0, ln):
  179. breakids.append(int(length * (i) / float(ln - 1)))
  180. # we have a dynamic range of 240
  181. colors = []
  182. for start in xrange(ln - 1):
  183. lor, log, lob = breakpoints[start]
  184. hir, hig, hib = breakpoints[start + 1]
  185. for id_ in xrange(*breakids[start:start + 2]):
  186. r = (id_ % (rng)) / float(rng) # linear space
  187. clr = [hir * r + lor * (1 - r),
  188. hig * r + log * (1 - r),
  189. hib * r + lob * (1 - r)]
  190. colors.append(clr)
  191. return colors
  192. #
  193. #def hijack_colors(colors):
  194. # """
  195. # Sets the 240 i.e. 256 - 16 available colors of a terminal to RGB values in
  196. # "colors". Colors should be a sequence of tuples or a rank-2
  197. # ``numpy.ndarray``.
  198. #
  199. # Arguments:
  200. #
  201. # - colors (``sequence`` or ``numpy.ndarray``) A sequence of 240 RGB
  202. # 3-tuples.
  203. # """
  204. # if len(colors) != 240:
  205. # raise ValueError("Array has to be of length 240.")
  206. # init = ''
  207. # for i, (r, g, b) in enumerate(colors):
  208. # init += "\x1b]4;%d;rgb:%02x/%02x/%02x\x1b\\" % \
  209. # (16 + i, int(r * 255), int(g * 255), int(b * 255))
  210. # init += '\n'
  211. # sys.stdout.write(init)
  212. #
  213. #def print_array(array, colors=None):
  214. # """
  215. # Prints an "array" to ``sys.stdout``. The color map is given by "colors".
  216. # Custom color maps can be constructed by the ``make_colors`` function.
  217. #
  218. # Arguments:
  219. #
  220. # - array (``numpy.ndarray``) Any array which makes sense viewed as
  221. # ``float``.
  222. # - colors (``sequence``) [default: ``COLDHOT``] See: ``make_colors`` and
  223. # ``hijack_colors``
  224. #
  225. # """
  226. # if array.typecode not in FLOAT_TYPECODES:
  227. # raise ValueError('array must be of float typecode')
  228. # if len(array.shape) != 3:
  229. # raise ValueError('array must be of rank-3')
  230. # colors = colors or COLDHOT
  231. # hijack_colors(colors)
  232. # # shift to positive
  233. # min_ = array.item_min()[0]
  234. # max_ = array.item_max()[0]
  235. # # normalize array to 0-1
  236. # norm_array = array.new()
  237. # norm_array.map_item('sub', min_)
  238. # norm_array.map_item('div', max_)
  239. # data = []
  240. # for row in norm_array.child_iter_fast():
  241. # for el in row.child_iter_fast():
  242. # clr_idx = int(el.data[0] * 239) + 16
  243. # assert clr_idx < 256
  244. # data.append("\x1b[48;5;%dm " % clr_idx)
  245. # data.append('\x1b[0m \n')
  246. # sys.stdout.write("".join(data))
  247. #def make_ruler(length, major=(20, '|'), minor=(10, '.')):
  248. # """
  249. # Constructs a ruler like that::
  250. #
  251. # # |---------.---------|-------
  252. # # 0 20
  253. #
  254. # Allows to specify the distance and character of minor/major ticks. Returns
  255. # two strings for the ruler and for the numbers corresponding to major ticks.
  256. #
  257. # Arguments:
  258. #
  259. # - length (``int``) length of the constructed ruler
  260. # - major (``tuple``) [default: (10, '.')] A tuple of the form
  261. # ``(N, 'X')``, where N is an integer, which means that a major-tick of
  262. # character 'X' will be placed every N symbols starting and including 0.
  263. # - minor (``tuple``) [default: (10, '.')] A tuple of the form
  264. # ``(M, 'Y')``, where M is an integer, which means that a minor-tick of
  265. # character 'Y' will be placed every M symbols, but only where no
  266. # major-tick is placed.
  267. # """
  268. # ruler = []
  269. # value = []
  270. # for pos in range(length):
  271. # if not pos % major[0]:
  272. # ruler.append('|')
  273. # s = "%" + ("-%ss" % major[0])
  274. # value.append(s % pos)
  275. # elif not pos % minor[0]:
  276. # ruler.append('.')
  277. # else:
  278. # ruler.append('-')
  279. # return ("".join(ruler), "".join(value))
  280. #def print_strings(strings, raw_strings=(), ruler=True, width=80, **kwargs):
  281. # """
  282. # Formats and prints strings wrapped to the specified "width" and interleaved.
  283. # Optionally a ruler is included.
  284. #
  285. # Arguments:
  286. #
  287. # - strings (``sequence``) A sequence of strings.
  288. # - raw_strings (``sequence``) A sequence of pre-wrapped
  289. # strings. A wrapped string is a sequence of strings of right length.
  290. # This is useful if string includes non-printable characters.
  291. # - ruler (``bool``) If ``True`` a ruler will be included *below* the
  292. # strings.
  293. # - width (``int``) The maximum width of the print-out.
  294. #
  295. # Additional keyworded arguments are passed to ``make_ruler``.
  296. # """
  297. # maxlen = max([len(string) for string in strings])
  298. # rul, num = make_ruler(maxlen, **kwargs)
  299. # wvals = []
  300. # for raw_seqs in raw_strings:
  301. # wvals.append(raw_seqs)
  302. # for seq in strings:
  303. # wvals.append(wrap(seq, width=width, break_on_hyphens=False))
  304. # if ruler:
  305. # wvals.append(wrap(rul, width=width, break_on_hyphens=False))
  306. # wvals.append(wrap(num, width=width, break_on_hyphens=False))
  307. #
  308. # for block in izip_longest(*wvals):
  309. # for part in block:
  310. # if part:
  311. # sys.stdout.write(part)
  312. # sys.stdout.write('\n')
  313. # sys.stdout.write('\n')
  314. GRAY = make_colors([
  315. (0., 0., 0.),
  316. (1., 1., 1.)
  317. ])
  318. COLDHOT = make_colors([
  319. (0.0, 0.0, 1.0),
  320. (0.0, 0.5, 1.0),
  321. (1.0, 1.0, 1.0),
  322. (1.0, 1.0, 0.0),
  323. (1.0, 0.0, 0.0)
  324. ])
  325. COLD = make_colors([
  326. (0.0, 0.0, 1.0),
  327. (0.5, 0.5, 1.0),
  328. (1.0, 1.0, 1.0)
  329. ])
  330. HOT = make_colors([
  331. (1.0, 1.0, 1.0),
  332. (1.0, 1.0, 0.0),
  333. (1.0, 0.0, 0.0)
  334. ])
  335. HEAT = make_colors([
  336. (0.0, 0.0, 0.0),
  337. (1.0, 0.0, 0.0),
  338. (1.0, 1.0, 0.0),
  339. (1.0, 1.0, 1.0)
  340. ])