Compare commits

...

9 Commits

Author SHA1 Message Date
Clemens Klug cbe414232c improve time tracking of tasks and CSV formatting 2019-10-15 14:42:51 +02:00
Clemens Klug bc74cbd19a fix non-OEBRenders 2019-10-10 11:58:45 +02:00
Clemens Klug 86adc973a2 add oeb-new config 2019-10-07 17:20:23 +02:00
Clemens Klug 29c04f2fdc commit uncommited changes 2019-10-02 13:20:51 +02:00
Clemens Klug 4a53aa5759 fix selector for multi-game configurations 2018-08-06 09:40:36 +02:00
Clemens Klug 51b5e8f04c add track length simplifier 2018-06-19 14:47:08 +02:00
agp8x c4e9d7462b cleanup 2018-06-15 11:02:46 +02:00
Clemens Klug 2170a4a3fd add missing result visualizing script 2018-06-15 11:00:00 +02:00
Clemens Klug 9533554cac frontend-reference: add https port mapping 2018-06-12 13:57:08 +02:00
39 changed files with 978 additions and 426 deletions

View File

@ -2,7 +2,7 @@ FROM alpine:edge
ADD ["requirements.txt", "/"] ADD ["requirements.txt", "/"]
RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \ RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing/" >> /etc/apk/repositories && \
apk add --update --no-cache libpng freetype python3 libstdc++ libxml2 libxslt openblas && \ apk add --update --no-cache libpng freetype python3 libstdc++ libxml2 libxslt openblas geos libc-dev && \
apk add --update --no-cache --virtual .build-deps libpng-dev freetype-dev g++ python3-dev openblas-dev libxml2-dev libxslt-dev && \ apk add --update --no-cache --virtual .build-deps libpng-dev freetype-dev g++ python3-dev openblas-dev libxml2-dev libxslt-dev && \
pip3 --no-cache-dir install -r requirements.txt && \ pip3 --no-cache-dir install -r requirements.txt && \
apk del .build-deps && \ apk del .build-deps && \

View File

