From d01be7002e989a7f86ba8b1abbdd8b2d56efc662 Mon Sep 17 00:00:00 2001
From: Britta Heymann <britta_hey@web.de>
Date: Thu, 5 Oct 2017 10:08:35 +0200
Subject: [PATCH] Refactor evaluation scripts

into multiple methods s.t. they can be combined in different ways.
---
 toolkit/reportSummary/broadcastAnalysis.py    | 56 +++++++++----------
 .../delayDistributionAnalysis.py              | 52 +++++++++++------
 toolkit/reportSummary/multicastAnalysis.py    | 46 +++++++--------
 .../reportSummary/privateMessageAnalysis.py   | 18 ++++--
 4 files changed, 102 insertions(+), 70 deletions(-)

diff --git a/toolkit/reportSummary/broadcastAnalysis.py b/toolkit/reportSummary/broadcastAnalysis.py
index bc616e59..07759e99 100644
--- a/toolkit/reportSummary/broadcastAnalysis.py
+++ b/toolkit/reportSummary/broadcastAnalysis.py
@@ -30,6 +30,29 @@ def findLinesConcerningPriority(all_lines, priority):
     nextPriorityLine = findNextLineContaining(all_lines, correctPriorityLine + 1, "prio")
     return all_lines[correctPriorityLine:nextPriorityLine]
 
+def parseBroadcastAnalysis(filename, priority):
+    """Parses a broadcast analysis file for the specified priority and returns (in that order) the time points, the
+    average number of reached people, and the minimum number of reached people.
+    """
+    # Read broadcast analysis from file
+    with open(filename) as analysis_file:
+        analysis = analysis_file.readlines()
+    relevantLines = findLinesConcerningPriority(analysis, priority)
+
+    # Interpret lines to find minimum and average number of reached people over time
+    timePoints = []
+    minimum = []
+    average = []
+    for line in relevantLines:
+        match = re.match("(\d+)\s+(\d+.\d+)\s+(\d+)", line)
+        if match is None:
+            continue
+        timePoints.append(float(match.group(1)) / 60)
+        average.append(float(match.group(2)))
+        minimum.append(int(match.group(3)))
+
+    return timePoints, average, minimum
+
 # Draws two functions over the same x values.
 # Labels are selected as appropriate for broadcast analysis.
 def drawPlots(x, y_minimum, y_average, priority):
@@ -45,40 +68,17 @@ def drawPlots(x, y_minimum, y_average, priority):
     axes.set_ylim(ymin = 0)
     axes.xaxis.set_major_locator(ticker.IndexLocator(base=60, offset=-5))
 
-
-def plotAnalysis(lines, priority, figure, plotNumber):
-    # Interpret lines to find minimum and average number of reached people over time
-    timePoints = []
-    minimum = []
-    average = []
-    for line in lines:
-        match = re.match("(\d+)\s+(\d+.\d+)\s+(\d+)", line)
-        if match is None:
-            continue
-        timePoints.append(float(match.group(1)) / 60)
-        average.append(float(match.group(2)))
-        minimum.append(int(match.group(3)))
-
-    # Draw plots.
-    figure.add_subplot(1, 3, plotNumber)
-    drawPlots(timePoints, minimum, average, priority)
-
 # Main function of the script. See script description at the top of the file for further information.
 def main(analysisFileName, graphicFileName):
-    # Read broadcast analysis from file
-    with open(analysisFileName) as analysis_file:
-        analysis = analysis_file.readlines()
-
     # Only look at priorities 2, 5 and 9
-    prio2Analysis = findLinesConcerningPriority(analysis, 2)
-    prio5Analysis = findLinesConcerningPriority(analysis, 5)
-    prio9Analysis = findLinesConcerningPriority(analysis, 9)
+    priorities = [2, 5, 9]
 
     # Draw plots for all those priorities.
     fig = plt.figure(figsize=(16, 4))
-    plotAnalysis(prio2Analysis, 2, fig, 1)
-    plotAnalysis(prio5Analysis, 5, fig, 2)
-    plotAnalysis(prio9Analysis, 9, fig, 3)
+    for idx, priority in enumerate(priorities):
+        timePoints, average, minimum = parseBroadcastAnalysis(analysisFileName, priority)
+        fig.add_subplot(1, 3, idx + 1)
+        drawPlots(timePoints, minimum, average, priority)
 
     # Save to file
     plt.tight_layout()
diff --git a/toolkit/reportSummary/delayDistributionAnalysis.py b/toolkit/reportSummary/delayDistributionAnalysis.py
index 035ea834..df68989a 100644
--- a/toolkit/reportSummary/delayDistributionAnalysis.py
+++ b/toolkit/reportSummary/delayDistributionAnalysis.py
@@ -29,10 +29,13 @@ from readFileUtilities import findNextLineContaining
 messageTypeIntro = "Delay distribution for delivered messages of type {}:"
 priorityIntro = "For priority {}:"
 
