Added displaying of configurations at the top of the page.
A table on the top of the page displays the test configurations of the input files present. The displayed string in the legend of each graph is now fetched from test configuration name instead of using the filename. Review URL: http://webrtc-codereview.appspot.com/279006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1104 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
23e1c0a0b1
commit
418bce5ccc
@ -1,7 +1,7 @@
|
||||
# Sample output from the video_quality_measurment program, included only for
|
||||
# reference. Geneate your own by running with the --python flag and then change
|
||||
# the filenames in main.py
|
||||
test_configuration = [{'name': 'name', 'value': 'Quality test'},
|
||||
test_configuration = [{'name': 'name', 'value': 'VP8 hardware test'},
|
||||
{'name': 'description', 'value': ''},
|
||||
{'name': 'test_number', 'value': '0'},
|
||||
{'name': 'input_filename', 'value': 'foreman_cif.yuv'},
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Sample output from the video_quality_measurment program, included only for
|
||||
# reference. Geneate your own by running with the --python flag and then change
|
||||
# the filenames in main.py
|
||||
test_configuration = [{'name': 'name', 'value': 'Quality test'},
|
||||
test_configuration = [{'name': 'name', 'value': 'VP8 software test'},
|
||||
{'name': 'description', 'value': ''},
|
||||
{'name': 'test_number', 'value': '0'},
|
||||
{'name': 'input_filename', 'value': 'foreman_cif.yuv'},
|
||||
|
@ -8,10 +8,10 @@
|
||||
in the file PATENTS. All contributing project authors may
|
||||
be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
Template file to be used to generate Charts for Video Quality Metrics.
|
||||
Template file to be used to generate Charts for Video Quality Metrics.
|
||||
-->
|
||||
<head>
|
||||
<link href="http://code.google.com/css/codesite.pack.04102009.css"
|
||||
<link href="http://code.google.com/css/codesite.pack.04102009.css"
|
||||
rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
<script src="https://www.google.com/jsapi" type="text/javascript"></script>
|
||||
@ -20,7 +20,9 @@
|
||||
|
||||
google.setOnLoadCallback(drawTable);
|
||||
function drawTable() {
|
||||
/* Build data table and views */
|
||||
/* Build data tables and views */
|
||||
var configurations_data_table =
|
||||
new google.visualization.DataTable(%(json_configurations)s);
|
||||
var ssim_data_table =
|
||||
new google.visualization.DataTable(%(json_ssim_data)s);
|
||||
var psnr_data_table =
|
||||
@ -28,47 +30,55 @@
|
||||
var packet_loss_data_table =
|
||||
new google.visualization.DataTable(%(json_packet_loss_data)s);
|
||||
var bit_rate_data_table =
|
||||
new google.visualization.DataTable(%(json_bit_rate_data)s);
|
||||
|
||||
new google.visualization.DataTable(%(json_bit_rate_data)s);
|
||||
|
||||
/* Display tables and charts */
|
||||
var configurations_table = new google.visualization.Table(
|
||||
document.getElementById('table_div_configurations'));
|
||||
configurations_table.draw(configurations_data_table, {
|
||||
height: 200
|
||||
});
|
||||
|
||||
var ssim_chart = new google.visualization.LineChart(
|
||||
document.getElementById('table_div_ssim'));
|
||||
ssim_chart.draw(ssim_data_table, {
|
||||
colors: ['blue', 'orange'],
|
||||
vAxis: {title: 'SSIM'},
|
||||
hAxis: {title: 'Frame'},
|
||||
colors: ['blue', 'red', 'lightblue', 'pink'],
|
||||
vAxis: {title: 'SSIM'},
|
||||
hAxis: {title: 'Frame'},
|
||||
width: 1200, height: 300,
|
||||
});
|
||||
|
||||
|
||||
var psnr_chart = new google.visualization.LineChart(
|
||||
document.getElementById('table_div_psnr'));
|
||||
psnr_chart.draw(psnr_data_table, {
|
||||
colors: ['blue', 'orange'],
|
||||
vAxis: {title: 'PSNR(dB)'},
|
||||
hAxis: {title: 'Frame'},
|
||||
colors: ['blue', 'red', 'lightblue', 'pink'],
|
||||
vAxis: {title: 'PSNR (dB)'},
|
||||
hAxis: {title: 'Frame'},
|
||||
width: 1200, height: 300,
|
||||
});
|
||||
|
||||
|
||||
var packet_loss_chart = new google.visualization.LineChart(
|
||||
document.getElementById('table_div_packet_loss'));
|
||||
packet_loss_chart.draw(packet_loss_data_table, {
|
||||
colors: ['blue', 'orange'],
|
||||
vAxis: {title: 'Packets dropped'},
|
||||
hAxis: {title: 'Frame'},
|
||||
colors: ['blue', 'red', 'lightblue', 'pink'],
|
||||
vAxis: {title: 'Packets dropped'},
|
||||
hAxis: {title: 'Frame'},
|
||||
width: 1200, height: 300,
|
||||
});
|
||||
|
||||
|
||||
var bit_rate_chart = new google.visualization.LineChart(
|
||||
document.getElementById('table_div_bit_rate'));
|
||||
bit_rate_chart.draw(bit_rate_data_table, {
|
||||
colors: ['blue', 'orange', 'red'],
|
||||
vAxis: {title: 'Bit rate'},
|
||||
hAxis: {title: 'Frame'},
|
||||
colors: ['blue', 'red', 'lightblue', 'pink', 'green'],
|
||||
vAxis: {title: 'Bit rate'},
|
||||
hAxis: {title: 'Frame'},
|
||||
width: 1200, height: 300,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<h3>Test Configurations:</h3>
|
||||
<div id="table_div_configurations"></div>
|
||||
<h3>Messages:</h3>
|
||||
<pre>%(messages)s</pre>
|
||||
<h3>Metrics measured per frame:</h3>
|
||||
@ -77,4 +87,4 @@
|
||||
<div id="table_div_packet_loss"></div>
|
||||
<div id="table_div_bit_rate"></div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -107,9 +107,9 @@ class DataHelper(object):
|
||||
self.messages.append("Couldn't find frame data for row %d "
|
||||
"for %s" % (row_number, self.names_list[dataset_index]))
|
||||
break
|
||||
return (result_table_description, result_data_table)
|
||||
return result_table_description, result_data_table
|
||||
|
||||
def GetOrdering(self, table_description):
|
||||
def GetOrdering(self, table_description):
|
||||
""" Creates a list of column names, ordered alphabetically except for the
|
||||
frame_number column which always will be the first column.
|
||||
|
||||
@ -131,4 +131,53 @@ class DataHelper(object):
|
||||
for column in sorted(table_description.keys()):
|
||||
if column != 'frame_number':
|
||||
columns_ordering.append(column)
|
||||
return columns_ordering
|
||||
return columns_ordering
|
||||
|
||||
def CreateConfigurationTable(self, configurations):
|
||||
""" Combines multiple test data configurations for display.
|
||||
|
||||
Args:
|
||||
configurations: List of one ore more configurations. Each configuration
|
||||
is required to be a list of dictionaries with two keys: 'name' and
|
||||
'value'.
|
||||
Example of a single configuration:
|
||||
[
|
||||
{'name': 'name', 'value': 'VP8 software'},
|
||||
{'name': 'test_number', 'value': '0'},
|
||||
{'name': 'input_filename', 'value': 'foreman_cif.yuv'},
|
||||
]
|
||||
Returns:
|
||||
A tuple containing:
|
||||
- a dictionary describing the columns in the configuration table to be
|
||||
displayed. All columns will have string as data type.
|
||||
Example:
|
||||
{
|
||||
'name': 'string',
|
||||
'test_number': 'string',
|
||||
'input_filename': 'string',
|
||||
}
|
||||
- a list containing dictionaries (one per configuration) with the
|
||||
configuration column names mapped to the value for each test run:
|
||||
|
||||
Example matching the columns above:
|
||||
[
|
||||
{'name': 'VP8 software',
|
||||
'test_number': '12',
|
||||
'input_filename': 'foreman_cif.yuv' },
|
||||
{'name': 'VP8 hardware',
|
||||
'test_number': '5',
|
||||
'input_filename': 'foreman_cif.yuv' },
|
||||
]
|
||||
"""
|
||||
result_description = {}
|
||||
result_data = []
|
||||
|
||||
for configuration in configurations:
|
||||
data = {}
|
||||
result_data.append(data)
|
||||
for dict in configuration:
|
||||
name = dict['name']
|
||||
value = dict['value']
|
||||
result_description[name] = 'string'
|
||||
data[name] = value
|
||||
return result_description, result_data
|
||||
|
@ -30,7 +30,17 @@ class Test(unittest.TestCase):
|
||||
'psnr': ('number', 'PSRN'),
|
||||
}
|
||||
self.names = ["Test 0", "Test 1"]
|
||||
|
||||
self.configurations = [
|
||||
[{'name': 'name', 'value': 'Test 0'},
|
||||
{'name': 'test_number', 'value': '13'},
|
||||
{'name': 'input_filename', 'value': 'foreman_cif.yuv'},
|
||||
],
|
||||
[{'name': 'name', 'value': 'Test 1'},
|
||||
{'name': 'test_number', 'value': '5'},
|
||||
{'name': 'input_filename', 'value': 'foreman_cif.yuv'},
|
||||
],
|
||||
]
|
||||
|
||||
def testCreateData(self):
|
||||
messages = []
|
||||
helper = webrtc.data_helper.DataHelper(self.all_data, self.type_description,
|
||||
@ -44,9 +54,9 @@ class Test(unittest.TestCase):
|
||||
self.assertTrue('ssim_1' in description)
|
||||
self.assertTrue('number' in description['ssim_1'][0])
|
||||
self.assertTrue('Test 1' in description['ssim_1'][1])
|
||||
|
||||
self.assertEqual(0, len(messages))
|
||||
|
||||
|
||||
self.assertEqual(0, len(messages))
|
||||
|
||||
self.assertEquals(2, len(data_table))
|
||||
row = data_table[0]
|
||||
self.assertEquals(0, row['frame_number'])
|
||||
@ -88,5 +98,18 @@ class Test(unittest.TestCase):
|
||||
self.assertEqual('ssim_0', columns[1])
|
||||
self.assertEqual('ssim_1', columns[2])
|
||||
|
||||
def testCreateConfigurationTable(self):
|
||||
messages = []
|
||||
helper = webrtc.data_helper.DataHelper(self.all_data, self.type_description,
|
||||
self.names, messages)
|
||||
description, data = helper.CreateConfigurationTable(self.configurations)
|
||||
self.assertEqual(3, len(description)) # 3 columns
|
||||
self.assertEqual(2, len(data)) # 2 data sets
|
||||
self.assertTrue(description.has_key('name'))
|
||||
self.assertTrue(description.has_key('test_number'))
|
||||
self.assertTrue(description.has_key('input_filename'))
|
||||
self.assertEquals('Test 0', data[0]['name'])
|
||||
self.assertEquals('Test 1', data[1]['name'])
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
@ -24,7 +24,7 @@ def main():
|
||||
- A data file in Python format, containing the following:
|
||||
- test_configuration - a dictionary of test configuration names and values.
|
||||
- frame_data_types - a dictionary that maps the different metrics to their
|
||||
data types
|
||||
data types.
|
||||
- frame_data - a list of dictionaries where each dictionary maps a metric to
|
||||
it's value.
|
||||
- The gviz_api.py of the Google Visualization Python API, available at
|
||||
@ -60,7 +60,7 @@ def main():
|
||||
|
||||
# Read data from all existing input files.
|
||||
data_list = []
|
||||
test_configurations_list = []
|
||||
test_configurations = []
|
||||
names = []
|
||||
|
||||
for filename in data_filenames:
|
||||
@ -74,7 +74,7 @@ def main():
|
||||
# Verify the data in the file loaded properly.
|
||||
if not table_description or not table_data:
|
||||
messages.append('Invalid input file: %s. Missing description list or '
|
||||
'data dictionary variables.', filename)
|
||||
'data dictionary variables.' % filename)
|
||||
continue
|
||||
|
||||
# Frame numbers appear as number type in the data, but Chart API requires
|
||||
@ -86,16 +86,25 @@ def main():
|
||||
row['frame_number'] = str(row['frame_number'])
|
||||
|
||||
# Store the unique data from this file in the high level lists.
|
||||
test_configurations_list.append(test_configuration)
|
||||
test_configurations.append(test_configuration)
|
||||
data_list.append(table_data)
|
||||
# Use the filenames for name; strip away directory path and extension.
|
||||
names.append(filename[filename.rfind('/')+1:filename.rfind('.')])
|
||||
# Name of the test run must be present.
|
||||
test_name = FindConfiguration(test_configuration, 'name')
|
||||
if not test_name:
|
||||
messages.append('Invalid input file: %s. Missing configuration key '
|
||||
'"name"', filename)
|
||||
continue
|
||||
names.append(test_name)
|
||||
|
||||
# Create data helper and build data tables for each graph.
|
||||
helper = webrtc.data_helper.DataHelper(data_list, table_description,
|
||||
names, messages)
|
||||
|
||||
# Loading it into gviz_api.DataTable objects and create JSON strings.
|
||||
description, data = helper.CreateConfigurationTable(test_configurations)
|
||||
configurations = gviz_api.DataTable(description, data)
|
||||
json_configurations = configurations.ToJSon()
|
||||
|
||||
description, data = helper.CreateData('ssim')
|
||||
ssim = gviz_api.DataTable(description, data)
|
||||
json_ssim_data = ssim.ToJSon(helper.GetOrdering(description))
|
||||
@ -112,13 +121,11 @@ def main():
|
||||
# Add a column of data points for the desired bit rate to be plotted.
|
||||
# (uses test configuration from the last data set, assuming it is the same
|
||||
# for all of them)
|
||||
desired_bit_rate = -1
|
||||
for row in test_configuration:
|
||||
if row['name'] == 'bit_rate_in_kbps':
|
||||
desired_bit_rate = int(row['value'])
|
||||
if desired_bit_rate == -1:
|
||||
ShowErrorPage('Cannot find bit rate in the test configuration.')
|
||||
desired_bit_rate = FindConfiguration(test_configuration, 'bit_rate_in_kbps')
|
||||
if not desired_bit_rate:
|
||||
ShowErrorPage('Cannot configuration field named "bit_rate_in_kbps"')
|
||||
return
|
||||
desired_bit_rate = int(desired_bit_rate)
|
||||
# Add new column data type description.
|
||||
description['desired_bit_rate'] = ('number', 'Desired bit rate (kbps)')
|
||||
for row in data:
|
||||
@ -132,6 +139,17 @@ def main():
|
||||
# Put the variables as JSon strings into the template.
|
||||
print page_template % vars()
|
||||
|
||||
def FindConfiguration(configuration, name):
|
||||
""" Finds a configuration value using it's name.
|
||||
Returns the first configuration with a matching name. Returns None if no
|
||||
matching configuration is found. """
|
||||
return_value = None
|
||||
for row in configuration:
|
||||
if row['name'] == name:
|
||||
return_value = row['value']
|
||||
break
|
||||
return return_value
|
||||
|
||||
def ShowErrorPage(error_message):
|
||||
print '<html><body>%s</body></html>' % error_message
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user