render.py 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
  1. # -*- coding: utf-8 -*-
  2. import logging
  3. import time
  4. from datetime import datetime
  5. from collections import defaultdict
  6. import string
  7. from utils.xml import StringToTree, TreeToFile, subelement, FileToTree
  8. from utils import pos2rgb
  9. import cPickle as pickle
  10. import scipy
  11. import simulate
  12. import evaluate
  13. import plotter
  14. log = logging.getLogger('lws')
  15. BASE = '''
  16. <html>
  17. <head>
  18. %(js)s
  19. <style type="text/css">
  20. a {color: #0000e0;}
  21. </style>
  22. <style type="text/css">
  23. %(css)s
  24. </style>
  25. </head>
  26. <body style="font-family: arial;">
  27. %(body)s
  28. </body>
  29. </html>
  30. '''
  31. def render(js=None, **kwargs):
  32. # prepare js definitions - optionally add a file given by @param js
  33. s = '<script type="text/javascript" src="/static/%s">&#160;</script>'
  34. jsfiles = ['jquery-1.7.1.min.js', 'main.js', 'loco.js']
  35. if isinstance(js, basestring):
  36. jsfiles.append(js)
  37. elif isinstance(js, (list, tuple)):
  38. jsfiles.extend(js)
  39. jsdefs = [s % f for f in jsfiles]
  40. data = defaultdict(str)
  41. data.update(kwargs)
  42. data['js'] = '\n '.join(jsdefs)
  43. return BASE % data
  44. def renderView(lws, station):
  45. trs = []
  46. for mac, cfg in sorted(lws.mac2cfg.items(), key=lambda e: e[1].name):
  47. ap_css_id = cfg['mac'].replace(':', '_')
  48. tr = '''<tr id="%s" class="aprow" style="display:none"> <td>%s</td> <td class="mean"> <td class="sigma"> <td class="history"></td></tr>''' % (ap_css_id, cfg.name)
  49. trs.append(tr)
  50. s = ''
  51. for i in range(-100, -10):
  52. rgb = pos2rgb(120+i, 100, spread=0.35, saturation=0.45)
  53. s += '<span id="rgb_%s">%s</span>' % (i, rgb)
  54. rgbvals = '<div id="rgbvals">%s</div>' % s
  55. body = '''
  56. <div id="meta" style="display:none">
  57. <span id="pagename">%s</span>
  58. <div id="stationinfo">
  59. <span id="name">%s</span>
  60. </div>
  61. %s
  62. </div>
  63. <table id="aps" style="border: 1px solid #ccc; float:left; font-size: 14">
  64. <thead>
  65. <tr class="header" style="font-weight:bold;background-color:#eee;">
  66. <td>AP</td>
  67. <td align="center">Mean</td>
  68. <td align="center">Sigma^2</td>
  69. <td align="center"><span id="clear_hist" style="color:blue;cursor:pointer;float:right">clear!</span><span>History</span></td>
  70. </tr
  71. </thead>
  72. %s
  73. </table>
  74. ''' % ('view2', station.name, rgbvals, '\n'.join(trs))
  75. return render(body=body)
  76. def getLastMeasurementRuns(lws, station, count):
  77. runs = []
  78. #~ print station, len(lws.stored_measurements[station])
  79. for locid in lws.stored_measurements[station]:
  80. ll = lws.stored_measurements[station][locid]
  81. # list of tuples (datetime, run dict)
  82. runs.extend([(e[0], e[1], locid) for e in ll])
  83. return [(e[1], e[2]) for e in list(sorted(runs))[-count:]]
  84. def renderMeasure(lws, station):
  85. trs = []
  86. locid_tds = ''
  87. if station is not None:
  88. lastruns = getLastMeasurementRuns(lws, station.name, 5)
  89. for ssid, mac, values in sorted((ssid, mac, values) for (mac, ssid), values in station.data.items()):
  90. rssi = values[-1].rssi
  91. delta = values[-1].delta
  92. try:
  93. apid = lws.mac2cfg[mac].name
  94. except Exception:
  95. apid = '?'
  96. continue
  97. avg_rssis_tds = ''
  98. for rssis, locid in lastruns:
  99. if mac in rssis:
  100. avg_rssi = '%.1f' % (sum(rssis[mac]) / float(len(rssis[mac])))
  101. else:
  102. avg_rssi = ''
  103. avg_rssis_tds += '<td>%s</td>' % avg_rssi
  104. tr = '''
  105. <tr class="aprow" id="%s">
  106. <td align="left">%s</td>
  107. <td align="left">%s/%s</td>
  108. <td align="left" class="rssi">%s</td>
  109. <td align="left" class="delta">%s</td>
  110. %s
  111. </tr>
  112. ''' % (mac.replace(':', '_'), apid, ssid[:6], mac[-6:], rssi, delta, avg_rssis_tds)
  113. trs.append(tr)
  114. for _, locid in lastruns:
  115. locid_tds += '<td>loc%s</td>' % locid
  116. activity_table = '''
  117. <table id="aplist" style="border: 1px solid #ccc; float:left; font-size: 14">
  118. <thead>
  119. <tr>
  120. <td>ID</td>
  121. <td>AccessPoint</td>
  122. <td>RSSI</td>
  123. <td>Delta</td>
  124. %s
  125. </tr>
  126. </thead>
  127. <tbody>
  128. %s
  129. </tbody>
  130. </table>''' % (locid_tds, '\n'.join(trs))
  131. body = '''
  132. <div id="meta" style="display:none">
  133. <span id="pagename">%s</span>
  134. <div id="stationinfo">
  135. <span id="name">%s</span>
  136. </div>
  137. </div>
  138. <form id="locationinfo" style="float:left">
  139. <table>
  140. <tr>
  141. <td>locid</td>
  142. <td>
  143. <input type="text" id="locid" value="0"/>
  144. </td>
  145. </tr>
  146. <tr>
  147. <td>duration</td>
  148. <td>
  149. <input type="text" id="duration" value="30"/>
  150. </td>
  151. </tr>
  152. <tr>
  153. <td>startts</td>
  154. <td id="startts">n/a</td>
  155. </tr>
  156. <tr>
  157. <td>endts</td>
  158. <td id="endts">n/a</td>
  159. </tr>
  160. <tr>
  161. <td colspan="2">
  162. <input style="width:100%%" type="submit" name="startmeasure" value="start"/>
  163. </td>
  164. </tr>
  165. <tr>
  166. <td colspan="2">
  167. <span id="activity"/>
  168. </td>
  169. </tr>
  170. </table>
  171. </form>
  172. %s
  173. <div id="cutplots">
  174. <img class="cutplot" src="/plot2DMap/eg" style="margin-top:10px" width="100%%"/>
  175. <img class="cutplot" src="/plot2DMap/og1" style="margin-top:10px" width="100%%"/>
  176. <img class="cutplot" src="/plot2DMap/og2" style="margin-top:10px" width="100%%"/>
  177. </div>
  178. ''' % ('measure', station.name if station is not None else 'UNKNOWN', activity_table)
  179. return render(body=body)
  180. def renderIndex(lws):
  181. body = '<h3>%s known mobile stations:</h3>' % len(lws.config['knownStations'])
  182. body += '<a href="/measurements">all measurements</a>'
  183. for station in lws.config['knownStations']:
  184. body += '''
  185. <h4>%(station)s: </h4>
  186. <a href="/view/%(station)s">view</a>
  187. <a href="/measure/%(station)s">measure</a>
  188. <a href="/collect/%(station)s">collect path</a>
  189. <a href="/evaluate/%(station)s">evaluate</a>
  190. <a href="/buildOptimizefile/%(station)s">build optfile</a>
  191. <a href="/localize/%(station)s">localize</a>
  192. ''' % {'station': station}
  193. body += '''</br>'''
  194. return render(body=body)
  195. def renderLocate(lws, station):
  196. LAST_N = 3
  197. avg_rssis = {}
  198. trs = []
  199. for (mac, ssid), values in station.data.items():
  200. if not mac in lws.mac2cfg:
  201. continue
  202. apid = lws.mac2cfg[mac].name
  203. apinfos = values[-LAST_N:]
  204. avg_rssi = sum(e.rssi for e in apinfos) / float(len(apinfos))
  205. tr = '''
  206. <tr class="aprow" id="%s">
  207. <td align="left" class="apid">%s</td>
  208. <td align="left">%s/%s</td>
  209. <td align="left" class="rssi">%.1f</td>
  210. </tr>
  211. ''' % (mac.replace(':', '_'), apid, ssid[:6], mac, avg_rssi)
  212. trs.append(tr)
  213. body = '''
  214. <div id="meta" style="display:none">
  215. <span id="pagename">%s</span>
  216. <div id="stationinfo">
  217. <span id="name">%s</span>
  218. </div>
  219. </div>
  220. <table id="aplist" style="border: 1px solid #ccc; float:left; font-size: 14">
  221. <thead>
  222. <tr>
  223. <td>ID</td>
  224. <td>AccessPoint</td>
  225. <td>RSSI</td>
  226. </tr>
  227. </thead>
  228. <tbody>
  229. %s
  230. </tbody>
  231. </table>
  232. <img src="/static/localize.png"/>
  233. ''' % ('locate', station.name, '\n'.join(trs))
  234. return render(body=body)
  235. def renderCluster(lws):
  236. worker_trs = []
  237. for wname, worker in sorted(lws.simulator.workers.items()):
  238. total = sum(worker.durations)
  239. avg = total / len(worker.durations) if total > 0 else 0
  240. num_per_hour = worker.jobcount / (total / 3600) if total > 0 else 0
  241. color = 'green' if worker.active else 'red'
  242. available_hours = (time.time() - worker.firstseen) / 3600
  243. active_hours = worker.jobcount * avg / 3600
  244. tr = '''
  245. <tr>
  246. <td style="background-color:%s">&#160;</td>
  247. <td>%s</td>
  248. <td align="center">%s</td>
  249. <td align="center">%s</td>
  250. <td align="center">%.1f</td>
  251. <td align="center">%.0f</td>
  252. <td align="center">%.2f</td>
  253. <td align="center">%.2f</td>
  254. <td align="center">%.1f</td>
  255. </tr>
  256. ''' % (color, wname, worker.jobcount, worker.failurecount, avg, num_per_hour, active_hours,
  257. available_hours, active_hours / available_hours * 100)
  258. worker_trs.append(tr)
  259. knownruns = simulate.Run.known
  260. waiting, running, finished = lws.simulator.queryRuns(set(knownruns.keys()))
  261. waiting_trs = []
  262. for runid in waiting:
  263. run = knownruns[runid]
  264. tr = '''
  265. <tr>
  266. <td>%s</td>
  267. <td align="center">%.1f</td>
  268. </tr>
  269. ''' % (run.id, time.time() - run.qts)
  270. waiting_trs.append(tr)
  271. running_trs = []
  272. for runid in running:
  273. run = knownruns[runid]
  274. tr = '''
  275. <tr>
  276. <td>%s</td>
  277. <td>%s</td>
  278. <td><a href="/brokenJob?worker=%s&runid=%s">requeue</a></td>
  279. <td align="center">%.1f</td>
  280. <td align="center">%.1f</td>
  281. </tr>
  282. ''' % (run.id, run.worker, run.worker, run.id, run.rts - run.qts, time.time()-run.rts)
  283. running_trs.append(tr)
  284. finished_trs = []
  285. # sort by finished ts
  286. finished = list(sorted(finished, key=lambda x: knownruns[x].fts))
  287. for runid in finished[-40:]:
  288. run = knownruns[runid]
  289. tr = '''
  290. <tr>
  291. <td>%s</td>
  292. <td>%s</td>
  293. <td align="center">%.1f</td>
  294. <td align="center">%.1f</td>
  295. </tr>
  296. ''' % (run.id, run.worker, run.rts - run.qts, run.fts - run.rts)
  297. finished_trs.append(tr)
  298. body = '''
  299. <div id="meta" style="display:none">
  300. <span id="pagename">%s</span>
  301. </div>
  302. <table id="workerlist" style="border: 1px solid #ccc; font-size: 14; float:left;">
  303. <thead>
  304. <tr style="background-color:#ddd;">
  305. <td style="background-color:#ccc;" colspan="15" align="center">
  306. <span>Worker Nodes (%s) </span>
  307. <a href="/simulatorStatsPlot">Plot Stats</a>
  308. </td>
  309. </tr>
  310. <tr style="background-color:#ddd;">
  311. <td/>
  312. <td>Worker</td>
  313. <td>Count</td>
  314. <td>Fail</td>
  315. <td>s/Jobs</td>
  316. <td>Jobs/h</td>
  317. <td>Active</td>
  318. <td>Available</td>
  319. <td>Ratio</td>
  320. </tr>
  321. </thead>
  322. <tbody>
  323. %s
  324. </tbody>
  325. </table>
  326. <table id="joblist" style="border: 1px solid #ccc; font-size: 14; float:left;">
  327. <thead>
  328. <tr>
  329. <td style="background-color:#ccc;" colspan="5" align="center">Waiting Jobs (%s)</td>
  330. </tr>
  331. <tr style="background-color:#ddd;">
  332. <td>Run-ID</td>
  333. <td style="padding-left:10px">Queuetime</td>
  334. </tr>
  335. </thead>
  336. <tbody>
  337. %s
  338. </tbody>
  339. </table>
  340. <table id="joblist" style="border: 1px solid #ccc; font-size: 14; float:left;">
  341. <thead>
  342. <tr>
  343. <td style="background-color:#ccc;" colspan="5" align="center">Running Jobs (%s)</td>
  344. </tr>
  345. <tr style="background-color:#ddd;">
  346. <td>Run-ID</td>
  347. <td style="padding-left:10px">Worker</td>
  348. <td style="padding-left:10px">Requeue</td>
  349. <td style="padding-left:10px">Queuetime</td>
  350. <td style="padding-left:10px">Runtime</td>
  351. </tr>
  352. </thead>
  353. <tbody>
  354. %s
  355. </tbody>
  356. </table>
  357. <table style="border: 1px solid #ccc; font-size: 14; float:left;">
  358. <thead>
  359. <tr style="background-color:#ddd;">
  360. <td style="background-color:#ccc;" colspan="5" align="center">Finished Jobs (%s)</td>
  361. </tr>
  362. <tr style="background-color:#ddd;">
  363. <td>Run-ID</td>
  364. <td style="padding-left:10px">Worker</td>
  365. <td style="padding-left:10px">Queuetime</td>
  366. <td style="padding-left:10px">Runtime</td>
  367. </tr>
  368. </thead>
  369. <tbody>
  370. %s
  371. </tbody>
  372. </table>
  373. ''' % ('cluster',
  374. len(worker_trs),
  375. '\n'.join(worker_trs),
  376. len(waiting_trs),
  377. '\n'.join(waiting_trs),
  378. len(running_trs),
  379. '\n'.join(running_trs),
  380. len(finished),
  381. '\n'.join(finished_trs),
  382. )
  383. return render(body=body)
  384. def getInterestingOptruns(lws):
  385. return [d.name for d in lws.optimizer.tmpdir.dirs() if d.joinpath('.interested').exists()]
  386. def getAllOptruns(lws, filter=None):
  387. ''' return optruns that have reached at least a minimum'''
  388. dirs = [d for d in lws.optimizer.tmpdir.dirs() if d.joinpath('mins.txt').exists()]
  389. if filter is not None:
  390. _dirs = []
  391. for d in dirs:
  392. data = [s for s in d.joinpath('mins.txt').lines()[-1].split()]
  393. data_init = [s for s in d.joinpath('init.txt').lines() if s.strip()]
  394. allowed = []
  395. if 'gen' in filter:
  396. for s in data:
  397. if s.startswith('gen:'):
  398. allowed.append(int(s[4:]) > filter['gen'])
  399. if filter.get('station'):
  400. for s in data_init:
  401. if s.startswith('station:'):
  402. allowed.append(any(e in s[8:] for e in filter['station'].split(',') if e.strip()))
  403. if filter.get('ts'):
  404. allowed.append(data[0] >= filter['ts'])
  405. if all(allowed):
  406. _dirs.append(d)
  407. dirs = set(_dirs)
  408. return list(sorted(d.name for d in dirs))
  409. def renderOptimizer(lws):
  410. active_session = lws.optimizer.optsession if lws.optimizer.running else None
  411. session_trs = []
  412. lastinit = {}
  413. files = sorted(lws.optimizer.tmpdir.dirs(),
  414. key=lambda x: x.files('*.txt')[0].mtime if len(x.files('*.txt')) > 0 else 0)
  415. for i, d in enumerate(reversed(files)):
  416. f = d.joinpath('init.txt')
  417. if not f.exists():
  418. continue
  419. initparams = dict([(e.split(':')[0], e.split(':')[1].strip())
  420. for e in f.text().split('\n') if e.strip()])
  421. if i == 0:
  422. lastinit = initparams
  423. trdata = defaultdict(str)
  424. trdata.update({'name': d.name,
  425. 'ts': datetime.fromtimestamp(d.mtime).strftime('%d.%m %H:%M')})
  426. trdata.update(initparams)
  427. trdata['min_avg_delta'] = ''
  428. trdata['min_generation'] = ''
  429. trdata['curr_generation'] = ''
  430. f = d.joinpath('mins.txt')
  431. if f.exists():
  432. lastmin = f.text().strip().split('\n')[-1].split()
  433. generation, orgid, mindelta = lastmin[1].split(':')[1], lastmin[2].split(':')[1], lastmin[3].split(':')[1]
  434. trdata['min_avg_delta'] = '%s@%s' % (mindelta, generation)
  435. cmp = lambda x: int(x.namebase.split('_')[1]) if x.namebase.startswith('population_') else -1
  436. popfiles = list(sorted(d.files('*.txt'), key=cmp))
  437. # and again get the last line
  438. lastsim = popfiles[-1].text().strip().split('\n')[-1].split()
  439. generation, orgid = lastsim[1].split(':')[1], lastsim[2].split(':')[1]
  440. trdata['curr_generation'] = '%s' % generation
  441. trdata['isinterest'] = 'yes' if d.joinpath('.interested').exists() else 'no'
  442. station_evaluate = []
  443. for station in initparams['station'].split(','):
  444. a = '<a href="/evaluate/%s/%s">%s</a>' % (station, d.name, station)
  445. station_evaluate.append(a)
  446. trdata['stations'] = '\n'.join(station_evaluate)
  447. restarturl = '/'
  448. tr = '''
  449. <tr class="optrun">
  450. <td><a href="/optruns?optruns=%(name)s">%(name)s</a></td>
  451. <td>%(stations)s</td>
  452. <td>%(timelimit)s</td>
  453. <td>%(genlimit)s</td>
  454. <td align="left">%(min_avg_delta)s</td>
  455. <td>%(curr_generation)s</td>
  456. <td align="center">%(scene)s</td>
  457. <td>%(ts)s</td>
  458. <td>%(power)s</td>
  459. <td align="center" class="raytracerparam">%(density)s</td>
  460. <td class="raytracerparam">%(resolution)s</td>
  461. <td class="raytracerparam" align="center">%(numphotons)s</td>
  462. <td class="raytracerparam">%(bbox)s</td>
  463. <td align="center">%(startpop)s</td>
  464. <td align="center" class="genparam">%(childcount)s</td>
  465. <td align="center" class="genparam">%(childcull)s</td>
  466. <td align="center" class="genparam">%(mutprob)s</td>
  467. <td align="center" class="genparam">%(mutamt)s</td>
  468. <td align="center"><a href="/interestingOptrun/%(name)s">%(isinterest)s</a></td>
  469. <td align="center"><a href="/buildOptrun/%(name)s">build</a></td>
  470. </tr>
  471. ''' % trdata
  472. session_trs.append(tr)
  473. body = '''
  474. <div id="meta" style="display:none">
  475. <span id="pagename">%(pagename)s</span>
  476. </div>
  477. <table>
  478. <form action="/startOptimizer">
  479. <tr style="background-color:#ddd;">
  480. <td style="background-color:#ccc;" colspan="5" align="center">
  481. <span>Start Optimizer Session</span>
  482. </td>
  483. </tr>
  484. <tr>
  485. <td>Session</td>
  486. <td>
  487. <input type="text" value="%(session)s" name="optsession"/>
  488. </td>
  489. </tr>
  490. <tr>
  491. <td>Station</td>
  492. <td>
  493. <input type="text" value="%(station)s" name="station"/>
  494. </td>
  495. </tr>
  496. <tr>
  497. <td>Timelimit (sec)</td>
  498. <td>
  499. <input type="text" value="%(timelimit)s" name="timelimit"/>
  500. </td>
  501. </tr>
  502. <tr>
  503. <td>max Gens</td>
  504. <td>
  505. <input type="text" value="%(genlimit)s" name="genlimit"/>
  506. </td>
  507. </tr>
  508. <tr style="background-color:#ddd;">
  509. <td colspan="2" align="center">Photon Params</td>
  510. </tr>
  511. <tr>
  512. <td>Power</td>
  513. <td>
  514. <input type="text" value="%(power)s" name="power"/>
  515. </td>
  516. </tr>
  517. <tr>
  518. <td>Density</td>
  519. <td>
  520. <input type="text" value="%(density)s" name="density"/>
  521. </td>
  522. </tr>
  523. <tr>
  524. <td>Numphotons</td>
  525. <td>
  526. <input type="text" value="%(numphotons)s" name="numphotons"/>
  527. </td>
  528. </tr>
  529. <tr>
  530. <td>Resolution (X)</td>
  531. <td>
  532. <input type="text" value="%(resolution)s" name="resolution"/>
  533. </td>
  534. </tr>
  535. <tr>
  536. <td>Bounding Box</td>
  537. <td>
  538. <input type="text" value="%(bbox)s" name="bbox"/>
  539. </td>
  540. </tr>
  541. <tr>
  542. <td>Scene</td>
  543. <td>
  544. <input type="text" value="%(scene)s" name="scene"/>
  545. </td>
  546. </tr>
  547. <tr style="background-color:#ddd;">
  548. <td colspan="2" align="center">Genetic Sim Params</td>
  549. </tr>
  550. <tr>
  551. <td>Startpop</td>
  552. <td>
  553. <input type="text" value="%(startpop)s" name="startpop"/>
  554. </td>
  555. </tr>
  556. <tr>
  557. <td>Childcount</td>
  558. <td>
  559. <input type="text" value="%(childcount)s" name="childcount"/>
  560. </td>
  561. </tr>
  562. <tr>
  563. <td>Childcull</td>
  564. <td>
  565. <input type="text" value="%(childcull)s" name="childcull"/>
  566. </td>
  567. </tr>
  568. <tr>
  569. <td>Mutprob</td>
  570. <td>
  571. <input type="text" value="%(mutprob)s" name="mutprob"/>
  572. </td>
  573. </tr>
  574. <tr>
  575. <td>Mutamt</td>
  576. <td>
  577. <input type="text" value="%(mutamt)s" name="mutamt"/>
  578. </td>
  579. </tr>
  580. <tr style="background-color:#ddd;">
  581. <td colspan="2" align="center">Resume Population</td>
  582. </tr>
  583. <tr>
  584. <td>Session</td>
  585. <td>
  586. <input type="text" value="" name="resume"/>
  587. </td>
  588. </tr>
  589. <tr>
  590. <td>New Organisms</td>
  591. <td>
  592. <input type="text" value="0" name="neworgs"/>
  593. </td>
  594. </tr>
  595. <tr>
  596. <td colspan="2">
  597. <input type="submit" value="start" name="start" style="width:100%%"/>
  598. </td>
  599. </tr>
  600. </form>
  601. </table>
  602. <table>
  603. <thead>
  604. <tr style="background-color:#ccc;">
  605. <td style="background-color:#ccc;" colspan="20" align="center">
  606. <span>Optimizer Sessions [Active: %(active_session)s]</span>
  607. <a style="display: %(stoppable)s" href="/stopOptimizer">Stop!</a>
  608. </td>
  609. </tr>
  610. <tr style="background-color:#ddd;">
  611. <td>Session</td>
  612. <td>Station</td>
  613. <td>Timelimit</td>
  614. <td>Genlimit</td>
  615. <td>MinDelta</td>
  616. <td>CurrGen</td>
  617. <td>Scene</td>
  618. <td>Started</td>
  619. <td>Power <span title="show all genetic raytracer params" style="color:blue;cursor:pointer" onclick="$('td.raytracerparam').toggle()">[+/-]</span></td>
  620. <td class="raytracerparam">Density</td>
  621. <td class="raytracerparam">Resolution</td>
  622. <td class="raytracerparam">Photons</td>
  623. <td class="raytracerparam">BoundingBox</td>
  624. <td>Startpop <span title="show all genetic sim params" style="color:blue;cursor:pointer" onclick="$('td.genparam').toggle()">[+/-]</span></td>
  625. <td class="genparam">Childcount</td>
  626. <td class="genparam">Childcull</td>
  627. <td class="genparam">Mutprob</td>
  628. <td class="genparam">Mutamt</td>
  629. <td>Interest</td>
  630. <td>Build</td>
  631. </tr>
  632. </thead>
  633. <tbody>
  634. %(lastsessions)s
  635. </tbody>
  636. </table>
  637. ''' % {'pagename': 'optimize',
  638. 'active_session': active_session,
  639. 'stoppable': 'none' if active_session is None else 'inline',
  640. 'lastsessions': '\n'.join(session_trs),
  641. 'power': lastinit.get('power', '2.0e-6'),
  642. 'session': lastinit.get('session', 'optsession'),
  643. 'station': lastinit.get('station', lws.config['defaultDevice']),
  644. 'timelimit': lastinit.get('timelimit', '0'),
  645. 'genlimit': lastinit.get('genlimit', '0'),
  646. 'density': lastinit.get('density', str(lws.activeScene['density'])),
  647. 'resolution': lastinit.get('resolution', ','.join(str(e) for e in lws.activeScene['resolution'])),
  648. 'numphotons': lastinit.get('numphotons', str(lws.activeScene['numphotons'])),
  649. 'bbox': lastinit.get('bbox', ','.join(str(e) for e in lws.activeScene['bbox'])),
  650. 'scene': lastinit.get('scene', lws.activeScene.name),
  651. 'startpop': lastinit.get('startpop', '6'),
  652. 'childcount': lastinit.get('childcount', '8'),
  653. 'childcull': lastinit.get('childcull', '20'),
  654. 'mutprob': lastinit.get('mutprob', '0.1'),
  655. 'mutamt': lastinit.get('mutamt', '0.1'),
  656. }
  657. css = '''
  658. td.genparam, td.raytracerparam {
  659. display:none;
  660. }
  661. tr.optrun:hover { background:#DDF; }
  662. table{
  663. border-collapse:collapse;
  664. border: 1px solid #ccc;
  665. font-size: 14;
  666. float:left;
  667. };
  668. '''
  669. return render(body=body, css=css)
  670. def renderEvaluteOptruns(lws, optruns, compact=False, **kwargs):
  671. optruns = [e for e in optruns.split(',') if e]
  672. if 'all' in optruns:
  673. optruns = getAllOptruns(lws, filter={'gen': 20,
  674. 'station': kwargs.get('station', ''),
  675. 'ts': kwargs.get('ts')})
  676. optruns_a = []
  677. for o in sorted(getInterestingOptruns(lws)):
  678. _optruns = set(optruns)
  679. if o in _optruns:
  680. if len(_optruns) > 1:
  681. _optruns.discard(o)
  682. style = 'style="font-weight:bold"'
  683. else:
  684. _optruns.add(o)
  685. style = 'style="font-weight:normal"'
  686. _compact = '' if not compact else '?compact'
  687. a = '<a %s href="/optruns/%s%s">%s</a>' % (style, ','.join(sorted(_optruns)), _compact, o)
  688. optruns_a.append(a)
  689. optrun_containerdata = defaultdict(list)
  690. for optrun in optruns:
  691. odir = lws.optimizer.tmpdir.joinpath(optrun)
  692. if not compact:
  693. ww = 'width="%s%%"' % int(100 / len(optruns))
  694. else:
  695. ww = ''
  696. td = '''
  697. <td class="header" %(ww)s>
  698. %(optrun)s
  699. </td>
  700. ''' % {'optrun': optrun, 'ww': ww}
  701. optrun_containerdata[optrun].append(td)
  702. trs = []
  703. f = odir.joinpath('mins.txt')
  704. if not f.exists():
  705. continue
  706. lastmin = f.lines()[-1]
  707. for i, s in enumerate(lastmin.split()):
  708. if i == 0:
  709. name = 'timestamp'
  710. value = s
  711. else:
  712. name, value = s.split(':')
  713. name_css = name.replace('.', '_').replace('/', '_')
  714. tr = '''<tr class="p_%(name_css)s param" n="%(name_css)s">
  715. <td class="name">%(name)s</td>
  716. <td class="value">%(value)s</td>
  717. </tr>''' % {'name_css': name_css, 'name': name, 'value': value}
  718. trs.append(tr)
  719. td = '''
  720. <td class="cell">
  721. <table>
  722. <tr>
  723. <td class="header">Param</td>
  724. <td class="header">Value</td>
  725. </tr>
  726. %s
  727. </table>
  728. </td>
  729. ''' % '\n'.join(trs)
  730. optrun_containerdata[optrun].append(td)
  731. if not compact:
  732. if len(optruns) < 6:
  733. td = '''
  734. <td class="cell">
  735. <img src="/optimizePlot?session=%(optrun)s&onlymins=true" width="100%%"/>
  736. </td>
  737. ''' % {'optrun': optrun}
  738. optrun_containerdata[optrun].append(td)
  739. if len(optruns) < 3:
  740. td = '''
  741. <td class="cell">
  742. <img src="/optimizePlot?session=%(optrun)s" width="100%%"/>
  743. </td>
  744. ''' % {'optrun': optrun}
  745. optrun_containerdata[optrun].append(td)
  746. num_tds = len(optrun_containerdata.values()[0]) if optrun_containerdata else 0
  747. optrun_containers = []
  748. for i in range(num_tds):
  749. tds = [tds[i] for optrun, tds in optrun_containerdata.items()]
  750. tr = '''<tr>%s</tr>''' % '\n'.join(tds)
  751. optrun_containers.append(tr)
  752. if not compact:
  753. ww = 'width="100%"'
  754. else:
  755. ww = ''
  756. body = '''
  757. <div id="meta" style="display:none">
  758. <span id="pagename">%(pagename)s</span>
  759. </div>
  760. <div>
  761. <b>Evaluate <a href="/optimize">Optruns</a>: </b>
  762. %(optruns)s
  763. </div>
  764. <table %(ww)s>
  765. <tr>
  766. %(optrun_containers)s
  767. </tr>
  768. </table>
  769. ''' % { 'pagename': 'optruns',
  770. 'optrun_containers': '\n'.join(optrun_containers),
  771. 'optruns': '\n'.join(optruns_a),
  772. 'ww': ww,
  773. }
  774. css = '''
  775. table {
  776. border-collapse:collapse;
  777. border: 1px solid #ccc;
  778. font-size: 14;
  779. float:left
  780. }
  781. td.cell {
  782. border-right: 3px solid grey;
  783. vertical-align:top;
  784. }
  785. td.header{
  786. background-color:#ccc;
  787. text-align:center;
  788. font-weight:bold;
  789. }
  790. ''' % {'width': (int(100 / len(optruns)) if optruns else 0)}
  791. return render(body=body, css=css)
  792. def renderMeasurements(lws, stations, view):
  793. tables = []
  794. ## full data grouped by APs
  795. stats = defaultdict(int)
  796. for mac, cfg in sorted(lws.mac2cfg.items(), key=lambda e: e[1].name):
  797. s2m = {}
  798. for station in stations:
  799. measurements = lws.getMeasurements(station=station, apid=cfg.name)
  800. s2m[station] = measurements
  801. locrows = []
  802. for locid in sorted(lws.known_locations.keys()):
  803. str_station_values = []
  804. for station in stations:
  805. measurements = s2m[station]
  806. vals = []
  807. rssis = []
  808. if measurements is not None and str(locid) in measurements:
  809. m = measurements[str(locid)]
  810. rssis = m.rssis
  811. for _view in view:
  812. if _view == 'mean':
  813. vals.append(str(int(scipy.mean(rssis))))
  814. if _view == 'median':
  815. vals.append(str(int(scipy.median(rssis))))
  816. if _view == 'stddev':
  817. stddev = scipy.std(rssis)
  818. vals.append('%.1f' % stddev)
  819. else:
  820. m = None
  821. str_station_values.append(('/'.join(e for e in vals),
  822. ','.join('%.1f' % e for e in sorted(rssis)),
  823. m,
  824. cfg,
  825. (lws.known_locations[locid].x, lws.known_locations[locid].y, lws.known_locations[locid].z),
  826. station
  827. ))
  828. if len(stations) == 2:
  829. # HACK FOR COMPARING TWO MEASUREMENT-SETS
  830. try:
  831. # most ugly
  832. delta = '%.1f' % (float(str_station_values[0][0].split('/')[0]) - float(str_station_values[1][0].split('/')[0]))
  833. except ValueError:
  834. delta = ''
  835. str_station_values.append((delta, '', None, None, None, None))
  836. def styleFromMeasurement(m, apcfg, location, station, locid):
  837. MAX_REQUIRED_DISTANCE = 20 # mark location grey if distance exceeds MAX_REQUIRED_DISTANCE
  838. MIN_REQUIRED_DISTANCE = 10
  839. if location is not None:
  840. dist = ((location[0]-apcfg['x'])**2 + (location[1]-apcfg['y'])**2 + + (location[2]-apcfg['z'])**2)**0.5
  841. else:
  842. dist = None
  843. if m is not None and len(m.rssis) > 0:
  844. stats[(station, 'collected')] += 1
  845. stats[(station, 'ap_%s' % apcfg.name)] += 1
  846. stats[(station, 'locid_%s' % locid)] += 1
  847. if station == 'wispy' and 'asus' != apcfg['powerid'] and m is None:
  848. return "background-color:silver"
  849. if dist is not None and dist > MAX_REQUIRED_DISTANCE and m is None:
  850. #~ stats[(station, 'faraway')] += 1
  851. return "background-color:silver"
  852. if dist is not None and dist < MIN_REQUIRED_DISTANCE and m is None:
  853. #~ stats[(station, 'faraway')] += 1
  854. return "background-color:#FFCCCC"
  855. elif m is None:
  856. stats[(station, 'missing')] += 1
  857. return ''
  858. elif scipy.std(m.rssis) > 10:
  859. stats[(station, 'highstddev')] += 1
  860. stats[(station, 'brutalstddev')] += 1
  861. return "background-color:#FF8866"
  862. elif scipy.std(m.rssis) > 5:
  863. stats[(station, 'highstddev')] += 1
  864. return "background-color:yellow"
  865. elif scipy.std(m.rssis) > 4:
  866. stats[(station, 'highstddev')] += 1
  867. return "background-color:FFFFCC"
  868. elif len(m.rssis) <= 5:
  869. stats[(station, 'tosmall')] += 1
  870. return "background-color:#CCCCFF"
  871. else:
  872. if len(m.rssis) > 0:
  873. stats[(station, 'nice')] += 1
  874. return ''
  875. locrow = '''<tr>
  876. <td>%s</td>
  877. %s
  878. </tr>
  879. ''' % (
  880. locid,
  881. '\n'.join('<td align="center" title="%s" style="%s">%s</td>' % (
  882. e[1],
  883. styleFromMeasurement(e[2], e[3], e[4], e[5], locid),
  884. e[0]
  885. ) for e in str_station_values)
  886. )
  887. locrows.append(locrow)
  888. table = '''
  889. <table style="border: 1px solid #ccc; font-size: 14; float:left;">
  890. <thead>
  891. <tr>
  892. <td colspan="10" style="background-color:#ccc;" align="center">%s</td>
  893. </tr>
  894. <tr style="background-color:#ddd;">
  895. <td>LocID</td>
  896. %s
  897. </tr>
  898. </thead>
  899. %s
  900. </table>
  901. ''' % ( '%s/%s' % (cfg.name, mac),
  902. '\n'.join(['<td>%s</td>' % s for s in stations] + (['<td>Delta</td>'] if len(stations) == 2 else [])),
  903. '\n'.join(locrows),
  904. )
  905. tables.append(table)
  906. ## aggregated by APs
  907. trs = []
  908. for station in stations:
  909. nice = stats[(station, 'nice')]
  910. collected = stats[(station, 'collected')]
  911. missing = stats[(station, 'missing')]
  912. highstddev = stats[(station, 'highstddev')]
  913. brutalstddev = stats[(station, 'brutalstddev')]
  914. tosmall = stats[(station, 'tosmall')]
  915. ap_aggregated = []
  916. for mac, cfg in sorted(lws.mac2cfg.items(), key=lambda e: e[1].name):
  917. v = stats[(station, 'ap_%s' % cfg.name)]
  918. ap_aggregated.append('<td>%s</td>' % v)
  919. tr = '''<tr>
  920. <td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td>
  921. %s
  922. </tr>''' % (station, collected, missing, nice, highstddev, brutalstddev, tosmall, '\n'.join(ap_aggregated))
  923. trs.append(tr)
  924. apheader = []
  925. for mac, cfg in sorted(lws.mac2cfg.items(), key=lambda e: e[1].name):
  926. apid = cfg.name
  927. apheader.append('<td style="background-color:#ccc;">%s</td>' % apid)
  928. table = '''
  929. <table cellspacing="0px" style="border: 1px solid #ccc; font-size: 14;" width="100%%">
  930. <thead>
  931. <tr>
  932. <td style="background-color:#ccc;">device</td>
  933. <td style="background-color:#ccc;">collected</td>
  934. <td style="background-color:#ccc;">missing</td>
  935. <td style="background-color:#ccc;">nice</td>
  936. <td style="background-color:#ccc;">highstddev</td>
  937. <td style="background-color:#ccc;">brutalstddev</td>
  938. <td style="background-color:#ccc;">tosmall</td>
  939. %s
  940. </tr>
  941. </thead>
  942. <tbody>
  943. %s
  944. </tbody>
  945. </table>
  946. ''' % ('\n'.join(apheader), '\n'.join(trs))
  947. tables.insert(0, table)
  948. ## aggregated by location
  949. trs = []
  950. for station in stations:
  951. locid_aggregated = []
  952. for locid in lws.known_locations:
  953. v = stats[(station, 'locid_%s' % locid)]
  954. style = 'background-color:#FFCCCC' if v == 0 else ''
  955. locid_aggregated.append('<td style="%s">%s</td>' % (style, v))
  956. tr = '''<tr>
  957. <td>%s</td><td>%s</td><td>%s</td>
  958. %s
  959. </tr>''' % (station, 0, 0, '\n'.join(locid_aggregated))
  960. trs.append(tr)
  961. locidheader = []
  962. for locid in lws.known_locations:
  963. locidheader.append('<td style="background-color:#ccc;">%s</td>' % locid)
  964. table = '''
  965. <table cellspacing="0px" style="border: 1px solid #ccc; font-size: 12;" width="100%%">
  966. <thead>
  967. <tr>
  968. <td style="background-color:#ccc;">device</td>
  969. <td style="background-color:#ccc;">avail</td>
  970. <td style="background-color:#ccc;">miss</td>
  971. %s
  972. </tr>
  973. </thead>
  974. <tbody>
  975. %s
  976. </tbody>
  977. </table>
  978. ''' % ('\n'.join(locidheader), '\n'.join(trs))
  979. tables.insert(1, table)
  980. ## the rest
  981. cutplanes = ['<a href="/plot2DMap/%s" style="margin-top:10px">cut %s</a>' % (s, s) for s in lws.activeScene['levels2d'].scalars]
  982. body = '''
  983. <div id="meta" style="display:none">
  984. <span id="pagename">%(pagename)s</span>
  985. </div>
  986. <div>
  987. <span>Examples: </span>
  988. <a href="/measurements?stations=%(stations)s&view=mean,median,stddev">All Stations with Mean/Median/Stddev</a>
  989. <a style="margin-left:20px" href="/measurements?stations=%(compare)s&view=mean">Compare mean of first 2 Stations</a>
  990. <a style="margin-left:20px" href="/measurements?stations=%(compare)s&view=stddev">Compare stdev of first 2 Stations</a>
  991. </div>
  992. <div>
  993. %(cutplanes)s
  994. </div>
  995. %(tables)s
  996. ''' % {'pagename': 'measurements',
  997. 'stations': ','.join(lws.config['knownStations']),
  998. 'compare': ','.join(lws.config['knownStations'][:2]),
  999. 'tables': '\n'.join(tables),
  1000. 'cutplanes': '\n'.join(cutplanes),
  1001. }
  1002. return render(body=body)
  1003. def renderCollectPath(lws, station):
  1004. spans = []
  1005. options = []
  1006. for pathid in sorted(lws.activeScene['paths'].scalars):
  1007. locids = ','.join(lws.activeScene['paths'][pathid])
  1008. spans.append('<span class="path" id="%s">%s</span>' % (pathid, locids))
  1009. options.append('<option value="%s">%s</option>' % (pathid, pathid))
  1010. eval_on_optrun = []
  1011. for optrun in 'all_5', 'all_31':
  1012. a = '''<a style="margin-left:15px;padding:10px;background-color:#CCC;border:1px solid grey;" href="/evaluatePath/%(station)s/%(optrun)s/LASTCOLLECTED/LASTCOLLECTED/end?refresh">%(optrun)s</a>'''
  1013. eval_on_optrun.append(a % {'optrun': optrun, 'station': station})
  1014. body = '''
  1015. <div id="meta" style="display:none">
  1016. <span id="pagename">%(pagename)s</span>
  1017. <div id="stationinfo">
  1018. <span id="name">%(station)s</span>
  1019. </div>
  1020. %(configured_paths)s
  1021. </div>
  1022. <div id="feedback" style="padding:5px;opacity:0.0;position:absolute;top:30%%;left:45%%;background-color:#FFF">feedback</div>
  1023. <div style="margin-bottom:5px">
  1024. <span id="nextButton" style="float:right;background-color:#CCC;cursor:pointer;padding-right:40px;padding-left:40px;padding-bottom:12px;padding-top:12px;border:1px solid grey;">next</span>
  1025. <div style="padding-left:10px;padding-top:15px" id="pushButtons">
  1026. <select id="pathid">
  1027. %(options_pathid)s
  1028. </select>
  1029. <span id="startButton" style="background-color:#52D017;cursor:pointer;padding:10px;border:1px solid grey;">start</span>
  1030. </div>
  1031. </div>
  1032. <div style="margin-top:25px; margin-bottom:5px">
  1033. <a href="/view/%(station)s">view %(station)s</a>
  1034. %(eval_on_optrun)s
  1035. </div>
  1036. <div id="cutplots">
  1037. <img class="cutplot" src="/plot2DMap/eg" style="margin-top:10px" width="100%%"/>
  1038. <img class="cutplot" src="/plot2DMap/og1" style="margin-top:10px" width="100%%"/>
  1039. <img class="cutplot" src="/plot2DMap/og2" style="margin-top:10px" width="100%%"/>
  1040. </div>
  1041. ''' % {'pagename': 'collect',
  1042. 'station': station,
  1043. 'configured_paths': '\n'.join(spans),
  1044. 'options_pathid': '\n'.join(options),
  1045. 'eval_on_optrun': '\n'.join(eval_on_optrun),
  1046. }
  1047. return render(body=body)
  1048. def renderEvaluate(lws, optruns, stations, cubewidth, errtype='3d', filter=None, refresh=False, algo='hmm'):
  1049. if optruns is None:
  1050. optruns = ''
  1051. station_divs = []
  1052. for station in stations.split(','):
  1053. pathids2runids = evaluate.getCollectedPathids2runids(station, lws.activeScene['paths'], lws.config['tmp_tracked'], filter)
  1054. settings = ['end', 'seq']
  1055. reload(evaluate)
  1056. tables = []
  1057. for optrun in sorted(optruns.split(',')):
  1058. try:
  1059. errors = evaluate.evaluate(lws, optrun, station, cubewidth, algo, pathids2runids, refresh)
  1060. except Exception:
  1061. log.exception('error during evaluate')
  1062. errors = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: (0, 0))))
  1063. rows = []
  1064. all_avg_errors = defaultdict(list)
  1065. for pathid, runs in sorted(pathids2runids.items()):
  1066. avg_errors = defaultdict(list)
  1067. runrows = []
  1068. for runid in runs:
  1069. setting_tds = []
  1070. for s in settings:
  1071. err3d, err2d = errors[pathid][runid][s]
  1072. if (err3d, err2d) == (0, 0):
  1073. e = 0.0
  1074. else:
  1075. if errtype == '3d':
  1076. e = err3d
  1077. else:
  1078. e = err2d
  1079. avg_errors[s].append(e)
  1080. href = '/evaluatePath/%s/%s/%s/%s/%s?cubewidth=%s&algo=%s%s' % (station, optrun, pathid, runid, s, cubewidth, algo, '&refresh' if not e else '')
  1081. setting_tds.append('<td><a href="%s">%.2f</a></td>' % (href, e))
  1082. tr = '<tr class="run" id="%s"><td>%s</td>%s</tr>' % (pathid, runid, ''.join(setting_tds))
  1083. runrows.append(tr)
  1084. tds = []
  1085. for s in settings:
  1086. if len(avg_errors[s]) > 0:
  1087. e = sum(avg_errors[s]) / float(len(avg_errors[s]))
  1088. else:
  1089. e = 0.0
  1090. href = '/evaluate/%s/%s?filter=%s&algo=%s' % (station, optruns, pathid, algo)
  1091. tds.append('<td><a href="%s">%.2f</a></td>' % (href, e))
  1092. all_avg_errors[s].extend(avg_errors[s])
  1093. tr = '<tr class="path" pathid="%s"><td>%s (%s)</td>%s</tr>' % (pathid, pathid, len(runrows), ''.join(tds))
  1094. rows.append(tr)
  1095. rows.extend(runrows)
  1096. tds = []
  1097. for s in settings:
  1098. if len(all_avg_errors[s]) > 0:
  1099. tds.append('<td>%.2f</td>' % (sum(all_avg_errors[s]) / float(len(all_avg_errors[s]))))
  1100. else:
  1101. tds.append('<td/>')
  1102. tr = '<tr style="background-color:#CCC;font-weight:bold"><td>total avg</td>%s</tr>' % ''.join(tds)
  1103. rows.append(tr)
  1104. table = '''
  1105. <table class="optrun">
  1106. <thead>
  1107. <tr>
  1108. <td colspan="10" style="background-color:#bbb;" align="center">%s - %s</td>
  1109. </tr>
  1110. <tr>
  1111. <td colspan="10" style="background-color:#ccc;" align="center">%s</td>
  1112. </tr>
  1113. <tr style="background-color:#ddd;">
  1114. <td>Run</td>
  1115. %s
  1116. </tr>
  1117. </thead>
  1118. %s
  1119. </table>
  1120. ''' % ( optrun,
  1121. station,
  1122. 'device: %s with cubewidth: %s and errtype: %s' % (station, cubewidth, errtype),
  1123. '\n'.join(['<td>%s</td>' % s for s in settings]),
  1124. '\n'.join(rows),
  1125. )
  1126. tables.append(table)
  1127. station_divs.append('<div style="clear:left">%s</div>' % '\n'.join(tables))
  1128. optruns_a = []
  1129. for o in sorted(getInterestingOptruns(lws)):
  1130. _optruns = set(e for e in optruns.split(',') if e)
  1131. if o in _optruns:
  1132. if len(_optruns) > 1:
  1133. _optruns.discard(o)
  1134. style = 'style="font-weight:bold"'
  1135. else:
  1136. _optruns.add(o)
  1137. style = 'style="font-weight:normal"'
  1138. qs = '?algo=' + algo
  1139. qs += '&filter=%s' % filter if filter else ''
  1140. a = '<a %s href="/evaluate/%s/%s%s">%s</a>' % (style, stations, ','.join(sorted(_optruns)), qs, o)
  1141. optruns_a.append(a)
  1142. stations_a = []
  1143. for s in sorted(lws.config['knownStations']):
  1144. _stations = set(stations.split(','))
  1145. if s in _stations:
  1146. if len(_stations) > 1:
  1147. _stations.discard(s)
  1148. style = 'style="font-weight:bold"'
  1149. else:
  1150. _stations.add(s)
  1151. style = 'style="font-weight:normal"'
  1152. qs = '?algo=' + algo
  1153. qs += '&filter=%s' % filter if filter else ''
  1154. a = '<a %s href="/evaluate/%s/%s%s">%s</a>' % (style, ','.join(sorted(_stations)), optruns, qs, s)
  1155. stations_a.append(a)
  1156. body = '''
  1157. <div id="meta" style="display:none">
  1158. <span id="pagename">%(pagename)s</span>
  1159. <div id="stationinfo">
  1160. <span id="name">%(station)s</span>
  1161. </div>
  1162. </div>
  1163. <div>
  1164. <b>Evaluate <a href="/optimize">Optruns</a>: </b>
  1165. %(optruns)s
  1166. <b>Stations: </b>
  1167. %(stations)s
  1168. </div>
  1169. %(station_divs)s
  1170. ''' % {'pagename': 'evaluate',
  1171. 'station': stations.split(',')[0],
  1172. 'station_divs': '\n'.join(station_divs),
  1173. 'optruns': '\n'.join(optruns_a),
  1174. 'stations': '\n'.join(stations_a),
  1175. }
  1176. css = '''
  1177. table {
  1178. border-collapse:collapse;
  1179. border: 1px solid #ccc;
  1180. font-size: 14;
  1181. float:left
  1182. }
  1183. tr.run {
  1184. display:none;
  1185. }
  1186. tr.path {
  1187. cursor:pointer;
  1188. background-color: #EEE;
  1189. }
  1190. '''
  1191. return render(body=body, css=css)
  1192. def renderEvaluatePath(lws, optrun, station, pathid, runid, setting, cubewidth, algo, refresh=False):
  1193. reload(evaluate)
  1194. errors = evaluate.evaluate(lws, optrun, station, cubewidth, algo, {pathid: [runid]}, refresh)
  1195. # exception case: should be handled better
  1196. assert errors[pathid][runid][setting] != (0, 0), 'propbably error during in evalAll worker threads '
  1197. cached_err_file = lws.config['tmp'].joinpath('evaluator', '%s/%s_%s_%s_%s_%s_%s.xml' % (optrun, station, cubewidth, algo, setting, pathid, runid))
  1198. tree = FileToTree(cached_err_file)
  1199. apids = set()
  1200. for e in tree.xpath('//apdata'):
  1201. apids.update(e.attrib.keys())
  1202. apids = list(apids)
  1203. pos_rows = []
  1204. posEls = tree.getroot().xpath('pos')
  1205. # move unseen aps backwards
  1206. if len(posEls) > 0:
  1207. apdata = posEls[0].xpath('apdata')[0].attrib
  1208. def move_unseen_backward(apid1, apid2):
  1209. if apdata[apid1].endswith('/2.0'):
  1210. return 2
  1211. elif apdata[apid2].endswith('/2.0'):
  1212. return -2
  1213. else:
  1214. return -1 if apid1 < apid2 else 1
  1215. apids.sort(cmp=move_unseen_backward)
  1216. for i, pel in enumerate(posEls):
  1217. tds = []
  1218. hexval = pos2rgb(i, len(posEls))
  1219. s = '<td style="width:10px;background-color:%s">%s</td>' % (hexval, i)
  1220. fw = 'bold' if pel.attrib['interpolated'] == 'false' else 'normal'
  1221. s += '<td style="font-weight:%s">%s,%s,%s</td>' % (fw, pel.attrib['x'], pel.attrib['y'], pel.attrib['z'])
  1222. s += '<td align="center">%s</td>' % pel.attrib['ts']
  1223. s += '<td align="center">%s</td>' % pel.attrib['err2d']
  1224. s += '<td align="center">%s,%s,%s</td>' % (pel.attrib['sx'], pel.attrib['sy'], pel.attrib['sz'])
  1225. s += '<td align="center">%s</td>' % pel.attrib['tp']
  1226. s += '<td align="center">%s,%s,%s</td>' % (pel.attrib['dx'], pel.attrib['dy'], pel.attrib['dz'])
  1227. s += '<td align="center">%s</td>' % pel.attrib['ep']
  1228. apdata = pel.xpath('apdata')[0].attrib
  1229. for apid in apids:
  1230. values = apdata[apid]
  1231. apid = apid[3:]
  1232. #~ if values != '-100.0/-1.0':
  1233. max_delta = 6.0
  1234. if values.endswith('/2.0'):
  1235. bgc = '#AAF'
  1236. delta = 0
  1237. continue
  1238. elif values.endswith('/1.0'):
  1239. bgc = '#DDD'
  1240. delta = 0
  1241. else:
  1242. simulated, measured = values.split('/')
  1243. delta = abs(float(simulated) - float(measured))
  1244. bgc = pos2rgb(max(0, max_delta - delta), max_delta, spread=0.35, saturation=0.5)
  1245. td = '<td style="background-color:%s" title="ap: %s, delta: %.1f">%s</td>' % (bgc, apid, delta, values)
  1246. tds.append(td)
  1247. cls = 'measured' if pel.attrib['interpolated'] == 'false' else 'interpolated'
  1248. pos_rows.append('<tr class="%s">%s</tr>' % (cls, s + ''.join(tds)))
  1249. ap_tds = ''.join('<td align="center">%s</td>' % apid[3:] for apid in apids if not posEls[0].xpath('apdata')[0].attrib[apid].endswith('/2.0'))
  1250. table = '''
  1251. <table style="border: 1px solid #ccc; font-size: 14;">
  1252. <thead>
  1253. <tr style="background-color:#ddd;">
  1254. <td style="width:10px">#</td>
  1255. <td>Pos</td>
  1256. <td>TS</td>
  1257. <td>Err2d</td>
  1258. <td align="center">Cube</td>
  1259. <td>Transition</td>
  1260. <td>tx,ty,tz</td>
  1261. <td>Emission</td>
  1262. %s
  1263. </tr>
  1264. </thead>
  1265. %s
  1266. </table>
  1267. ''' % (ap_tds, ''.join(pos_rows))
  1268. plots = [
  1269. ('end', '<img class="plots" src="/plotEvaluatedPath/%s/%s/%s/%s/%s?cubewidth=%s&algo=%s"/>' % (optrun, station, pathid, runid, 'end', cubewidth, algo)),
  1270. ('seq', '<img class="plots" src="/plotEvaluatedPath/%s/%s/%s/%s/%s?cubewidth=%s&algo=%s"/>' % (optrun, station, pathid, runid, 'seq', cubewidth, algo)),
  1271. ]
  1272. levels = lws.activeScene['levels2d'].scalars
  1273. plots.extend(('%s' % l, '<img class="plots" src="/plot2DMap/%s"/>' % l) for l in levels)
  1274. plots_table = '''
  1275. <table id="plots">
  1276. <tr>
  1277. <td id="imgs1" width="50%%">
  1278. %(imgs)s
  1279. </td>
  1280. <td id="imgs2" width="50%%">
  1281. %(imgs)s
  1282. </td>
  1283. </tr>
  1284. <tr>
  1285. <td id="switch1">
  1286. %(switchs)s
  1287. </td>
  1288. <td id="switch2">
  1289. %(switchs)s
  1290. </td>
  1291. </tr>
  1292. </table>
  1293. '''
  1294. imgs = '\n'.join(e[1] for e in plots)
  1295. switchs = ''.join('<span class="switch">%s</span>' % e[0] for e in plots)
  1296. plots_table = plots_table % {'imgs': imgs, 'switchs': switchs}
  1297. num_measurements = int(tree.getroot().xpath('count(//pos[@interpolated="false"])'))
  1298. num_signals = int(tree.getroot().xpath('count(//pos)'))
  1299. duration = float(tree.getroot().xpath('string(//pos[position()=last()]/@ts)'))
  1300. sec_permeasurements = duration / num_measurements
  1301. body = '''
  1302. <div id="meta" style="display:none">
  1303. <span id="pagename">%(pagename)s</span>
  1304. <div id="stationinfo">
  1305. <span id="name">%(station)s</span>
  1306. </div>
  1307. </div>
  1308. <h3><a href="/evaluate/%(station)s/%(optrun)s?filter=%(pathid)s">%(pathid)s</a>/%(runid)s</h3>
  1309. <div> err2d: <b>%(err2d)s </b>seq-err2d: <b>%(seqerr2d)s</b> duration: <b>%(duration)s sec</b>
  1310. measurements: <b>%(num_measurements)s</b> [%(num_signals)s] sec/measurements: <b>%(sec_permeasurements).2f sec</b></div>
  1311. %(plots_table)s
  1312. %(table)s
  1313. ''' % {'pagename': 'evaluatePath',
  1314. 'station': station,
  1315. 'plots_table': plots_table,
  1316. 'table': table,
  1317. 'pathid': pathid,
  1318. 'runid': runid,
  1319. 'err2d': tree.getroot().attrib['err2d'],
  1320. 'seqerr2d': tree.getroot().attrib['seqerr2d'],
  1321. 'duration': duration,
  1322. 'num_measurements': num_measurements,
  1323. 'sec_permeasurements': sec_permeasurements,
  1324. 'num_signals': num_signals,
  1325. 'optrun': optrun,
  1326. }
  1327. css = '''
  1328. table {
  1329. border-collapse:collapse;
  1330. width: 100%;
  1331. }
  1332. tr.measured td {
  1333. border-top: 1px solid #999;
  1334. }
  1335. img.plots {
  1336. display: none;
  1337. width: 100%;
  1338. }
  1339. span.switch {
  1340. margin-left: 10px;
  1341. cursor: pointer;
  1342. }
  1343. '''
  1344. return render(body=body, css=css)
  1345. def renderLocalize(lws, device, refresh=False):
  1346. numcolors = 256
  1347. rgbdata = ','.join(pos2rgb(i, numcolors, spread=0.75, saturation=0.85) for i in range(0, numcolors))
  1348. from utils.tiles import createLog2Tiles
  1349. for level in lws.activeScene['levels2d']:
  1350. destfile = lws.config['tmp'].joinpath('tiling_%s.png' % level)
  1351. plotter.plot2DMap(lws.activeScene, level, {}, {}, destfile=destfile, resizeFactor=8, refresh=refresh)
  1352. destdir = lws.config['tmp'].joinpath('tiles_%s' % level)
  1353. if not destdir.exists() or refresh:
  1354. createLog2Tiles(destfile, destdir, logger=log)
  1355. aptrs = []
  1356. aptds = []
  1357. for i, apcfg in enumerate(sorted(lws.mac2cfg.values(), key=lambda e: e.name)):
  1358. apid, x, y, z = apcfg.name, apcfg['x'], apcfg['y'], apcfg['z']
  1359. x, y, z = lws.intoMapSpace(x, y, z)
  1360. activeness = ' inactive_ap' if apid in lws.localizeSessionInactiveAPs[device] else 'active_ap'
  1361. s = '''<td style="font-weight:bold;padding-left:2px">
  1362. <span class="apdisable %s" apid="%s">[x]</span>
  1363. <span class="apid " apid="%s">%s:</span>
  1364. <span class="apinfo" id="api_%s" apid="%s" x="%s" y="%s" z ="%s">&#160;</span>
  1365. </td>''' % (activeness, apid, apid, apid, apid, apid, x, y, z)
  1366. aptds.append(s)
  1367. if i % 7 == 6:
  1368. aptrs.append('<tr>%s</tr>' % ''.join(aptds))
  1369. aptds[:] = []
  1370. aptrs.append('<tr>%s</tr>' % ''.join(aptds))
  1371. body = '''
  1372. <div id="meta" style="display:none">
  1373. <span id="pagename">%(pagename)s</span>
  1374. <div id="stationinfo">
  1375. <span id="name">%(station)s</span>
  1376. </div>
  1377. <span id="rgbdata" numcolors="%(numcolors)s">%(rgbdata)s</span>
  1378. </div>
  1379. <div id="info" style="position:absolute;left:10px;z-index:1000;background-color:white;font-size:small;border: 1px solid #EEE;">
  1380. <span> session ID: </span>
  1381. <span id="session_id"></span>
  1382. <span id="queuesize">queuesize: </span>
  1383. <span id="clientqueuesize">client: </span>
  1384. <span id="debug"></span>
  1385. <span> z: </span>
  1386. <span id="top_z"></span>
  1387. <span> hight (m): </span>
  1388. <span id="pos_hight"></span>
  1389. <table id="aptable">
  1390. %(aptrs)s
  1391. </table>
  1392. </div>
  1393. <div id="buttons" style="top:20px;position:absolute;right:20px; z-index:1001">
  1394. <div class="layer" layer="topn_vlayer">Top N</div>
  1395. <br/>
  1396. <div class="layer" layer="ap_vlayer">APs</div>
  1397. <br/>
  1398. <div class="layer" layer="pos_vlayer">Positions</div>
  1399. <br/>
  1400. <br/>
  1401. <div class="baselayer" layer="eg_layer" style="background-color:#CFC">EG</div>
  1402. <br/>
  1403. <div class="baselayer" layer="og1_layer">OG1</div>
  1404. <br/>
  1405. <div class="baselayer" layer="og2_layer">OG2</div>
  1406. <br/>
  1407. <br/>
  1408. <div id="startstop">Start</div>
  1409. </div>
  1410. <div id="map"/>
  1411. ''' % {'pagename': 'localize',
  1412. 'station': device,
  1413. 'rgbdata':rgbdata,
  1414. 'numcolors': numcolors,
  1415. 'aptrs': '\n'.join(aptrs),
  1416. }
  1417. css = '''
  1418. table {
  1419. border-collapse:collapse;
  1420. width: 100%;
  1421. }
  1422. div#buttons div {
  1423. padding-left: 10px;
  1424. padding-right: 10px;
  1425. padding-top: 5px;
  1426. padding-bottom: 5px;
  1427. background-color: #EEE;
  1428. border: 2px solid #AAA;
  1429. cursor:pointer;
  1430. font-weight:bold;
  1431. }
  1432. div#buttons div:hover {
  1433. border: 2px solid #444;
  1434. }
  1435. div#buttons div#startstop {
  1436. background-color: #25BB25;
  1437. }
  1438. table#aptable {
  1439. font-size: small;
  1440. width: 1250px;
  1441. }
  1442. span.apinfo {
  1443. font-weight: normal;
  1444. float:right;
  1445. }
  1446. span.apid {
  1447. cursor: pointer;
  1448. }
  1449. span.apdisable {
  1450. cursor: pointer;
  1451. font-weight: normal;
  1452. }
  1453. span.inactive_ap {
  1454. color: red;
  1455. }
  1456. span.show_ap_data {
  1457. color: green;
  1458. }
  1459. '''
  1460. js = ['/OpenLayers-2.12/OpenLayers.js', 'localize.js']
  1461. #~ js = ['OpenLayers-2.8/OpenLayers.js', 'localize.js']
  1462. return render(body=body, css=css, js=js)