Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Unified Diff: webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py

Issue 2456373002: Update BWE_TEST_LOGGING_PLOT output format, and fix plot_dynamics.py script. (Closed)
Patch Set: Suppress warnings about unused variable. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py
diff --git a/webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py b/webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py
index 164300141d3917be1482d40f4c0af4dfa43b9adf..dac47626debf72c3761db6ff53ee98cf11fd9d8b 100755
--- a/webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py
+++ b/webrtc/modules/remote_bitrate_estimator/test/plot_dynamics.py
@@ -7,11 +7,15 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
-# This script is used to plot simulation dynamics.
-# Able to plot each flow separately. Other plot boxes can be added,
-# currently one for Throughput, one for Latency and one for Packet Loss.
+# This script is used to plot simulation dynamics. The expected format is
+# PLOT <plot_number> <var_name>:<ssrc>@<alg_name> <time> <value>
+# <var_name> may optionally be followed by #<axis_alignment> but it is
+# deprecated. <plot_number> is also deprecated.
+# Each combination <var_name>:<ssrc>@<alg_name> is stored in it's own time
+# series. The main function defines which time series should be displayed and
+# whether they should should be displayed in the same or separate windows.
+
-import matplotlib
import matplotlib.pyplot as plt
import numpy
import re
@@ -20,144 +24,145 @@ import sys
# Change this to True to save the figure to a file. Look below for details.
save_figure = False
-class Variable(object):
- def __init__(self, variable):
- self._ID = variable[0]
- self._xlabel = variable[1]
- self._ylabel = variable[2]
- self._subplot = variable[3]
- self._y_max = variable[4]
+class ParsePlotLineException(Exception):
+ def __init__(self, reason, line):
+ super(ParsePlotLineException, self).__init__()
+ self.reason = reason
+ self.line = line
+
+
+def parse_plot_line(line):
+ split_line = line.split()
+ if len(split_line) != 5:
+ raise ParsePlotLineException("Expected 5 arguments on line", line)
+ (plot, _, annotated_var, time, value) = split_line
+ if plot != "PLOT":
+ raise ParsePlotLineException("Line does not begin with \"PLOT\\t\"", line)
+ # The variable name can contain any non-whitespace character except "#:@"
+ match = re.match(r'([^\s#:@]+)(?:#\d)?:(\d+)@(\S+)', annotated_var)
+
+ if match == None:
+ raise ParsePlotLineException("Could not parse variable name, ssrc and \
+ algorithm name", annotated_var)
+ var_name = match.group(1)
+ ssrc = match.group(2)
+ alg_name = match.group(3).replace('_', ' ')
+
+ return (var_name, ssrc, alg_name, time, value)
+
+
+def generate_label(var_name, ssrc, ssrc_count, alg_name):
+ label = var_name
+ if ssrc_count > 1 or ssrc != "0":
+ label = label + " flow " + ssrc
+ if alg_name != "-":
+ label = label + " " + alg_name
+ return label
+
+
+class Figure(object):
+ def __init__(self, name):
+ self.name = name
+ self.subplots = []
+
+ def addSubplot(self, var_names, xlabel, ylabel):
+ self.subplots.append(Subplot(var_names, xlabel, ylabel))
+
+ def addSample(self, var_name, ssrc, alg_name, time, value):
+ for s in self.subplots:
+ s.addSample(var_name, ssrc, alg_name, time, value)
+
+ def plotFigure(self, fig):
+ n = len(self.subplots)
+ for i in range(n):
+ ax = fig.add_subplot(n, 1, i+1)
+ self.subplots[i].plotSubplot(ax)
+
+
+class Subplot(object):
+ def __init__(self, var_names, xlabel, ylabel):
+ self.xlabel = xlabel
+ self.ylabel = ylabel
+ self.var_names = var_names
self.samples = dict()
- def getID(self):
- return self._ID
-
- def getXLabel(self):
- return self._xlabel
-
- def getYLabel(self):
- return self._ylabel
-
- def getSubplot(self):
- return self._subplot
-
- def getYMax(self):
- return self._y_max
-
- def getNumberOfFlows(self):
- return len(self.samples)
-
-
- def addSample(self, line):
- groups = re.search(r'_(((\d)+((,(\d)+)*))_(\D+))#\d:(\d)@(\S+)', line)
-
- # Each variable will be plotted in a separated box.
- var_name = groups.group(1)
- alg_name = groups.group(9)
-
- alg_name = alg_name.replace('_', ' ')
+ def addSample(self, var_name, ssrc, alg_name, time, value):
+ if var_name not in self.var_names:
+ return
if alg_name not in self.samples.keys():
self.samples[alg_name] = {}
+ if ssrc not in self.samples[alg_name].keys():
+ self.samples[alg_name][ssrc] = {}
+ if var_name not in self.samples[alg_name][ssrc].keys():
+ self.samples[alg_name][ssrc][var_name] = []
- if var_name not in self.samples[alg_name].keys():
- self.samples[alg_name][var_name] = []
-
- sample = re.search(r'(\d+\.\d+)\t([-]?\d+\.\d+)', line)
-
- s = (sample.group(1), sample.group(2))
- self.samples[alg_name][var_name].append(s)
-
-def plotVar(v, ax, show_legend, show_x_label):
- if show_x_label:
- ax.set_xlabel(v.getXLabel(), fontsize='large')
- ax.set_ylabel(v.getYLabel(), fontsize='large')
+ self.samples[alg_name][ssrc][var_name].append((time, value))
- for alg in v.samples.keys():
+ def plotSubplot(self, ax):
+ ax.set_xlabel(self.xlabel)
+ ax.set_ylabel(self.ylabel)
- for series in v.samples[alg].keys():
+ count = 0
+ for alg_name in self.samples.keys():
+ for ssrc in self.samples[alg_name].keys():
+ for var_name in self.samples[alg_name][ssrc].keys():
+ x = [sample[0] for sample in self.samples[alg_name][ssrc][var_name]]
+ y = [sample[1] for sample in self.samples[alg_name][ssrc][var_name]]
+ x = numpy.array(x)
+ y = numpy.array(y)
- x = [sample[0] for sample in v.samples[alg][series]]
- y = [sample[1] for sample in v.samples[alg][series]]
- x = numpy.array(x)
- y = numpy.array(y)
+ ssrc_count = len(self.samples[alg_name].keys())
+ l = generate_label(var_name, ssrc, ssrc_count, alg_name)
+ plt.plot(x, y, label=l, linewidth=2.0)
+ count += 1
- line = plt.plot(x, y, label=alg, linewidth=4.0)
+ plt.grid(True)
+ if count > 1:
+ plt.legend(loc='best')
- colormap = {'Available0':'#AAAAAA',
- 'Available1':'#AAAAAA',
- 'GCC0':'#80D000',
- 'GCC1':'#008000',
- 'GCC2':'#00F000',
- 'GCC3':'#00B000',
- 'GCC4':'#70B020',
- 'NADA0':'#0000AA',
- 'NADA1':'#A0A0FF',
- 'NADA2':'#0000FF',
- 'NADA3':'#C0A0FF',
- 'NADA4':'#9060B0',}
-
- flow_id = re.search(r'(\d+(,\d+)*)', series) # One or multiple ids.
- key = alg + flow_id.group(1)
-
- if key in colormap:
- plt.setp(line, color=colormap[key])
- elif alg == 'TCP':
- plt.setp(line, color='#AAAAAA')
- else:
- plt.setp(line, color='#654321')
-
- if alg.startswith('Available'):
- plt.setp(line, linestyle='--')
- plt.grid(True)
-
- # x1, x2, y1, y2
- _, x2, _, y2 = plt.axis()
- if v.getYMax() >= 0:
- y2 = v.getYMax()
- plt.axis((0, x2, 0, y2))
-
- if show_legend:
- plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.40),
- shadow=True, fontsize='large', ncol=len(v.samples))
def main():
- variables = [
- ('Throughput_kbps', "Time (s)", "Throughput (kbps)", 1, 4000),
- ('Delay_ms', "Time (s)", "One-way Delay (ms)", 2, 500),
- ('Packet_Loss', "Time (s)", "Packet Loss Ratio", 3, 1.0),
- ]
-
- var = []
-
- # Create objects.
- for variable in variables:
- var.append(Variable(variable))
-
- # Add samples to the objects.
+ receiver = Figure("PacketReceiver")
+ receiver.addSubplot(['Throughput_kbps', 'MaxThroughput_', 'Capacity_kbps',
+ 'PerFlowCapacity_kbps', 'MetricRecorderThroughput_kbps'],
+ "Time (s)", "Throughput (kbps)")
+ receiver.addSubplot(['Delay_ms_', 'Delay_ms'], "Time (s)",
+ "One-way delay (ms)")
+ receiver.addSubplot(['Packet_Loss_'], "Time (s)", "Packet Loss Ratio")
+
+ kalman_state = Figure("KalmanState")
+ kalman_state.addSubplot(['kc', 'km'], "Time (s)", "Kalman gain")
+ kalman_state.addSubplot(['slope_1/bps'], "Time (s)", "Slope")
+ kalman_state.addSubplot(['var_noise'], "Time (s)", "Var noise")
+
+ detector_state = Figure("DetectorState")
+ detector_state.addSubplot(['offset_ms'], "Time (s)", "Offset")
+ detector_state.addSubplot(['gamma_ms'], "Time (s)", "Gamma")
+
+ # Select which figures to plot here.
+ figures = [receiver, detector_state]
+
+ # Add samples to the figures.
for line in sys.stdin:
if line.startswith("[ RUN ]"):
test_name = re.search(r'\.(\w+)', line).group(1)
if line.startswith("PLOT"):
- for v in var:
- if v.getID() in line:
- v.addSample(line)
-
- matplotlib.rcParams.update({'font.size': 48/len(variables)})
-
- # Plot variables.
- fig = plt.figure()
-
- # Offest and threshold on the same plot.
- n = var[-1].getSubplot()
- i = 0
- for v in var:
- ax = fig.add_subplot(n, 1, v.getSubplot())
- plotVar(v, ax, i == 0, i == n - 1)
- i += 1
-
- if save_figure:
- fig.savefig(test_name + ".png")
+ try:
+ (var_name, ssrc, alg_name, time, value) = parse_plot_line(line)
+ for f in figures:
+ # The sample will be ignored bv the figures that don't need it.
+ f.addSample(var_name, ssrc, alg_name, time, value)
+ except ParsePlotLineException as e:
+ print e.reason
+ print e.line
+
+ # Plot figures.
+ for f in figures:
+ fig = plt.figure(f.name)
+ f.plotFigure(fig)
+ if save_figure:
+ fig.savefig(test_name + f.name + ".png")
plt.show()
if __name__ == '__main__':

Powered by Google App Engine
This is Rietveld 408576698