work on result rendering

* add tracks + heat map
* copy result lists instead of using just a reference
* introduce proper logging
simu_flags
agp8x 2017-08-16 15:26:44 +02:00
parent b81719aba3
commit 36ff8fd0be
12 changed files with 249 additions and 28 deletions

View File

@ -1,15 +1,15 @@
from typing import List
from .analyzer import Analyzer, Result
from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer
from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer, ActivationSequenceAnalyzer
from .analyzer.default import LogEntryCountAnalyzer, LocationAnalyzer, LogEntrySequenceAnalyzer, ActionSequenceAnalyzer
from .analyzer.locomotion import LocomotionActionAnalyzer, CacheSequenceAnalyzer
from .analyzer.mask import MaskSpatials
from .render import Render
from .render.default import PrintRender, JSONRender
from .render.default import PrintRender, JSONRender, TrackRender, HeatMapRender
from .render.locomotion import LocomotionActionRelativeRender, LocomotionActionAbsoluteRender, \
LocomotionActionRatioRender
from .render.biogames import SimulationRoundsRender
from .render.biogames import SimulationRoundsRender, BoardDurationHistRender, BoardDurationBoxRender
__FALLBACK__ = PrintRender
__MAPPING__ = {
@ -23,7 +23,18 @@ __MAPPING__ = {
SimulationRoundsAnalyzer: [
JSONRender,
SimulationRoundsRender,
]
],
BoardDurationAnalyzer: [
BoardDurationHistRender,
BoardDurationBoxRender,
],
ActivationSequenceAnalyzer: [
JSONRender,
],
LocationAnalyzer: [
TrackRender,
#HeatMapRender,
],
}
@ -37,4 +48,6 @@ def render(cls: type, results: List[Result]):
for r in get_renderer(cls):
p = r()
p.result_types.append(cls)
p.render(results)
rendered = p.render(results)
if rendered:
print(str(r))

View File

@ -1,19 +1,24 @@
from analyzers.settings import LogSettings
import logging
log = logging.getLogger(__name__)
class Result:
def __init__(self, analysis, result):
self.result = result
self.__analysis__ = analysis
log.debug("set" + str(len(self.result)))
def analysis(self):
return self.__analysis__
def get(self):
log.debug("get" + str(len(self.result)))
return self.result
def __repr__(self):
return "<Result " + str(self.__analysis__) + ": " + str(type(self.result)) + ">"
return "<Result " + str(self.__analysis__) + ": " + str(type(self.result)) + " "+str(len(self.result))+">"
class Analyzer:

View File

@ -1,7 +1,10 @@
import logging
from collections import defaultdict
from . import Result, LogSettings, Analyzer
logger = logging.getLogger(__name__)
class BoardDurationAnalyzer(Analyzer):
"""
@ -61,3 +64,21 @@ class SimulationRoundsAnalyzer(Analyzer):
simu_id = entry['answers']["@id"]
self.store[simu_id] += 1
return False
class ActivationSequenceAnalyzer(Analyzer):
__name__ = "ActivationSequence"
def __init__(self, settings: LogSettings):
super().__init__(settings)
self.store = []
def result(self) -> Result:
return Result(type(self), self.store)
def process(self, entry: dict) -> bool:
if entry[self.settings.type_field] in self.settings.sequences['start']:
if entry['cache']:
self.store.append(entry['cache']['@id'])
else:
logger.error("null cache")

View File

@ -1,4 +1,4 @@
import json
import logging
from collections import defaultdict
from . import Result, LogSettings, Analyzer
@ -10,25 +10,19 @@ class LocationAnalyzer(Analyzer):
"""
entries = []
__name__ = "Location"
class Formats:
geojson = 0
log = logging.getLogger(__name__)
def __init__(self, settings: LogSettings):
super().__init__(settings)
def result(self) -> Result:
# return self.entries
return Result(type(self), self.entries)
def render(self, format: int = Formats.geojson):
if format is self.Formats.geojson:
return json.dumps([entry['location']['coordinates'] for entry in self.entries])
raise NotImplementedError()
self.log.debug(len(self.entries))
return Result(type(self), list(self.entries))
def process(self, entry: dict) -> bool:
if entry[self.settings.type_field] in self.settings.spatials:
self.entries.append(entry)
#self.log.debug(len(self.entries))
return False
@ -57,7 +51,7 @@ class LogEntrySequenceAnalyzer(Analyzer):
__name__ = "LogEntrySequence"
def result(self) -> Result:
return Result(type(self), self.store)
return Result(type(self), list(self.store))
def process(self, entry: dict) -> bool:
entry_type = entry[self.settings.type_field]

