diff --git a/analyzers/analyzer/biogames.py b/analyzers/analyzer/biogames.py index cbf9306..e7ff5ae 100644 --- a/analyzers/analyzer/biogames.py +++ b/analyzers/analyzer/biogames.py @@ -140,6 +140,16 @@ class ActivityMapper(Analyzer): "sequence.question.": "question", "error": "error" } + colors = { + "simu": "blue", + "question": "orange", + "image": "green", + "audio": "red", + "video": "purple", + "other": "brown", + "map": "violet", + "error": "grey" + } def __init__(self, settings: LogSettings) -> None: super().__init__(settings) @@ -157,29 +167,28 @@ class ActivityMapper(Analyzer): self.State: NamedTuple = namedtuple("State", ["sequence", "events", "track", "timestamp"]) - def result_old(self, store: ResultStore) -> None: - instance_config_id = self.instance_config_id - for active_segment in self.store: # active_segment → sequence or None (None → map active) - seq_data_url = "/game2/editor/config/{config_id}/sequence/{sequence_id}/".format( - config_id=instance_config_id, - sequence_id=active_segment.sequence, - ) - source = self.settings.source - seq_data = source._get(seq_data_url).json() - # TODO: use sequence names - logger.warning(seq_data) - for event in active_segment.events: - if event[self.settings.type_field] in self.settings.boards: - sequence_id = active_segment.sequence - board_id = event["board_id"] - local_file = download_board(board_id, instance_config_id, sequence_id, source) - if local_file is not None: - event["image"] = local_file[16:] - store.add(Result(type(self), {"instance": instance_config_id, "store": [x._asdict() for x in self.store]})) - - def result(self, store: ResultStore) -> None: - - store.add(Result(type(self), {"instance": self.instance_config_id, "track": self.tracks, "boards": self.timeline})) + def result(self, store: ResultStore, **kwargs) -> None: + for board in self.timeline: + if board[self.settings.type_field] in self.settings.boards: + if board["extra_data"]["activity_type"] == "simu": + board["image"] = "simu.png" + continue + local_file = download_board(board["board_id"], self.instance_config_id, board["sequence_id"], + self.settings.source) + if local_file: + board['image'] = local_file + else: + board['image'] = "ERROR_FETCHING_FILE" + logger.error("error downloading board! %s %s %s", self.instance_config_id, board["sequence_id"], + board["board_id"]) + else: + board["image"] = "map.png" + store.add(Result(type(self), { + "instance": self.instance_config_id, + "track": self.tracks, + "boards": self.timeline, + "colors": self.colors, + })) def process(self, entry: dict) -> bool: if self.track is None: @@ -193,8 +202,9 @@ class ActivityMapper(Analyzer): self.add_location(entry) elif entry[self.settings.type_field] in self.settings.boards: board_data = get_board_data(self.settings.source, self.instance_config_id, entry["sequence_id"], - entry["board_id"]) + entry["board_id"]) entry["extra_data"] = board_data + entry["extra_data"]["activity_type"] = self.classify_entry(entry) entry['coordinate'] = self.new_coordinate() self.timeline.append(entry) return False @@ -202,25 +212,28 @@ class ActivityMapper(Analyzer): def update_board_type(self, entry): type = self.classify_entry(entry) if not type == self.last_board_type: - self.add_track(activity_type=self.last_board_type,end_timestamp=entry['timestamp']) + self.add_track(activity_type=self.last_board_type, end_timestamp=entry['timestamp']) self.last_board_type = type def classify_entry(self, entry): entry_type = entry[self.settings.type_field] if self.filters.end(entry): + data = {"extra_data": {"activity_type": "map"},"coordinate": self.new_coordinate()} + data.update(entry) + self.timeline.append(data) return "map" if not entry_type in self.settings.boards: return self.last_board_type board_data = get_board_data(self.settings.source, self.instance_config_id, entry["sequence_id"], - entry["board_id"]) + entry["board_id"]) for pattern in self.classes: if pattern in board_data['class']: return self.classes[pattern] if board_data['has_video']: return "video" - elif board_data['has_audio']: + elif board_data['has_audio']: return "audio" - elif board_data['has_image']: + elif board_data['has_image']: return "image" return "other" @@ -236,6 +249,8 @@ class ActivityMapper(Analyzer): self.track['properties'].update(props) self.tracks.append(self.track) self.track = self.new_track(props['end_timestamp']) + if self.last_coordinate: + self.track['coordinates'].append(self.last_coordinate) def new_track(self, timestamp): return {"type": "LineString", "coordinates": [], "properties": {'start_timestamp': timestamp}} @@ -305,7 +320,7 @@ class SimulationOrderAnalyzer(Analyzer): class SimulationCategorizer(CategorizerStub): # TODO: refactor categorizer - __name__ = "SimulationCategorizer"# TODO: rename -.- (InstanceConfigIDCategorizer) + __name__ = "SimulationCategorizer" # TODO: rename -.- (InstanceConfigIDCategorizer) def process(self, entry: dict) -> bool: if self.key is "default": @@ -334,5 +349,3 @@ class SimulationFlagsAnalyzer(Analyzer): def result(self, store: ResultStore, name=None) -> None: store.add(Result(type(self), self.store, name=name)) - - diff --git a/analyzers/render/biogames.py b/analyzers/render/biogames.py index 415b8a9..ebe38dd 100644 --- a/analyzers/render/biogames.py +++ b/analyzers/render/biogames.py @@ -40,7 +40,7 @@ def __plot_or_show(name=None): def plot(src_data: List[Tuple[str, List[int]]], ylabel="simulation rounds", title="simulation retries", - rotation='vertical', name=None): + rotation='vertical', name=None): names, datas = list(zip(*src_data)) # plt.boxplot(datas, labels=names, showfliers=False, showmeans=True, meanline=True) rand = np.random.rand(len(datas), len(datas[0])) @@ -53,7 +53,7 @@ def plot(src_data: List[Tuple[str, List[int]]], ylabel="simulation rounds", titl def graph_plot(src_data: List[Tuple[str, List[int]]], ylabel="simulation rounds", title="sequential simulation retries", - rotation='vertical', name=None): + rotation='vertical', name=None): config_name = CONFIG_NAMES[name] if name in CONFIG_NAMES else "---" counts_per_group = [sum(i) for i in src_data] label = "{}: n={n}; # of sim runs: ⌀={avg:.2f}, median={median}".format( @@ -154,8 +154,9 @@ class ActivityMapperRender(Render): print(os.getcwd()) for result in self.filter(results): data = result.get() - with open(os.path.join("static", "progress", "data", data['instance']), "w") as out: - json.dump(data["store"], out, indent=1) + with open(os.path.join("static", "progress", "data", data['instance'] + "_" + str(name) + ".json"), + "w") as out: + json.dump(data, out, indent=1) return "ok" @@ -187,7 +188,8 @@ class SimulationGroupRender(Render): def render(self, results: List[Result], name=None): data = [r.get() for r in self.filter(results)] print(name, len(data)) - graph_plot(list(data), ylabel="simulation retries", title="sequential simulation retries", rotation=None, name=name) - #graph_fit(list(data), name=name) + # graph_fit(list(data), name=name) + graph_plot(list(data), ylabel="simulation retries", title="sequential simulation retries", rotation=None, + name=name) result_types = [SimulationOrderAnalyzer] diff --git a/biogames2.json b/biogames2.json index 7bedcb9..589805d 100644 --- a/biogames2.json +++ b/biogames2.json @@ -13,7 +13,8 @@ ], "analyzers": { "analyzers": [ - "SimulationCategorizer", + "BiogamesCategorizer", + "ActivityMapper", "SimulationFlagsAnalyzer" ] }, @@ -23,6 +24,7 @@ "LogEntryCountAnalyzer", "SimulationOrderAnalyzer", "ProgressAnalyzer", + "SimulationCategorizer", "InstanceConfig"], "disabled_analyzers": [ "LocomotionActionAnalyzer", diff --git a/log_analyzer.py b/log_analyzer.py index 9b773e0..3a492c6 100644 --- a/log_analyzer.py +++ b/log_analyzer.py @@ -14,13 +14,11 @@ from loaders import LOADERS logging.basicConfig(format='%(levelname)s %(name)s:%(message)s', level=logging.DEBUG) log: logging.Logger = logging.getLogger(__name__) -requests_log = logging.getLogger('requests') -requests_log.setLevel(logging.WARN) +logging.getLogger('requests').setLevel(logging.WARN) +logging.getLogger("urllib3").setLevel(logging.WARNING) -def process_log(log_id: str, settings: LogSettings) -> List[Analyzer]: - logfile: str = "data/inst_{id}.{format}".format(id=log_id, format=settings.log_format) - logfile = log_id +def process_log(logfile: str, settings: LogSettings) -> List[Analyzer]: loader = LOADERS[settings.log_format]() try: loader.load(logfile) @@ -41,48 +39,102 @@ def process_log(log_id: str, settings: LogSettings) -> List[Analyzer]: return analyzers +def run_analysis(log_ids: list, settings): + store: ResultStore = ResultStore() + for log_id in log_ids: + for analysis in process_log(log_id, settings): + log.info("* Result for " + analysis.name()) + analysis.result(store, name=log_id) + return store + + +def load_ids(name: str): + log_ids = [] + with open(name) as src: + for line in src: + line = line.strip() + log_ids.append(line) + return log_ids + + +def urach_logs(log_ids, settings): + return ["data/inst_{id}.{format}".format(id=log_id, format=settings.log_format) for log_id in log_ids] + + +def write_logentry_count_csv(): + global cat, data, lines, csvfile + LogEntryCountCSV.summary = None + for cat in store.get_categories(): + data = store.get_category(cat) + render(analyzers.LogEntryCountAnalyzer, data, name=cat) + if LogEntryCountCSV.summary: + headers = [] + lines = [] + for name in LogEntryCountCSV.summary: + data = LogEntryCountCSV.summary[name] + for head in data: + if not head in headers: + headers.append(head) + line = [name] + for head in headers: + line.append(data[head]) if head in data else line.append(0) + lines.append(line) + import csv + + with open('logentrycount.csv', 'w', newline='') as csvfile: + writer = csv.writer(csvfile, quoting=csv.QUOTE_NONE) + writer.writerow(["name"] + [h.split(".")[-1] for h in headers]) + for line in lines: + writer.writerow(line) + + +def write_simulation_flag_csv(): + global csvfile, result, i + from datetime import datetime + json.dump(store.serializable(), open("simus.json", "w"), indent=2) + with open("simus.csv", "w") as csvfile: + csvfile.write("instanceconfig,log,simu,answered,universe_state,selected_actions,timestamp,time\n") + for key in store.get_store(): + csvfile.write("{}\n".format(key)) + for result in store.store[key]: + csvfile.write(",{}\n".format(result.name)) + for i in result.get(): + csvfile.write(",,{},{},{},{},{},{}\n".format( + i['answers']['@id'], + i['answers']['answered'], + len(i['answers']['universe_state']) if i['answers']['universe_state'] else 0, + len(i['selected_actions']) if i['selected_actions'] else 0, + i['timestamp'], + str(datetime.fromtimestamp(i['timestamp'] / 1000)) + )) + + if __name__ == '__main__': settings: LogSettings = load_settings("biogames2.json") - log_ids: List[str] = [ - "20d4244719404ffab0ca386c76e4b112", - "56d9b64144ab44e7b90bf766f3be32e3", - "dc2cdc28ca074715b905e4aa5badff10", - "e32b16998440475b994ab46d481d3e0c", - ] - log_ids: List[str] = [ + log_ids_urach: List[str] = urach_logs([ # "34fecf49dbaca3401d745fb467", # "44ea194de594cd8d63ac0314be", # "57c444470dbf88605433ca935c", # "78e0c545b594e82edfad55bd7f", # "91abfd4b31a5562b1c66be37d9", - "597b704fe9ace475316c345903", - "e01a684aa29dff9ddd9705edf8", - "fbf9d64ae0bdad0de7efa3eec6", - # "fe1331481f85560681f86827ec", - "fe1331481f85560681f86827ec"] - # "fec57041458e6cef98652df625", ] - log_ids = [] - # with open("/home/clemens/git/ma/test/filtered") as src: - with open("/home/agp8x/git/uni/ma/project/data/0000_ref") as src: - for line in src: - line = line.strip() - log_ids.append(line) - store: ResultStore = ResultStore() - for log_id in log_ids: - for analysis in process_log(log_id, settings): - log.info("* Result for " + analysis.name()) - # print(analysis.result()) - # print(analysis.render()) - analysis.result(store, name=log_id) + # "597b704fe9ace475316c345903", + # "e01a684aa29dff9ddd9705edf8", + # "fbf9d64ae0bdad0de7efa3eec6", + "fe1331481f85560681f86827ec", + # "fe1331481f85560681f86827ec"] + "fec57041458e6cef98652df625", ] + ,settings) + store: ResultStore = run_analysis(log_ids_urach, settings) if False: for r in get_renderer(analyzers.LocomotionActionAnalyzer): r().render(store.get_all()) if False: render(analyzers.LocationAnalyzer, store.get_all()) # print(json.dumps(store.serializable(), indent=1)) - if False: - render(analyzers.ActivityMapper, store.get_all()) - render(analyzers.ProgressAnalyzer, store.get_all()) + if True: + for cat in store.get_categories(): + render(analyzers.ActivityMapper, store.get_category(cat), name=cat) + # render(analyzers.ProgressAnalyzer, store.get_all()) if False: from analyzers.postprocessing import graph @@ -95,49 +147,26 @@ if __name__ == '__main__': data = store.get_category(cat) render(analyzers.SimulationOrderAnalyzer, data, name=cat) if False: - LogEntryCountCSV.summary = None - for cat in store.get_categories(): - data = store.get_category(cat) - render(analyzers.LogEntryCountAnalyzer, data, name=cat) - if LogEntryCountCSV.summary: - headers = [] - lines = [] - for name in LogEntryCountCSV.summary: - data = LogEntryCountCSV.summary[name] - for head in data: - if not head in headers: - headers.append(head) - line = [name] - for head in headers: - line.append(data[head]) if head in data else line.append(0) - lines.append(line) - import csv - - with open('logentrycount.csv', 'w', newline='') as csvfile: - writer = csv.writer(csvfile, quoting=csv.QUOTE_NONE) - writer.writerow(["name"] + [h.split(".")[-1] for h in headers]) - for line in lines: - writer.writerow(line) - if True: - from datetime import datetime - json.dump(store.serializable(), open("simus.json", "w"), indent=2) - with open("simus.csv", "w") as csvfile: - csvfile.write("instanceconfig,log,simu,answered,universe_state,selected_actions,timestamp,time\n") - for key in store.get_store(): - csvfile.write("{}\n".format(key)) - for result in store.store[key]: - csvfile.write(",{}\n".format(result.name)) - for i in result.get(): - csvfile.write(",,{},{},{},{},{},{}\n".format( - i['answers']['@id'], - i['answers']['answered'], - len(i['answers']['universe_state']) if i['answers']['universe_state'] else 0, - len(i['selected_actions']) if i['selected_actions'] else 0, - i['timestamp'], - str(datetime.fromtimestamp(i['timestamp']/1000)) - )) + write_logentry_count_csv() if False: - #json.dump(store.serializable(), open("new.json", "w"), indent=1) + write_simulation_flag_csv() + + + def calc_distance(geojson: str): + from shapely.geometry import LineString + from shapely.ops import transform + from functools import partial + import pyproj + track = LineString(json.loads(geojson)['coordinates']) + project = partial( + pyproj.transform, + pyproj.Proj(init='EPSG:4326'), + pyproj.Proj(init='EPSG:32633')) + return transform(project, track).length + + + if False: + # json.dump(store.serializable(), open("new.json", "w"), indent=1) from collections import defaultdict keys = [ @@ -150,7 +179,8 @@ if __name__ == '__main__': "map" ] import matplotlib.pyplot as plt - #results = [] + + # results = [] places = defaultdict(list) @@ -162,23 +192,24 @@ if __name__ == '__main__': print(json.dumps(result, indent=4)) total = sum(result.values()) print(total) - percentage = defaultdict(lambda :0) - minutes = defaultdict(lambda:0) + percentage = defaultdict(lambda: 0) + minutes = defaultdict(lambda: 0) for i in result: - percentage[i]= result[i]/total - minutes[i] = result[i]/60_000 - print(json.dumps(percentage,indent=4)) + percentage[i] = result[i] / total + minutes[i] = result[i] / 60_000 + print(json.dumps(percentage, indent=4)) if not 'error' in result: - #places[log.get()['instance']].append(percentage) + # places[log.get()['instance']].append(percentage) places[log.get()['instance']].append(minutes) for place in places: - places[place] = sorted(places[place], key=lambda item:item['map']) + places[place] = sorted(places[place], key=lambda item: item['map']) - dummy = [0]*len(keys) + dummy = [0] * len(keys) results = [] sites = [] from util.meta_temp import CONFIG_NAMES + for i in places: for j in places[i]: ordered = [] @@ -188,38 +219,37 @@ if __name__ == '__main__': results.append(dummy) sites.append(CONFIG_NAMES[i] if i in CONFIG_NAMES else "---") - size = len(results) ind = np.arange(size) - width=0.9 + width = 0.9 print(results) data = list(zip(*results)) print(data) lines = [] - bottom = [0]*len(results) + bottom = [0] * len(results) for i in range(0, len(data)): - lines.append(plt.bar(ind,data[i], bottom=bottom, width=width)[0]) - for k,x in enumerate(data[i]): + lines.append(plt.bar(ind, data[i], bottom=bottom, width=width)[0]) + for k, x in enumerate(data[i]): bottom[k] += x plt.legend(lines, keys) plt.title(", ".join(sites)) plt.show() - #size = len(results) - #ind = np.arange(size) - #width = 0.9 - #print(results) - #data = list(zip(*results)) - #print(data) - #lines = [] - #bottom = [0] * len(results) - #for i in range(0, len(data)): + # size = len(results) + # ind = np.arange(size) + # width = 0.9 + # print(results) + # data = list(zip(*results)) + # print(data) + # lines = [] + # bottom = [0] * len(results) + # for i in range(0, len(data)): # lines.append(plt.bar(ind, data[i], bottom=bottom, width=width)[0]) # for k, x in enumerate(data[i]): # bottom[k] += x - #plt.legend(lines, keys) - #plt.title("Zwei Spiele in Filderstadt (t1=237min; t2=67min)") - #plt.show() + # plt.legend(lines, keys) + # plt.title("Zwei Spiele in Filderstadt (t1=237min; t2=67min)") + # plt.show() diff --git a/static/progress/index.html b/static/progress/index.html index efade76..bc641e6 100644 --- a/static/progress/index.html +++ b/static/progress/index.html @@ -1,15 +1,98 @@ - - - + src="https://code.jquery.com/jquery-3.2.1.min.js" + integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" + crossorigin="anonymous"> + + + + + - \ No newline at end of file + +