-# Main function of the script. See script description at the top of the file for further information.
-def main(analysisFileName, messageType, messagePrio, graphicFileName):
+def parseDelayAnalysis(fileName, messageType, messagePrio):
+    """Parses a delay analysis file for information about the provided message type and priority and
+    returns (in that order) the different delay classes (identified by max delay), the percentage of delivered messages
+    delivered in those intervals, and the cumulative percentages.
+    """
     # Read delay analysis from file
-    with open(analysisFileName) as analysis_file:
+    with open(fileName) as analysis_file:
         analysis = analysis_file.readlines()
 
     # Only look at text for correct type
@@ -46,9 +49,9 @@ def main(analysisFileName, messageType, messagePrio, graphicFileName):
     analysis = analysis[correctPriorityLine:nextPriorityLine]
 
     # Find data both for bar chart and cumulative chart
-    bins = []
-    vals = []
-    cumulative = {}
+    delayClasses = []
+    percentageDelivered = []
+    cumulativePercentages = {}
     sumOfPercentages = 0
     for line in analysis:
         match = re.match(".*<\s*(\d+):\s*(\d+.\d+)%", line)
@@ -56,23 +59,25 @@ def main(analysisFileName, messageType, messagePrio, graphicFileName):
             continue
         maxDelay = int(match.group(1)) / 60
         percentage = float(match.group(2))
-        bins.append(maxDelay)
-        vals.append(percentage)
+        delayClasses.append(maxDelay)
+        percentageDelivered.append(percentage)
         sumOfPercentages += percentage
-        cumulative[maxDelay] = sumOfPercentages
+        cumulativePercentages[maxDelay] = sumOfPercentages
 
-    # Plot bar chart
-    plt.subplot(2,1,1)
-    plt.title('Delay distribution of delivered {} messages\nPriority {}'.format(messageType, messagePrio))
-    plt.bar(bins, vals)
+    return delayClasses, percentageDelivered, cumulativePercentages
+
+def plotDelayDistribution(title, delayClasses, percentageDelivered):
+    """Plots a delay distribution as a bar chart."""
+    plt.title(title)
+    plt.bar(delayClasses, percentageDelivered)
     plt.ylabel('Percentage of messages')
     plt.grid(True)
     axes = plt.gca()
     axes.set_xlim(xmin = 0)
 
-    # Directly below, plot cumulative chart
-    plt.subplot(2,1,2)
-    plt.plot(bins, [cumulative[bin] for bin in bins])
+def plotCumulativeDelay(delayClasses, cumulativePercentages):
+    """Plots a cumulative delay chart."""
+    plt.plot(delayClasses, [cumulativePercentages[delayClass] for delayClass in delayClasses])
     plt.xlabel('Delay in minutes')
     plt.ylabel('Cumulative percentage')
     plt.grid(True)
@@ -80,6 +85,21 @@ def main(analysisFileName, messageType, messagePrio, graphicFileName):
     axes.set_xlim(xmin = 0)
     axes.set_ylim(ymin = 0)
 
+# Main function of the script. See script description at the top of the file for further information.
+def main(analysisFileName, messageType, messagePrio, graphicFileName):
+    delayClasses, percentageDelivered, cumulativePercentages = parseDelayAnalysis(analysisFileName, messageType, messagePrio)
+
+    # Plot bar chart
+    plt.subplot(2,1,1)
+    plotDelayDistribution(
+        title='Delay distribution of delivered {} messages\nPriority {}'.format(messageType, messagePrio),
+        delayClasses=delayClasses,
+        percentageDelivered=percentageDelivered)
+
+    # Directly below, plot cumulative chart
+    plt.subplot(2,1,2)
+    plotCumulativeDelay(delayClasses, cumulativePercentages)
+
     # Save to file
     plt.savefig(graphicFileName, dpi = 300)
     plt.close()
diff --git a/toolkit/reportSummary/multicastAnalysis.py b/toolkit/reportSummary/multicastAnalysis.py
index 3f375019..8e0be53b 100644
--- a/toolkit/reportSummary/multicastAnalysis.py
+++ b/toolkit/reportSummary/multicastAnalysis.py
@@ -15,25 +15,13 @@ import re
 # 600	0.0	0.0164942207497068  0.0 0.01223002342392
 # 900	0.0	0.0340330430435976  0.0 0.024223002342392
 