View File

@ -87,7 +87,7 @@ class CacheSequenceAnalyzer(Analyzer):
return False
def result(self) -> Result:
return Result(type(self), self.store)
return Result(type(self), list(self.store))
def __init__(self, settings: LogSettings):
super().__init__(settings)

View File

@ -4,7 +4,7 @@ from typing import List, Tuple
import matplotlib.pyplot as plt
from . import Render
from .. import Result, SimulationRoundsAnalyzer
from .. import Result, SimulationRoundsAnalyzer, BoardDurationAnalyzer
def plot(src_data: List[Tuple[str, List[int]]]):
@ -29,3 +29,36 @@ class SimulationRoundsRender(Render):
plot(data_tuples)
result_types = [SimulationRoundsAnalyzer]
class BoardDurationHistRender(Render):
result_types = [BoardDurationAnalyzer]
def render(self, results: List[Result]):
data = []
for result in self.filter(results):
session = result.get()
_data = []
for board in session:
if "active" in board:
_data.append(board["active"])
else:
_data.append(0)
data.append(_data)
n, bins, patches = plt.hist(data, log=True)
plt.show()
class BoardDurationBoxRender(Render):
result_types = [BoardDurationAnalyzer]
def render(self, results: List[Result]):
data = defaultdict(list)
for result in self.filter(results):
get = result.get()
for board in get:
duration = board['active'] if 'active' in board else 0
data[board['id']].append(duration)
data_tuples = [(key, data[key]) for key in sorted(data)]
data_tuples = sorted(data_tuples, key=lambda x: sum(x[1]))
plot(data_tuples)

View File

@ -1,7 +1,11 @@
import json
import logging
from typing import List
from . import Render, Result
from .. import LocationAnalyzer
log = logging.getLogger(__name__)
class PrintRender(Render):
@ -12,3 +16,34 @@ class PrintRender(Render):
class JSONRender(Render):
def render(self, results: List[Result]):
print(json.dumps([r.get() for r in self.filter(results)], indent=1))
class TrackRender(Render):
result_types = [LocationAnalyzer]
def render(self, results: List[Result]):
data = []
log.debug(results)
for result in self.filter(results):
if len(result.get()) > 0:
data.append(
[[entry['location']['coordinates'][1], entry['location']['coordinates'][0]] for entry in
result.get()])
dumps = json.dumps(data)
with open("track_data.js", "w") as out:
out.write("tracks=" + dumps + ";")
return dumps
class HeatMapRender(TrackRender):
weight = 0.01
def render(self, results: List[Result]):
raw = super(HeatMapRender, self).render(results)
data = []
for session in json.loads(raw):
data += [(entry[0], entry[1], self.weight) for entry in session]
dumps = json.dumps(data)
with open('heat_data.js', 'w') as out:
out.write("coords = " + dumps + ";")
return dumps

View File

