2023-02-22 16:45:39 +01:00
#!/bin/python3
2023-02-23 14:37:45 +01:00
import os , sys
import time
import xml . etree . ElementTree as ET
import matplotlib . pyplot as plt
import numpy as np
import seaborn as sns
from itertools import combinations
2023-04-21 09:45:17 +00:00
from mplfinance . original_flavor import candlestick_ohlc
2023-02-22 16:45:39 +01:00
class Visualizer :
2023-04-20 18:15:02 +02:00
def __init__ ( self , execID , config ) :
2023-02-22 16:45:39 +01:00
self . execID = execID
2023-04-20 18:15:02 +02:00
self . config = config
2023-02-22 16:45:39 +01:00
self . folderPath = " results/ " + self . execID
2023-03-30 11:24:30 +00:00
self . parameters = [ ' run ' , ' blockSize ' , ' failureRate ' , ' numberNodes ' , ' netDegree ' , ' chi ' , ' vpn1 ' , ' vpn2 ' , ' class1ratio ' , ' bwUplinkProd ' , ' bwUplink1 ' , ' bwUplink2 ' ]
2023-02-26 18:36:02 +01:00
self . minimumDataPoints = 2
2023-04-21 17:14:55 +02:00
self . maxTTA = 99
2023-02-22 16:45:39 +01:00
def plottingData ( self ) :
2023-03-22 23:17:19 +00:00
""" Store data with a unique key for each params combination """
2023-02-23 14:37:45 +01:00
data = { }
2023-03-30 11:24:30 +00:00
bw = [ ]
2023-04-21 17:14:55 +02:00
print ( " Getting data from the folder... " )
2023-03-22 23:17:19 +00:00
""" Loop over the xml files in the folder """
2023-02-23 14:37:45 +01:00
for filename in os . listdir ( self . folderPath ) :
2023-03-22 23:17:19 +00:00
""" Loop over the xmls and store the data in variables """
2023-02-23 14:37:45 +01:00
if filename . endswith ( ' .xml ' ) :
tree = ET . parse ( os . path . join ( self . folderPath , filename ) )
root = tree . getroot ( )
run = int ( root . find ( ' run ' ) . text )
blockSize = int ( root . find ( ' blockSize ' ) . text )
failureRate = int ( root . find ( ' failureRate ' ) . text )
2023-03-13 15:03:55 +01:00
numberNodes = int ( root . find ( ' numberNodes ' ) . text )
2023-03-30 11:24:30 +00:00
class1ratio = float ( root . find ( ' class1ratio ' ) . text )
2023-02-23 14:37:45 +01:00
netDegree = int ( root . find ( ' netDegree ' ) . text )
chi = int ( root . find ( ' chi ' ) . text )
2023-03-13 15:00:43 +01:00
vpn1 = int ( root . find ( ' vpn1 ' ) . text )
vpn2 = int ( root . find ( ' vpn2 ' ) . text )
2023-03-07 14:36:13 +01:00
bwUplinkProd = int ( root . find ( ' bwUplinkProd ' ) . text )
bwUplink1 = int ( root . find ( ' bwUplink1 ' ) . text )
bwUplink2 = int ( root . find ( ' bwUplink2 ' ) . text )
2023-02-23 14:37:45 +01:00
tta = int ( root . find ( ' tta ' ) . text )
2023-04-21 17:14:55 +02:00
if tta == - 1 :
tta = self . maxTTA
2023-03-30 11:24:30 +00:00
""" Store BW """
bw . append ( bwUplinkProd )
""" Loop over all possible combinations of length of the parameters minus x, y params """
2023-03-21 10:41:52 +01:00
for combination in combinations ( self . parameters , len ( self . parameters ) - 2 ) :
2023-02-23 14:37:45 +01:00
# Get the indices and values of the parameters in the combination
2023-03-26 13:01:07 +00:00
2023-02-23 14:37:45 +01:00
indices = [ self . parameters . index ( element ) for element in combination ]
2023-03-30 11:24:30 +00:00
selectedValues = [ run , blockSize , failureRate , numberNodes , netDegree , chi , vpn1 , vpn2 , class1ratio , bwUplinkProd , bwUplink1 , bwUplink2 ]
2023-02-23 14:37:45 +01:00
values = [ selectedValues [ index ] for index in indices ]
names = [ self . parameters [ i ] for i in indices ]
keyComponents = [ f " { name } _ { value } " for name , value in zip ( names , values ) ]
2023-03-21 10:41:52 +01:00
key = tuple ( keyComponents [ : len ( self . parameters ) - 2 ] )
2023-03-30 11:24:30 +00:00
""" Get the names of the other parameters that are not included in the key """
2023-03-07 14:36:13 +01:00
otherParams = [ self . parameters [ i ] for i in range ( len ( self . parameters ) ) if i not in indices ]
2023-03-30 11:24:30 +00:00
""" Append the values of the other parameters and the ttas to the lists for the key """
2023-02-23 14:37:45 +01:00
otherIndices = [ i for i in range ( len ( self . parameters ) ) if i not in indices ]
2023-03-22 23:17:19 +00:00
""" Initialize the dictionary for the key if it doesn ' t exist yet """
2023-02-23 14:37:45 +01:00
if key not in data :
data [ key ] = { }
2023-03-30 11:24:30 +00:00
""" Initialize lists for the other parameters and the ttas with the key """
2023-02-23 14:37:45 +01:00
data [ key ] [ otherParams [ 0 ] ] = [ ]
data [ key ] [ otherParams [ 1 ] ] = [ ]
data [ key ] [ ' ttas ' ] = [ ]
if otherParams [ 0 ] in data [ key ] :
data [ key ] [ otherParams [ 0 ] ] . append ( selectedValues [ otherIndices [ 0 ] ] )
else :
data [ key ] [ otherParams [ 0 ] ] = [ selectedValues [ otherIndices [ 0 ] ] ]
if otherParams [ 1 ] in data [ key ] :
data [ key ] [ otherParams [ 1 ] ] . append ( selectedValues [ otherIndices [ 1 ] ] )
else :
data [ key ] [ otherParams [ 1 ] ] = [ selectedValues [ otherIndices [ 1 ] ] ]
data [ key ] [ ' ttas ' ] . append ( tta )
2023-02-22 16:45:39 +01:00
return data
2023-04-20 18:15:02 +02:00
2023-03-30 11:24:30 +00:00
def averageRuns ( self , data , runs ) :
2023-04-21 09:45:17 +00:00
""" Get the average of all runs for each key """
2023-03-22 23:17:19 +00:00
newData = { }
2023-04-20 21:53:25 +02:00
allTta = [ ]
print ( " Getting the average of the runs... " )
2023-03-22 23:17:19 +00:00
for key , value in data . items ( ) :
runExists = False
""" Check if the key contains ' run_ ' with a numerical value """
for item in key :
2023-03-30 11:24:30 +00:00
if item . startswith ( ' run_ ' ) :
2023-03-22 23:17:19 +00:00
runExists = True
break
if runExists :
for item in key :
""" Create a new key with the other items in the tuple """
if item . startswith ( ' run_ ' ) :
newKey = tuple ( [ x for x in key if x != item ] )
2023-03-30 11:24:30 +00:00
""" Average the similar key values """
total = [ 0 ] * len ( data [ key ] [ ' ttas ' ] )
for i in range ( runs ) :
key0 = ( f ' run_ { i } ' , ) + newKey
for cnt , tta in enumerate ( data [ key0 ] [ ' ttas ' ] ) :
total [ cnt ] + = tta
2023-04-20 21:53:25 +02:00
allTta . append ( tta )
2023-03-30 11:24:30 +00:00
for i in range ( len ( total ) ) :
total [ i ] = total [ i ] / runs
2023-03-22 23:17:19 +00:00
averages = { }
2023-03-30 11:24:30 +00:00
for subkey in data [ key ] . keys ( ) :
if subkey == ' ttas ' :
averages [ subkey ] = total
else :
averages [ subkey ] = data [ key ] [ subkey ]
2023-03-22 23:17:19 +00:00
newData [ newKey ] = averages
return newData
2023-02-22 16:45:39 +01:00
def similarKeys ( self , data ) :
2023-03-22 23:17:19 +00:00
""" Get the keys for all data with the same x and y labels """
2023-02-23 14:37:45 +01:00
filteredKeys = { }
for key1 , value1 in data . items ( ) :
subKeys1 = list ( value1 . keys ( ) )
filteredKeys [ ( subKeys1 [ 0 ] , subKeys1 [ 1 ] ) ] = [ key1 ]
for key2 , value2 in data . items ( ) :
subKeys2 = list ( value2 . keys ( ) )
if key1 != key2 and subKeys1 [ 0 ] == subKeys2 [ 0 ] and subKeys1 [ 1 ] == subKeys2 [ 1 ] :
try :
filteredKeys [ ( subKeys1 [ 0 ] , subKeys1 [ 1 ] ) ] . append ( key2 )
except KeyError :
filteredKeys [ ( subKeys1 [ 0 ] , subKeys1 [ 1 ] ) ] = [ key2 ]
2023-02-22 16:45:39 +01:00
print ( " Getting filtered keys from data... " )
return filteredKeys
2023-02-26 18:36:02 +01:00
def formatLabel ( self , label ) :
2023-03-22 23:17:19 +00:00
""" Label formatting for the figures """
2023-02-26 18:36:02 +01:00
result = ' ' . join ( [ f " { char } " if char . isupper ( ) else char for char in label ] )
return result . title ( )
2023-03-21 10:41:52 +01:00
2023-02-23 14:37:45 +01:00
def formatTitle ( self , key ) :
2023-03-22 23:17:19 +00:00
""" Title formatting for the figures """
2023-02-23 14:37:45 +01:00
name = ' ' . join ( [ f " { char } " if char . isupper ( ) else char for char in key . split ( ' _ ' ) [ 0 ] ] )
number = key . split ( ' _ ' ) [ 1 ]
return f " { name . title ( ) } : { number } "
2023-02-22 16:45:39 +01:00
def plotHeatmaps ( self ) :
2023-03-22 23:17:19 +00:00
""" Plot and store the 2D heatmaps in subfolders """
2023-03-30 11:24:30 +00:00
data = self . plottingData ( )
""" Average the runs if needed """
2023-04-20 18:15:02 +02:00
if ( len ( self . config . runs ) > 1 ) :
data = self . averageRuns ( data , len ( self . config . runs ) )
2023-02-22 16:45:39 +01:00
filteredKeys = self . similarKeys ( data )
2023-03-30 11:24:30 +00:00
vmin , vmax = 0 , self . maxTTA
2023-02-22 16:45:39 +01:00
print ( " Plotting heatmaps... " )
2023-04-20 18:15:02 +02:00
2023-03-22 23:17:19 +00:00
""" Create the directory if it doesn ' t exist already """
2023-02-23 14:37:45 +01:00
heatmapsFolder = self . folderPath + ' /heatmaps '
if not os . path . exists ( heatmapsFolder ) :
os . makedirs ( heatmapsFolder )
2023-03-22 23:17:19 +00:00
""" Plot """
2023-02-23 14:37:45 +01:00
for labels , keys in filteredKeys . items ( ) :
for key in keys :
xlabels = np . sort ( np . unique ( data [ key ] [ labels [ 0 ] ] ) )
ylabels = np . sort ( np . unique ( data [ key ] [ labels [ 1 ] ] ) )
2023-02-26 18:36:02 +01:00
if len ( xlabels ) < self . minimumDataPoints or len ( ylabels ) < self . minimumDataPoints :
continue
2023-03-30 11:24:30 +00:00
hist , xedges , yedges = np . histogram2d ( data [ key ] [ labels [ 0 ] ] , data [ key ] [ labels [ 1 ] ] , bins = ( len ( xlabels ) , len ( ylabels ) ) , weights = data [ key ] [ ' ttas ' ] , normed = False )
2023-02-23 14:37:45 +01:00
hist = hist . T
fig , ax = plt . subplots ( figsize = ( 10 , 6 ) )
2023-04-21 17:14:55 +02:00
sns . heatmap ( hist , xticklabels = xlabels , yticklabels = ylabels , cmap = ' hot_r ' , cbar_kws = { ' label ' : ' Time to block availability ' } , linecolor = ' black ' , linewidths = 0.3 , annot = True , fmt = " .2f " , ax = ax , vmin = vmin , vmax = vmax )
2023-02-26 18:36:02 +01:00
plt . xlabel ( self . formatLabel ( labels [ 0 ] ) )
plt . ylabel ( self . formatLabel ( labels [ 1 ] ) )
2023-02-23 14:37:45 +01:00
filename = " "
title = " "
paramValueCnt = 0
for param in self . parameters :
2023-03-22 23:17:19 +00:00
if param != labels [ 0 ] and param != labels [ 1 ] and param != ' run ' :
2023-02-23 14:37:45 +01:00
filename + = f " { key [ paramValueCnt ] } "
formattedTitle = self . formatTitle ( key [ paramValueCnt ] )
title + = formattedTitle
paramValueCnt + = 1
title_obj = plt . title ( title )
font_size = 16 * fig . get_size_inches ( ) [ 0 ] / 10
title_obj . set_fontsize ( font_size )
filename = filename + " .png "
targetFolder = os . path . join ( heatmapsFolder , f " { labels [ 0 ] } Vs { labels [ 1 ] } " )
if not os . path . exists ( targetFolder ) :
os . makedirs ( targetFolder )
plt . savefig ( os . path . join ( targetFolder , filename ) )
plt . close ( )
plt . clf ( )
2023-04-20 18:15:02 +02:00
2023-03-30 11:24:30 +00:00
def plotHist ( self , bandwidth ) :
""" Plot Bandwidth Frequency Histogram """
plt . hist ( bandwidth , bins = 5 )
plt . xlabel ( ' Bandwidth ' )
plt . ylabel ( ' Frequency ' )
plt . title ( ' Bandwidth Histogram ' )
""" Create the directory if it doesn ' t exist already """
histogramFolder = self . folderPath + ' /histogram '
if not os . path . exists ( histogramFolder ) :
os . makedirs ( histogramFolder )
filename = os . path . join ( histogramFolder , ' histogram.png ' )
plt . savefig ( filename )
2023-04-20 18:15:02 +02:00
plt . clf ( )
2023-04-21 09:45:17 +00:00
def plotHist ( self , bandwidth ) :
""" Plot Bandwidth Frequency Histogram """
plt . hist ( bandwidth , bins = 5 )
plt . xlabel ( ' Bandwidth ' )
plt . ylabel ( ' Frequency ' )
plt . title ( ' Bandwidth Histogram ' )
""" Create the directory if it doesn ' t exist already """
histogramFolder = self . folderPath + ' /histogram '
if not os . path . exists ( histogramFolder ) :
os . makedirs ( histogramFolder )
filename = os . path . join ( histogramFolder , ' histogram.png ' )
plt . savefig ( filename )
plt . clf ( )
def plotCandleStick ( self , TX_prod , TX_avg , TX_max ) :
#x-axis corresponding to steps
steps = range ( len ( TX_prod ) )
#Plot the candlestick chart
ohlc = [ ]
for i in range ( len ( TX_prod ) ) :
ohlc . append ( [ steps [ i ] , TX_prod [ i ] , TX_max [ i ] , TX_avg [ i ] ] )
fig , ax = plt . subplots ( )
candlestick_ohlc ( ax , ohlc , width = 0.6 , colorup = ' green ' , colordown = ' red ' )
#Ticks, title and labels
plt . xticks ( steps , [ ' run {} ' . format ( i ) for i in steps ] , rotation = 45 )
plt . title ( ' Candlestick Chart ' )
plt . xlabel ( ' Step ' )
plt . ylabel ( ' Price ' )
#Test
2023-04-21 17:14:55 +02:00
plt . show ( )