import json import tempfile from collections import defaultdict from typing import List, Tuple import matplotlib.pyplot as plt import os import numpy as np from scipy.interpolate import interp1d import networkx as nx import itertools from analysis.analyzers import Store, BiogamesStore, SimulationOrderAnalyzer, LocationAnalyzer, BiogamesDuration, \ 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 Result, SimulationRoundsAnalyzer, BoardDurationAnalyzer, ActivityMapper def add_edge(graph, src, dest): if graph.has_edge(src, dest): weight = graph.get_edge_data(src, dest)['weight'] + 1 else: weight = 1 graph.add_edge(tuple(src), tuple(dest), weight=weight) def pairs(iterable): a, b = itertools.tee(iterable) next(b, None) return zip(a, b) def __plot_or_show(name=None): if name: plt.savefig(name) else: plt.show() plt.cla() plt.clf() plt.close() def plot(src_data: List[Tuple[str, List[int]]], ylabel="simulation rounds", title="simulation retries", 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])) plt.plot(datas + rand, linewidth=.2) plt.xticks(rotation=rotation) # plt.margins() plt.ylabel(ylabel) plt.title(title) __plot_or_show(name) def graph_plot(src_data: List[Tuple[str, List[int]]], ylabel="simulation rounds", title="sequential simulation retries", 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( config_name, n=len(src_data), avg=np.mean(counts_per_group), median=np.median(counts_per_group) ) print(config_name) name = "plots/{}.png".format(name) g = nx.Graph() for group in src_data: for i in pairs(enumerate(group)): add_edge(g, i[0], i[1]) positions = {} for node in g.nodes(): positions[node] = node widths = [x[2] / 10.0 for x in g.edges.data('weight')] print(max(widths)) nx.draw_networkx_edges(g, positions, width=widths) # rand = np.random.rand(len(datas),len(datas[0])) # plt.plot(datas+rand, linewidth=.2) plt.xticks(rotation=rotation) # plt.margins() plt.ylabel(ylabel) plt.title(title) plt.figtext(0.5, 0.13, label, ha="center") __plot_or_show(name) def graph_fit(src_data, deg=5, name=None): plt.title("polyfit(x,y,deg=" + str(deg) + ")") for i in src_data: # plt.plot(i) count = len(i) xp = np.linspace(0, count - 1, num=count, endpoint=True) # fit = np.poly1d(np.polyfit(range(len(i)), i, deg=deg)) # plt.plot(xp, fit(xp), linewidth=0.1) xnew = np.linspace(0, count - 1, num=count * 20, endpoint=True) f = interp1d(xp, i, kind='quadratic') plt.plot(range(count), i, '.', markersize=1) plt.plot(xnew, f(xnew), linewidth=0.2) __plot_or_show(name) class SimulationRoundsRender(Render): def render(self, results: List[Result], name=None): data = defaultdict(list) for result in self.filter(results): get = result.get() for key in get: data[key].append(get[key]) data_tuples = [(key, data[key]) for key in sorted(data)] data_tuples = sorted(data_tuples, key=lambda x: sum(x[1])) plot(data_tuples) result_types = [SimulationRoundsAnalyzer] class BoardDurationHistRender(Render): result_types = [BoardDurationAnalyzer] def render(self, results: List[Result], name=None): 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], name=None) -> [str]: data = defaultdict(list) for result in self.filter(results): for board in result.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, name=name) return [name] class ActivityMapperRender(Render): result_types = [ActivityMapper] def render(self, results: List[Result], name=None): print(os.getcwd()) files = [] for result in self.filter(results): data = result.get() path = os.path.join("/tmp", data["properties"]['instance'] + "_" + str(name) + ".json") with open(path, "w") as out: json.dump(data, out, indent=1) files.append(path) return files class StoreRender(Render): result_types = [Store, BiogamesStore] def render(self, results: List[Result], name=None): for result in self.filter(results): with open(os.path.join("static", "progress", "data", "fooo"), "w") as out: json.dump(result.get(), out, indent=1) class SimulationOrderRender(Render): def render(self, results: List[Result], name=None): data = defaultdict(list) for result in self.filter(results): get = result.get() for i, value in enumerate(get): data[i].append(value) # data_tuples = [(key, data[key]) for key in sorted(data)] # data_tuples = sorted(data_tuples, key=lambda x: sum(x[1])) # plot(enumerate([r.get() for r in self.filter(results)])) plot(list(data.items()), ylabel="simulation retries", title="sequential simulation retries", rotation=None) result_types = [SimulationOrderAnalyzer] class SimulationGroupRender(Render): def render(self, results: List[Result], name=None): # data = [r.get() for r in self.filter(results)] data = [] for r in self.filter(results): raw = r.get() if len(raw) < 6: raw = [0] + raw data.append(raw) print(name, len(data)) # graph_fit(list(data), name=name) graph_plot(list(data), ylabel="simulation retries", title="sequential simulation retries", rotation=None, name=name) 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