@ -13,16 +13,18 @@
],
"analyzers": {
"analyzers": [
"LocationAnalyzer",
"LocationAnalyzer"
]
},
"disabled_analyzers":[
"LogEntryCountAnalyzer",
"LogEntrySequenceAnalyzer",
"ActionSequenceAnalyzer",
"BoardDurationAnalyzer",
"LocomotionActionAnalyzer",
"CacheSequenceAnalyzer",
"SimulationRoundsAnalyzer"
]
},
"SimulationRoundsAnalyzer",
"ActivationSequenceAnalyzer"],
"sequences": {
"start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryCache",
"end": {

View File

@ -1,3 +1,4 @@
import logging
from load import LOADERS
from typing import List
from analyzers import get_renderer, Analyzer, render
@ -5,6 +6,10 @@ from analyzers.settings import LogSettings, load_settings
import analyzers
logging.basicConfig(format='%(levelname)s %(name)s:%(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
def process_log(log_id: str, settings: LogSettings) -> List[Analyzer]:
logfile = "data/inst_{id}.{format}".format(id=log_id, format=settings.log_format)
loader = LOADERS[settings.log_format]()
@ -28,7 +33,8 @@ if __name__ == '__main__':
"20d4244719404ffab0ca386c76e4b112",
"56d9b64144ab44e7b90bf766f3be32e3",
"dc2cdc28ca074715b905e4aa5badff10",
"e32b16998440475b994ab46d481d3e0c", ]
"e32b16998440475b994ab46d481d3e0c",
]
log_ids = [
"34fecf49dbaca3401d745fb467",
"44ea194de594cd8d63ac0314be",
@ -41,16 +47,17 @@ if __name__ == '__main__':
"fe1331481f85560681f86827ec",
"fec57041458e6cef98652df625", ]
results = []
#TODO: capture session ID, dict
for log_id in log_ids:
for analysis in process_log(log_id, settings):
print("* Result for " + analysis.name())
logger.info("* Result for " + analysis.name())
# print(analysis.result())
# print(analysis.render())
results.append(analysis.result())
if False:
for r in get_renderer(analyzers.LocomotionActionAnalyzer):
r().render(results)
render(analyzers.SimulationRoundsAnalyzer, results)
render(analyzers.LocationAnalyzer, results)
# for analyzers in analyzers:
# if analyzers.name() in ["LogEntryCount", "ActionSequenceAnalyzer"]:

View File

@ -1 +0,0 @@
[]

46
static/heatmap.html Normal file
View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet.heat demo</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.js"></script>
<style>
#map { width: 1024px; height: 768px; }
body { font: 16px/1.4 "Helvetica Neue", Arial, sans-serif; }
.ghbtns { position: relative; top: 4px; margin-left: 5px; }
a { color: #0077ff; }
</style>
</head>
<body>
<div id="map"></div>
<!-- <script src="../node_modules/simpleheat/simpleheat.js"></script>
<script src="../src/HeatLayer.js"></script> -->
<script src="https://rawgit.com/Leaflet/Leaflet.heat/gh-pages/dist/leaflet-heat.js"></script>
<!--script src="./test.js"></script-->
<script>
var options = {maxZoom:22};
var map = L.map('map', options).setView([49.90299388, 10.87004638], 17);
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
function addHeat(coords){
var transformed = coords.map(function (p) { return [p[1], p[0], 0.25]; });
var heat = L.heatLayer(transformed).addTo(map);
}
//coords = coords.map(function (p) { return [p[1], p[0], 0.05]; });
//var heat = L.heatLayer(coords).addTo(map);
addHeat(coords);
</script>
<!--script src="./coord.js"></script>
<script>
//addHeat(coords);
</script-->
</body>
</html>

66
static/trackmap.html Normal file
View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<title>Leaflet.heat demo</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
crossorigin=""></script>
<style>
#map { width: 1024px; height: 768px; }
body { font: 16px/1.4 "Helvetica Neue", Arial, sans-serif; }
.ghbtns { position: relative; top: 4px; margin-left: 5px; }
a { color: #0077ff; }
</style>
</head>
<body>
<div id="map"></div>
<!-- <script src="../node_modules/simpleheat/simpleheat.js"></script>
<script src="../src/HeatLayer.js"></script> -->
<script src="http://rawgit.com/Leaflet/Leaflet.heat/gh-pages/dist/leaflet-heat.js"></script>
<script src="./track_data.js"></script>
<script>
var options = {maxZoom:22};
//var map = L.map('map', options).setView([49.90299388, 10.87004638], 17);
var map = L.map('map', options);
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
function addHeat(coords){
//var transformed = coords.map(function (p) { return [p[1], p[0], 0.25]; });
var heat = L.heatLayer(coords).addTo(map);
}
var layers=[];
function addTrack(tracks, i){
layers[i] = L.polyline(tracks[i], {color:"green"});
map.fitBounds(layers[i].getBounds());
layers[i].on('mouseover', function (e) {
e.target.setStyle({'color':'red'});
});
layers[i].on('mouseout', function (e) {
e.target.setStyle({'color':'green'});
});
}
//coords = coords.map(function (p) { return [p[1], p[0], 0.05]; });
//var heat = L.heatLayer(coords).addTo(map);
//addHeat(coords);
for (var i in tracks) {
addTrack(tracks, i);
}
L.control.layers(null, layers).addTo(map);
</script>
<!--script src="./heat_data.js"></script>
<script>
addHeat(coords);
</script-->
</body>
</html>