1689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#!/usr/bin/env python
2689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#
4689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  Use of this source code is governed by a BSD-style license
5689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  that can be found in the LICENSE file in the root of the source
6689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  tree. An additional intellectual property rights grant can be found
7689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  in the file PATENTS.  All contributing project authors may
8689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org#  be found in the AUTHORS file in the root of the source tree.
9689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org
10689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org__author__ = 'kjellander@webrtc.org (Henrik Kjellander)'
11689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org
12689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.orgclass DataHelper(object):
13689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  """
14689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  Helper class for managing table data.
15689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  This class does not verify the consistency of the data tables sent into it.
16689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  """
17689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org
18689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  def __init__(self, data_list, table_description, names_list, messages):
19689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """ Initializes the DataHelper with data.
205d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
21689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    Args:
225d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org      data_list: List of one or more data lists in the format that the
23689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        Google Visualization Python API expects (list of dictionaries, one
245d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        per row of data). See the gviz_api.DataTable documentation for more
25689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        info.
26689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      table_description: dictionary describing the data types of all
27689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        columns in the data lists, as defined in the gviz_api.DataTable
28689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        documentation.
29689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      names_list: List of strings of what we're going to name the data
305d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        columns after. Usually different runs of data collection.
31689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      messages: List of strings we might append error messages to.
32689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """
33689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.data_list = data_list
34689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.table_description = table_description
35689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.names_list = names_list
36689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.messages = messages
37689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.number_of_datasets = len(data_list)
38689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    self.number_of_frames = len(data_list[0])
395d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
40689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org  def CreateData(self, field_name, start_frame=0, end_frame=0):
41689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """ Creates a data structure for a specified data field.
425d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
435d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    Creates a data structure (data type description dictionary and a list
445d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    of data dictionaries) to be used with the Google Visualization Python
45689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    API. The frame_number column is always present and one column per data
465d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    set is added and its field name is suffixed by _N where N is the number
47689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    of the data set (0, 1, 2...)
485d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
49689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    Args:
50689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      field_name: String name of the field, must be present in the data
51689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        structure this DataHelper was created with.
52689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      start_frame: Frame number to start at (zero indexed). Default: 0.
535d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org      end_frame: Frame number to be the last frame. If zero all frames
54689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        will be included. Default: 0.
555d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
56689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    Returns:
57689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      A tuple containing:
58689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      - a dictionary describing the columns in the data result_data_table below.
595d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        This description uses the name for each data set specified by
605d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        names_list.
615d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
62689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        Example with two data sets named 'Foreman' and 'Crew':
63689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        {
64689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         'frame_number': ('number', 'Frame number'),
65689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         'ssim_0': ('number', 'Foreman'),
66689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         'ssim_1': ('number', 'Crew'),
67689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         }
68689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      - a list containing dictionaries (one per row) with the frame_number
695d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        column and one column of the specified field_name column per data
705d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        set.
715d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
72689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        Example with two data sets named 'Foreman' and 'Crew':
73689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        [
74689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         {'frame_number': 0, 'ssim_0': 0.98, 'ssim_1': 0.77 },
75689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org         {'frame_number': 1, 'ssim_0': 0.81, 'ssim_1': 0.53 },
76689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        ]
77689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """
785d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
79689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # Build dictionary that describes the data types
805d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    result_table_description = {'frame_number': ('string', 'Frame number')}
81689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    for dataset_index in range(self.number_of_datasets):
82689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      column_name = '%s_%s' % (field_name, dataset_index)
83689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      column_type = self.table_description[field_name][0]
84689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      column_description = self.names_list[dataset_index]
85689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      result_table_description[column_name] = (column_type, column_description)
86689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org
875d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    # Build data table of all the data
88689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    result_data_table = []
895d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    # We're going to have one dictionary per row.
90689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # Create that and copy frame_number values from the first data set
91689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    for source_row in self.data_list[0]:
9257e5fd2e604ff7e60425c3f7654b40da03fc763cHenrik Kjellander      row_dict = {'frame_number': source_row['frame_number']}
93689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      result_data_table.append(row_dict)
945d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
95689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # Pick target field data points from the all data tables
96689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    if end_frame == 0:  # Default to all frames
97689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      end_frame = self.number_of_frames
985d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
99689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    for dataset_index in range(self.number_of_datasets):
100689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      for row_number in range(start_frame, end_frame):
101689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        column_name = '%s_%s' % (field_name, dataset_index)
102689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        # Stop if any of the data sets are missing the frame
103689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        try:
104689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org          result_data_table[row_number][column_name] = \
105689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org          self.data_list[dataset_index][row_number][field_name]
106689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        except IndexError:
107689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org          self.messages.append("Couldn't find frame data for row %d "
1085d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org          "for %s" % (row_number, self.names_list[dataset_index]))
109689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org          break
110418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    return result_table_description, result_data_table
111689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org
1125d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org  def GetOrdering(self, table_description):  # pylint: disable=R0201
113689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """ Creates a list of column names, ordered alphabetically except for the
114689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      frame_number column which always will be the first column.
1155d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
116689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      Args:
117689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        table_description: A dictionary of column definitions as defined by the
118689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org          gviz_api.DataTable documentation.
119689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      Returns:
120689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        A list of column names, where frame_number is the first and the
121689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        remaining columns are sorted alphabetically.
122689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    """
123689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # The JSON data representation generated from gviz_api.DataTable.ToJSon()
1245d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    # must have frame_number as its first column in order for the chart to
125689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # use it as it's X-axis value series.
1265d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org    # gviz_api.DataTable orders the columns by name by default, which will
127689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # be incorrect if we have column names that are sorted before frame_number
128689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # in our data table.
129689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    columns_ordering = ['frame_number']
130689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    # add all other columns:
131689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org    for column in sorted(table_description.keys()):
132689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org      if column != 'frame_number':
133689cb300b5050f771a77fb1808b1af8fdd6144d3kjellander@webrtc.org        columns_ordering.append(column)
134418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    return columns_ordering
1355d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org
1365d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org  def CreateConfigurationTable(self, configurations):  # pylint: disable=R0201
137418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    """ Combines multiple test data configurations for display.
138418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org
139418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    Args:
140418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      configurations: List of one ore more configurations. Each configuration
141418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      is required to be a list of dictionaries with two keys: 'name' and
142418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      'value'.
143418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      Example of a single configuration:
144418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      [
145418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        {'name': 'name', 'value': 'VP8 software'},
146418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        {'name': 'test_number', 'value': '0'},
147418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        {'name': 'input_filename', 'value': 'foreman_cif.yuv'},
148418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      ]
149418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    Returns:
150418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      A tuple containing:
151418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      - a dictionary describing the columns in the configuration table to be
152418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        displayed. All columns will have string as data type.
153418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        Example:
154418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        {
155418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'name': 'string',
156418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'test_number': 'string',
157418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'input_filename': 'string',
158418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org         }
159418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      - a list containing dictionaries (one per configuration) with the
160418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        configuration column names mapped to the value for each test run:
161418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org
162418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        Example matching the columns above:
163418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        [
164418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org         {'name': 'VP8 software',
165418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'test_number': '12',
166418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'input_filename': 'foreman_cif.yuv' },
167418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org         {'name': 'VP8 hardware',
168418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'test_number': '5',
169418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org          'input_filename': 'foreman_cif.yuv' },
170418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        ]
171418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    """
172418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    result_description = {}
173418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    result_data = []
174418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org
175418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    for configuration in configurations:
176418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      data = {}
177418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org      result_data.append(data)
1785d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org      for values in configuration:
1795d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        name = values['name']
1805d37139374178479c16956a2a4eefd231206c2a1phoglund@webrtc.org        value = values['value']
181418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        result_description[name] = 'string'
182418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org        data[name] = value
183418bce5ccceaee666e0f6142f23a858a35a98df7kjellander@webrtc.org    return result_description, result_data
184