First version of PythonCharts.
The reason why it is so simple is that I wanted to get something into the project that people can use to compare different test runs easily. More functionality will come later.

tools/python_charts/src/gviz_api.py is a copy of the Google visualization Python API available from http://google-visualization-python.googlecode.com/svn/trunk/

Review URL: http://webrtc-codereview.appspot.com/257003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@893 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/tools/python_charts/webrtc/main.py b/tools/python_charts/webrtc/main.py
new file mode 100644
index 0000000..a06e960
--- /dev/null
+++ b/tools/python_charts/webrtc/main.py
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+#  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+#
+#  Use of this source code is governed by a BSD-style license
+#  that can be found in the LICENSE file in the root of the source
+#  tree. An additional intellectual property rights grant can be found
+#  in the file PATENTS.  All contributing project authors may
+#  be found in the AUTHORS file in the root of the source tree.
+
+__author__ = 'kjellander@webrtc.org (Henrik Kjellander)'
+
+import os
+import gviz_api
+import webrtc.data_helper
+
+def main():
+  """
+  This Python script displays a web page with test created with the 
+  video_quality_measurement program, which is a tool in WebRTC.
+  
+  The script requires on two external files and one Python library:
+  - A HTML template file with layout and references to the json variables 
+    defined in this script
+  - 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  
+    - 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
+    http://code.google.com/p/google-visualization-python/
+  
+  The HTML file is shipped with the script, while the data file must be 
+  generated by running video_quality_measurement with the --python flag
+  specified.
+  """
+  print 'Content-type: text/html\n' # the newline is required!
+
+  page_template_filename = '../templates/chart_page_template.html'
+  # The data files must be located in the project tree for app engine being
+  # able to access them.
+  data_filenames = [ '../data/vp8_sw.py', '../data/vp8_hw.py' ]
+  # Will contain info/error messages to be displayed on the resulting page.
+  messages = []
+  # Load the page HTML template.
+  try:
+    f = open(page_template_filename)
+    page_template = f.read()
+    f.close()
+  except IOError as e:
+    ShowErrorPage('Cannot open page template file: %s<br>Details: %s' % 
+                  (page_template_filename, e))
+    return
+  
+  # Read data from external Python script files. First check that they exist.
+  for filename in data_filenames:
+    if not os.path.exists(filename):
+      messages.append('Cannot open data file: %s' % filename)
+      data_filenames.remove(filename)
+  
+  # Read data from all existing input files.
+  data_list = []
+  test_configurations_list = []
+  names = []
+  
+  for filename in data_filenames:
+    read_vars = {} # empty dictionary to load the data into.
+    execfile(filename, read_vars, read_vars)
+    
+    test_configuration = read_vars['test_configuration']
+    table_description = read_vars['frame_data_types']
+    table_data = read_vars['frame_data']
+    
+    # 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)
+      continue
+    
+    # Frame numbers appear as number type in the data, but Chart API requires
+    # values of the X-axis to be of string type.
+    # Change the frame_number column data type: 
+    table_description['frame_number'] = ('string', 'Frame number')
+    # Convert all the values to string types: 
+    for row in table_data:
+      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)
+    data_list.append(table_data)
+    # Use the filenames for name; strip away directory path and extension.
+    names.append(filename[filename.rfind('/')+1:filename.rfind('.')])
+    
+  # 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.CreateData('ssim')
+  ssim = gviz_api.DataTable(description, data)
+  json_ssim_data = ssim.ToJSon(helper.GetOrdering(description))
+  
+  description, data = helper.CreateData('psnr')
+  psnr = gviz_api.DataTable(description, data)
+  json_psnr_data = psnr.ToJSon(helper.GetOrdering(description))
+  
+  description, data = helper.CreateData('packets_dropped')
+  packet_loss = gviz_api.DataTable(description, data)
+  json_packet_loss_data = packet_loss.ToJSon(helper.GetOrdering(description))  
+  
+  description, data = helper.CreateData('bit_rate')
+  # 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.')
+    return
+  # Add new column data type description.
+  description['desired_bit_rate'] = ('number', 'Desired bit rate (kbps)')
+  for row in data:
+    row['desired_bit_rate'] = desired_bit_rate
+  bit_rate = gviz_api.DataTable(description, data)
+  json_bit_rate_data = bit_rate.ToJSon(helper.GetOrdering(description))
+
+  # Format the messages list with newlines.
+  messages = '\n'.join(messages)
+  
+  # Put the variables as JSon strings into the template.
+  print page_template % vars()
+
+def ShowErrorPage(error_message):
+  print '<html><body>%s</body></html>' % error_message
+  
+if __name__ == '__main__':
+  main()