das-research/DAS/visualizor.py
Arunima Chaudhuri 2a42c17a1f debug
2025-01-28 00:32:31 +05:30

1740 lines
88 KiB
Python

#!/bin/python3
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import os
import pandas as pd
def plotData(conf):
plt.clf()
fig = plt.figure("9, 3")
plt.grid(True)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
if conf["type"] == "plot" or conf["type"] == "plot_with_1line":
for i in range(len(conf["data"])):
# plt.plot(conf["xdots"], conf["data"][i], conf["colors"][i], label=conf["labels"][i])
plt.plot(conf["xdots"], conf["data"][i], label=conf["labels"][i])
elif conf["type"] == "individual_bar" or conf["type"] == "individual_bar_with_2line":
plt.bar(conf["xdots"], conf["data"])
elif conf["type"] == "grouped_bar":
for i in range(len(conf["data"])):
plt.bar(conf["xdots"], conf["data"][i], label=conf["labels"][i])
if conf["type"] == "individual_bar_with_2line":
plt.axhline(y = conf["expected_value1"], color='w', linestyle='--', label=conf["line_label1"])
plt.axhline(y = conf["expected_value2"], color='g', linestyle='--', label=conf["line_label2"])
if conf["type"] == "plot_with_1line":
plt.axhline(y = conf["expected_value"], color='g', linestyle='--', label=conf["line_label"])
plt.title(conf["title"], fontsize=14)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylim(0, conf["yaxismax"]*1.1 if conf["yaxismax"] > 0 else 1)
plt.legend(loc=conf["legLoc"])
plt.savefig(conf["path"], bbox_inches="tight")
def plotBoxData(conf):
plt.clf()
plt.grid(True)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
num_boxes = len(conf["data"])
positions = np.arange(num_boxes)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.boxplot(conf["data"], patch_artist=True, showmeans=True, meanline=True, positions=positions)
plt.title(conf["title"], fontsize=14)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
plt.savefig(conf["path"], bbox_inches="tight")
class Visualizor:
"""This class helps the visualization of the results"""
def __init__(self, execID, config, results):
"""Initialize the visualizer module"""
self.execID = execID
self.config = config
self.results = results
os.makedirs("results/"+self.execID+"/plots", exist_ok=True)
def __get_attrbs__(self, result):
text = str(result.shape).split("-")
d = dict()
for i in range(0, len(text), 2):
d[text[i]] = text[i + 1]
return d
def __getNodeTypes__(self, group):
theGroup = dict()
for nt in self.config.nodeTypesGroup:
if nt['group'] == group:
for _k, _v in nt["classes"].items():
theGroup[_k] = {
"vpn": _v["def"]["validatorsPerNode"],
"bw": _v["def"]["bwUplinks"],
"w": _v["weight"]
}
break
return theGroup
def __getNodeRanges(self, shape):
nodeClasses, nodeRatios = [], []
for _k, _v in shape.nodeTypes["classes"].items():
nodeClasses.append(_k)
nodeRatios.append(_v['weight'])
nodeCounts = [int(shape.numberNodes * ratio / sum(nodeRatios)) for ratio in nodeRatios]
commulativeSum = [sum(nodeCounts[:i+1]) for i in range(len(nodeCounts))]
commulativeSum[-1] = shape.numberNodes
return nodeClasses, commulativeSum
def plotHeatmaps(self, x, y):
"""Plot the heatmap using the parameters given as x axis and y axis"""
print("Plotting heatmap "+x+" vs "+y)
#Find the location of x in shape
#Find the location of y in shape
#Find the location od r in shape
#Loop over all results
#Add unique values foir every parameter
#Find number of runs from r
#If number of values for x and y > 3 then plot heatmap, otherwise finish
#Create a 2D grid with the dimensions of the number of values for x and y
#For all values of x
#For all values of y
# For all values in r
#Fixing all other values to 1 (in the mean time)
#Add/sum TTA into 2D grid
#if last r divide by number of runs
#Plot 2D grid
def plotHeatmaps(self, x, y):
"""Plot the heatmap using the parameters given as x axis and y axis"""
print("Plotting heatmap "+x+" vs "+y)
#Find the location of x in shape
#Find the location of y in shape
#Find the location od r in shape
#Loop over all results
#Add unique values foir every parameter
#Find number of runs from r
#If number of values for x and y > 3 then plot heatmap, otherwise finish
#Create a 2D grid with the dimensions of the number of values for x and y
#For all values of x
#For all values of y
# For all values in r
#Fixing all other values to 1 (in the mean time)
#Add/sum TTA into 2D grid
#if last r divide by number of runs
#Plot 2D grid
def plotAll(self):
"""Plot all the important elements of each result"""
for result in self.results:
plotPath = "results/"+self.execID+"/plots/"+str(result.shape)
os.makedirs(plotPath, exist_ok=True)
self.plotMissingSegments(result, plotPath)
self.plotProgress(result, plotPath)
self.plotSamplesReceived(result, plotPath)
self.plotSentData(result, plotPath)
self.plotRecvData(result, plotPath)
self.plotDupData(result, plotPath)
# self.plotSamplesRepaired(result, plotPath)
# self.plotMessagesSent(result, plotPath)
# self.plotMessagesRecv(result, plotPath)
# self.plotSampleRecv(result, plotPath)
# self.plotRestoreRowCount(result, plotPath)
# self.plotRestoreColumnCount(result, plotPath)
if self.config.saveRCdist:
self.plotRowCol(result, plotPath)
# self.plotBoxSamplesRepaired(result, plotPath)
# self.plotBoxMessagesSent(result, plotPath)
# self.plotBoxMessagesRecv(result, plotPath)
# self.plotBoxSampleRecv(result, plotPath)
# self.plotBoxRestoreColumnCount(result, plotPath)
# self.plotBoxRestoreRowCount(result, plotPath)
# if self.config.saveRCdist:
# self.plotBoxRowCol(result, plotPath)
self.plotBoxenSamplesRepaired(result, plotPath)
self.plotBoxenMessagesSent(result, plotPath)
self.plotBoxenMessagesRecv(result, plotPath)
self.plotBoxenSamplesRecv(result, plotPath)
self.plotBoxenRestoreRowCount(result, plotPath)
self.plotBoxenRestoreColumnCount(result, plotPath)
if self.config.saveRCdist:
self.plotBoxenRowColDist(result, plotPath)
self.plotECDFSamplesRepaired(result, plotPath)
self.plotECDFMessagesSent(result, plotPath)
self.plotECDFMessagesRecv(result, plotPath)
self.plotECDFSamplesReceived(result, plotPath)
self.plotECDFRestoreRowCount(result, plotPath)
self.plotECDFRestoreColumnCount(result, plotPath)
if self.config.saveRCdist:
self.plotECDFRowColDist(result, plotPath)
# plots for query results
self.plot_query_times_boxplot_all(result, plotPath)
self.plot_query_results(result, plotPath)
self.plot_retries_boxplot(result, plotPath)
self.plot_retries_sum_per_node_boxplot(result, plotPath)
def plot_query_times_boxplot_all(self, result, plotPath):
"""Plot boxplots for query times for all nodes."""
attrbs = self.__get_attrbs__(result)
plt.figure(figsize=(14, 7))
all_query_times = [time for time in result.query_total_time if time is not None]
plt.boxplot(all_query_times, patch_artist=True, boxprops=dict(facecolor="lightblue"))
plt.title(f"Total Query Time for each node", fontsize=16)
plt.ylabel("Query Time (seconds)", fontsize=16)
plt.grid(True, axis='y', color='gray', linestyle='--', linewidth=0.5)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.axhline(y=12, color='red', linestyle='--', linewidth=1)
plt.subplots_adjust(top=0.85)
plt.figtext(
0.3, 0.96,
f"Custody Rows: {attrbs['cusr']}, Custody Columns: {attrbs['cusc']} Malicious nodes: {attrbs['mn']}%",
fontsize=16,
ha='center',
bbox=dict(facecolor='white', edgecolor='black', boxstyle='round')
)
os.makedirs(plotPath, exist_ok=True)
plt.savefig(os.path.join(plotPath, 'query_times_all_connections_boxplot.png'))
plt.close()
def plot_query_results(self, result, plotPath):
"""Plot a single pie chart for block availability based on query results."""
attrbs = self.__get_attrbs__(result)
query_results = result.query_results
available_count = query_results.count('success')
not_available_count = query_results.count('failure')
sizes = [available_count, not_available_count]
colors = ['lightgreen', 'salmon']
fig, ax = plt.subplots(figsize=(7, 7))
wedges, texts, autotexts = ax.pie(
sizes, autopct='%1.1f%%', startangle=140, colors=colors, textprops={'fontsize': 16}
)
for autotext in autotexts:
autotext.set_fontsize(16)
ax.set_title("Block Availability", fontsize=16)
plt.figtext(
0.5, 0.96,
f"Custody Rows: {attrbs['cusr']}, Custody Columns: {attrbs['cusc']} Malicious Nodes: {attrbs['mn']}%",
fontsize=16,
ha='center',
bbox=dict(facecolor='white', edgecolor='black', boxstyle='round')
)
os.makedirs(plotPath, exist_ok=True)
output_path = os.path.join(plotPath, 'query_results_pie_chart.png')
plt.savefig(output_path)
plt.close()
def plot_retries_boxplot(self, result, plotPath):
"""Plot boxplots for original retries for all nodes."""
attrbs = self.__get_attrbs__(result)
plt.figure(figsize=(14, 7))
all_original_retries = [
retry for sublist in result.all_original_retries for retry in sublist if retry is not None
]
plt.boxplot(all_original_retries, patch_artist=True, boxprops=dict(facecolor="lightgreen"))
plt.title("Number of peers queried by each node for a sample", fontsize=16)
plt.ylabel("Count of Queried Peers", fontsize=16)
plt.grid(True, axis='y', color='gray', linestyle='--', linewidth=0.5)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.figtext(
0.3, 0.96,
f"Custody Rows: {attrbs['cusr']}, Custody Columns: {attrbs['cusc']} Malicious nodes: {attrbs['mn']}%",
fontsize=16,
ha='center',
bbox=dict(facecolor='white', edgecolor='black', boxstyle='round')
)
os.makedirs(plotPath, exist_ok=True)
plt.savefig(os.path.join(plotPath, 'original_retries_all_connections_boxplot.png'))
plt.close()
def plot_retries_sum_per_node_boxplot(self, result, plotPath):
attrbs = self.__get_attrbs__(result)
plt.figure(figsize=(14, 7))
all_retries_sum = [retries for retries in result.original_retries_sum if retries is not None]
plt.boxplot(all_retries_sum, patch_artist=True,
boxprops=dict(facecolor="lightgreen"))
plt.title("Total Sampling Requests Sent by Each Node", fontsize=16)
plt.ylabel("Sum of all sampling requests for each node", fontsize=16)
plt.grid(True, axis='y', color='gray', linestyle='--', linewidth=0.5)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.figtext(
0.3, 0.96,
f"Custody Rows: {attrbs['cusr']}, Custody Columns: {attrbs['cusc']} Malicious nodes: {attrbs['mn']}%",
fontsize=16,
ha='center',
bbox=dict(facecolor='white', edgecolor='black', boxstyle='round')
)
output_path = os.path.join(plotPath, 'retries_sum_boxplot_per_node.png')
plt.savefig(output_path)
plt.close()
def plotBoxRestoreRowCount(self, result, plotPath):
"""Box Plot of restoreRowCount for all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Box Plot of Restore Row Count by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Restore Row Count"
n1 = int(result.numberNodes * result.class1ratio)
class1_data = result.restoreRowCount[1: n1]
class2_data = result.restoreRowCount[n1+1: ]
data = [class1_data, class2_data]
plt.boxplot(data)
plt.xticks([1, 2], ['Class 1 Nodes', 'Class 2 Nodes'])
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/box_restoreRowCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/box_restoreRowCount.png"))
def plotBoxRestoreColumnCount(self, result, plotPath):
"""Box Plot of restoreColumnCount for all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Box Plot of Restore Column Count by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Restore Column Count"
n1 = int(result.numberNodes * result.class1ratio)
class1_data = result.restoreColumnCount[1: n1]
class2_data = result.restoreColumnCount[n1+1: ]
data = [class1_data, class2_data]
plt.boxplot(data)
plt.xticks([1, 2], ['Class 1 Nodes', 'Class 2 Nodes'])
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/box_restoreColumnCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/box_restoreColumnCount.png"))
def plotBoxenRestoreRowCount(self, result, plotPath):
"""Plots the Boxen plot of restoreRowCount for all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Boxen Plot of Restore Row Count by Nodes"
conf["xlabel"] = "Restore Row Count"
conf["ylabel"] = "Nodes"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.restoreRowCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
plt.figure(figsize=(8, 6))
sns.boxenplot(x='category', y='values', hue='category', data=data, palette="Set2", ax=plt.gca(), width=0.8)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/boxen_restoreRowCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/boxen_restoreRowCount.png"))
def plotBoxenRestoreColumnCount(self, result, plotPath):
"""Plots the Boxen plot of restoreColumnCount for all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Boxen Plot of Restore Column Count by Nodes"
conf["xlabel"] = "Restore Column Count"
conf["ylabel"] = "Nodes"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.restoreColumnCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
plt.figure(figsize=(8, 6))
sns.boxenplot(x='category', y='values', hue='category', data=data, palette="Set2", ax=plt.gca(), width=0.8)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/boxen_restoreColumnCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/boxen_restoreColumnCount.png"))
def plotECDFRestoreRowCount(self, result, plotPath):
"""Plots the ECDF of restoreRowCount for all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Restore Row Count by Nodes"
conf["xlabel"] = "Restore Row Count"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.repairedSampleCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
max_val = max(result.restoreRowCount) * 1.1
plt.xlim(left=0, right=max_val if max_val > 0 else 1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.legend(title='Node Class', labels=labels, loc=1)
plt.savefig(plotPath + "/ecdf_restoreRowCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_restoreRowCount.png"))
def plotECDFRestoreColumnCount(self, result, plotPath):
"""Plots the ECDF of restoreColumnCount for all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Restore Column Count by Nodes"
conf["xlabel"] = "Restore Column Count"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.repairedSampleCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
max_val = max(result.restoreColumnCount) * 1.1
plt.xlim(left=0, right=max_val if max_val > 0 else 1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.legend(title='Node Class', labels=labels, loc=1)
plt.savefig(plotPath + "/ecdf_restoreColumnCount.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_restoreColumnCount.png"))
def plotECDFMessagesSent(self, result, plotPath):
"""Plots the ECDF of messages sent by all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Messages Sent by Nodes"
conf["xlabel"] = "Number of Messages Sent"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.msgSentCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.legend(title='Node Class', labels=labels)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
plt.xlim(left=0, right=max(result.msgSentCount) * 1.1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/ecdf_messagesSent.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_messagesSent.png"))
def plotECDFMessagesRecv(self, result, plotPath):
"""Plots the ECDF of messages received by all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Messages Received by Nodes"
conf["xlabel"] = "Number of Messages Received"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.msgRecvCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.legend(title='Node Class', labels=labels)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
plt.xlim(left=0, right=max(result.msgRecvCount) * 1.1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/ecdf_messagesRecv.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_messagesRecv.png"))
def plotECDFSamplesReceived(self, result, plotPath):
"""Plots the ECDF of samples received by all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Samples Received by Nodes"
conf["xlabel"] = "Number of Samples Received"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.sampleRecvCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.legend(title='Node Class', labels=labels)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
plt.xlim(left=0, right=max(result.sampleRecvCount) * 1.1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/ecdf_samplesReceived.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_samplesReceived.png"))
def plotECDFRowColDist(self, result, plotPath):
"""Plots the ECDF of row col distribution by all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Row-Col Distribution by Nodes"
conf["xlabel"] = "Row-Col Distribution"
conf["ylabel"] = "ECDF"
vector1 = result.metrics["rowDist"]
vector2 = result.metrics["columnDist"]
sns.ecdfplot(data=vector1, label='Rows')
sns.ecdfplot(data=vector2, label='Columns')
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
plt.xlim(left=0, right=max(max(vector1), max(vector2)) * 1.1)
plt.legend(labels=['Row Dist', 'Column Dist'], loc=1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/ecdf_rowColDist.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_rowColDist.png"))
def plotECDFSamplesRepaired(self, result, plotPath):
"""Plots the ECDF of samples repaired by all nodes using seaborn's ecdfplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "ECDF of Samples Repaired by Nodes"
conf["xlabel"] = "Number of Samples Repaired"
conf["ylabel"] = "ECDF"
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
start = 1
labels = []
for i, rng in enumerate(nodeRanges):
class_data = result.repairedSampleCount[start: rng + 1]
label = f"Class {nodeClasses[i]} Nodes"
labels.append(label)
start = rng + 1
sns.ecdfplot(data=class_data, label=label)
plt.legend(title='Node Class', labels=labels)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
plt.xlim(left=0, right=max(result.repairedSampleCount) * 1.1)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/ecdf_samplesRepaired.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/ecdf_samplesRepaired.png"))
def plotBoxenSamplesRecv(self, result, plotPath):
"""Boxen Plot of the number of samples received by all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Samples Received by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Samples Received"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.sampleRecvCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
plt.figure(figsize=(8, 6))
sns.boxenplot(x='category', y='values', hue='category', data=data, palette="Set2", ax=plt.gca(), width=0.8)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.tight_layout()
plt.savefig(plotPath + "/boxen_samplesRecv.png")
plt.close()
print("Plot %s created." % (plotPath + "/boxen_samplesRecv.png"))
def plotBoxenSamplesRepaired(self, result, plotPath):
"""Boxen Plot of the number of samples repaired by all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Samples Repaired by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Samples Repaired"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.repairedSampleCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
plt.figure(figsize=(8, 6))
sns.boxenplot(x='category', y='values', hue='category', data=data, width=0.8, palette="Set2", ax=plt.gca())
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.tight_layout()
plt.savefig(plotPath + "/boxen_samplesRepaired.png")
plt.close()
print("Plot %s created." % (plotPath + "/boxen_samplesRepaired.png"))
def plotBoxenRowColDist(self, result, plotPath):
"""Boxen Plot of the Row/Column distribution"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Row/Column Distribution"
conf["xlabel"] = "Row/Column Type"
conf["ylabel"] = "Validators Subscribed"
vector1 = result.metrics["rowDist"]
vector2 = result.metrics["columnDist"]
if len(vector1) > len(vector2):
vector2 += [np.nan] * (len(vector1) - len(vector2))
elif len(vector1) < len(vector2):
vector1 += [np.nan] * (len(vector2) - len(vector1))
data = [vector1, vector2]
plt.figure(figsize=(8, 6))
sns.boxenplot(data=data, width=0.8)
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.tight_layout()
plt.savefig(plotPath + "/boxen_rowColDist.png")
plt.close()
print("Plot %s created." % (plotPath + "/boxen_rowColDist.png"))
def plotBoxenMessagesSent(self, result, plotPath):
"""Plots the number of messages sent by all nodes using seaborn's boxenplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Sent by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Messages Sent"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.msgSentCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
sns.boxenplot(x='category', y='values', hue='category', data=data, width=0.8, palette="Set2", ax=plt.gca())
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/boxen_messagesSent.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/boxen_messagesSent.png"))
def plotBoxenMessagesRecv(self, result, plotPath):
"""Plots the number of messages received by all nodes using seaborn's boxenplot"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Received by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Messages Received"
data = []
nodeClasses, nodeRanges = self.__getNodeRanges(result.shape)
_start = 1
for _range in nodeRanges:
data.append(result.msgRecvCount[_start: _range])
_start = _range
_values, _categories = [], []
for _d, _nc in zip(data, nodeClasses):
_values += _d
_categories += [f'Class {_nc}'] * len(_d)
data = pd.DataFrame({
'values': _values,
'category': _categories
})
sns.boxenplot(x='category', y='values', hue='category', data=data, palette="Set2", ax=plt.gca())
plt.xlabel(conf["xlabel"], fontsize=12)
plt.ylabel(conf["ylabel"], fontsize=12)
plt.title(conf["title"], fontsize=14)
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
plt.text(1.05, 0.05, conf["textBox"], fontsize=14, verticalalignment='bottom', transform=plt.gca().transAxes, bbox=props)
plt.savefig(plotPath + "/boxen_messagesRecv.png", bbox_inches="tight")
print("Plot %s created." % (plotPath + "/boxen_messagesRecv.png"))
def plotBoxSamplesRepaired(self, result, plotPath):
"""Box Plot of the number of samples repaired by all nodes"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Samples Repaired by Nodes"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Samples Repaired"
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [result.repairedSampleCount[1: n1], result.repairedSampleCount[n1+1: ]]
conf["path"] = plotPath + "/box_samplesRepaired.png"
plotBoxData(conf)
print("Plot %s created." % conf["path"])
def plotBoxRowCol(self, result, plotPath):
"""Box Plot of the Row/Column distribution"""
plt.clf()
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Row/Column Distribution"
conf["xlabel"] = ""
conf["ylabel"] = "Validators Subscribed"
vector1 = result.metrics["rowDist"]
vector2 = result.metrics["columnDist"]
if len(vector1) > len(vector2):
vector2 += [np.nan] * (len(vector1) - len(vector2))
elif len(vector1) < len(vector2):
vector1 += [np.nan] * (len(vector2) - len(vector1))
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [vector1, vector2]
conf["path"] = plotPath + "/box_rowColDist.png"
plotBoxData(conf)
print("Plot %s created." % conf["path"])
def plotRestoreRowCount(self, result, plotPath):
"""Plots the restoreRowCount for each node"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Restore Row Count for Each Node"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Restore Row Count"
conf["data"] = result.restoreRowCount
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/restoreRowCount.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotRestoreColumnCount(self, result, plotPath):
"""Plots the restoreColumnCount for each node"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Restore Column Count for Each Node"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Restore Column Count"
conf["data"] = result.restoreColumnCount
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/restoreColumnCount.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotSampleRecv(self, result, plotPath):
"""Plots the percentage sampleRecv for each node"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Percentage of Samples Received by Nodes"
conf["type"] = "individual_bar_with_2line"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Percentage of samples received (%)"
total_samples = result.shape.nbCols * result.shape.nbRows
percentage_data = [(count / total_samples) * 100 for count in result.sampleRecvCount]
conf["data"] = percentage_data
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/sampleRecv.png"
maxi = max(conf["data"])
# conf["yaxismax"] = maxi * 1.1
expected_percentage1 = (result.shape.vpn1 * (result.shape.nbCols * result.shape.custodyRows + result.shape.nbRows * result.shape.custodyCols) * 100)/total_samples
expected_percentage2 = (result.shape.vpn2 * (result.shape.nbCols * result.shape.custodyRows + result.shape.nbRows * result.shape.custodyCols) * 100)/total_samples
if expected_percentage1 > 100:
expected_percentage1 = 100
if expected_percentage2 > 100:
expected_percentage2 = 100
conf["expected_value1"] = expected_percentage1
conf["expected_value2"] = expected_percentage2
conf["line_label1"] = "Expected Value for class 1 nodes"
conf["line_label2"] = "Expected Value for class 2 nodes"
conf["yaxismax"] = max(expected_percentage1, expected_percentage2) * 1.05
plotData(conf)
print("Plot %s created." % conf["path"])
def plotBoxSampleRecv(self, result, plotPath):
"""Box Plot of the sampleRecv for each node"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Samples Received by Nodes"
conf["type"] = "individual_bar_with_2line"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of samples received (%)"
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [result.sampleRecvCount[1: n1], result.sampleRecvCount[n1+1: ]]
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/box_sampleRecv.png"
plotBoxData(conf)
print("Plot %s created." % conf["path"])
def plotMissingSegments(self, result, plotPath):
"""Plots the missing segments in the network"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)+"\nMissing Segment: "+str(round(min(result.missingVector) * 100 / max(result.missingVector), 3))+"%"\
+"\nMissing Segments: "+str(result.missingVector[-1])
conf["title"] = "Missing Segments"
conf["type"] = "plot_with_1line"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["colors"] = ["m-"]
conf["labels"] = ["Missing Segments"]
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Number of Missing Segments"
conf["data"] = [result.missingVector]
conf["xdots"] = [x*self.config.stepDuration for x in range(len(result.missingVector))]
conf["path"] = plotPath+"/missingSegments.png"
maxi = 0
for v in conf["data"]:
if max(v) > maxi:
maxi = max(v)
conf["yaxismax"] = maxi
x = result.shape.nbCols * result.shape.custodyRows + result.shape.nbRows * result.shape.custodyCols
conf["expected_value"] = (result.shape.numberNodes - 1) * x * sum([(_v['w'] * _v['vpn']) for _v in nodeTypes.values()]) / sum([_v['w'] for _v in nodeTypes.values()])
conf["line_label"] = "Total segments to deliver"
plotData(conf)
print("Plot %s created." % conf["path"])
def plotProgress(self, result, plotPath):
"""Plots the percentage of nodes ready in the network"""
vector1 = [x * 100 for x in result.metrics["progress"]["nodes ready"]]
vector2 = [x * 100 for x in result.metrics["progress"]["validators ready"]]
vector3 = [x * 100 for x in result.metrics["progress"]["samples received"]]
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Nodes/validators ready"
conf["type"] = "plot"
conf["legLoc"] = 2
conf["desLoc"] = 2
conf["colors"] = ["g-", "b-", "r-"]
conf["labels"] = ["Nodes", "Validators", "Samples"]
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Percentage (%)"
conf["data"] = [vector1, vector2, vector3]
conf["xdots"] = [x*self.config.stepDuration for x in range(len(vector1))]
conf["path"] = plotPath+"/nodesReady.png"
conf["yaxismax"] = 100
plotData(conf)
print("Plot %s created." % conf["path"])
def plotSamplesReceived(self, result, plotPath):
"""Plots the min, max, avg percentage of samples recived by nodes"""
samplesReceived = result.metrics["samplesReceived"]
expectedSamples = result.metrics["expectedSamples"]
vector1, vector2, vector3 = [], [], []
for i in range(len(samplesReceived)):
percentages = []
for j in range(1, result.numberNodes):
percentages.append(samplesReceived[i][j - 1] * 100 / expectedSamples[j - 1])
vector1.append(max(percentages))
vector2.append(min(percentages))
vector3.append(sum(percentages) / len(percentages))
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Percentages of Samples Received"
conf["type"] = "plot"
conf["legLoc"] = 2
conf["desLoc"] = 2
conf["colors"] = ["g-", "b-", "r-"]
conf["labels"] = ["Max", "Min", "Average"]
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Percentage (%)"
conf["data"] = [vector1, vector2, vector3]
conf["xdots"] = [x*self.config.stepDuration for x in range(len(vector1))]
conf["path"] = plotPath+"/samplesReceivedPercentages.png"
conf["yaxismax"] = 100
plotData(conf)
print("Plot %s created." % conf["path"])
def plotSentData(self, result, plotPath):
"""Plots the percentage of nodes ready in the network"""
vectors = { 0: result.metrics["progress"]["TX builder mean"] }
for nc in result.shape.nodeClasses:
if nc != 0: vectors[nc] = result.metrics["progress"][f"TX class{nc} mean"]
for _k in vectors.keys():
for i in range(len(list(vectors.values())[0])):
vectors[_k][i] = (vectors[_k][i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Sent data"
conf["type"] = "plot"
conf["legLoc"] = 2
conf["desLoc"] = 2
# conf["colors"] = ["y-", "c-", "m-"]
conf["labels"] = ["Block Builder"]
conf["data"] = [vectors[0]]
for _k, _v in vectors.items():
if _k != 0:
conf["labels"].append(f"Node Class: {_k}")
conf["data"].append(_v)
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Bandwidth (MBits/s)"
conf["xdots"] = [x*self.config.stepDuration for x in range(len(list(vectors.values())[0]))]
conf["path"] = plotPath+"/sentData.png"
maxi = 0
for v in conf["data"]:
if max(v) > maxi:
maxi = max(v)
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotRecvData(self, result, plotPath):
"""Plots the percentage of nodes ready in the network"""
vectors = {}
for nc in result.shape.nodeClasses:
if nc != 0: vectors[nc] = result.metrics["progress"][f"RX class{nc} mean"]
for _k in vectors.keys():
for i in range(len(list(vectors.values())[0])):
vectors[_k][i] = (vectors[_k][i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Received data"
conf["type"] = "plot"
conf["legLoc"] = 2
conf["desLoc"] = 2
# conf["colors"] = ["c-", "m-"]
conf["labels"] = []
conf["data"] = []
for _k, _v in vectors.items():
conf["labels"].append(f"Node Class: {_k}")
conf["data"].append(_v)
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Bandwidth (MBits/s)"
conf["xdots"] = [x*self.config.stepDuration for x in range(len(list(vectors.values())[0]))]
conf["path"] = plotPath+"/recvData.png"
maxi = 0
for v in conf["data"]:
if max(v) > maxi:
maxi = max(v)
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotDupData(self, result, plotPath):
"""Plots the percentage of nodes ready in the network"""
vectors = {}
for nc in result.shape.nodeClasses:
if nc != 0: vectors[nc] = result.metrics["progress"][f"Dup class{nc} mean"]
for _k in vectors.keys():
for i in range(len(list(vectors.values())[0])):
vectors[_k][i] = (vectors[_k][i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Duplicated data"
conf["type"] = "plot"
conf["legLoc"] = 2
conf["desLoc"] = 2
# conf["colors"] = ["c-", "m-"]
conf["labels"] = []
conf["data"] = []
for _k, _v in vectors.items():
conf["labels"].append(f"Node Class: {_k}")
conf["data"].append(_v)
conf["xlabel"] = "Time (ms)"
conf["ylabel"] = "Bandwidth (MBits/s)"
conf["xdots"] = [x*self.config.stepDuration for x in range(len(list(vectors.values())[0]))]
conf["path"] = plotPath+"/dupData.png"
maxi = 0
for v in conf["data"]:
if max(v) > maxi:
maxi = max(v)
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotRowCol(self, result, plotPath):
"""Plots the percentage of nodes ready in the network"""
vector1 = result.metrics["rowDist"]
vector2 = result.metrics["columnDist"]
if len(vector1) > len(vector2):
vector2 += [np.nan] * (len(vector1) - len(vector2))
elif len(vector1) < len(vector2):
vector1 += [np.nan] * (len(vector2) - len(vector1))
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Row/Column distribution"
conf["type"] = "grouped_bar"
conf["legLoc"] = 2
conf["desLoc"] = 2
conf["colors"] = ["r+", "b+"]
conf["labels"] = ["Rows", "Columns"]
conf["xlabel"] = "Row/Column ID"
conf["ylabel"] = "Validators subscribed"
conf["data"] = [vector1, vector2]
conf["xdots"] = range(len(vector1))
conf["path"] = plotPath+"/RowColDist.png"
maxi = 0
for v in conf["data"]:
if np.nanmax(v) > maxi:
maxi = max(v)
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotMessagesSent(self, result, plotPath):
"""Plots the number of messages sent by all nodes"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Sent by Nodes"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Number of Messages Sent"
conf["data"] = result.msgSentCount
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/messagesSent.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotBoxMessagesSent(self, result, plotPath):
"""Box Plot of the number of messages sent by all nodes"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Sent by Nodes"
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Messages Sent"
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [result.msgSentCount[1: n1], result.msgSentCount[n1+1: ]]
conf["path"] = plotPath + "/box_messagesSent.png"
plotBoxData(conf)
print("Plot %s created." % conf["path"])
def plotMessagesRecv(self, result, plotPath):
"""Plots the number of messages received by all nodes"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Received by Nodes"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Number of Messages Received"
conf["data"] = result.msgRecvCount
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/messagesRecv.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotBoxMessagesRecv(self, result, plotPath):
"""Plots the number of messages received by all nodes"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Messages Received by Nodes"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Node Type"
conf["ylabel"] = "Number of Messages Received"
n1 = int(result.numberNodes * result.class1ratio)
conf["data"] = [result.msgRecvCount[1: n1], result.msgRecvCount[n1+1: ]]
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/box_messagesRecv.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotBoxData(conf)
print("Plot %s created." % conf["path"])
def plotSamplesRepaired(self, result, plotPath):
"""Plots the number of samples repaired by all nodes"""
conf = {}
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
conf["textBox"] = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNumber of nodes: "+attrbs['nn']+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"+"\nNetwork degree: "+attrbs['nd']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"+"\n"+nodeTypesTxt\
+"\nSegment Size: "+str(self.config.segmentSize)
conf["title"] = "Number of Samples Repaired by Nodes"
conf["type"] = "individual_bar"
conf["legLoc"] = 1
conf["desLoc"] = 1
conf["xlabel"] = "Nodes"
conf["ylabel"] = "Number of Samples Repaired"
conf["data"] = result.repairedSampleCount
conf["xdots"] = range(result.shape.numberNodes)
conf["path"] = plotPath + "/repairedSampleCount.png"
maxi = max(conf["data"])
conf["yaxismax"] = maxi
plotData(conf)
print("Plot %s created." % conf["path"])
def plotHeatMapData(self, conf):
data = {'x': conf['x'], 'y': conf['y'], 'weights': conf['weights']}
df = pd.DataFrame(data)
pivot_df = df.pivot_table(index='y', columns='x', values='weights', aggfunc="sum")
# Create subplots
fig, (ax_heatmap, ax_textbox) = plt.subplots(1, 2, figsize=(18, 6))
# Plot heatmap
sns.heatmap(pivot_df, annot=True, cmap='viridis', fmt='.0f', ax=ax_heatmap)
ax_heatmap.set_xlabel(conf['xlabel'])
ax_heatmap.set_ylabel(conf['ylabel'])
ax_heatmap.set_title(conf['title'])
# Plot textbox
props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
ax_textbox.text(0.5, 0.5, conf["textBox"], fontsize=14, verticalalignment='center', transform=ax_textbox.transAxes, bbox=props)
ax_textbox.axis('off') # Turn off axis for the textbox subplot
folder = f"results/{self.execID}/heatmaps/{conf['folder']}"
os.makedirs(folder, exist_ok=True)
plt.savefig(f"{folder}/{conf['path']}")
plt.clf()
plt.close()
# Number of simulation runs with the same parameters for statistical relevance
def totalRuns(self):
rs = []
for result in self.results:
attrbs = self.__get_attrbs__(result)
rs.append(int(attrbs['r']))
return max(rs) - min(rs) + 1
# x -> network degree, y -> number of nodes, weights -> simulation duration
def plotNWDegVsNodeOnRuntime(self):
xyS = dict()
for result in self.results:
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
textBox = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nFailure rate: "+attrbs['fr']+"%"+"\nMalicious Node: "+attrbs['mn']+"%"\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"\
+"\n"+nodeTypesTxt
filename = "bsrn_" + attrbs['bsrn'] +\
"_bsrk_" + attrbs['bsrk'] +\
"_bscn_" + attrbs['bscn' ] +\
"_bsck_" + attrbs['bsck'] +\
"_fr_" + attrbs['fr'] +\
"_mn_" + attrbs['mn'] +\
"_cusr_" + attrbs['cusr'] +\
"_cusc_" + attrbs['cusc'] +\
"_ntypes_" + attrbs['ntypes']
identifier = (
attrbs['bsrn'], attrbs['bsrk'], attrbs['bscn'],
attrbs['bsck'], attrbs['fr'], attrbs['mn'],
attrbs['cusr'], attrbs['cusc'], attrbs['ntypes']
)
if identifier in xyS.keys():
xyS[identifier]['x'].append(result.shape.netDegree)
xyS[identifier]['y'].append(result.shape.numberNodes)
xyS[identifier]['w'].append(self.config.stepDuration * (len(result.missingVector) - 1))
else:
xyS[identifier] = {
'x': [result.shape.netDegree],
'y': [result.shape.numberNodes],
'w': [self.config.stepDuration * (len(result.missingVector) - 1)],
'textBox': textBox,
'filename': filename
}
runs = self.totalRuns()
for v in xyS.values():
x = v['x']
y = v['y']
weights = [(w / runs) for w in v['w']]
if len(set(x)) * len(set(y)) < 2: return # Not enough unique params for heatmap
conf = {
'x': x,
'y': y,
'weights': weights,
'xlabel': 'Net Degree',
'ylabel': 'Number of Nodes',
'title': 'Net Degree vs. Number of Nodes on Simulation Runtime (ms)',
'folder': 'NWDegVsNodeOnRuntime',
'textBox': v['textBox'],
'path': f"{v['filename']}.png"
}
self.plotHeatMapData(conf)
# x -> network degree, y -> % of malicious nodes, weights -> no of missing samples
def plotNWDegVsMalNodeOnMissingSamples(self):
xyS = dict()
for result in self.results:
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
textBox = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nFailure rate: "+attrbs['fr']+"%"+"\nNodes: "+attrbs['nn']\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"\
+"\n"+nodeTypesTxt
filename = "bsrn_" + attrbs['bsrn'] +\
"_bsrk_" + attrbs['bsrk'] +\
"_bscn_" + attrbs['bscn' ] +\
"_bsck_" + attrbs['bsck'] +\
"-nn-" + attrbs['nn'] +\
"_fr_" + attrbs['fr'] +\
"_cusr_" + attrbs['cusr'] +\
"_cusc_" + attrbs['cusc'] +\
"_ntypes_" + attrbs['ntypes']
identifier = (
attrbs['bsrn'], attrbs['bsrk'], attrbs['bscn'],
attrbs['bsck'], attrbs['fr'], attrbs['nn'],
attrbs['cusr'], attrbs['cusc'], attrbs['ntypes']
)
if identifier in xyS.keys():
xyS[identifier]['x'].append(result.shape.netDegree)
xyS[identifier]['y'].append(result.shape.maliciousNodes)
xyS[identifier]['w'].append(result.missingVector[-1])
else:
xyS[identifier] = {
'x': [result.shape.netDegree],
'y': [result.shape.maliciousNodes],
'w': [result.missingVector[-1]],
'textBox': textBox,
'filename': filename
}
runs = self.totalRuns()
for v in xyS.values():
x = v['x']
y = v['y']
weights = [(w / runs) for w in v['w']]
if len(set(x)) * len(set(y)) < 2: return # Not enough unique params for heatmap
conf = {
'x': x,
'y': y,
'weights': weights,
'xlabel': 'Net Degree',
'ylabel': 'Malicious Nodes (%)',
'title': 'Net Degree vs Malicious Nodes (%) on Missing Samples',
'folder': 'NWDegVsMalNodeOnMissingSamples',
'textBox': v['textBox'],
'path': f"{v['filename']}.png"
}
self.plotHeatMapData(conf)
# x -> network degree, y -> failure rate, weights -> no of missing samples
def plotNWDegVsFailureRateOnMissingSamples(self):
xyS = dict()
for result in self.results:
attrbs = self.__get_attrbs__(result)
nodeTypes = self.__getNodeTypes__(attrbs['ntypes'])
nodeTypesTxt = ""
for _k, _v in nodeTypes.items():
nodeTypesTxt += f"Type ({_k}): " + str(_v) + "\n"
if nodeTypesTxt != "": nodeTypesTxt = nodeTypesTxt[: -1]
textBox = "Row Size (N, K): "+attrbs['bsrn']+ ", "+attrbs['bsrk']\
+"\nColumn Size: (N, K): "+attrbs['bscn']+ ", "+attrbs['bsck']\
+"\nNodes: "+attrbs['nn']+"\nMalicious Node: "+attrbs['mn']+"%"\
+"\nCustody Rows: "+attrbs['cusr']+" (Min: "+attrbs['mcusr']+")"+"\nCustody Cols: "+attrbs['cusc']+" (Min: "+attrbs['mcusc']+")"\
+"\n"+nodeTypesTxt
filename = "bsrn_" + attrbs['bsrn'] +\
"_bsrk_" + attrbs['bsrk'] +\
"_bscn_" + attrbs['bscn' ] +\
"_bsck_" + attrbs['bsck'] +\
"-nn-" + attrbs['nn'] +\
"_mn_" + attrbs['mn'] +\
"_cusr_" + attrbs['cusr'] +\
"_cusc_" + attrbs['cusc'] +\
"_ntypes_" + attrbs['ntypes']
identifier = (
attrbs['bsrn'], attrbs['bsrk'], attrbs['bscn'],
attrbs['bsck'], attrbs['mn'], attrbs['nn'],
attrbs['cusr'], attrbs['cusc'], attrbs['ntypes']
)
if identifier in xyS.keys():
xyS[identifier]['x'].append(result.shape.netDegree)
xyS[identifier]['y'].append(result.shape.failureRate)
xyS[identifier]['w'].append(result.missingVector[-1])
else:
xyS[identifier] = {
'x': [result.shape.netDegree],
'y': [result.shape.failureRate],
'w': [result.missingVector[-1]],
'textBox': textBox,
'filename': filename
}
runs = self.totalRuns()
for v in xyS.values():
x = v['x']
y = v['y']
weights = [(w / runs) for w in v['w']]
if len(set(x)) * len(set(y)) < 2: return # Not enough unique params for heatmap
conf = {
'x': x,
'y': y,
'weights': weights,
'xlabel': 'Net Degree',
'ylabel': 'Failure Rate (%)',
'title': 'Net Degree vs Failure Rate (%) on Missing Samples',
'folder': 'NWDegVsFailureRateOnMissingSamples',
'textBox': v['textBox'],
'path': f"{v['filename']}.png"
}
self.plotHeatMapData(conf)
def plotAllHeatMaps(self):
self.plotNWDegVsNodeOnRuntime()
self.plotNWDegVsMalNodeOnMissingSamples()
self.plotNWDegVsFailureRateOnMissingSamples()