import math
import os
from copy import deepcopy
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.tri as tri
from visualizing.simulating import Simulation
from visualizing.model import Data, GlobalData
from visualizing.helpers import TwoSlopeLoggedNorm
is_evaluating = False
workload_max = None delta_workload_min_max = None
class Figure():
class Colorbar():
def __init__(self, shrink=0.9, extend='neither'):
self._shrink = shrink
self._extend = extend
@property
def shrink(self):
return self._shrink
@property
def extend(self):
return self._extend
def __init__(self, colorbar: Colorbar):
self._colorbar = colorbar
@property
def colorbar(self):
return self._colorbar
class Machine():
def __init__(
self,
*,
dpi=256,
plot_file_type='png',
is_light: bool,
fig_style=Figure(colorbar=Figure.Colorbar()),
):
self._dpi = dpi
self._plot_file_type = plot_file_type
self._is_light = is_light
self._fig_style = fig_style
@property
def dpi(self) -> int:
return self._dpi
@property
def plot_file_type(self) -> str:
return self._plot_file_type
@property
def is_light(self) -> bool:
return self._is_light
@property
def plt_theme(self) -> str:
if self.is_light:
return 'default'
else:
return 'dark_background'
@property
def fig(self) -> Figure:
return deepcopy(self._fig_style)
def plot_all_sorted_workloads(
self,
global_data: GlobalData,
sim: Simulation
):
data = Data(global_data=global_data)
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(f'all occured workloads')
if self.is_light:
cmap = plt.get_cmap('gist_heat_r')
else:
cmap = plt.get_cmap('copper')
for iteration in range(sim.num_iter):
data.prepare_new_iteration(sim=sim)
sorted_lon_lat_workloads = data.sorted_lon_lat_workloads()[:, 2]
mapped_values = []
for i in range(len(sorted_lon_lat_workloads)):
value = sorted_lon_lat_workloads[i]
if value > 0.0:
mapped_values.append(value)
xp, fp = [0, sim.num_iter - 1], [0.2, 1.0]
alpha = np.interp(x=iteration, xp=xp, fp=fp)
color = cmap(alpha)
ax.plot(
range(len(mapped_values)),
mapped_values,
color=color,
alpha=alpha
)
ax.plot(
len(mapped_values)-1,
mapped_values[-1],
'x',
color=color,
alpha=alpha
)
ax.set_xlabel('')
ax.set_ylabel('workload')
ax.grid(b=True)
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'sorted_workloads.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_all_boxplot_workloads(
self,
global_data: GlobalData,
sim: Simulation
):
data = Data(global_data=global_data)
q_low, q_high = 0, 99
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(f'all workloads > 0, then in [{q_low} %, {q_high} %]')
for iteration in range(sim.iteration_max + 1):
data.prepare_new_iteration(sim=sim)
mapped_values = np.array(list(filter(
lambda x: x > 0.0,
data.workloads.raw
)))
ax.boxplot(
mapped_values,
positions=[iteration],
showfliers=False,
whis=[q_low, q_high]
)
ax.set_xlabel('iteration')
ax.set_ylabel('workload')
ax.grid(b=True, axis='y', which='both')
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'workload-boxplots.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_all_max_workloads(self, global_data: GlobalData, sim: Simulation):
data = Data(global_data=global_data)
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(f'all max (delta-) workloads')
if self.is_light:
c_max = 'k'
cmap = plt.get_cmap('seismic')
c_delta_max = cmap(0.75)
c_delta_min = cmap(0.25)
else:
c_max = 'w'
cmap = plt.get_cmap('twilight')
c_delta_max = cmap(0.75)
c_delta_min = cmap(0.25)
max_workloads = []
max_delta_workloads = []
min_delta_workloads = []
for _ in range(sim.num_iter):
data.prepare_new_iteration(sim=sim)
max_workloads.append(data.workloads.max)
if data.iteration > 0:
max_delta_workloads.append(data.delta_workloads.max)
min_delta_workloads.append(data.delta_workloads.min)
ax.plot(
range(len(max_workloads)),
max_workloads,
'x-',
color=c_max,
label='max workloads'
)
ax.plot(
np.array(range(len(max_delta_workloads))) + 0.5,
max_delta_workloads,
'x-',
color=c_delta_max,
label='max delta-workloads'
)
ax.plot(
np.array(range(len(min_delta_workloads))) + 0.5,
min_delta_workloads,
'x-',
color=c_delta_min,
label='min delta-workloads'
)
ax.set_xlabel('iteration')
ax.set_ylabel('(delta-) workload')
ax.grid(b=True)
plt.legend()
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'max_workloads.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_all_unique_edges(self, global_data: GlobalData, sim: Simulation):
data = Data(global_data=global_data)
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(f'number of unique edges')
if self.is_light:
color = 'k'
else:
color = 'w'
num_unique_edges = []
for _ in range(sim.num_iter):
data.prepare_new_iteration(sim=sim)
num_unique_edges.append(
np.array(data.workloads.raw).astype(bool).sum()
)
ax.plot(
range(len(num_unique_edges)),
num_unique_edges,
'x-',
color=color,
)
ax.set_xlabel('iteration')
ax.set_ylabel('amount of unique edges')
ax.grid(b=True, axis='y', which='both')
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'num_unique_edges.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_workloads(self, data: Data, sim: Simulation):
sorted_lon_lat_workloads = data.sorted_lon_lat_workloads()
plt.style.use(self.plt_theme)
fig, ax = plt.subplots()
ax.set_title(
'workloads$_{'
+ (f'{data.iteration}' if not is_evaluating else 'eval')
+ '}$'
+ f' in [{data.workloads.min}, {data.workloads.max}]'
)
if self.is_light:
cmap = 'cubehelix_r'
else:
cmap = 'copper'
norm = {
'PuRd': colors.Normalize(),
'binary': TwoSlopeLoggedNorm(base=5),
'Purples': TwoSlopeLoggedNorm(base=10),
'gist_heat_r': TwoSlopeLoggedNorm(base=20),
'cubehelix_r': TwoSlopeLoggedNorm(base=3),
'copper': TwoSlopeLoggedNorm(base=50),
}.get(cmap, colors.Normalize())
if workload_max is not None:
norm.vmax = workload_max
else:
norm.vmax = data.global_data.max_workload
plot_collection = ax.scatter(
x=sorted_lon_lat_workloads[:, 0],
y=sorted_lon_lat_workloads[:, 1],
c=sorted_lon_lat_workloads[:, 2],
s=2, alpha=1.0,
edgecolors='none',
cmap=cmap,
norm=norm,
)
ax.set_xlabel('longitude')
ax.set_ylabel('latitude')
ax.set_aspect(1.0 / np.cos(np.deg2rad(data.lats.center)))
fig.colorbar(
mappable=plot_collection,
shrink=self.fig.colorbar.shrink,
extend=self.fig.colorbar.extend
)
ax.grid(b=False)
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'workloads.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_workload_quantiles(self, data: Data, sim: Simulation):
sorted_lon_lat_workloads = data.sorted_lon_lat_workloads()
n = len(sorted_lon_lat_workloads)
q_low, q_high = 0.0, 0.95
q_low_idx, q_high_idx = (
int(q_low * n),
int(q_high * n)
)
q_low_val, q_high_val = (
sorted_lon_lat_workloads[q_low_idx, 2],
sorted_lon_lat_workloads[q_high_idx, 2]
)
plt.style.use(self.plt_theme)
fig, ax = plt.subplots()
ax.set_title(
'workloads$_{'
+ (f'{data.iteration}' if not is_evaluating else 'eval')
+ '}$'
+ f' in [{data.workloads.min}, {data.workloads.max}]'
)
if self.is_light:
cmap = 'cubehelix_r'
else:
cmap = 'copper'
cmap = plt.get_cmap(cmap)
boundaries = []
if q_low_val > 0.0:
boundaries.append(0.0)
boundaries.extend([q_low_val, q_high_val])
if q_high_val < data.global_data.max_workload:
boundaries.append(data.global_data.max_workload)
norm = colors.BoundaryNorm(
boundaries=boundaries,
ncolors=cmap.N
)
plot_collection = ax.scatter(
x=sorted_lon_lat_workloads[:, 0],
y=sorted_lon_lat_workloads[:, 1],
c=sorted_lon_lat_workloads[:, 2],
s=2, alpha=1.0,
edgecolors='none',
cmap=cmap,
norm=norm,
)
ax.set_xlabel('longitude')
ax.set_ylabel('latitude')
ax.set_aspect(1.0 / np.cos(np.deg2rad(data.lats.center)))
fig.colorbar(
label=f'upper {100 * (1.0 - q_high):3.1f} % of workloads'
+ '$_{'
+ f'{data.iteration}'
+ '}$',
mappable=plot_collection,
shrink=self.fig.colorbar.shrink,
extend=self.fig.colorbar.extend
)
ax.grid(b=False)
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'workload-quantiles.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_delta_workloads(self, data: Data, sim: Simulation):
sorted_lon_lat_deltas = data.abs_sorted_lon_lat_deltas()
plt.style.use(self.plt_theme)
fig, ax = plt.subplots()
ax.set_title(
'delta-workloads$_{'
+ (f'{data.iteration-1}, {data.iteration}' if not is_evaluating else 'eval')
+ '}$'
+ f' in [{data.delta_workloads.min}, {data.delta_workloads.max}]'
)
if self.is_light:
cmap = 'seismic'
else:
cmap = 'twilight'
norm = {
'seismic': colors.TwoSlopeNorm(vcenter=0.0),
'PRGn_r': TwoSlopeLoggedNorm(vcenter=0.0),
'RdGy': TwoSlopeLoggedNorm(vcenter=0.0),
'twilight': TwoSlopeLoggedNorm(vcenter=0.0),
}.get(cmap, colors.TwoSlopeNorm(vcenter=0.0))
if delta_workload_min_max is not None:
norm.vmin = delta_workload_min_max[0]
norm.vmax = delta_workload_min_max[1]
plot_collection = ax.scatter(
x=sorted_lon_lat_deltas[:, 0],
y=sorted_lon_lat_deltas[:, 1],
c=sorted_lon_lat_deltas[:, 2],
s=2, alpha=1.0,
edgecolors='none',
norm=norm,
cmap=cmap,
)
ax.set_xlabel('longitude')
ax.set_ylabel('latitude')
ax.set_aspect(1 / np.cos(np.deg2rad(data.lats.center)))
fig.colorbar(
mappable=plot_collection,
shrink=self.fig.colorbar.shrink,
extend=self.fig.colorbar.extend
)
ax.grid(b=False)
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'delta_workloads.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_delta_workload_quantiles(self, data: Data, sim: Simulation):
sorted_lon_lat_deltas = data.sorted_lon_lat_deltas()
n = len(sorted_lon_lat_deltas)
q_low, q_high = 0.05, 0.95
q_low_idx, q_high_idx = (
int(q_low * n),
int(q_high * n)
)
q_low_val, q_high_val = (
sorted_lon_lat_deltas[q_low_idx, 2],
sorted_lon_lat_deltas[q_high_idx, 2]
)
plt.style.use(self.plt_theme)
fig, ax = plt.subplots()
ax.set_title(
'delta-workloads$_{'
+ (f'{data.iteration-1}, {data.iteration}' if not is_evaluating else 'eval')
+ '}$'
+ f' in [{data.delta_workloads.min}, {data.delta_workloads.max}]'
)
if self.is_light:
cmap = 'seismic'
else:
cmap = 'twilight'
cmap = plt.get_cmap(cmap)
boundaries = [
data.delta_workloads.min,
q_low_val,
q_high_val,
data.delta_workloads.max,
]
norm = colors.BoundaryNorm(
boundaries=boundaries,
ncolors=cmap.N
)
plot_collection = ax.scatter(
x=sorted_lon_lat_deltas[:, 0],
y=sorted_lon_lat_deltas[:, 1],
c=sorted_lon_lat_deltas[:, 2],
s=2, alpha=1.0,
edgecolors='none',
norm=norm,
cmap=cmap,
)
ax.set_xlabel('longitude')
ax.set_ylabel('latitude')
ax.set_aspect(1 / np.cos(np.deg2rad(data.lats.center)))
fig.colorbar(
label=f'lower {100 * (q_low):3.1f} %'
+ f' and upper {100 * (1.0 - q_high):3.1f} % \n'
+ 'of delta-workloads$_{'
+ f'{data.iteration - 1}, {data.iteration}'
+ '}$',
mappable=plot_collection,
shrink=self.fig.colorbar.shrink,
extend=self.fig.colorbar.extend
)
ax.grid(b=False)
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'delta_workloads-quantiles.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_workload_histogram(self, data: Data, sim: Simulation):
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(
f'density-function of workloads'
+ '$_{'
+ (f'{data.iteration}' if not is_evaluating else 'eval')
+ '}$ > 0'
)
if self.is_light:
fc = 'k'
ec = 'k'
else:
fc = 'w'
ec = 'w'
num_bins = int(np.ceil(data.workloads.max)) - \
int(np.floor(data.workloads.min))
_n, _bins, _patches = ax.hist(
data.workloads.raw_nz,
bins=num_bins,
fc=fc,
ec=ec
)
ax.set_xlabel('workloads')
ax.set_ylabel('amount of occurence')
ax.grid(b=True, axis='y', which='both')
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'workloads_hist.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def plot_lanecount_to_workload(self, data: Data, sim: Simulation):
q_low, q_high = 1, 99
plt.style.use(self.plt_theme)
_fig, ax = plt.subplots()
ax.set_title(
f'workloads'
+ '$_{'
+ (f'{data.iteration}' if not is_evaluating else 'eval')
+ '}$ > 0, then'
+ f' in [{q_low} %, {q_high} %], per lane-count'
)
zipped_data = sorted(
filter(
lambda x: x[1] > 0.0,
zip(data.lane_counts.raw, data.workloads.raw)
),
key=lambda x: x[0]
)
split_indices = []
for i in range(1, len(zipped_data)):
prev_lane_count = zipped_data[i-1][0]
lane_count = zipped_data[i][0]
if prev_lane_count != lane_count:
split_indices.append(i)
zipped_data = list(
zipped_data[i:j]
for i, j in zip(
[0] + split_indices,
split_indices + [None]
)
)
for vec in zipped_data:
workloads = list(map(lambda x: x[1], vec))
lane_count = int(vec[0][0])
ax.boxplot(
workloads,
positions=[lane_count],
showfliers=False,
notch=True,
whis=[q_low, q_high],
)
ax.set_xlabel('lane-count')
ax.set_ylabel('workload')
ax.minorticks_on()
ax.grid(b=True, axis='y', which='both')
plt.tight_layout()
plt.savefig(
os.path.join(
sim.results_dir,
f'{data.iteration}',
'stats',
f'lane-count_to_workload.{self.plot_file_type}'
),
dpi=self.dpi,
bbox_inches="tight"
)
plt.close()
def light():
return Machine(is_light=True)
def dark():
return Machine(is_light=False)