plotter.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. import time
  2. import logging
  3. from datetime import datetime
  4. from collections import defaultdict
  5. from pylab import plt, date2num, title, axvline
  6. from matplotlib import dates
  7. import numpy as np
  8. from scipy.misc import pilutil
  9. from PIL import ImageDraw, Image, ImageFilter
  10. from intersect import Mesh2D
  11. from utils.objparser import Mesh
  12. from utils import pos2rgb
  13. from utils.tiles import createLog2Tiles
  14. log = logging.getLogger('lws')
  15. ## the plot functions are not threadsafe
  16. ## the locking has to be done at the call site
  17. def plotOptimizeRun(lines, destfile, xaxis='date', highlightmins=True):
  18. xaxis = ''
  19. currmin = 10**9
  20. freeparams = defaultdict(list)
  21. orgidx = []
  22. avgdeltas = []
  23. dts = []
  24. simsperhour = defaultdict(int)
  25. mins_idx = []
  26. for j, l in enumerate(lines):
  27. if j % 500 == 0:
  28. log.debug('processing line %s of %s' % (j, len(lines)))
  29. for i, e in enumerate(l.split()):
  30. if i == 0:
  31. dt = datetime.strptime(e, '%Y-%m-%dT%H:%M:%S')
  32. simsperhour[dt.day * 24 + dt.hour] += 1 # will break at months end
  33. dts.append(dt)
  34. elif e.startswith('gen:'):
  35. pass
  36. elif e.startswith('org:'):
  37. #~ orgidx.append(int(e[4:]))
  38. pass
  39. elif e.startswith('avg-delta:'):
  40. v = float(e[10:])
  41. avgdeltas.append(v)
  42. if v < currmin:
  43. if xaxis == 'date':
  44. mins_idx.append(dt)
  45. else:
  46. mins_idx.append(j)
  47. currmin = v
  48. else:
  49. name, values = e.split(':')
  50. if ',' in values:
  51. freeparams[name].append([float(v) for v in values.split(',')])
  52. else:
  53. freeparams[name].append(float(values))
  54. if xaxis == 'date':
  55. xs = date2num(dts)
  56. mins_idx = date2num(mins_idx)
  57. else:
  58. xs = range(len(lines))
  59. min_x, max_x = min(xs), max(xs)
  60. # HACK: FILTER DA-PARAMS
  61. freeparams = {k:v for k, v in freeparams.items() if not k.startswith('da/')}
  62. numcols = 3
  63. fig = plt.figure(figsize=(18, len(freeparams) * 3.0 / numcols)) # 20x15 inches
  64. numrows = (len(freeparams) + 2) / numcols + 1
  65. if len(xs) < 1000:
  66. POINT_SIZE = 5
  67. elif len(xs) < 10000:
  68. POINT_SIZE = 3
  69. else:
  70. POINT_SIZE = 2
  71. ax = fig.add_subplot(numrows, numcols, 1)
  72. if highlightmins:
  73. plotfunc = lambda ax: ax.scatter
  74. kwargs = dict(s=POINT_SIZE, alpha=0.8, linewidth=0)
  75. else:
  76. plotfunc = lambda ax: ax.plot
  77. kwargs = dict()
  78. ax.grid()
  79. plotfunc(ax)(xs, avgdeltas, color='blue', **kwargs)
  80. ax.set_xlim(min_x, max_x)
  81. if xaxis == 'date':
  82. ax.xaxis_date()
  83. ax.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
  84. for xtl in ax.get_xticklabels():
  85. xtl.set_fontsize(8)
  86. title('average delta' )
  87. if highlightmins:
  88. for m in mins_idx:
  89. axvline(m, color='black', linewidth=0.5)
  90. ax = fig.add_subplot(numrows, numcols, 2)
  91. xs_h, ys = zip(*list(sorted(simsperhour.items())))
  92. ax.grid()
  93. m = min(xs_h)
  94. ax.bar([x - m for x in xs_h], ys)
  95. title('sims per hour (all aps)')
  96. for i, (name, values) in enumerate(sorted(freeparams.items()), 1):
  97. ax = fig.add_subplot(numrows, numcols, 2 + i)
  98. ax.grid()
  99. ax.set_xlim(min_x, max_x)
  100. if name.startswith('da/'):
  101. plotfunc(ax)(xs, values, **kwargs)
  102. if name.startswith('n/'):
  103. plotfunc(ax)(xs, values, **kwargs)
  104. elif isinstance(values[0], float): # it's a power value
  105. ax.set_yscale('log')
  106. plotfunc(ax)(xs, values, **kwargs)
  107. ax.set_ylim(min(values)*0.5, max(values)*2)
  108. else:
  109. reflect, alpha = zip(*values)
  110. plotfunc(ax)(xs, reflect, color='blue', **kwargs)
  111. plotfunc(ax)(xs, alpha, color='green', **kwargs)
  112. ax.set_ylim(0, 1)
  113. if xaxis == 'date':
  114. ax.xaxis_date()
  115. ax.xaxis.set_major_formatter(dates.DateFormatter('%H:%M'))
  116. for xtl in ax.get_xticklabels():
  117. xtl.set_fontsize(8)
  118. title(name, y=0.95, fontsize=10, backgroundcolor='#EFEFEF')
  119. if highlightmins:
  120. for m in mins_idx:
  121. axvline(m, color='black', linewidth=0.5, alpha=0.6)
  122. fig.subplots_adjust(bottom=0.05, left=0.03, right=0.99, top=0.98)
  123. fig.savefig(destfile, format='png', dpi=90)
  124. plt.close(fig)
  125. def plotSimulatorStats(lines, destfile):
  126. LAST_HOURS = 12
  127. fig = plt.figure(figsize=(18, 12))
  128. xs = []
  129. waiting = []
  130. running = []
  131. finished = []
  132. last_waiting = 0
  133. generations = defaultdict(int)
  134. simulations = defaultdict(int)
  135. for l in lines:
  136. data = l.split()
  137. ts = float(data[1])
  138. if time.time() - ts > LAST_HOURS * 3600:
  139. continue
  140. dt = datetime.fromtimestamp(ts)
  141. curr_hour = dt.replace(minute=0, second=0, microsecond=0)
  142. xs.append(dt)
  143. w = int(data[3])
  144. waiting.append(w)
  145. if w > last_waiting:
  146. generations[curr_hour] += 1
  147. last_waiting = w
  148. simulations[curr_hour] += 1
  149. running.append(int(data[5]))
  150. finished.append(int(data[7]))
  151. xs = date2num(xs)
  152. for i, (datadict, name) in enumerate(((generations, 'generations/hour'), (simulations, 'simulations/hour')), 1):
  153. ax = fig.add_subplot(5, 1, i)
  154. ax.xaxis_date()
  155. _xs = date2num(datadict.keys())
  156. ax.set_xlim(min(_xs), max(_xs)+1/24.0)
  157. ax.bar(_xs, datadict.values(), [1/24.0]*len(_xs))
  158. title(name, y=0.95, fontsize=10, backgroundcolor='#EFEFEF')
  159. for i, (name, ys) in enumerate([('waiting', waiting), ('running', running), ('finished', finished)], 3):
  160. ax = fig.add_subplot(5, 1, i)
  161. ax.set_xlim(min(xs), max(xs))
  162. ax.plot(xs, ys)
  163. ax.xaxis_date()
  164. title(name, y=0.95, fontsize=10, backgroundcolor='#EFEFEF')
  165. fig.subplots_adjust(bottom=0.05, left=0.03, right=0.99, top=0.98)
  166. fig.savefig(destfile, format='png', dpi=90)
  167. plt.close(fig)
  168. def plot2DMapAPData(lws, activeSceneCfg, env, apid):
  169. x1, x2, y1, y2, z1, z2 = activeSceneCfg['bbox']
  170. pixel_per_meter = activeSceneCfg['2dpixelpermeter']
  171. width = int((x2 - x1) * pixel_per_meter) * 8
  172. height = int((y2 - y1) * pixel_per_meter) * 8
  173. cube_size = int(0.2 * pixel_per_meter * 8) # in mapspace
  174. img = Image.new('RGBA', (width, height), color=(0, 0, 0, 0))
  175. draw = ImageDraw.Draw(img)
  176. x_size, y_size, _ = env.aps[apid].dbdata.shape
  177. apcfg = lws.config['aps'][apid]
  178. _, _, z = env.translateToVoxel(apcfg['x'], apcfg['y'], apcfg['z'])
  179. max_rssi = env.aps[apid].dbdata[:,:, z].max()
  180. cut_off = -90
  181. _, y_m, _ = env.translateToMeter(0, y_size, 0)
  182. _, y_map_max, _ = lws.intoMapSpace(0, y_m, 0)
  183. for x in range(x_size):
  184. for y in range(y_size):
  185. rssi = env.aps[apid].dbdata[x, y, z]
  186. if rssi < cut_off:
  187. continue
  188. x_m, y_m, z_m = env.translateToMeter(x, y, z)
  189. x_map, y_map, _ = lws.intoMapSpace(x_m, y_m, z_m)
  190. rgb = pos2rgb(-rssi+max_rssi*1.1, -cut_off + max_rssi, spread=0.7, saturation=0.7)
  191. draw.rectangle([x_map, y_map_max-y_map, x_map+cube_size, y_map_max-y_map+cube_size], fill=rgb)
  192. destfile = lws.config['tmp'].joinpath('apdatatiles_%s.png' % apid)
  193. img.save(destfile)
  194. destdir = lws.config['tmp'].joinpath('apdatatiles_%s' % apid)
  195. createLog2Tiles(destfile, destdir, logger=log, rgba=True)
  196. def plot2DMap(activeSceneCfg, level, locations, aps, destfile, refresh=False, customdraw=None, resizeFactor=1):
  197. z_cut = activeSceneCfg['levels2d'][level] - 0.50
  198. objfile = activeSceneCfg['objfile']
  199. x1, x2, y1, y2, _, _ = activeSceneCfg['bbox']
  200. mesh = Mesh()
  201. mesh.parseObjFile(objfile)
  202. mesh_xlim = (int(x1), int(x2))
  203. mesh_ylim = (int(y1), int(y2))
  204. pixel_per_meter = activeSceneCfg['2dpixelpermeter']
  205. m2d = Mesh2D(mesh, mesh_xlim, mesh_ylim, pixel_per_meter)
  206. log.info('building %s...' % level)
  207. if destfile.exists() and destfile.mtime > objfile.mtime and not refresh:
  208. if customdraw is not None:
  209. img = Image.open(destfile)
  210. img = img.convert('RGBA')
  211. draw = ImageDraw.Draw(img)
  212. customdraw(img, draw, m2d, z_cut, aps, locations)
  213. return
  214. to_be_combined = []
  215. for objname in m2d.objnames:
  216. log.debug('object: %s' % objname)
  217. img = m2d.cut(objname, z_cut)
  218. to_be_combined.append(pilutil.fromimage(img))
  219. all_objects = np.add.reduce(np.array(to_be_combined))
  220. #~ combined_object_image
  221. log.info('save file to %s' % destfile.abspath())
  222. img = pilutil.toimage(all_objects)
  223. img = img.convert('RGBA')
  224. draw = ImageDraw.Draw(img)
  225. for apid, apcfg in aps.items():
  226. if abs(apcfg['z'] - z_cut) < 2:
  227. _x, _y = m2d.meter2pixel(apcfg['x'], apcfg['y'])
  228. draw.text((_x - 20, _y), apid, fill='#11CC11')
  229. draw.point((_x, _y), fill='#00FF00')
  230. for locid, loc in locations.items():
  231. if -1.0 < (loc.z - z_cut) < 2.0:
  232. _x, _y = m2d.meter2pixel(loc.x, loc.y)
  233. draw.text((_x, _y), str(locid), fill='#CC1111')
  234. draw.point((_x, _y), fill='#00FF00')
  235. draw.text((10, 10), 'scene: %s level: %s' % (activeSceneCfg.name, level), fill='#FFFFFF')
  236. if resizeFactor != 1:
  237. log.info('resizing...')
  238. img = img.resize((int(img.size[0]*resizeFactor), int(img.size[1]*resizeFactor)), Image.ANTIALIAS)
  239. img.save(destfile)
  240. if customdraw is not None:
  241. img = Image.open(destfile)
  242. draw = ImageDraw.Draw(img)
  243. customdraw(img, draw, m2d, z_cut, aps, locations)
  244. def plotHistogram(destfile, data=None, format=None, title='', **kwargs):
  245. assert data is not None
  246. assert format in ('materials', )
  247. fig = plt.figure(figsize=(15, 6))
  248. ax = fig.add_subplot(1, 1, 1)
  249. #~ fig.subplots_adjust(bottom=0.2, left=0.03, right=0.99, top=0.98)
  250. if format == 'materials':
  251. dd = data.split('|')
  252. values2 = []
  253. if ',' in dd[0]:
  254. values1 = [round(float(e.split(',')[0]), 2) for e in dd]
  255. ax.set_xlim((0, 1))
  256. ax.hist(values1, color="blue", alpha=0.5)
  257. values2 = [round(float(e.split(',')[1]), 2) for e in dd]
  258. ax.hist(values2, color="green", alpha=0.5)
  259. title = title + '\n' + ','.join('%.2f' % e for e in sorted(values1)) + '\n' + ','.join('%.2f' % e for e in sorted(values2))
  260. else:
  261. values1 = [float(e.split(',')[0]) for e in dd]
  262. title = title + '\n' + ','.join('%.1e' % e for e in sorted(values1))
  263. ax.hist(values1)
  264. #~ else:
  265. #~ ax.set_xlim((0, 1))
  266. ax.set_title(title, fontsize=8)
  267. fig.savefig(destfile, format='png', dpi=90)
  268. plt.close(fig)