@ -3,18 +3,19 @@ from typing import List
from .analyzer import Analyzer, Result from .analyzer import Analyzer, Result
from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer, ActivationSequenceAnalyzer, \ from .analyzer.biogames import BoardDurationAnalyzer, SimulationRoundsAnalyzer, ActivationSequenceAnalyzer, \
BiogamesCategorizer, ActivityMapper, BiogamesStore, InstanceConfig, SimulationOrderAnalyzer, SimulationCategorizer, \ BiogamesCategorizer, ActivityMapper, BiogamesStore, InstanceConfig, SimulationOrderAnalyzer, SimulationCategorizer, \
SimulationFlagsAnalyzer SimulationFlagsAnalyzer, GameField_InstanceCategorizer, BiogamesTasks, BiogamesDuration, GameFieldInstanceGroup
from .analyzer.default import LogEntryCountAnalyzer, LocationAnalyzer, LogEntrySequenceAnalyzer, ActionSequenceAnalyzer, \ from .analyzer.default import LogEntryCountAnalyzer, LocationAnalyzer, LogEntrySequenceAnalyzer, ActionSequenceAnalyzer, \
CategorizerStub, Store, ProgressAnalyzer, SimpleCategorizer CategorizerStub, Store, ProgressAnalyzer, SimpleCategorizer, WhitelistAnalyzer
from .analyzer.locomotion import LocomotionActionAnalyzer, CacheSequenceAnalyzer from .analyzer.locomotion import LocomotionActionAnalyzer, CacheSequenceAnalyzer
from .analyzer.mask import MaskSpatials from .analyzer.mask import MaskSpatials
from .render import Render from .render import Render
from .render.biogames import SimulationRoundsRender, BoardDurationHistRender, BoardDurationBoxRender, \ from .render.biogames import SimulationRoundsRender, BoardDurationHistRender, BoardDurationBoxRender, \
ActivityMapperRender, StoreRender, SimulationOrderRender, SimulationGroupRender ActivityMapperRender, StoreRender, SimulationOrderRender, SimulationGroupRender
from .render.default import PrintRender, JSONRender, TrackRender, HeatMapRender, LogEntryCountAnalyzerPlot, \ from .render.default import PrintRender, JSONRender, TrackRender, HeatMapRender, LogEntryCountAnalyzerPlot, \
LogEntryCountCSV, KMLRender LogEntryCountCSV, KMLRender, GeoJSON
from .render.locomotion import LocomotionActionRelativeRender, LocomotionActionAbsoluteRender, \ from .render.locomotion import LocomotionActionRelativeRender, LocomotionActionAbsoluteRender, \
LocomotionActionRatioRender LocomotionActionRatioRender
#from .render.wip import get_all_data, plot_time_space_rel
__FALLBACK__ = PrintRender __FALLBACK__ = PrintRender
__MAPPING__ = { __MAPPING__ = {

View File

@ -29,13 +29,16 @@ class Result:
class ResultStore: class ResultStore:
"""Store Results""" """Store Results"""
def __init__(self, store_entry: Type[Collection] = list, store_action: callable = list.append) -> None: def __init__(self, store_entry: Type[Collection] = list, store_action: callable = list.append, key_index=None) -> None:
self.store = {} self.store = {}
self.category = None self.category = None
self.entry: Type[Collection] = store_entry self.entry: Type[Collection] = store_entry
self.action: callable = store_action self.action: callable = store_action
self.key_index = key_index
def new_category(self, key) -> None: def new_category(self, key) -> None:
if not self.key_index is None:
key = key[self.key_index]
self.category = key self.category = key
if not key in self.store: if not key in self.store:
self.store[key] = self.entry() self.store[key] = self.entry()

View File

@ -133,6 +133,48 @@ class BiogamesCategorizer(CategorizerStub): # TODO: refactor
return False return False
class GameField_InstanceCategorizer(CategorizerStub): # TODO: refactor
__name__ = "BiogamesCategorizer"
def __init__(self, settings: LogSettings):
super().__init__(settings)
def process(self, entry: dict) -> bool:
if self.key is "default":
if entry[self.settings.type_field] in self.settings.custom['instance_start']:
try:
self.key = json_path(entry, self.settings.custom['instance_config_id']) + "_" + entry[self.settings.custom['instance_id']] + "_" + str(entry["timestamp"])
except KeyError as e:
print(entry)
raise e
return False
class GameFieldInstanceGroup(Analyzer):
__name__ = "BiogamesGamefieldInstanceGroupAnalizer"
def __init__(self, settings: LogSettings):
super().__init__(settings)
self.metadata = None
def process(self, entry: dict) -> bool:
if not self.metadata:
if entry[self.settings.type_field] in self.settings.custom['instance_start']:
try:
self.metadata = {"instance_config_id": json_path(entry, self.settings.custom['instance_config_id']),
"instance_id": entry[self.settings.custom['instance_id']],
"timestamp": str(entry["timestamp"]),
"player_group_name": entry['player_group_name']
}
except KeyError as e:
print(entry)
raise e
return False
def result(self, store: ResultStore, **kwargs) -> None:
store.add(Result(type(self), self.metadata))
class ActivityMapper(Analyzer): class ActivityMapper(Analyzer):
__name__ = "ActivityMapper" __name__ = "ActivityMapper"
classes = { classes = {
@ -158,6 +200,7 @@ class ActivityMapper(Analyzer):
self.last_board = {} self.last_board = {}
self.last_board_type = "other" self.last_board_type = "other"
self.last_coordinate = None self.last_coordinate = None
self.last_timestamp = None
self.tracks = [] self.tracks = []
self.track = None self.track = None
self.instance_config_id: str = None self.instance_config_id: str = None
@ -173,21 +216,28 @@ class ActivityMapper(Analyzer):
if board["extra_data"]["activity_type"] == "simu": if board["extra_data"]["activity_type"] == "simu":
board["image"] = "simu.png" board["image"] = "simu.png"
continue continue
local_file = download_board(board["board_id"], self.instance_config_id, board["sequence_id"], try:
local_file = download_board(board["board_id"], self.instance_config_id, board["sequence_id"],
self.settings.source) self.settings.source)
if local_file: if local_file:
board['image'] = local_file board['image'] = local_file
else: else:
raise ValueError
except Exception as e:
board['image'] = "ERROR_FETCHING_FILE" board['image'] = "ERROR_FETCHING_FILE"
logger.error("error downloading board! %s %s %s", self.instance_config_id, board["sequence_id"], logger.error("error downloading board! %s %s %s", self.instance_config_id, board["sequence_id"],
board["board_id"]) board["board_id"])
logger.exception(e)
else: else:
board["image"] = "map.png" board["image"] = "map.png"
store.add(Result(type(self), { store.add(Result(type(self), {
"instance": self.instance_config_id, "type": "FeatureCollection",
"track": self.tracks, "features": self.tracks,
"boards": self.timeline, "properties": {
"colors": self.colors, "instance": self.instance_config_id,
"boards": self.timeline,
"colors": self.colors,
},
})) }))
def process(self, entry: dict) -> bool: def process(self, entry: dict) -> bool:
@ -242,20 +292,120 @@ class ActivityMapper(Analyzer):
def add_location(self, entry): def add_location(self, entry):
coordinates = json_path(entry, self.settings.custom['coordinates']) coordinates = json_path(entry, self.settings.custom['coordinates'])
self.track['coordinates'].append(coordinates) self.track["geometry"]['coordinates'].append(coordinates)
self.track['properties']['coordTimes'].append(entry['timestamp']) #FIXME
self.last_coordinate = coordinates self.last_coordinate = coordinates
self.last_timestamp = entry['timestamp']
def add_track(self, **props): def add_track(self, **props):
self.track['properties'].update(props) self.track['properties'].update(props)
if "activity_type" in self.track['properties'] and self.track['properties']['activity_type'] in self.colors:
if not "stroke" in self.track['properties']:
self.track['properties']['stroke'] = self.colors[self.track['properties']['activity_type']]
self.tracks.append(self.track) self.tracks.append(self.track)
self.track = self.new_track(props['end_timestamp']) self.track = self.new_track(props['end_timestamp'])
if self.last_coordinate: if self.last_coordinate:
self.track['coordinates'].append(self.last_coordinate) self.track["geometry"]['coordinates'].append(self.last_coordinate)
self.track['properties']['coordTimes'].append(self.last_timestamp)
def new_track(self, timestamp): def new_track(self, timestamp):
return {"type": "LineString", "coordinates": [], "properties": {'start_timestamp': timestamp}} return {"type": "Feature", "geometry": {"type": "LineString", "coordinates": []}, "properties": {'start_timestamp': timestamp, 'coordTimes': []}}
class BiogamesDuration(Analyzer):
__name__ = "BiogamesDuration"
def __init__(self, settings: LogSettings) -> None:
super().__init__(settings)
self.first = None
self.last = None
self.sequences = defaultdict(list)
self.filters = SimpleNamespace()
self.filters.start = lambda entry: combinate(self.settings.custom["sequences2"]["start"], entry)
self.filters.end = lambda entry: combinate(self.settings.custom["sequences2"]["end"], entry)
self.sequence = None
self.sequence_start = None
self.cache = "None"
def process(self, entry: dict) -> bool:
if not self.first:
self.first = entry['timestamp']
self.last = entry['timestamp']
if not self.sequence and self.filters.start(entry):
self.sequence = entry['sequence_id']
self.sequence_start = entry['timestamp']
elif self.sequence and self.filters.end(entry):
self.sequences[f"{self.cache}+{self.sequence}"].append((self.sequence_start, entry['timestamp']))
self.sequences[f"only+{self.sequence}"].append((self.sequence_start, entry['timestamp']))
self.sequence = None
self.sequence_start = 0
self.cache = "None"
if entry['@class'] in self.settings.sequences['start']:
if entry['cache']:
self.cache = entry['cache']['@id']
else:
self.cache = "None"
return False
def result(self, store: ResultStore, name=None) -> None:
results = {"start": self.first, "end": self.last, "duration": self.last - self.first}
for sid in self.sequences:
seq = self.sequences[sid]
#print([end-start for start,end in seq])
results[f"sequence_{sid}_duration"] = sum([end-start for start,end in seq])
store.add(Result(type(self), results))
class BiogamesTasks(Analyzer):
__name__ = "BiogamesTasks"
DATA_CLASSES = ("de.findevielfalt.games.game2.instance.log.entry.LogEntryQuestion", )
BOARD_CLASSES = ("de.findevielfalt.games.game2.instance.log.entry.ShowBoardLogEntry",)
def __init__(self, settings: LogSettings) -> None:
super().__init__(settings)
self.settings: LogSettings = settings
self.tasks = {}
self.first_board_view = {}
self.last_board = None
self.instance_config_id: str = None
def process(self, entry: dict) -> bool:
if self.instance_config_id is None:
if entry[self.settings.type_field] in self.settings.custom['instance_start']:
self.instance_config_id = json_path(entry, self.settings.custom['instance_config_id'])
if self.is_task(entry):
task_id = entry['answers']['@id']
if task_id not in self.first_board_view:
logger.error("task_id is not in self.first_board_view!", task_id, entry)
else:
entry['__duration'] = entry['timestamp'] - self.first_board_view[task_id]['timestamp']
self.tasks[self.ids(task_id)] = entry
if self.is_board(entry):
self.first_board_view[entry['board_id']] = entry
return False
def result(self, store: ResultStore, name=None) -> None:
results = {}
for ids in self.tasks:
task = self.tasks[ids]
for action in task['selected_actions']:
if self.is_dollar_action(action):
results[ids] = {"duration": task['__duration'], "result": action['increment']}
store.add(Result(type(self), results))
def ids(self, task_id):
task = self.first_board_view[task_id]
return f"{self.instance_config_id}_{task['sequence_id']}_{task['board_id']}"
def is_task(self, entry) -> bool:
return entry['@class'] in self.DATA_CLASSES
def is_board(self, entry) -> bool:
return entry['@class'] in self.BOARD_CLASSES
def is_dollar_action(self, action):
return action['@class'] in ("de.findevielfalt.games.game2.instance.action.IncrementDiversityDollarAction")
class BiogamesStore(Store): class BiogamesStore(Store):
__name__ = "BiogamesStore" __name__ = "BiogamesStore"

View File

@ -5,6 +5,26 @@ from analysis.util import json_path
from . import Result, LogSettings, Analyzer, ResultStore from . import Result, LogSettings, Analyzer, ResultStore
class WhitelistAnalyzer(Analyzer): #TODO
__name__ = "WhiteList"
def __init__(self, settings: LogSettings) -> None:
super().__init__(settings)
self.key = settings.custom["whitelist"]["key"]
self.filter_objs = settings.custom["whitelist"]["objs"]
self.valid_entries = settings.custom["whitelist"]["valid"]
self.blocked = False
def result(self, store: ResultStore, name=None) -> None:
store.add(Result(type(self), {"blocked": self.blocked}, name=name))
def process(self, entry: dict) -> bool:
if entry[self.settings.type_field] in self.filter_objs:
if not json_path(entry, self.key) in self.valid_entries:
self.blocked = True
return self.blocked
class LocationAnalyzer(Analyzer): class LocationAnalyzer(Analyzer):
""" """
store spatial log entries store spatial log entries
@ -17,7 +37,7 @@ class LocationAnalyzer(Analyzer):
self.entries = [] self.entries = []
def result(self, store: ResultStore, **kwargs) -> None: def result(self, store: ResultStore, **kwargs) -> None:
self.log.debug(len(self.entries)) #self.log.debug(len(self.entries))
store.add(Result(type(self), list(self.entries), name=kwargs['name'])) store.add(Result(type(self), list(self.entries), name=kwargs['name']))
def process(self, entry: dict) -> bool: def process(self, entry: dict) -> bool:
@ -90,7 +110,8 @@ class CategorizerStub(Analyzer):
__name__ = "Categorizer" __name__ = "Categorizer"
def result(self, store: ResultStore, name=None) -> None: def result(self, store: ResultStore, name=None) -> None:
store.new_category(name if name else self.key) print(name if name else self.key)
store.new_category((name, self.key) if name else self.key)
def __init__(self, settings: LogSettings): def __init__(self, settings: LogSettings):
super().__init__(settings) super().__init__(settings)

View File

@ -41,7 +41,7 @@ class LocomotionActionAnalyzer(Analyzer):
self.current_cache = None self.current_cache = None
self.last = None self.last = None
def result(self, store: ResultStore) -> None: def result(self, store: ResultStore, **kwargs) -> None:
if self.last is not None: if self.last is not None:
if self.current_cache is None: if self.current_cache is None:
self.locomotion.append(self.last - self.cache_time) self.locomotion.append(self.last - self.cache_time)
@ -50,7 +50,14 @@ class LocomotionActionAnalyzer(Analyzer):
self.last = None self.last = None
locomotion = sum(self.locomotion) locomotion = sum(self.locomotion)
action = sum(self.actions) action = sum(self.actions)
if action== 0:
action = 42
print("Division by zero") #FIXME
total = locomotion + action total = locomotion + action
if not self.last_timestamp:
self.last_timestamp = 0
if not self.instance_start:
self.instance_start = 0
store.add(Result(type(self), { store.add(Result(type(self), {
'locomotion_sum': locomotion, 'locomotion_sum': locomotion,
'action_sum': action, 'action_sum': action,

View File

@ -1,6 +1,10 @@
import logging
from typing import List from typing import List
from analysis.analyzers.analyzer import ResultStore
from .. import Result from .. import Result
logger = logging.getLogger(__name__)
class Render: class Render:
result_types = [] result_types = []
@ -8,6 +12,11 @@ class Render:
def render(self, results: List[Result], name=None) -> [str]: def render(self, results: List[Result], name=None) -> [str]:
raise NotImplementedError() raise NotImplementedError()
def render_store(self, store: ResultStore, name=None) -> str:
logging.getLogger(__name__).warning("using default implementation!")
for category in store.get_categories():
self.render(store.get_category(category), name=name)
def filter(self, results: List[Result]): def filter(self, results: List[Result]):
if len(self.result_types) == 0: if len(self.result_types) == 0:
return results return results

View File

@ -1,4 +1,5 @@
import json import json
import tempfile
from collections import defaultdict from collections import defaultdict
from typing import List, Tuple from typing import List, Tuple
@ -9,8 +10,13 @@ from scipy.interpolate import interp1d
import networkx as nx import networkx as nx
import itertools import itertools
from analysis.analyzers import Store, BiogamesStore, SimulationOrderAnalyzer from analysis.analyzers import Store, BiogamesStore, SimulationOrderAnalyzer, LocationAnalyzer, BiogamesDuration, \
from analysis.util.meta_temp import CONFIG_NAMES BiogamesTasks, GameFieldInstanceGroup
from analysis.analyzers.analyzer import ResultStore
from analysis.analyzers.render.default import GeoJSON
from analysis.util.geo import calc_distance, calc_distance_simplified
from analysis.util.meta_temp import CONFIG_NAMES, TASK_NAMES, CACHE_NAMES, SEQUENCE_NAMES
from analysis.util.output import flat_dict_to_csv, pretty_ts
from . import Render from . import Render
from .. import Result, SimulationRoundsAnalyzer, BoardDurationAnalyzer, ActivityMapper from .. import Result, SimulationRoundsAnalyzer, BoardDurationAnalyzer, ActivityMapper
@ -155,7 +161,7 @@ class ActivityMapperRender(Render):
files = [] files = []
for result in self.filter(results): for result in self.filter(results):
data = result.get() data = result.get()
path = os.path.join("/tmp", data['instance'] + "_" + str(name) + ".json") path = os.path.join("/tmp", data["properties"]['instance'] + "_" + str(name) + ".json")
with open(path, "w") as out: with open(path, "w") as out:
json.dump(data, out, indent=1) json.dump(data, out, indent=1)
files.append(path) files.append(path)
@ -201,3 +207,60 @@ class SimulationGroupRender(Render):
name=name) name=name)
result_types = [SimulationOrderAnalyzer] result_types = [SimulationOrderAnalyzer]
class OEBRender(Render):
result_types = [LocationAnalyzer, BiogamesTasks, BiogamesDuration, GameFieldInstanceGroup]
timestamp_fields = ("timestamp", "start", "end")
def render(self, results: List[Result], name=None) -> [str]:
data = {}
for r in self.filter(results):
if r.analysis() is LocationAnalyzer:
geojson = GeoJSON()
json = geojson.make_geojson(r.get())
data[f"{r.analysis().__name__}__distance"] = calc_distance(json, "features.0.geometry.coordinates", load=False)
data[f"{r.analysis().__name__}__distance_simplified"] = calc_distance_simplified(json, "features.0.geometry.coordinates", load=False)
else:
for i in r.get():
a = r.analysis().__name__
value = r.get()[i]
if i in self.timestamp_fields:
value = pretty_ts(value)
key = f"{a}__{i}"
key = self.replace(key, i)
if type(value) is dict:
for j in value:
data[key+"__"+j] = value[j]
else:
data[key] = value
return data
def render_store(self, store: ResultStore, name=None) -> str:
data = []
for category in store.get_categories():
data.append(self.render(store.get_category(category)))
#import json
#print(json.dumps(data, indent=1))
csv = flat_dict_to_csv(data)
#print(csv)
if name:
filename = str(name) + ".csv"
else:
filename = "/tmp/biogames" + ".csv"
try:
with open(filename, "w") as out:
out.write(csv)
except PermissionError as e:
raise PermissionError(e, filename)
return filename
def replace(self, key, i):
if i in TASK_NAMES:
key = f"{TASK_NAMES[i]} ({key})"
if "sequence_" in i:
sid = i.split("_")[1]
cache, seq = sid.split("+")
cache = CACHE_NAMES.get(cache, cache)
seq = SEQUENCE_NAMES.get(seq, seq)
key = f"{cache}->{seq} {sid} duration"
return key

View File

@ -1,3 +1,4 @@
import copy
import json import json
import logging import logging
from typing import List from typing import List
@ -6,7 +7,7 @@ import datetime
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from analysis.analyzers import LogEntryCountAnalyzer from analysis.analyzers import LogEntryCountAnalyzer
from analysis.util.meta_temp import KML_PATTERN from analysis.util.meta_temp import GEOJSON_COORDINATES, GEOJSON_PATTERN, KML_PATTERN
from . import Render, Result from . import Render, Result
from analysis.analyzers import LocationAnalyzer from analysis.analyzers import LocationAnalyzer
@ -23,9 +24,12 @@ class JSONRender(Render):
print(json.dumps([r.get() for r in self.filter(results)], indent=1)) print(json.dumps([r.get() for r in self.filter(results)], indent=1))
class TrackRender(Render): class SpatialRender:
result_types = [LocationAnalyzer] result_types = [LocationAnalyzer]
class TrackRender(SpatialRender, Render):
def render(self, results: List[Result], name=None): def render(self, results: List[Result], name=None):
data = [] data = []
log.debug(results) log.debug(results)
@ -42,11 +46,10 @@ class TrackRender(Render):
def format_time(ts): def format_time(ts):
return datetime.datetime.fromtimestamp(ts/1000).strftime("%Y-%m-%dT%H:%M:%S.%f") return datetime.datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%dT%H:%M:%S.%f")
class KMLRender(Render): class KMLRender(SpatialRender, Render):
result_types = [LocationAnalyzer]
def render(self, results: List[Result], name=None): def render(self, results: List[Result], name=None):
files = [] files = []
@ -59,14 +62,59 @@ class KMLRender(Render):
long=entry['location']['coordinates'][0]) long=entry['location']['coordinates'][0])
for entry in result.get() for entry in result.get()
] ]
filename = str(result.name)+".kml" if name:
filename = str(name) + ".kml"
else:
filename = str(result.name) + ".kml"
print(filename) print(filename)
with open(filename, "w") as out: with open(filename, "w") as out:
out.write(KML_PATTERN.format(name=str(result.name), coordinates="\n".join(coords), when="\n".join(times))) out.write(
KML_PATTERN.format(name=str(result.name), coordinates="\n".join(coords), when="\n".join(times)))
#with open(filename + ".json", "w") as out: #FIXME: why am I here??
# json.dump(result.get(), out, indent=1)
files.append(filename) files.append(filename)
return files return files
class GeoJSON(SpatialRender, Render):
template = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": []
}
}
]
}
def make_geojson(self, src):
coordinates = []
times = []
for location in src:
#print(location)
coordinates.append(location["location"]["coordinates"])
times.append(location["timestamp"])
template = copy.deepcopy(self.template)
template["features"][0]["properties"] = {"times": times}
template["features"][0]["geometry"]["coordinates"] = coordinates
return template
def render(self, results: List[Result], name=None) -> [str]:
files = []
for result in self.filter(results):
if name:
filename = str(name) + ".geojson"
else:
filename = str(result.name) + ".geojson"
json = self.make_geojson(result.get())
with open(filename, "w") as out:
json.dump(self.template, out, indent=1)
files.append(filename)
return files
class HeatMapRender(TrackRender): class HeatMapRender(TrackRender):
@ -104,6 +152,7 @@ class LogEntryCountAnalyzerPlot(Render):
plt.clf() plt.clf()
plt.close() plt.close()
class LogEntryCountCSV(Render): class LogEntryCountCSV(Render):
result_types = [LogEntryCountAnalyzer] result_types = [LogEntryCountAnalyzer]
summary = None summary = None
@ -113,4 +162,4 @@ class LogEntryCountCSV(Render):
return return
for result in self.filter(results): for result in self.filter(results):
raw_data = result.get() raw_data = result.get()
self.summary[name] = raw_data self.summary[name] = raw_data

