log-to-heatmap.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #! /usr/bin/env python
  2. import json
  3. import os
  4. import sys
  5. import re
  6. from math import floor
  7. cr_coord_map = [
  8. [
  9. # Row 0
  10. [ 4, 0], [ 4, 2], [ 2, 0], [ 1, 0], [ 2, 2], [ 3, 0], [ 3, 2],
  11. [ 3, 4], [ 3, 6], [ 2, 4], [ 1, 2], [ 2, 6], [ 4, 4], [ 4, 6],
  12. ],
  13. [
  14. # Row 1
  15. [ 8, 0], [ 8, 2], [ 6, 0], [ 5, 0], [ 6, 2], [ 7, 0], [ 7, 2],
  16. [ 7, 4], [ 7, 6], [ 6, 4], [ 5, 2], [ 6, 6], [ 8, 4], [ 8, 6],
  17. ],
  18. [
  19. # Row 2
  20. [12, 0], [12, 2], [10, 0], [ 9, 0], [10, 2], [11, 0], [ ],
  21. [ ], [11, 2], [10, 4], [ 9, 2], [10, 6], [12, 4], [12, 6],
  22. ],
  23. [
  24. # Row 3
  25. [17, 0], [17, 2], [15, 0], [14, 0], [15, 2], [16, 0], [13, 0],
  26. [13, 2], [16, 2], [15, 4], [14, 2], [15, 6], [17, 4], [17, 6],
  27. ],
  28. [
  29. # Row 4
  30. [20, 0], [20, 2], [19, 0], [18, 0], [19, 2], [], [], [], [],
  31. [19, 4], [18, 2], [19, 6], [20, 4], [20, 6],
  32. ],
  33. [
  34. # Row 5
  35. [ ], [23, 0], [22, 2], [22, 0], [22, 4], [21, 0], [21, 2],
  36. [24, 0], [24, 2], [25, 0], [25, 4], [25, 2], [26, 0], [ ],
  37. ],
  38. ]
  39. def set_attr_at(j, b, n, attr, fn, val):
  40. blk = j[b][n]
  41. if attr in blk:
  42. blk[attr] = fn(blk[attr], val)
  43. else:
  44. blk[attr] = fn(None, val)
  45. def coord(col, row):
  46. return cr_coord_map[row][col]
  47. def set_attr(orig, new):
  48. return new
  49. def set_bg(j, (b, n), color):
  50. set_attr_at(j, b, n, "c", set_attr, color)
  51. #set_attr_at(j, b, n, "g", set_attr, False)
  52. def _set_tap_info(o, count, cap):
  53. ns = 4 - o.count ("\n")
  54. return o + "\n" * ns + "%.02f%%" % (float(count) / float(cap) * 100)
  55. def set_tap_info(j, (b, n), count, cap):
  56. j[b][n + 1] = _set_tap_info (j[b][n + 1], count, cap)
  57. def heatmap_color (v):
  58. colors = [ [0.3, 0.3, 1], [0.3, 1, 0.3], [1, 1, 0.3], [1, 0.3, 0.3]]
  59. fb = 0
  60. if v <= 0:
  61. idx1, idx2 = 0, 0
  62. elif v >= 1:
  63. idx1, idx2 = len(colors) - 1, len(colors) - 1
  64. else:
  65. val = v * (len(colors) - 1)
  66. idx1 = int(floor(val))
  67. idx2 = idx1 + 1
  68. fb = val - float(idx1)
  69. r = (colors[idx2][0] - colors[idx1][0]) * fb + colors[idx1][0]
  70. g = (colors[idx2][1] - colors[idx1][1]) * fb + colors[idx1][1]
  71. b = (colors[idx2][2] - colors[idx1][2]) * fb + colors[idx1][2]
  72. r, g, b = [x * 255 for x in r, g, b]
  73. return "#%02x%02x%02x" % (r, g, b)
  74. # Load the keylog
  75. def load_keylog(fname, restrict_row):
  76. keylog = {}
  77. total = 0
  78. with open(fname, "r") as f:
  79. lines = f.readlines()
  80. for line in lines:
  81. m = re.search ('KL: col=(\d+), row=(\d+)', line)
  82. if not m:
  83. continue
  84. (c, r) = (int(m.group (2)), int(m.group (1)))
  85. if restrict_row != None and r != int(restrict_row):
  86. continue
  87. if (c, r) in keylog:
  88. keylog[(c, r)] = keylog[(c, r)] + 1
  89. else:
  90. keylog[(c, r)] = 1
  91. total = total + 1
  92. return total / 2, keylog
  93. def l_flat(s):
  94. f = s.split("\n")
  95. return ", ".join (f)
  96. def main(base_fn, log_fn, restrict_row = None):
  97. with open(base_fn, "r") as f:
  98. layout = json.load (f)
  99. ## Reset colors
  100. for row in cr_coord_map:
  101. for col in row:
  102. if col != []:
  103. set_bg (layout, col, "#d9dae0")
  104. #set_attr_at (layout, col[0], col[1], "g", set_attr, True)
  105. total, log = load_keylog (log_fn, restrict_row)
  106. max_cnt = 0
  107. for (c, r) in log:
  108. max_cnt = max(max_cnt, log[(c, r)])
  109. # Create the heatmap
  110. for (c, r) in log:
  111. coords = coord(c, r)
  112. b, n = coords
  113. cap = max_cnt
  114. v = float(log[(c, r)]) / cap
  115. print >> sys.stderr, "%s => %d/%d => %f = %s" % (l_flat(layout[b][n+1]), log[(c,r)], cap, v, heatmap_color(v))
  116. set_bg (layout, coord(c, r), heatmap_color (v))
  117. set_tap_info (layout, coord (c, r), log[(c, r)], total)
  118. print json.dumps(layout)
  119. if __name__ == "__main__":
  120. if len(sys.argv) < 3:
  121. print """Log to Heatmap -- creates a heatmap out of keyboard logs
  122. Usage: log-to-heatmap.py base-layout.json logfile [row] >layout.json"""
  123. sys.exit (1)
  124. main(*sys.argv[1:])