#!/bin/python3 import matplotlib.pyplot as plt import os def plotData(conf): plt.clf() fig = plt.figure("9, 3") plt.grid(True) if conf["desLoc"] == 1: xDes = 0 else: xDes = conf["xdots"][-1] * 0.6 props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) plt.text(xDes, conf["yaxismax"]/3, conf["textBox"], fontsize=10, verticalalignment='top', bbox=props) if conf["type"] == "plot": for i in range(len(conf["data"])): plt.plot(conf["xdots"], conf["data"][i], conf["colors"][i], label=conf["labels"][i]) elif conf["type"] == "individual_bar": 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]) plt.title(conf["title"]) plt.ylabel(conf["ylabel"]) plt.xlabel(conf["xlabel"]) plt.ylim(0, conf["yaxismax"]*1.1) plt.legend(loc=conf["legLoc"]) 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 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.plotRestoreRowCount(result, plotPath) self.plotRestoreColumnCount(result, plotPath) self.plotMessagesSent(result, plotPath) self.plotMessagesRecv(result, plotPath) self.plotSampleRecv(result, plotPath) self.plotMissingSamples(result, plotPath) self.plotProgress(result, plotPath) self.plotSentData(result, plotPath) self.plotRecvData(result, plotPath) self.plotDupData(result, plotPath) if self.config.saveRCdist: self.plotRowCol(result, plotPath) def plotRestoreRowCount(self, result, plotPath): """Plots the restoreRowCount for each node""" conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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 = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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 = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Percentage of Samples Received by Nodes" conf["type"] = "individual_bar" conf["legLoc"] = 1 conf["desLoc"] = 1 conf["xlabel"] = "Nodes" conf["ylabel"] = "Percentage of samples received (%)" total_samples = result.shape.blockSize * result.shape.blockSize 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 plotData(conf) print("Plot %s created." % conf["path"]) def plotMissingSamples(self, result, plotPath): """Plots the missing samples in the network""" conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Missing Samples" conf["type"] = "plot" conf["legLoc"] = 1 conf["desLoc"] = 1 conf["colors"] = ["m-"] conf["labels"] = ["Missing Samples"] conf["xlabel"] = "Time (ms)" conf["ylabel"] = "Number of Missing Samples" conf["data"] = [result.missingVector] conf["xdots"] = [x*self.config.stepDuration for x in range(len(result.missingVector))] conf["path"] = plotPath+"/missingSamples.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 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 = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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" 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 plotSentData(self, result, plotPath): """Plots the percentage of nodes ready in the network""" vector1 = result.metrics["progress"]["TX builder mean"] vector2 = result.metrics["progress"]["TX class1 mean"] vector3 = result.metrics["progress"]["TX class2 mean"] for i in range(len(vector1)): vector1[i] = (vector1[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 vector3[i] = (vector3[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Sent data" conf["type"] = "plot" conf["legLoc"] = 2 conf["desLoc"] = 2 conf["colors"] = ["y-", "c-", "m-"] conf["labels"] = ["Block Builder", "Solo stakers", "Staking pools"] conf["xlabel"] = "Time (ms)" conf["ylabel"] = "Bandwidth (MBits/s)" conf["data"] = [vector1, vector2, vector3] conf["xdots"] = [x*self.config.stepDuration for x in range(len(vector1))] 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""" vector1 = result.metrics["progress"]["RX class1 mean"] vector2 = result.metrics["progress"]["RX class2 mean"] for i in range(len(vector1)): vector1[i] = (vector1[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Received data" conf["type"] = "plot" conf["legLoc"] = 2 conf["desLoc"] = 2 conf["colors"] = ["c-", "m-"] conf["labels"] = ["Solo stakers", "Staking pools"] conf["xlabel"] = "Time (ms)" conf["ylabel"] = "Bandwidth (MBits/s)" conf["data"] = [vector1, vector2] conf["xdots"] = [x*self.config.stepDuration for x in range(len(vector1))] 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""" vector1 = result.metrics["progress"]["Dup class1 mean"] vector2 = result.metrics["progress"]["Dup class2 mean"] for i in range(len(vector1)): vector1[i] = (vector1[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 vector2[i] = (vector2[i] * 8 * (1000/self.config.stepDuration) * self.config.segmentSize) / 1000000 conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" conf["title"] = "Duplicated data" conf["type"] = "plot" conf["legLoc"] = 2 conf["desLoc"] = 2 conf["colors"] = ["c-", "m-"] conf["labels"] = ["Solo stakers", "Staking pools"] conf["xlabel"] = "Time (ms)" conf["ylabel"] = "Bandwidth (MBits/s)" conf["data"] = [vector1, vector2] conf["xdots"] = [x*self.config.stepDuration for x in range(len(vector1))] 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"] conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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 max(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 = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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 plotMessagesRecv(self, result, plotPath): """Plots the number of messages received by all nodes""" conf = {} text = str(result.shape).split("-") conf["textBox"] = "Block Size: "+text[1]+"\nNumber of nodes: "+text[3]\ +"\nFailure rate: "+text[7]+" \nNetwork degree: "+text[23]+"\nX: "+text[11]+" rows/columns"+"\nMalicious Nodes: "+text[27]+"%" 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"])