View File

@ -3,6 +3,7 @@ import json
import numpy as np import numpy as np
import analysis.analyzers import analysis.analyzers
from analysis import analyzers
from analysis.util.geo import calc_distance from analysis.util.geo import calc_distance
@ -188,10 +189,11 @@ def get_all_data(store, sort=False, relative=True):
if not log.analysis() == analyzers.ActivityMapper: if not log.analysis() == analyzers.ActivityMapper:
continue continue
result = defaultdict(lambda: defaultdict(lambda: 0)) result = defaultdict(lambda: defaultdict(lambda: 0))
for i in log.get()['track']: for i in log.get()['features']:
coords = i['coordinates'] coords = i["geometry"]['coordinates']
print(coords)
if len(coords) > 1: if len(coords) > 1:
distance = calc_distance(coords) distance = calc_distance(json.dumps(i["geometry"]))
else: else:
distance = 0.0 distance = 0.0
result["space"][i['properties']['activity_type']] += distance result["space"][i['properties']['activity_type']] += distance
@ -219,9 +221,9 @@ def get_all_data(store, sort=False, relative=True):
value = percentage value = percentage
else: else:
value = total value = total
places[log.get()['instance']].append(value) places[log.get()["properties"]['instance']].append(value)
simus = defaultdict(lambda: 0) simus = defaultdict(lambda: 0)
for item in log.get()['boards']: for item in log.get()["properties"]['boards']:
if item["extra_data"]["activity_type"] == "simu": if item["extra_data"]["activity_type"] == "simu":
simus[item["board_id"]] += 1 simus[item["board_id"]] += 1
simu_distribution[len(simus)] += 1 simu_distribution[len(simus)] += 1
@ -381,7 +383,7 @@ def plot_time_space_rel(combined, keys):
print([CONFIG_NAMES[i] if i in CONFIG_NAMES else "---" for i in ids]) print([CONFIG_NAMES[i] if i in CONFIG_NAMES else "---" for i in ids])
# plt.show() # plt.show()
dpi = 200 dpi = 200
plt.savefig("speed2.png", dpi=dpi) plt.savefig("speed2_2019.png", dpi=dpi)

