Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 # | 3 # |
| 4 # Use of this source code is governed by a BSD-style license | 4 # Use of this source code is governed by a BSD-style license |
| 5 # that can be found in the LICENSE file in the root of the source | 5 # that can be found in the LICENSE file in the root of the source |
| 6 # tree. An additional intellectual property rights grant can be found | 6 # tree. An additional intellectual property rights grant can be found |
| 7 # in the file PATENTS. All contributing project authors may | 7 # in the file PATENTS. All contributing project authors may |
| 8 # be found in the AUTHORS file in the root of the source tree. | 8 # be found in the AUTHORS file in the root of the source tree. |
| 9 | 9 |
| 10 # This script is used to plot simulation dynamics. | 10 # This script is used to plot simulation dynamics. |
| 11 # Able to plot each flow separately. Other plot boxes can be added, | 11 # Able to plot each flow separately. Other plot boxes can be added, |
| 12 # currently one for Throughput, one for Latency and one for Packet Loss. | 12 # currently one for Throughput, one for Latency and one for Packet Loss. |
| 13 | 13 |
| 14 import matplotlib | |
| 15 import matplotlib.pyplot as plt | 14 import matplotlib.pyplot as plt |
| 16 import numpy | 15 import numpy |
| 17 import re | 16 import re |
| 18 import sys | 17 import sys |
| 19 | 18 |
| 20 # Change this to True to save the figure to a file. Look below for details. | 19 # Change this to True to save the figure to a file. Look below for details. |
| 21 save_figure = False | 20 save_figure = False |
| 22 | 21 |
| 23 class Variable(object): | 22 class ParsePlotLineException(Exception): |
| 24 def __init__(self, variable): | 23 def __init__(self, reason, line): |
| 25 self._ID = variable[0] | 24 super(ParsePlotLineException, self).__init__() |
| 26 self._xlabel = variable[1] | 25 self.reason = reason |
| 27 self._ylabel = variable[2] | 26 self.line = line |
| 28 self._subplot = variable[3] | 27 |
| 29 self._y_max = variable[4] | 28 def parse_plot_line(line): |
| 29 split_line = line.split() | |
| 30 if len(split_line) != 5: | |
| 31 raise ParsePlotLineException("Expected 5 aegumesnts on line", line) | |
|
Gaetano Carlucci
2016/10/31 12:10:58
aegumesnts -> arguments
terelius
2016/11/02 09:37:16
Done.
| |
| 32 (plot, _, annotated_var, time, value) = split_line | |
| 33 if plot != "PLOT": | |
| 34 raise ParsePlotLineException("Line does not begin with \"PLOT\\t\"", line) | |
| 35 # The variable name can contain any non-whitespace character except "#:@" | |
| 36 match = re.match(r'([^\s#:@]+)(?:#\d)?:(\d+)@(\S+)', annotated_var) | |
| 37 if match == None: | |
| 38 raise ParsePlotLineException("Could not parse variable name, ssrc and \ | |
| 39 algorithm name", annotated_var) | |
| 40 | |
| 41 var_name = match.group(1) | |
| 42 ssrc = match.group(2) | |
| 43 alg_name = match.group(3).replace('_', ' ') | |
| 44 | |
| 45 return (var_name, ssrc, alg_name, time, value) | |
| 46 | |
| 47 | |
| 48 class Figure(object): | |
| 49 def __init__(self, name): | |
| 50 self.name = name | |
| 51 self.subplots = [] | |
| 52 | |
| 53 def addSubplot(self, xlabel, ylabel, var_names): | |
| 54 self.subplots.append(Subplot(xlabel, ylabel, var_names)) | |
| 55 | |
| 56 def addSample(self, var_name, ssrc, alg_name, time, value): | |
| 57 for s in self.subplots: | |
| 58 s.addSample(var_name, ssrc, alg_name, time, value) | |
| 59 | |
| 60 def plotFigure(self, fig): | |
| 61 n = len(self.subplots) | |
| 62 for i in range(n): | |
| 63 ax = fig.add_subplot(n, 1, i+1) | |
| 64 self.subplots[i].plotSubplot(ax) | |
| 65 | |
| 66 | |
| 67 class Subplot(object): | |
| 68 def __init__(self, xlabel, ylabel, var_names): | |
| 69 self.xlabel = xlabel | |
| 70 self.ylabel = ylabel | |
| 71 self.var_names = var_names | |
| 30 self.samples = dict() | 72 self.samples = dict() |
| 31 | 73 |
| 32 def getID(self): | 74 def addSample(self, var_name, ssrc, alg_name, time, value): |
| 33 return self._ID | 75 if var_name not in self.var_names: |
| 34 | 76 return |
| 35 def getXLabel(self): | |
| 36 return self._xlabel | |
| 37 | |
| 38 def getYLabel(self): | |
| 39 return self._ylabel | |
| 40 | |
| 41 def getSubplot(self): | |
| 42 return self._subplot | |
| 43 | |
| 44 def getYMax(self): | |
| 45 return self._y_max | |
| 46 | |
| 47 def getNumberOfFlows(self): | |
| 48 return len(self.samples) | |
| 49 | |
| 50 | |
| 51 def addSample(self, line): | |
| 52 groups = re.search(r'_(((\d)+((,(\d)+)*))_(\D+))#\d:(\d)@(\S+)', line) | |
| 53 | |
| 54 # Each variable will be plotted in a separated box. | |
| 55 var_name = groups.group(1) | |
| 56 alg_name = groups.group(9) | |
| 57 | |
| 58 alg_name = alg_name.replace('_', ' ') | |
| 59 | 77 |
| 60 if alg_name not in self.samples.keys(): | 78 if alg_name not in self.samples.keys(): |
| 61 self.samples[alg_name] = {} | 79 self.samples[alg_name] = {} |
| 62 | 80 |
| 63 if var_name not in self.samples[alg_name].keys(): | 81 if ssrc not in self.samples[alg_name].keys(): |
| 64 self.samples[alg_name][var_name] = [] | 82 self.samples[alg_name][ssrc] = {} |
| 65 | 83 |
| 66 sample = re.search(r'(\d+\.\d+)\t([-]?\d+\.\d+)', line) | 84 if var_name not in self.samples[alg_name][ssrc].keys(): |
| 85 self.samples[alg_name][ssrc][var_name] = [] | |
| 67 | 86 |
| 68 s = (sample.group(1), sample.group(2)) | 87 self.samples[alg_name][ssrc][var_name].append((time, value)) |
| 69 self.samples[alg_name][var_name].append(s) | |
| 70 | 88 |
| 71 def plotVar(v, ax, show_legend, show_x_label): | 89 def plotSubplot(self, ax): |
| 72 if show_x_label: | 90 ax.set_xlabel(self.xlabel) |
| 73 ax.set_xlabel(v.getXLabel(), fontsize='large') | 91 ax.set_ylabel(self.ylabel) |
| 74 ax.set_ylabel(v.getYLabel(), fontsize='large') | |
| 75 | 92 |
| 76 for alg in v.samples.keys(): | 93 for alg_name in self.samples.keys(): |
| 94 for ssrc in self.samples[alg_name].keys(): | |
| 95 for var_name in self.samples[alg_name][ssrc].keys(): | |
| 96 x = [sample[0] for sample in self.samples[alg_name][ssrc][var_name]] | |
| 97 y = [sample[1] for sample in self.samples[alg_name][ssrc][var_name]] | |
| 98 x = numpy.array(x) | |
| 99 y = numpy.array(y) | |
| 77 | 100 |
| 78 for series in v.samples[alg].keys(): | 101 plt.plot(x, y, label=var_name, linewidth=2.0) |
| 102 plt.grid(True) | |
| 79 | 103 |
| 80 x = [sample[0] for sample in v.samples[alg][series]] | 104 plt.legend(loc='best', shadow=True, ncol=len(self.samples)) |
| 81 y = [sample[1] for sample in v.samples[alg][series]] | |
| 82 x = numpy.array(x) | |
| 83 y = numpy.array(y) | |
| 84 | 105 |
| 85 line = plt.plot(x, y, label=alg, linewidth=4.0) | |
| 86 | |
| 87 colormap = {'Available0':'#AAAAAA', | |
| 88 'Available1':'#AAAAAA', | |
| 89 'GCC0':'#80D000', | |
| 90 'GCC1':'#008000', | |
| 91 'GCC2':'#00F000', | |
| 92 'GCC3':'#00B000', | |
| 93 'GCC4':'#70B020', | |
| 94 'NADA0':'#0000AA', | |
| 95 'NADA1':'#A0A0FF', | |
| 96 'NADA2':'#0000FF', | |
| 97 'NADA3':'#C0A0FF', | |
| 98 'NADA4':'#9060B0',} | |
| 99 | |
| 100 flow_id = re.search(r'(\d+(,\d+)*)', series) # One or multiple ids. | |
| 101 key = alg + flow_id.group(1) | |
| 102 | |
| 103 if key in colormap: | |
| 104 plt.setp(line, color=colormap[key]) | |
| 105 elif alg == 'TCP': | |
| 106 plt.setp(line, color='#AAAAAA') | |
| 107 else: | |
| 108 plt.setp(line, color='#654321') | |
| 109 | |
| 110 if alg.startswith('Available'): | |
| 111 plt.setp(line, linestyle='--') | |
| 112 plt.grid(True) | |
| 113 | |
| 114 # x1, x2, y1, y2 | |
| 115 _, x2, _, y2 = plt.axis() | |
| 116 if v.getYMax() >= 0: | |
| 117 y2 = v.getYMax() | |
| 118 plt.axis((0, x2, 0, y2)) | |
| 119 | |
| 120 if show_legend: | |
| 121 plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.40), | |
| 122 shadow=True, fontsize='large', ncol=len(v.samples)) | |
| 123 | 106 |
| 124 def main(): | 107 def main(): |
| 125 variables = [ | 108 receiver = Figure("PacketReceiver") |
| 126 ('Throughput_kbps', "Time (s)", "Throughput (kbps)", 1, 4000), | 109 receiver.addSubplot("Time (s)", "Throughput (kbps)", ['Throughput_kbps']) |
| 127 ('Delay_ms', "Time (s)", "One-way Delay (ms)", 2, 500), | 110 receiver.addSubplot("Time (s)", "One-way Delay (ms)", ['Delay_ms']) |
|
Gaetano Carlucci
2016/10/31 12:10:58
Delay_ms -> Delay_ms_
It seems that an extra _ is
terelius
2016/11/02 09:37:16
There are actually two variables, one with undersc
| |
| 128 ('Packet_Loss', "Time (s)", "Packet Loss Ratio", 3, 1.0), | 111 receiver.addSubplot("Time (s)", "Packet Loss Ratio", ['Packet_Loss']) |
|
Gaetano Carlucci
2016/10/31 12:10:58
Packet_Loss -> Packet_Loss_
terelius
2016/11/02 09:37:16
Done.
| |
| 129 ] | |
| 130 | 112 |
| 131 var = [] | 113 kalman_state = Figure("KalmanState") |
| 114 kalman_state.addSubplot("Time (s)", "", ['kc', 'km']) | |
| 115 kalman_state.addSubplot("Time (s)", "Slope", ['slope_1/bps']) | |
| 116 kalman_state.addSubplot("Time (s)", "Var noise", ['var_noise']) | |
| 132 | 117 |
| 133 # Create objects. | 118 detector_state = Figure("DetectorState") |
| 134 for variable in variables: | 119 detector_state.addSubplot("Time (s)", "Offset", ['offset_ms']) |
| 135 var.append(Variable(variable)) | 120 detector_state.addSubplot("Time (s)", "Gamma", ['gamma_ms']) |
| 136 | 121 |
| 137 # Add samples to the objects. | 122 # Select which figures to plot here. |
| 123 figures = [receiver, detector_state] | |
| 124 | |
| 125 # Add samples to the figures. | |
| 138 for line in sys.stdin: | 126 for line in sys.stdin: |
| 139 if line.startswith("[ RUN ]"): | 127 if line.startswith("[ RUN ]"): |
| 140 test_name = re.search(r'\.(\w+)', line).group(1) | 128 test_name = re.search(r'\.(\w+)', line).group(1) |
| 141 if line.startswith("PLOT"): | 129 if line.startswith("PLOT"): |
| 142 for v in var: | 130 try: |
| 143 if v.getID() in line: | 131 (var_name, ssrc, alg_name, time, value) = parse_plot_line(line) |
| 144 v.addSample(line) | 132 for f in figures: |
| 145 | 133 # The sample will be ignored bv the figures that don't need it. |
| 146 matplotlib.rcParams.update({'font.size': 48/len(variables)}) | 134 f.addSample(var_name, ssrc, alg_name, time, value) |
| 135 except ParsePlotLineException as e: | |
| 136 print e.reason | |
| 137 print e.line | |
| 147 | 138 |
| 148 # Plot variables. | 139 # Plot variables. |
| 149 fig = plt.figure() | 140 for f in figures: |
| 150 | 141 fig = plt.figure(f.name) |
| 151 # Offest and threshold on the same plot. | 142 f.plotFigure(fig) |
| 152 n = var[-1].getSubplot() | 143 if save_figure: |
| 153 i = 0 | 144 fig.savefig(test_name + f.name + ".png") |
| 154 for v in var: | |
| 155 ax = fig.add_subplot(n, 1, v.getSubplot()) | |
| 156 plotVar(v, ax, i == 0, i == n - 1) | |
| 157 i += 1 | |
| 158 | |
| 159 if save_figure: | |
| 160 fig.savefig(test_name + ".png") | |
| 161 plt.show() | 145 plt.show() |
| 162 | 146 |
| 163 if __name__ == '__main__': | 147 if __name__ == '__main__': |
| 164 main() | 148 main() |
| OLD | NEW |