-# Draws two functions over the same x values.
-# Labels are selected as appropiate for multicast analysis.
-def drawPlots(x, y_minimum, y_average, y_minForAll, y_avgForAll):
-    plt.title('Multicast delivery rates')
-    plt.xlabel('Minutes since message creation')
-    plt.ylabel('Delivery rate')
-    plt.plot(x, y_minimum, '.-', label='Minimum for existent messages')
-    plt.plot(x, y_average, '.-',  label='Average for existent messages')
-    #Currently not plotted as both minima are constantly zero and if the ever get higher it will be more noticably in
-    #the minimum delivery ratio for existent messages, two overlaying graphs make viewers search for the 'missing' one
-    #plt.plot(x, y_minForAll, '.-', label='Minimum for all messages ever created')
-    plt.plot(x, y_avgForAll, '.-',  label='Average for all messages ever created')
-    plt.legend(loc='upper left')
-    plt.grid(True)
-
-# Main function of the script. See script description at the top of the file for further information.
-def main(analysisFileName, graphicFileName):
+def parseMulticastAnalysis(filename):
+    """Parses a multicast analysis file and returns (in that order) the time points, the minimum delivery rates for
+    existing messages, the average delivery rates for existing messages, and the average delivery rates over all
+    messages ever created.
+    """
     # Read multicast analysis from file
-    with open(analysisFileName) as analysis_file:
+    with open(filename) as analysis_file:
         analysis = analysis_file.readlines()
     # Skip first line which only contains explanation.
     analysis = analysis[1:]
@@ -41,7 +29,6 @@ def main(analysisFileName, graphicFileName):
     # Interpret lines to find minimum and average delivery rates over time
     timePoints = []
     minimum = []
-    minimumForAll = []
     average = []
     averageForAll = []
     for line in analysis:
@@ -51,11 +38,26 @@ def main(analysisFileName, graphicFileName):
         timePoints.append(float(match.group(1)) / 60)
         minimum.append(float(match.group(2)))
         average.append(float(match.group(3)))
-        minimumForAll.append(float(match.group(4)))
         averageForAll.append(float(match.group(5)))
 
-    # Draw plots.
-    drawPlots(timePoints, minimum, average, minimumForAll, averageForAll)
+    return timePoints, minimum, average, averageForAll
+
+# Draws two functions over the same x values.
+# Labels are selected as appropiate for multicast analysis.
+def drawPlots(x, y_minimum, y_average, y_avgForAll):
+    plt.title('Multicast delivery rates')
+    plt.xlabel('Minutes since message creation')
+    plt.ylabel('Delivery rate')
+    plt.plot(x, y_minimum, '.-', label='Minimum for existent messages')
+    plt.plot(x, y_average, '.-',  label='Average for existent messages')
+    plt.plot(x, y_avgForAll, '.-',  label='Average for all messages ever created')
+    plt.legend(loc='upper left')
+    plt.grid(True)
+
+# Main function of the script. See script description at the top of the file for further information.
+def main(analysisFileName, graphicFileName):
+    timePoints, minimum, average, averageForAll = parseMulticastAnalysis(analysisFileName)
+    drawPlots(timePoints, minimum, average, averageForAll)
 
     # Save to file
     plt.savefig(graphicFileName)
diff --git a/toolkit/reportSummary/privateMessageAnalysis.py b/toolkit/reportSummary/privateMessageAnalysis.py
index e327f502..21431ee3 100644
--- a/toolkit/reportSummary/privateMessageAnalysis.py
+++ b/toolkit/reportSummary/privateMessageAnalysis.py
@@ -26,16 +26,21 @@ def getValueFromString(string):
         return float(match.group(2))
     return int(match.group(2))
 
-# Main function of the script. See script description at the top of the file for further information.
-def main(analysisFileName, graphicFileName):
-    # Read delivery probability from file
-    with open(analysisFileName) as analysis_file:
+def parseDeliveryProbabilityReport(fileName):
+    """Parses a delivery probability report file and returns (in that order) the number of created messages,
+    the number of delivered messages, and the delivery probability.
+    """
+    with open(fileName) as analysis_file:
         analysis = analysis_file.readlines()
 
     created = getValueFromString(analysis[2])
     delivered = getValueFromString(analysis[3])
     delivery_prob = getValueFromString(analysis[4])
 
+    return created, delivered, delivery_prob
+
+def createDeliveryPieChart(created, delivered, delivery_prob):
+    """Creates a graphical presentation of delivery probability."""
     values=[delivery_prob, 1-delivery_prob]
     labels=["delivered:\n{p:.1f}% ({t})".format(p=delivery_prob*100, t=delivered),
             "not delivered:\n{p:.1f}% ({t})".format(p=(1-delivery_prob)*100, t=(created-delivered))]
@@ -49,6 +54,11 @@ def main(analysisFileName, graphicFileName):
     plt.figtext(0.6, 0.05, 'Total created messages: %d' % created)
     plt.title("Message delivery ratio for one-to-one messages")
 
+# Main function of the script. See script description at the top of the file for further information.
+def main(analysisFileName, graphicFileName):
+    created, delivered, delivery_prob = parseDeliveryProbabilityReport(analysisFileName)
+    createDeliveryPieChart(created, delivered, delivery_prob)
+
     # Save to file
     plt.savefig(graphicFileName)
     plt.close()
-- 
GitLab