View File

@ -7,17 +7,19 @@ from analysis.analyzers import get_renderer, render
from analysis.analyzers.analyzer import ResultStore from analysis.analyzers.analyzer import ResultStore
from analysis.analyzers.analyzer.default import write_logentry_count_csv, write_simulation_flag_csv from analysis.analyzers.analyzer.default import write_logentry_count_csv, write_simulation_flag_csv
from analysis.analyzers.render import wip from analysis.analyzers.render import wip
from analysis.analyzers.render.default import LogEntryCountCSV, KMLRender from analysis.analyzers.render.default import LogEntryCountCSV, KMLRender, GeoJSON
from analysis.analyzers.render.wip import time_distribution, plot_data from analysis.analyzers.render.wip import time_distribution, plot_data
from analysis.analyzers.settings import LogSettings, load_settings, parse_settings from analysis.analyzers.settings import LogSettings, load_settings, parse_settings
from analysis.loaders import LOADERS from analysis.loaders import LOADERS
from analysis.util.processing import grep, run_analysis, src_file from analysis.util.processing import grep, run_analysis, src_file
from analysis.util.meta_temp import CONFIG_NAMES
logging.basicConfig(format='%(levelname)s %(name)s:%(message)s', level=logging.DEBUG) logging.basicConfig(format='%(levelname)s %(name)s:%(message)s', level=logging.DEBUG)
log: logging.Logger = logging.getLogger(__name__) log: logging.Logger = logging.getLogger(__name__)
logging.getLogger('requests').setLevel(logging.WARN) logging.getLogger('requests').setLevel(logging.WARN)
logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("urllib3").setLevel(logging.WARN)
logging.getLogger("shapely").setLevel(logging.WARN)
def urach_logs(log_ids, settings): def urach_logs(log_ids, settings):
@ -107,16 +109,127 @@ if __name__ == '__main__':
# plot_time_space_rel(combined, keys) # plot_time_space_rel(combined, keys)
plot_data(combined, wip.keys) plot_data(combined, wip.keys)
if True: if False:
def store(x):
pass
settings: LogSettings = load_settings("../oeb_kml.json") settings: LogSettings = load_settings("../oeb_kml.json")
log_ids = src_file("/home/clemens/git/ma/test/oeb_2016_path") #log_ids = src_file("/app/log_data/oeb/oeb_2016_path")
log_ids = log_ids[0:2] log_ids = src_file("/app/log_data/oeb/oeb_paths")
#log_ids = log_ids[0:10]
print(log_ids) print(log_ids)
store: ResultStore = run_analysis(log_ids, settings, LOADERS) store: ResultStore = run_analysis(log_ids, settings, LOADERS, ResultStore(key_index=1))
print("render") print("render")
kml = KMLRender() kml = GeoJSON()
kml.render(store.get_all()) fields = store.get_categories()
artifacts = {key: kml.render(store.get_category(key)) for key in fields}
print(artifacts)
print("done") print("done")
def atrifact_to_length(filename):
g = json.load(open(filename))
from analysis.util.geo import calc_distance
return calc_distance(json.dumps(g), "features.0.geometry.coordinates")
def simplified_length(filename):
from analysis.util.geo import json_to_track,distance
g = json.load(open(filename))
track = json_to_track(json.dumps(g), "features.0.geometry.coordinates")
simplified = track.simplify(0.0002, preserve_topology=True)
from shapely.geometry import mapping
json.dump(mapping(simplified), open(f"{filename}.simplified.geojson","w"), indent=1)
return distance(simplified)
from collections import defaultdict
def get_lengths(artifacts, atrifact_to_length=atrifact_to_length):
stats = defaultdict(list)
for field in artifacts:
print(field, CONFIG_NAMES[field])
for i in artifacts[field]:
distance = atrifact_to_length(i)
warn = "\tLONG!" if distance > 10000 else "\tSHORT!" if distance < 1000 else ""
print(f"\t{i}\t{distance}{warn}")
stats[field].append(distance)
return stats
stats = get_lengths(artifacts)
import numpy as np
def quart_1(x):
return np.percentile(x, 25)
def quart_2(x):
return np.percentile(x, 50)
def quart_3(x):
return np.percentile(x, 75)
def quart_4(x):
return np.percentile(x, 100)
def print_stats(stats):
fns = [np.size, np.min, np.max, np.mean, np.median]#, quart_1, quart_2, quart_3, quart_4]
names = "\t".join([x.__name__ for x in fns] + ["id","name"])
print(names)
for i in stats:
stat = [f"{fn(stats[i]):.2f}" for fn in fns]
print("\t".join(stat + [i, CONFIG_NAMES[i]]))
def plot_stats(stats, filtered_stats, suffix=""):
import matplotlib.pyplot as plt
keys = sorted(stats.keys())
names = [CONFIG_NAMES[i] for i in keys]
values = [stats[i] for i in keys]
values_filtered = [filtered_stats[i] for i in keys]
fig, ax = plt.subplots()
ax.boxplot(values, labels=names, showfliers=False, showmeans=True, meanline=True)
fig.savefig(f"/app/log_data/oeb/plots/plot_raw{suffix}.png")
fig, ax = plt.subplots()
ax.boxplot(values_filtered, labels=names, showfliers=False, showmeans=True, meanline=True)
fig.savefig(f"/app/log_data/oeb/plots/plot_filtered{suffix}.png")
fig, ax = plt.subplots()
agg_data = values + values_filtered
agg_labels = names + [f"filtered(…{i[-4:]})" for i in names]
ax.boxplot(agg_data, labels=agg_labels, showfliers=False, showmeans=True, meanline=True)
fig.savefig(f"/app/log_data/oeb/plots/plot_combined{suffix}.png")
MIN = 1000
MAX = 100000
def filter(stats):
stats_filtered = defaultdict(list)
for i in stats:
stats_filtered[i] = [x for x in stats[i] if MIN < x < MAX]
return stats_filtered
stats_filtered = filter(stats)
stats_simple = get_lengths(artifacts, atrifact_to_length=simplified_length)
stats_filtered_simple = filter(stats_simple)
def summary(stats, stats_filtered, title):
print_stats(stats)
print(f"filter {MIN} < x < {MAX}")
print_stats(stats_filtered)
plot_stats(stats, stats_filtered, suffix=f"_{title}")
summary(stats, stats_filtered, "raw")
print("\nsimplified\n")
summary(stats_simple, stats_filtered_simple, "simplified")
if True:
settings: LogSettings = load_settings("time.json")
# log_ids = src_file("/app/log_data/oeb/oeb_2016_path")
log_ids = src_file("log_data/oeb/oeb_paths_host")
log_ids = src_file("/home/clemens/git/ma/test/src")
log_ids = src_file("/home/clemens/git/ma/project/log_data/neocartographer/index")
# log_ids = log_ids[0:10]
print(log_ids)
store: ResultStore = run_analysis(log_ids, settings, LOADERS, ResultStore(key_index=1))
results = {}
for cat in store.get_categories():
results[cat] = [result.get() for result in store.get_category(cat)]
with open("times_neo.json", "w") as out:
json.dump(results, out, indent=1)
####################
#for cat in store.get_categories(): #for cat in store.get_categories():
# render(analyzers.ActivityMapper, store.get_category(cat), name=cat) # render(analyzers.ActivityMapper, store.get_category(cat), name=cat)

View File

@ -6,7 +6,8 @@ from analysis.util import json_path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def download_board(board_id, instance_config_id, sequence_id, source, path="/data/results/"): #def download_board(board_id, instance_config_id, sequence_id, source, path="/data/results/"): #FIXME: I was changed
def download_board(board_id, instance_config_id, sequence_id, source, path="activity/data/results/"):
local_file = os.path.join("static", instance_config_id, sequence_id, board_id) local_file = os.path.join("static", instance_config_id, sequence_id, board_id)
abs_path = os.path.join(path, local_file) abs_path = os.path.join(path, local_file)
if os.path.exists(abs_path): if os.path.exists(abs_path):

View File

@ -1,12 +1,33 @@
def calc_distance(geojson: str): import json
from shapely.geometry import LineString
from shapely.ops import transform import pyproj
from functools import partial from shapely.geometry import LineString, mapping
import pyproj from shapely.ops import transform
import json from functools import partial
track = LineString(json.loads(geojson)['coordinates'])
from analysis.util import json_path
def distance(track):
project = partial( project = partial(
pyproj.transform, pyproj.transform,
pyproj.Proj(init='EPSG:4326'), pyproj.Proj(init='EPSG:4326'),
pyproj.Proj(init='EPSG:32633')) pyproj.Proj(init='EPSG:32633'))
return transform(project, track).length return transform(project, track).length
def json_to_track(geojson, path, load=True):
if load:
geojson = json.loads(geojson)
return LineString(json_path(geojson, path))
def calc_distance(geojson: str, path="coordinates", load=True):
track = json_to_track(geojson, path, load)
return distance(track)
def calc_distance_simplified(geojson, path="coordinates", load=True):
track = json_to_track(geojson, path, load)
simplified = track.simplify(0.0002, preserve_topology=True)
return distance(simplified)

