266 lines
8.0 KiB
Python
266 lines
8.0 KiB
Python
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 |