visual_metrics.py : error catching, and order fixing

auto generate list of metrics stt file

Change-Id: Ic55b6b2b7fd7b0b9f75a5eeb349d385ab943d9c9
diff --git a/scripts/metrics_template.html b/scripts/metrics_template.html
index b10f307..72fd51f 100644
--- a/scripts/metrics_template.html
+++ b/scripts/metrics_template.html
@@ -126,7 +126,6 @@
 span.google-visualization-table-sortind {
   color: #000;
 }
-
 .header-style {
   font-weight: bold;
   border: 1px solid #fff;
@@ -145,7 +144,7 @@
   background-color: #f0f0f0;
 }
 </style>
-<script type="text/javascript" src="https://www.google.com/jsapi"></script>
+<script type="text/javascript" src="http://www.google.com/jsapi"></script>
 <script type="text/javascript">
 var chart_left   = 40;
 var chart_top    = 6;
@@ -158,6 +157,7 @@
 var filestable_avg = [];
 
 // Python template code replaces the following 2 lines.
+//%%metrics_js%%//
 //%%filestable_dpsnr%%//
 //%%filestable_avg%%//
 //%%filestable_drate%%//
@@ -169,12 +169,13 @@
 var chart=0;
 var better=0;
 var metricdata=0;
-var metricview=0;
+var metricView=0;
 var column=1;
 var formatter=0;
 
 function changeColumn(col) {
   column = col;
+  console.log(col)
   draw_files();
 }
 
@@ -191,6 +192,20 @@
       document.getElementById("bettertable"));
 
   draw_files();