View File

@ -1,14 +1,21 @@
def json_path(obj: dict, key: str): def json_path(obj: dict, key: str):# TODO: test me!
"""Query a nested dict with a dot-separated path""" """Query a nested dict with a dot-separated path"""
if not type(obj) is dict: #if type(obj) is list and not "." in key:
return None # return obj[int(key)]
if type(obj) not in (dict, list):
raise ValueError("obj is no object (no list, too)")
if "." not in key: if "." not in key:
if key not in obj: if key not in obj:
return None return KeyError("key not in object", key)
return obj[key] return obj[key]
child_key = key.split(".") child_key = key.split(".")
if child_key[0] not in obj: if child_key[0] not in obj:
return None try:
index = int(child_key[0])
return json_path(obj[index], ".".join(child_key[1:]))
except:
raise KeyError("key not in object", key)
raise KeyError("key not in object", key)
return json_path(obj[child_key[0]], ".".join(child_key[1:])) return json_path(obj[child_key[0]], ".".join(child_key[1:]))

View File

@ -99,7 +99,7 @@ CONFIG_NAMES = {
} }
KML_PATTERN="""<?xml version="1.0" encoding="UTF-8"?> KML_PATTERN = """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"> <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document> <Document>
<Placemark> <Placemark>
@ -113,4 +113,92 @@ KML_PATTERN="""<?xml version="1.0" encoding="UTF-8"?>
</Placemark> </Placemark>
</Document> </Document>
</kml> </kml>
""" """
GEOJSON_PATTERN = """{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {properties},
"geometry": {
"type": "LineString",
"coordinates": {coordinates}
}
}
]
}
"""# TODO: fix me
GEOJSON_COORDINATES = "[{lon},{lat}]"
TASK_NAMES = {
"16fc3117-61db-4f50-b84f-81de6310206f_13127209-103c-4aed-9cce-b8a2cd9f7663_32e93082-1aa7-11e5-9827-74d43509b03a": "Lebensraum",
"16fc3117-61db-4f50-b84f-81de6310206f_13127209-103c-4aed-9cce-b8a2cd9f7663_3a27040f-1a9c-11e5-9827-74d43509b03a": "Simulation",
"16fc3117-61db-4f50-b84f-81de6310206f_2119b80e-74d3-4f3b-b0e0-e6a1f2c1d075_096093b0-d1ca-49f3-8d51-f32fa8874db5": "Biosphärenreservat",
"16fc3117-61db-4f50-b84f-81de6310206f_2119b80e-74d3-4f3b-b0e0-e6a1f2c1d075_b10951a5-1a8a-11e5-b1a2-74d43509b03a": "Simulation",
"16fc3117-61db-4f50-b84f-81de6310206f_41abfe17-aef3-41ee-b1e5-eedc8208680f_255d9c6d-1aa0-11e5-9827-74d43509b03a": "Simulation",
"16fc3117-61db-4f50-b84f-81de6310206f_41abfe17-aef3-41ee-b1e5-eedc8208680f_e0d2dee8-1a9f-11e5-9827-74d43509b03a": "Fellbestimmung",
"16fc3117-61db-4f50-b84f-81de6310206f_b9571a6b-c537-4a92-8618-2d73415dec87_10c3329f-7a88-4aa4-9567-14c811d2a6bc": "Lockstock-Code",
"16fc3117-61db-4f50-b84f-81de6310206f_b9571a6b-c537-4a92-8618-2d73415dec87_5732fe6c-1a9e-11e5-9827-74d43509b03a": "Lockstock-Nachweis",
"16fc3117-61db-4f50-b84f-81de6310206f_b9571a6b-c537-4a92-8618-2d73415dec87_e4bbaf4c-1a9d-11e5-9827-74d43509b03a": "Simulation",
"16fc3117-61db-4f50-b84f-81de6310206f_e08ffe7c-b24d-4fcd-9355-8a459a2c07b7_597c651a-1a8c-11e5-b1a2-74d43509b03a": "Simulation",
"16fc3117-61db-4f50-b84f-81de6310206f_e08ffe7c-b24d-4fcd-9355-8a459a2c07b7_da49b7be-bc13-11e4-a0de-6364e0bfe983": "Holzbedarf",
"17d401a9-de21-49a2-95bc-7dafa53dda64_027dcc39-d642-4900-91c4-abbd9c317cb8_610e91d9-0a1c-4a38-9399-deb0ff8dcb05": "Fellbestimmung",
"17d401a9-de21-49a2-95bc-7dafa53dda64_027dcc39-d642-4900-91c4-abbd9c317cb8_6a03c92d-9e23-4c67-9e76-6a5e28224371": "Simulation",
"17d401a9-de21-49a2-95bc-7dafa53dda64_25a3a482-a119-4db4-8c4e-235ea9d8dab7_90a01be2-dc8a-4733-b302-de5554969453": "Simulation",
"17d401a9-de21-49a2-95bc-7dafa53dda64_25a3a482-a119-4db4-8c4e-235ea9d8dab7_914778bc-f7e9-4327-a78b-71b6fa8762b1": "Biosphärenreservat",
"17d401a9-de21-49a2-95bc-7dafa53dda64_7a8ff4c4-7976-45e0-8ef5-cb386d536cb3_3ae4452e-ed67-4687-849d-e9341fca2900": "Simulation",
"17d401a9-de21-49a2-95bc-7dafa53dda64_7a8ff4c4-7976-45e0-8ef5-cb386d536cb3_f6f5c087-487c-43d8-9409-648a59684a09": "Lebensraum",
"17d401a9-de21-49a2-95bc-7dafa53dda64_97b86d4e-4724-4431-9c94-d2f57696fe2e_26e6558e-8069-45a1-961d-ab1ec9c5aa83": "Holzbedarf",
"17d401a9-de21-49a2-95bc-7dafa53dda64_97b86d4e-4724-4431-9c94-d2f57696fe2e_970ff4e0-16bd-4380-8e69-91a324a59523": "Simulation",
"17d401a9-de21-49a2-95bc-7dafa53dda64_a4f5c5d8-43b0-45f3-b3cf-3749fcb81f05_3366d6a3-684f-423a-bd7f-5c0107d4b972": "Simulation",
"17d401a9-de21-49a2-95bc-7dafa53dda64_a4f5c5d8-43b0-45f3-b3cf-3749fcb81f05_a7188b81-e25b-456d-9742-5f11adb7d461": "Lockstock-Nachweis",
"17d401a9-de21-49a2-95bc-7dafa53dda64_a4f5c5d8-43b0-45f3-b3cf-3749fcb81f05_d29537b9-de0b-42c2-b3da-27a3dbc57988": "Lockstock-Code",
}
CACHE_NAMES = {
"043ab9fe-64e8-4e76-8bf6-8cc9db35eba1": "1a_Infozentrum",
"37f326ed-9732-44b5-9ba7-e666d31cc4e7": "2a_Holzlager",
"bf96eee0-4c92-43d8-aced-a95e4eedae9f": "2b_Holzstapel",
"a5723715-7ba7-4431-9d0b-c91c351a3ccc": "3a_Lebensraum_Hecke",
"dd68ba57-a081-46be-9a76-e49cd5209383": "3b_Lebensraum_Hecke",
"bb21628e-d039-4c16-9fe1-68de7f448fa4": "4a_Lockstock_finden",
"8291c397-b3a9-4564-9365-bd660ab1abcc": "4b_Lockstock_finden",
"e92d8175-a65f-40de-ae76-3cbde55dfd4d": "5a_Straße",
"30451de3-2d5d-44c7-84b2-2abddbc8adcc": "5b_Straße",
"22fcc44c-64d4-4f84-ad05-8107542a04d2": "6a_Jaegerstand",
"1740e151-cd75-45c0-a06e-d724b9d69729": "6a_Jaegerstand",
"6d97d48a-7ac1-4e3a-b797-c2b4aa681a10": "5a_Straße",
"98e60f51-c4d5-4833-bc3b-2820e1bdd09d": "4b_Lockstock_finden",
"61d6dc12-11b5-4a9c-b0d8-7a38a29d772a": "5b_Straße",
"f4762feb-addb-4e82-b923-78f8c7b6aff9": "2b_Holzstapel",
"25b2cc3b-f8fd-4a21-9350-d175d837f6b6": "3a_Lebensraum_Hecke",
"5ba5046f-c956-4c21-aea5-a0a6055ed7e4": "1a_Infozentrum",
"fb60b94b-3f82-4ba9-98ac-f52105bd26f1": "2a_Holzlager",
"12b9584a-14b4-40c6-aa13-9fb11062e917": "4a_Lockstock_finden",
"19908306-8c70-4861-bec8-49e849e94722": "3b_Lebensraum_Hecke",
"None": "initial",
"only": "",
}
SEQUENCE_NAMES = {
"89b769f8-2c98-4f55-b741-1dfa022c3286": "1_Videoerklaerung",
"286cab41-6a81-4dfe-9bef-e86923ca8c97": "A_Einleitung",
"2119b80e-74d3-4f3b-b0e0-e6a1f2c1d075": "B",
"25a3a482-a119-4db4-8c4e-235ea9d8dab7": "B",
"97b86d4e-4724-4431-9c94-d2f57696fe2e": "C_mit_Dilemma",
"e08ffe7c-b24d-4fcd-9355-8a459a2c07b7": "C_mit_Dilemma",
"5f644fb4-5cc7-43a2-afb4-191dce80c875": "D_Dilemmasequenz",
"847ab5ff-7c98-4cdc-bc9e-bb619a0a98bb": "D_Dilemmasequenz",
"13127209-103c-4aed-9cce-b8a2cd9f7663": "E",
"7a8ff4c4-7976-45e0-8ef5-cb386d536cb3": "E",
"a4f5c5d8-43b0-45f3-b3cf-3749fcb81f05": "F",
"b9571a6b-c537-4a92-8618-2d73415dec87": "F",
"027dcc39-d642-4900-91c4-abbd9c317cb8": "G",
"41abfe17-aef3-41ee-b1e5-eedc8208680f": "G",
"be59a20a-69ce-471b-8f70-76ce200e32c9": "H_Abschlusserzaehlung",
"d4073563-da42-4ad2-9a9b-20ef29da6309": "H_Abschlusserzaehlung",
"54e03082-1a6b-11e5-aa26-00199963ac6e": "seq_score",
"95d82cd3-5bda-465a-8757-7179cdafe590": "seq_score",
}

28
analysis/util/output.py Normal file
View File

@ -0,0 +1,28 @@
from datetime import datetime as dt
SEP = "\",\""
LS = "\""
LE = "\""
NL = LS + "\n" + LE
def flat_dict_to_csv(data):
keys = set()
for i in data:
keys = keys.union(set(i.keys()))
keys = sorted(keys)
out = SEP.join(keys)
for i in data:
out += NL + SEP.join([escape(i.get(j, "")) for j in keys])
return LS + out + LE
def escape(value):
val = str(value)
val = val.replace(".", ",")
return val
def pretty_ts(timestamp, fmt="%Y-%m-%d %H:%M:%S"):
d = dt.fromtimestamp(int(timestamp)/1000.0)
return d.strftime(fmt)

View File

@ -12,7 +12,7 @@ def process_log(logfile: str, settings: LogSettings, loaders) -> List[Analyzer]:
try: try:
loader.load(logfile) loader.load(logfile)
except BaseException as e: except BaseException as e:
raise RuntimeError(e) raise RuntimeError(e, logfile)
analyzers: List[Analyzer] = [] analyzers: List[Analyzer] = []
log.debug("build analyzers") log.debug("build analyzers")
for analyzer in settings.analyzers: for analyzer in settings.analyzers:
@ -28,8 +28,10 @@ def process_log(logfile: str, settings: LogSettings, loaders) -> List[Analyzer]:
return analyzers return analyzers
def run_analysis(log_ids: list, settings, loaders): def run_analysis(log_ids: list, settings, loaders, result_store=None):
store: ResultStore = ResultStore() if not result_store:
result_store = ResultStore()
store: ResultStore = result_store
for log_id in log_ids: for log_id in log_ids:
log.info("LOG_ID: "+ str(log_id)) log.info("LOG_ID: "+ str(log_id))
for analysis in process_log(log_id, settings, loaders): for analysis in process_log(log_id, settings, loaders):

19
data/results/index.html Normal file
View File

@ -0,0 +1,19 @@
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"></script>
<script src="https://rawgit.com/Leaflet/Leaflet.heat/gh-pages/dist/leaflet-heat.js"></script>
<script src="my.js"></script>
<link href="style.css" rel="stylesheet"/>
<main>
<div class="mapDiv" id="mainMap"></div>
<div class="sequenceContainer">
<div class="sequence"></div>
</div>
</main>
<!--div style="font-size:0.1px;position:absolute;bottom:0;">OSM Logo: CC-BY-SA
http://wiki.openstreetmap.org/wiki/File:Mag_map-120x120.png
</div-->

BIN
data/results/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

110
data/results/my.js Normal file
View File

@ -0,0 +1,110 @@
function loadData() {
console.log($(location).attr('hash').substr(1));
$.getJSON($(location).attr('hash').substr(1), function (data) {
var images = {};
var tiles = {
"openstreetmap": L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxNativeZoom: 19,
maxZoom: 24,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}),
"esri sat": L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
maxNativeZoom: 19,
maxZoom: 24,
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
}),
"google sat": L.tileLayer('https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
maxNativeZoom: 20,
maxZoom: 24,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
})
};
var map = L.map("mainMap", {layers: [tiles.openstreetmap]});
function styleTrack(feature) {
var styles = {};
styles.color = data.properties.colors[feature.properties.activity_type];
return styles;
}
var highlighted = null;
function onClick(e) {
var start = e.target.feature.geometry.properties.start_timestamp;
var end = e.target.feature.geometry.properties.end_timestamp;
var changed = highlighted !== e.target.feature;
$.each(images, function (timestamp, board) {
if ((timestamp >= start && timestamp < end) && changed) {
board.image.first().addClass("highlight");
} else {
board.image.removeClass("highlight");
highlighted = null;
}
}
);
if (changed) {
highlighted = e.target.feature;
}
}
var coords = [];
function onEachFeature(feature, layer) {
layer.setStyle(styleTrack(feature));
layer.on('click', onClick);
if (feature.geometry.coordinates.length > 1) {
coords = coords.concat(feature.geometry.coordinates.map(function (p) {
return [p[1], p[0], 0.1];
}));
}
}
var track = L.geoJSON(data['features'], {
//style: styleTrack,
onEachFeature: onEachFeature
}).addTo(map);
map.fitBounds(track.getBounds());
//var heat = L.heatLayer(coords);
//L.control.layers(tiles, {"heatmap": heat}).addTo(map);
var list = $("<ul />");
var current = {
"pos": data.properties["boards"][0].coordinate.coordinates
};
var i = 0;
while (current.pos == undefined) {
i+=1;
current.pos = data.properties["boards"][i].coordinate.coordinates;
}
console.log(current);
var marker = L.marker([current.pos[1], current.pos[0]]).addTo(map);
$.each(data.properties["boards"], function (index, entry) {
//console.log(index, entry);
var item = $("<li>", {class: entry.extra_data.activity_type});
var container = $("<div>", {class: "board"});
var image = $("<img>", {src: entry.image.replace("static/progress/", "")});
image.attr("data-time", entry.timestamp);
image.hover(function () {
marker.setLatLng([entry.coordinate.coordinates[1], entry.coordinate.coordinates[0]]);
}, function () {
marker.setLatLng(current.pos.coordinates[1], current.pos.coordinates[0]);
});
image.click(function (e) {
current.board = image;
current.pos = entry.coordinate;
});
images[entry.timestamp] = {image: image, coordinate: entry.coordinate};
image.appendTo(container);
container.appendTo(item);
item.appendTo(list);
});
current.board = images[data.properties["boards"][1].timestamp];
list.appendTo(".sequence");
});
}
$(document).ready(function () {
loadData();
});

BIN
data/results/simu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -2,7 +2,7 @@ version: "3"
services: services:
app: app:
image: docker.clkl.de/ma/celery:0.4.1 image: docker.clkl.de/ma/celery:0.4.2
build: . build: .
volumes: volumes:
- ./:/app - ./:/app
@ -21,7 +21,7 @@ services:
- "traefik.url.frontend.rule=Host:select.ma.potato.kinf.wiai.uni-bamberg.de" - "traefik.url.frontend.rule=Host:select.ma.potato.kinf.wiai.uni-bamberg.de"
celery: celery:
image: docker.clkl.de/ma/celery:0.4.1 image: docker.clkl.de/ma/celery:0.4.2
environment: environment:
- PYTHONPATH=/app - PYTHONPATH=/app
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1

View File

@ -26,10 +26,13 @@
1. Be on a host with port 80 available from the internet 1. Be on a host with port 80 available from the internet
2. Follw HTTP usage above up to step 2 2. Follw HTTP usage above up to step 2
3. Add acme.json volume: 3. Reconfigure docker-compose
* Uncomment the line for the acme.json volume * Add acme.json volume:
* Adjust the host path * Uncomment the line for the acme.json volume
* Syntax: <host-path>:<container-path> * Adjust the host path
* Syntax: <host-path>:<container-path>
* Add port mapping for HTTPS
* Uncomment the line for the 443:443 port mapping
4. Create acme.json 4. Create acme.json
* touch acme.json * touch acme.json
* chmod 600 acme.json * chmod 600 acme.json

View File

@ -5,10 +5,11 @@ services:
command: --configFile=/traefik.toml command: --configFile=/traefik.toml
volumes: volumes:
- ./config.toml:/traefik.toml - ./config.toml:/traefik.toml
# - /srv/traefik/acme.json:/acme.json # - /srv/traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
ports: ports:
- 80:80 - 80:80
# - 443:443
networks: networks:
- net - net
labels: labels:

66
oeb_kml.json Normal file
View File

@ -0,0 +1,66 @@
{
"logFormat": "zip",
"entryType": "@class",
"spatials": [
"de.findevielfalt.games.game2.instance.log.entry.LogEntryLocation"
],
"actions": [
"...QuestionAnswerEvent",
"...SimuAnswerEvent"
],
"boards": [
"de.findevielfalt.games.game2.instance.log.entry.ShowBoardLogEntry"
],
"analyzers": {
"analysis.analyzers": [
"SimulationCategorizer",
"LocationAnalyzer"
]
},
"sequences": {
"start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryCache",
"end": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.LogEntryInstanceAction",
"action.@class": "de.findevielfalt.games.game2.instance.action.CacheEnableAction"
}
},
"custom": {
"simulation_rounds": [
"de.findevielfalt.games.game2.instance.log.entry.LogEntryQuestion"
],
"simu_data": [
"de.findevielfalt.games.game2.instance.data.sequence.simulation.SimulationBoardData"
],
"instance_start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryStartInstance",
"instance_id": "instance_id",
"instance_config_id": "config.@id",
"sequences2": {
"id_field": "sequence_id",
"start": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.ShowSequenceLogEntry",
"action": "START"
},
"end": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.ShowSequenceLogEntry",
"action": "PAUSE"
}
},
"coordinates": "location.coordinates",
"metadata": {
"timestamp": "timestamp",
"gamefield": "instance_id",
"user": "player_group_name"
}
},
"source": {
"type": "Biogames",
"username": "ba",
"password": "853451",
"host": "http://biogames.potato.kinf.wiai.uni-bamberg.de"
},
"render": [
"KMLRender"
]
}

View File

@ -12,4 +12,7 @@ flask==0.12.2
celery==4.1.1 celery==4.1.1
redis==2.10.6 redis==2.10.6
lxml==4.2.1 lxml==4.2.1
shapely==1.6.4
pyproj==1.9.5.1

View File

@ -53,7 +53,7 @@ KML = """{
"type": "Biogames", "type": "Biogames",
"username": "ba", "username": "ba",
"password": "853451", "password": "853451",
"host": "http://biogames.potato.kinf.wiai.uni-bamberg.de" "host": "http://biodiv2govm.kinf.wiai.uni-bamberg.de"
}, },
"render": [ "render": [
"KMLRender" "KMLRender"
@ -115,25 +115,137 @@ ACTIVITY = """{
"type": "Biogames", "type": "Biogames",
"username": "ba", "username": "ba",
"password": "853451", "password": "853451",
"host": "http://biogames.potato.kinf.wiai.uni-bamberg.de" "host": "http://biodiv2govm.kinf.wiai.uni-bamberg.de"
}, },
"render": [ "render": [
"ActivityMapper" "ActivityMapper"
] ]
}""" }"""
CONFIGS = { # TODO: more KML_geo = """{
"KML": KML, "logFormat": "neocartographer",
"ActivityMapper": ACTIVITY, "entryType": "type",
"spatials": [
"location"
],
"actions": [],
"boards": [],
"analyzers": {
"analysis.analyzers": [
"SimpleCategorizer",
"LocationAnalyzer"
]
},
"sequences": {},
"custom": {
"coordinates": "location.coordinates",
"metadata": {
"timestamp": "timestamp",
"gamefield": "instance_id",
"user": "player_group_name"
}
},
"source": {
"type": "Geogames",
"host": "http://log_data/",
"path": "neocartographer"
},
"render": [
"KMLRender"
]
}"""
OEB = """{
"logFormat": "zip",
"entryType": "@class",
"spatials": [
"de.findevielfalt.games.game2.instance.log.entry.LogEntryLocation"
],
"actions": [
"...QuestionAnswerEvent",
"...SimuAnswerEvent"
],
"boards": [
"de.findevielfalt.games.game2.instance.log.entry.ShowBoardLogEntry"
],
"analyzers": {
"analysis.analyzers": [
"BiogamesCategorizer",
"LocationAnalyzer",
"BiogamesDuration",
"BiogamesTasks",
"GameFieldInstanceGroup"
]
},
"sequences": {
"start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryCache",
"end": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.LogEntryInstanceAction",
"action.@class": "de.findevielfalt.games.game2.instance.action.CacheEnableAction"
}
},
"custom": {
"simulation_rounds": [
"de.findevielfalt.games.game2.instance.log.entry.LogEntryQuestion"
],
"simu_data": [
"de.findevielfalt.games.game2.instance.data.sequence.simulation.SimulationBoardData"
],
"instance_start": "de.findevielfalt.games.game2.instance.log.entry.LogEntryStartInstance",
"instance_id": "instance_id",
"instance_config_id": "config.@id",
"sequences2": {
"id_field": "sequence_id",
"start": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.ShowSequenceLogEntry",
"action": "START"
},
"end": {
"@class": "de.findevielfalt.games.game2.instance.log.entry.ShowSequenceLogEntry",
"action": "PAUSE"
}
},
"coordinates": "location.coordinates",
"metadata": {
"timestamp": "timestamp",
"gamefield": "instance_id",
"user": "player_group_name"
}
},
"source": {
"type": "Biogames",
"username": "ba",
"password": "853451",
"host": "https://biogames.kinf.wiai.uni-bamberg.de"
},
"render": [
"OEBRender"
]
}
"""
CONFIGS = {
"Biogames": {
"ActivityMapper": ACTIVITY,
"KML": KML,
"DauerEntfernungPunkteZeit": OEB,
},
"Geogames": {
"KML": KML_geo,
},
} }
URLS = { URLS = {
"KML": "/", "KML": "/",
"DauerEntfernungPunkteZeit": "/",
"ActivityMapper": "#", "ActivityMapper": "#",
} }
HOSTS = { HOSTS = {
"Biogames": "http://biogames.potato.kinf.wiai.uni-bamberg.de", #"Biogames": "http://biogames.potato.kinf.wiai.uni-bamberg.de",
#"Biogames": "http://www.biodiv2go.de",
"Biogames": "http://biogames.kinf.wiai.uni-bamberg.de/",
"Geogames": "http://log_data/", "Geogames": "http://log_data/",
} }

View File

@ -1,5 +1,5 @@
body { body {
background-color: aqua; /* background-color: limegreen;*/
} }
#data{ #data{
display: none; display: none;

View File

@ -34,7 +34,7 @@ def login():
session['username'] = request.form['username'] session['username'] = request.form['username']
session['cookies'] = client.cookies session['cookies'] = client.cookies
session['game'] = game session['game'] = game
session['host'] = BIOGAMES_HOST session['host'] = HOSTS[game]
clients[session['uid']] = client clients[session['uid']] = client
return redirect("/results") return redirect("/results")
return redirect("/?fail") return redirect("/?fail")
@ -65,7 +65,7 @@ def games():
return redirect("/") return redirect("/")
if session['logged_in'] and not session['uid'] in clients: if session['logged_in'] and not session['uid'] in clients:
clients[session['uid']] = CLIENTS[session['game']](host=session['host'], **session['cookies']) clients[session['uid']] = CLIENTS[session['game']](host=session['host'], **session['cookies'])
return render_template("games.html", logs=clients[session['uid']].list(), configs=CONFIGS) return render_template("games.html", logs=clients[session['uid']].list(), configs=CONFIGS[session['game']])
@app.route("/start", methods=['POST']) @app.route("/start", methods=['POST'])
@ -79,7 +79,7 @@ def start():
} }
params = { params = {
"log_ids": request.form.getlist('logs'), "log_ids": request.form.getlist('logs'),
"config": CONFIGS[request.form['config']], "config": CONFIGS[session['game']][request.form['config']],
"username": session['username'], "username": session['username'],
"cookies": session['cookies'], "cookies": session['cookies'],
"host": session['host'], "host": session['host'],

View File

@ -1,45 +0,0 @@
<!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="./heat_data.js"></script>
<script>
var options = {maxZoom:22};
var map = L.map('map', options).setView(coords[0], 17);
L.control.scale().addTo(map);
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 heat = L.heatLayer(coords).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>

View File

@ -1,8 +0,0 @@
version: "2"
services:
http:
image: httpd:alpine
volumes:
- ./:/usr/local/apache2/htdocs
ports:
- 5001:80

View File

@ -1,25 +0,0 @@
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<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>
<script src="https://rawgit.com/Leaflet/Leaflet.heat/gh-pages/dist/leaflet-heat.js"></script>
<script src="my.js"></script>
<link href="style.css" rel="stylesheet"/>
<main>
<div class="mapDiv" id="mainMap"></div>
<div class="sequenceContainer">
<div class="sequence"></div>
</div>
</main>
<!--div style="font-size:0.1px;position:absolute;bottom:0;">OSM Logo: CC-BY-SA
http://wiki.openstreetmap.org/wiki/File:Mag_map-120x120.png
</div-->

View File

@ -1,15 +0,0 @@
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<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>
<script src="log.js"></script>
<style>
.map { width: 512px; height: 512px; }
</style>

View File

@ -1,72 +0,0 @@
$.getJSON("data/fooo", function (data) {
var list = $("<ul />");
var mapC = $("<div />", {class: "map", id: "map"});
mapC.appendTo("body");
var track = [];
var times = [];
$.each(data.spatials, function (i, elem) {
track.push([elem.coordinates[1], elem.coordinates[0]]);
times.push(i);
});
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
});
var map = L.map("map", {layers: [tiles]});
L.control.scale().addTo(map);
var layer = L.polyline(track).addTo(map);
map.fitBounds(layer.getBounds());
$.each(data, function (key, value) {
//console.log(key, value);
//key: instance_id, value: AnlysisResult
//value.result.instance: InstanceConfig_id
// console.log(key, value[0].result.store[0].timestamp);
/*$.each(value[0].result.store, function (index, entry) {
//console.log(entry);
var time = new Date(entry.timestamp);
var item = $("<li>", {html: entry.sequence + " @ " + time.toLocaleDateString() + " "+ time.toLocaleTimeString()});
var container = $("<p />");
if (entry.track.length > 0) {
var mapName = "map" + index;
//console.log(mapName, entry.track.length);
var mapContainer = $("<div />", {id: mapName, class: "map"});
var track = [];
$.each(entry.track, function (i, elem) {
track.push([elem.coordinates[1], elem.coordinates[0]]);
});
maps[mapName] = track;
mapContainer.appendTo(container);
}
$.each(entry.events, function (i, event) {
if ("image" in event) {
$("<img />", {src: event.image, height: 200}).appendTo(container);
}
});
container.appendTo(item);
item.appendTo(list);
});*/
});
list.appendTo("body");
var slider = $("<input />", {type: "range", start:0,end:100});
slider.appendTo("body");
/*});
$(window).on("load", function () {*/
// setTimeout(function () {
//console.log(maps);
/*$.each(maps, function (mapName, track) {
//console.log("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa");
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
});
var map = L.map(mapName, {layers: [tiles]});
L.control.scale().addTo(map);
// console.log(mapName, track);
var layer = L.polyline(track, {color: "green"}).addTo(map);
map.fitBounds(layer.getBounds());
//console.log(layer)
//L.control.layers({"osm":tiles}, {layer]).addTo(map);
});*/
// }, 2000);
});

View File

@ -1,103 +0,0 @@
//$.getJSON("data/ff8f1e8f-6cf5-4a7b-835b-5e2226c1e771_03b9b6b4-c8ab-4182-8902-1620eebe8889.json", function (data) { //urach
//$.getJSON("data/ff8f1e8f-6cf5-4a7b-835b-5e2226c1e771_de7df5b5-edd5-4070-840f-68854ffab9aa.json", function (data) { //urach
//$.getJSON("data/90278021-4c57-464e-90b1-d603799d07eb_07da99c9-398a-424f-99fc-2701763a63e9.json", function (data) { //eichstätt
//$.getJSON("data/13241906-cdae-441a-aed0-d57ebeb37cac_d33976a6-8a56-4a63-b492-fe5427dbf377.json", function (data) { //stadtökologie
$.getJSON("data/5e64ce07-1c16-4d50-ac4e-b3117847ea43_2f664d7b-f0d8-42f5-8731-c034ef86703e.json", function (data) { //filderstadt
//$.getJSON("data/17d401a9-de21-49a2-95bc-7dafa53dda64_98edcb70-03db-4465-b185-a9c9574995ce.json", function (data) { //oeb2016
var images = {};
var tiles = {
"openstreetmap": L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxNativeZoom: 19,
maxZoom: 24,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}),
"esri sat": L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
maxNativeZoom: 19,
maxZoom: 24,
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
}),
"google sat": L.tileLayer('https://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
maxNativeZoom: 20,
maxZoom: 24,
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
})
};
var map = L.map("mainMap", {layers: [tiles.openstreetmap]});
function styleTrack(feature) {
var styles = {};
styles.color = data.colors[feature.properties.activity_type];
return styles;
}
var highlighted = null;
function onClick(e) {
var start = e.target.feature.geometry.properties.start_timestamp;
var end = e.target.feature.geometry.properties.end_timestamp;
var changed = highlighted !== e.target.feature;
$.each(images, function (timestamp, board) {
if ((timestamp >= start && timestamp < end) && changed) {
board.image.first().addClass("highlight");
} else {
board.image.removeClass("highlight");
highlighted = null;
}
}
);
if (changed) {
highlighted = e.target.feature;
}
}
var coords = [];
function onEachFeature(feature, layer) {
layer.setStyle(styleTrack(feature));
layer.on('click', onClick);
if (feature.coordinates.length > 1) {
coords = coords.concat(feature.coordinates.map(function (p) {
return [p[1], p[0], 0.1];
}));
}
}
var track = L.geoJSON(data['track'], {
//style: styleTrack,
onEachFeature: onEachFeature
}).addTo(map);
map.fitBounds(track.getBounds());
var heat = L.heatLayer(coords);
L.control.layers(tiles, {"heatmap": heat}).addTo(map);
var list = $("<ul />");
var current = {
"pos":data["boards"][1].coordinate.coordinates
};
console.log(current);
var marker = L.marker([current.pos[1], current.pos[0]]).addTo(map);
$.each(data["boards"], function (index, entry) {
//console.log(index, entry);
var item = $("<li>", {class: entry.extra_data.activity_type});
var container = $("<div>", {class: "board"});
var image = $("<img>", {src: entry.image.replace("static/progress/", "")});
image.attr("data-time", entry.timestamp);
image.hover(function () {
marker.setLatLng([entry.coordinate.coordinates[1], entry.coordinate.coordinates[0]]);
}, function () {
marker.setLatLng(current.pos.coordinates[1], current.pos.coordinates[0]);
});
image.click(function (e) {
current.board = image;
current.pos = entry.coordinate;
});
images[entry.timestamp] = {image: image, coordinate: entry.coordinate};
image.appendTo(container);
container.appendTo(item);
item.appendTo(list);
});
current.board=images[data["boards"][1].timestamp];
list.appendTo(".sequence");
});

View File

@ -1,68 +0,0 @@
<!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);
L.control.scale().addTo(map);
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){
var elem = L.polyline(tracks[i], {color:"green"});
// layers[i] =L.LayerGroup([elem]);
layers[i] = elem;
map.fitBounds(elem.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>

View File

@ -10,15 +10,17 @@ import time
from celery import Celery from celery import Celery
from analysis import log_analyzer as la from analysis import log_analyzer as la
from analysis.analyzers import KMLRender, ActivityMapperRender from analysis.analyzers import KMLRender, ActivityMapperRender
from analysis.analyzers.render.biogames import OEBRender
from clients.webclients import CLIENTS from clients.webclients import CLIENTS
FLASK_DB = 1 FLASK_DB = 1
REDIS_HOST = "redis" REDIS_HOST = "redis"
DATA_PATH = "/app/data/results/" DATA_PATH = "/data/results/"
RENDERERS = { # TODO RENDERERS = { # TODO
"KMLRender": KMLRender, "KMLRender": KMLRender,
"ActivityMapper": ActivityMapperRender, "ActivityMapper": ActivityMapperRender,
"OEBRender": OEBRender
} }
app = Celery('tasks', backend='redis://redis', broker='redis://redis') app = Celery('tasks', backend='redis://redis', broker='redis://redis')
@ -48,22 +50,29 @@ def analyze(config, log_ids, **kwargs):
tmpdir = client.download_files(urls) tmpdir = client.download_files(urls)
log.info(tmpdir.name, list(os.scandir(tmpdir.name))) log.info(tmpdir.name, list(os.scandir(tmpdir.name)))
update_status(kwargs['username'], kwargs['name'], ('start', 'RUNNING')) uid = str(uuid.uuid4())
update_status(kwargs['username'], kwargs['name'], ('start', 'RUNNING'), uid=uid)
results = []
settings = la.parse_settings(config) settings = la.parse_settings(config)
store = la.run_analysis([p.path for p in os.scandir(tmpdir.name)], settings, la.LOADERS) store = la.run_analysis([p.path for p in os.scandir(tmpdir.name)], settings, la.LOADERS)
render = RENDERERS[settings.render[0]]() # TODO
files = render.render(store.get_all())
uid = str(uuid.uuid4())
results = []
log.error(files)
os.mkdir(os.path.join(DATA_PATH, uid)) os.mkdir(os.path.join(DATA_PATH, uid))
render = RENDERERS[settings.render[0]]() # TODO
files = []
if settings.render[0] == "OEBRender":
files.append(render.render_store(store))
else:
for category in store.get_categories():
data = store.get_category(category)
print(category, type(category))
files = render.render(data, name=category[1])
log.error(files)
for file in files: for file in files:
try: try:
head, tail = os.path.split(file) head, tail = os.path.split(file)
target = os.path.join(DATA_PATH, uid, tail) target = os.path.join(DATA_PATH, uid, tail)
shutil.move(file, target) log.error(target)
log.error(shutil.move(file, target))
results.append(target) results.append(target)
except FileNotFoundError as e: except FileNotFoundError as e:
log.exception(e) log.exception(e)