project/analysis/analyzers/render/biogames.py

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