+  build_metrics_radio();
+}
+
+function build_metrics_radio() {
+  for (metric=1; metric < metrics.length; metric++) {
+    var rb = document.createElement('input');
+    var l = document.createElement('label');
+    rb.setAttribute('type','radio');
+    rb.setAttribute('name','metric');
+    rb.setAttribute('onClick', "changeColumn('"+metric.toString()+"')");
+    l.innerHTML = metrics[metric];
+    document.getElementById('metrics').appendChild(rb);
+    document.getElementById('metrics').appendChild(l);
+  }
 }
 
 function draw_files() {
@@ -221,10 +236,11 @@
   imagestr = better.getFormattedValue(selected, 0)
   var metricjson = eval('(' + snrs[column][selected] + ')');
   metricdata = new google.visualization.DataTable(metricjson, 0.6);
-  if( metricview != 0 ) delete metricview;
-  metricview = new google.visualization.DataView(metricdata);
+  if( metricView != 0 ) delete metricView;
+  metricView = new google.visualization.DataView(metricdata);
 
-  chart.draw(metricview, {curveType:'function',
+  chart.draw(metricView, {curveType:'function',
+      explorer: {},
       chartArea:{left:chart_left, top:chart_top, width:chart_width,
       height:chart_height-90},
       hAxis:{title:"Datarate in kbps"}, vAxis:{title:"Quality in decibels"},
@@ -252,11 +268,12 @@
   var cols = metricdata.getNumberOfColumns();
   var rows = metricdata.getNumberOfRows();
 
-  var sel_bitrate = metricview.getValue(row, 0 );
-  var sel_metric = metricview.getValue(row, col);
+  var sel_bitrate = metricView.getValue(row, 0 );
+  var sel_metric = metricView.getValue(row, col);
 
-  var message = "At " + sel_metric.toFixed(2) + " decibels, <em>"
-  message = message + metricdata.getColumnLabel(col) + "</em> is <ul>"
+  var message = '<ul>' + metricView.getColumnLabel(col) +
+     ' (' + sel_bitrate.toFixed(0) + ' kbps, ' + sel_metric.toFixed(2) + ')' + ' is ';
+
 
   // col 0 is datarate
   for( var i=1;i<cols;++i) {
@@ -321,17 +338,17 @@
 function chartSelect() {
   var selection = chart.getSelection();
   var message = '';
-  var min = metricview.getFormattedValue(selection[0].row, 0);
-  var max = metricview.getFormattedValue(selection[selection.length-1].row, 0);
-  var val = metricview.getFormattedValue(selection[0].row,selection[0].column);
+  var min = metricView.getFormattedValue(selection[0].row, 0);
+  var max = metricView.getFormattedValue(selection[selection.length-1].row, 0);
+  var val = metricView.getFormattedValue(selection[0].row,selection[0].column);
 
   pointDifference(selection[0].row, selection[0].column)
   min = min / 3
   max = max * 3
-  metricview.setRows(metricdata.getFilteredRows(
+  metricView.setRows(metricdata.getFilteredRows(
       [{column: 0,minValue: min, maxValue:max}]));
 
-  chart.draw(metricview, {curveType:'function',
+  chart.draw(metricView, {curveType:'function',
       chartArea:{left:40, top:10, width:chart_width, height:chart_height - 110},
       hAxis:{title:"datarate in kbps"}, vAxis:{title:"quality in decibels"},
       legend:{position:"in"}, title:imagestr, pointSize:2, lineWidth:1,
@@ -347,6 +364,7 @@
   query_file()
 }
 
+
 google.load('visualization', '1', {'packages' : ['corechart','table']});
 google.setOnLoadCallback(setup_vis);
 </script>
@@ -372,12 +390,7 @@
           onClick="changeMetric('filestable_drate')" />BDRATE
       </form>
 
-      <form name="myform">
-        Average size reduction to get the same quality <input type="radio"
-          checked name="column" value="1" onClick="changeColumn('1')" />Average
-        PSNR <input type="radio" name="column" value="2"
-          onClick="changeColumn('2')" />Global PSNR <input type="radio"
-          name="column" value="3" onClick="changeColumn('5')" />SSIM
+      <form id="metrics" name="myform">
       </form>
 
     </div>
diff --git a/scripts/visual_metrics.py b/scripts/visual_metrics.py
index 29cecac..4a67b23 100755
--- a/scripts/visual_metrics.py
+++ b/scripts/visual_metrics.py
@@ -16,6 +16,7 @@
 import string
 import sys
 import math
+import warnings
 
 import gviz_api
 
@@ -39,28 +40,39 @@
   psnr1 = [x[1] for x in metric_set1]
   rate2 = [x[0] for x in metric_set2]
   psnr2 = [x[1] for x in metric_set2]
+  if not psnr1 or not psnr2:
+    return 0.0
+
+  psnr1 = [100.0 if x == float('inf') else x for x in psnr1]
+  psnr2 = [100.0 if x == float('inf') else x for x in psnr2]
+
 
   log_rate1 = map(lambda x: math.log(x), rate1)
   log_rate2 = map(lambda x: math.log(x), rate2)
 
-  # Best cubic poly fit for graph represented by log_ratex, psrn_x.
-  p1 = numpy.polyfit(log_rate1, psnr1, 3)
-  p2 = numpy.polyfit(log_rate2, psnr2, 3)
+  try:
+    # Best cubic poly fit for graph represented by log_ratex, psrn_x.
+    p1 = numpy.polyfit(log_rate1, psnr1, 3)
+    p2 = numpy.polyfit(log_rate2, psnr2, 3)
 
-  # Integration interval.
-  min_int = max([min(log_rate1),min(log_rate2)])
-  max_int = min([max(log_rate1),max(log_rate2)])
+    # Integration interval.
+    min_int = max([min(log_rate1),min(log_rate2)])
+    max_int = min([max(log_rate1),max(log_rate2)])
 
-  # Integrate p1, and p2.
-  p_int1 = numpy.polyint(p1)
-  p_int2 = numpy.polyint(p2)
+    # Integrate p1, and p2.
+    p_int1 = numpy.polyint(p1)
+    p_int2 = numpy.polyint(p2)
 
-  # Calculate the integrated value over the interval we care about.
-  int1 = numpy.polyval(p_int1, max_int) - numpy.polyval(p_int1, min_int)
-  int2 = numpy.polyval(p_int2, max_int) - numpy.polyval(p_int2, min_int)
+    # Calculate the integrated value over the interval we care about.
+    int1 = numpy.polyval(p_int1, max_int) - numpy.polyval(p_int1, min_int)
+    int2 = numpy.polyval(p_int2, max_int) - numpy.polyval(p_int2, min_int)
 
-  # Calculate the average improvement.
-  avg_diff = (int2 - int1) / (max_int - min_int)
+    # Calculate the average improvement.
+    avg_diff = (int2 - int1) / (max_int - min_int)
+
+  except (TypeError, ZeroDivisionError, ValueError, numpy.RankWarning) as e:
+    return 0
+
   return avg_diff
 
 def bdrate(metric_set1, metric_set2):
@@ -80,27 +92,38 @@
   rate2 = [x[0] for x in metric_set2]
   psnr2 = [x[1] for x in metric_set2]
 
+  if not psnr1 or not psnr2:
+    return 0.0
+
+  psnr1 = [100.0 if x == float('inf') else x for x in psnr1]
+  psnr2 = [100.0 if x == float('inf') else x for x in psnr2]
+
   log_rate1 = map(lambda x: math.log(x), rate1)
   log_rate2 = map(lambda x: math.log(x), rate2)
 
-  # Best cubic poly fit for graph represented by log_ratex, psrn_x.
-  p1 = numpy.polyfit(psnr1, log_rate1, 3)
-  p2 = numpy.polyfit(psnr2, log_rate2, 3)
+  try:
+    # Best cubic poly fit for graph represented by log_ratex, psrn_x.
+    p1 = numpy.polyfit(psnr1, log_rate1, 3)
+    p2 = numpy.polyfit(psnr2, log_rate2, 3)
 
-  # Integration interval.
-  min_int = max([min(psnr1),min(psnr2)])
-  max_int = min([max(psnr1),max(psnr2)])
+    # Integration interval.
+    min_int = max([min(psnr1),min(psnr2)])
+    max_int = min([max(psnr1),max(psnr2)])
 
-  # find integral
-  p_int1 = numpy.polyint(p1)
-  p_int2 = numpy.polyint(p2)
+    # find integral
+    p_int1 = numpy.polyint(p1)
+    p_int2 = numpy.polyint(p2)
 
-  # Calculate the integrated value over the interval we care about.
-  int1 = numpy.polyval(p_int1, max_int) - numpy.polyval(p_int1, min_int)
-  int2 = numpy.polyval(p_int2, max_int) - numpy.polyval(p_int2, min_int)
+    # Calculate the integrated value over the interval we care about.
+    int1 = numpy.polyval(p_int1, max_int) - numpy.polyval(p_int1, min_int)
+    int2 = numpy.polyval(p_int2, max_int) - numpy.polyval(p_int2, min_int)
 
-  # Calculate the average improvement.
-  avg_exp_diff = (int2 - int1) / (max_int - min_int)
+    # Calculate the average improvement.
+    avg_exp_diff = (int2 - int1) / (max_int - min_int)
+
+  except (TypeError, ZeroDivisionError, ValueError, numpy.RankWarning) as e:
+    return 0
+
 
   # In really bad formed data the exponent can grow too large.
   # clamp it.
@@ -129,10 +152,18 @@
   """
   The metrics files produced by vpxenc are started with a B for headers.
   """
-  if line[0:1] != "B":
+  # If the first char of the first word on the line is a digit
+  if len(line) == 0:
+    return False
+  if len(line.split()) == 0:
+    return False
+  if line.split()[0][0:1].isdigit():
     return True
   return False
 
+def GetMetrics(file_name):
+  metric_file = open(file_name, "r")
+  return metric_file.readline().split();
 
 def ParseMetricFile(file_name, metric_column):
   metric_set1 = set([])
@@ -282,18 +313,22 @@
   baseline_dir = variables[3]
   snrs = ''
   filestable = {}
+
   filestable['dsnr'] = ''
   filestable['drate'] = ''
   filestable['avg'] = ''
 
-  # Go through each metric in the list.
-  for column in range(1, 6):
+  # Dirs is directories after the baseline to compare to the base.
+  dirs = variables[4:len(variables)]
 
-    # Dirs is directories after the baseline to compare to the base.
-    dirs = variables[4:len(variables)]
+  # Find the metric files in the baseline directory.
+  dir_list = sorted(fnmatch.filter(os.listdir(baseline_dir), file_pattern))
 
-    # Find the metric files in the baseline directory.
-    dir_list = sorted(fnmatch.filter(os.listdir(baseline_dir), file_pattern))
+  metrics = GetMetrics(baseline_dir + "/" + dir_list[0])
+
+  metrics_js = 'metrics = ["' + '", "'.join(metrics) + '"];'
+
+  for column in range(1, len(metrics)):
 
     for metric in ['avg','dsnr','drate']:
       description = {"file": ("string", "File")}
@@ -342,8 +377,8 @@
       data_table.LoadData(data)
 
       filestable[metric] = ( filestable[metric] + "filestable_" + metric +
-                             "[" + str(column) + "]=" + data_table.ToJSon()
-                             + "\n" )
+                             "[" + str(column) + "]=" +
+                             data_table.ToJSon(columns_order=["file"]+dirs) + "\n" )
 
     filestable_avg = filestable['avg']
     filestable_dpsnr = filestable['dsnr']
@@ -397,4 +432,4 @@
 if len(sys.argv) < 3:
   print HandleFiles.__doc__
 else:
-  HandleFiles(sys.argv)
\ No newline at end of file
+  HandleFiles(sys.argv)