예제 #1
0
    def monsoon_data_plot_power(self, samples, voltage, dest_path, plot_title):
        """Plot the monsoon power data using bokeh interactive plotting tool.

        Args:
            samples: a list of tuples in which the first element is a timestamp
            and the second element is the sampled current at that time
            voltage: the voltage that was used during the measurement
            dest_path: destination path
            plot_title: a filename and title for the plot.

        """

        logging.info('Plotting the power measurement data.')

        time_relative = [sample[0] for sample in samples]
        duration = time_relative[-1] - time_relative[0]
        current_data = [sample[1] * 1000 for sample in samples]
        avg_current = sum(current_data) / len(current_data)

        power_data = [current * voltage for current in current_data]

        color = ['navy'] * len(samples)

        # Preparing the data and source link for bokehn java callback
        source = ColumnDataSource(
            data=dict(x0=time_relative, y0=power_data, color=color))
        s2 = ColumnDataSource(
            data=dict(z0=[duration],
                      y0=[round(avg_current, 2)],
                      x0=[round(avg_current * voltage, 2)],
                      z1=[round(avg_current * voltage * duration, 2)],
                      z2=[round(avg_current * duration, 2)]))
        # Setting up data table for the output
        columns = [
            TableColumn(field='z0', title='Total Duration (s)'),
            TableColumn(field='y0', title='Average Current (mA)'),
            TableColumn(field='x0', title='Average Power (4.2v) (mW)'),
            TableColumn(field='z1', title='Average Energy (mW*s)'),
            TableColumn(field='z2', title='Normalized Average Energy (mA*s)')
        ]
        dt = DataTable(source=s2,
                       columns=columns,
                       width=1300,
                       height=60,
                       editable=True)

        output_file(os.path.join(dest_path, plot_title + '.html'))
        tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
        # Create a new plot with the datatable above
        plot = figure(plot_width=1300,
                      plot_height=700,
                      title=plot_title,
                      tools=tools,
                      output_backend='webgl')
        plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='width'))
        plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='height'))
        plot.line('x0', 'y0', source=source, line_width=2)
        plot.circle('x0', 'y0', source=source, size=0.5, fill_color='color')
        plot.xaxis.axis_label = 'Time (s)'
        plot.yaxis.axis_label = 'Power (mW)'
        plot.title.text_font_size = {'value': '15pt'}
        jsscript = open(self.customjsfile, 'r')
        customjsscript = jsscript.read()
        # Callback Java scripting
        source.callback = CustomJS(args=dict(mytable=dt), code=customjsscript)

        # Layout the plot and the datatable bar
        save(layout([[dt], [plot]]))
def monsoon_data_plot(mon_info, monsoon_results, tag=''):
    """Plot the monsoon current data using bokeh interactive plotting tool.

    Plotting power measurement data with bokeh to generate interactive plots.
    You can do interactive data analysis on the plot after generating with the
    provided widgets, which make the debugging much easier. To realize that,
    bokeh callback java scripting is used. View a sample html output file:
    https://drive.google.com/open?id=0Bwp8Cq841VnpT2dGUUxLYWZvVjA

    Args:
        mon_info: obj with information of monsoon measurement, including
            monsoon device object, measurement frequency, duration, etc.
        monsoon_results: a MonsoonResult or list of MonsoonResult objects to
                         to plot.
        tag: an extra tag to append to the resulting filename.

    Returns:
        plot: the plotting object of bokeh, optional, will be needed if multiple
           plots will be combined to one html file.
        dt: the datatable object of bokeh, optional, will be needed if multiple
           datatables will be combined to one html file.
    """
    if not isinstance(monsoon_results, list):
        monsoon_results = [monsoon_results]
    logging.info('Plotting the power measurement data.')

    voltage = monsoon_results[0].voltage

    total_current = 0
    total_samples = 0
    for result in monsoon_results:
        total_current += result.average_current * result.num_samples
        total_samples += result.num_samples
    avg_current = total_current / total_samples

    time_relative = [
        data_point.time for monsoon_result in monsoon_results
        for data_point in monsoon_result.get_data_points()
    ]

    current_data = [
        data_point.current * 1000 for monsoon_result in monsoon_results
        for data_point in monsoon_result.get_data_points()
    ]

    total_data_points = sum(result.num_samples for result in monsoon_results)
    color = ['navy'] * total_data_points

    # Preparing the data and source link for bokehn java callback
    source = ColumnDataSource(
        data=dict(x=time_relative, y=current_data, color=color))
    s2 = ColumnDataSource(
        data=dict(a=[mon_info.duration],
                  b=[round(avg_current, 2)],
                  c=[round(avg_current * voltage, 2)],
                  d=[round(avg_current * voltage * mon_info.duration, 2)],
                  e=[round(avg_current * mon_info.duration, 2)]))
    # Setting up data table for the output
    columns = [
        TableColumn(field='a', title='Total Duration (s)'),
        TableColumn(field='b', title='Average Current (mA)'),
        TableColumn(field='c', title='Average Power (4.2v) (mW)'),
        TableColumn(field='d', title='Average Energy (mW*s)'),
        TableColumn(field='e', title='Normalized Average Energy (mA*s)')
    ]
    dt = DataTable(source=s2,
                   columns=columns,
                   width=1300,
                   height=60,
                   editable=True)

    plot_title = (
        os.path.basename(os.path.splitext(monsoon_results[0].tag)[0]) + tag)
    output_file(os.path.join(mon_info.data_path, plot_title + '.html'))
    tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
    # Create a new plot with the datatable above
    plot = figure(plot_width=1300,
                  plot_height=700,
                  title=plot_title,
                  tools=tools)
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='width'))
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='height'))
    plot.line('x', 'y', source=source, line_width=2)
    plot.circle('x', 'y', source=source, size=0.5, fill_color='color')
    plot.xaxis.axis_label = 'Time (s)'
    plot.yaxis.axis_label = 'Current (mA)'
    plot.title.text_font_size = {'value': '15pt'}

    # Callback JavaScript
    source.selected.js_on_change(
        "indices",
        CustomJS(args=dict(source=source, mytable=dt),
                 code="""
        const inds = source.selected.indices;
        const d1 = source.data;
        const d2 = mytable.source.data;
        var ym = 0
        var ts = 0
        var min=d1['x'][inds[0]]
        var max=d1['x'][inds[0]]
        d2['a'] = []
        d2['b'] = []
        d2['c'] = []
        d2['d'] = []
        d2['e'] = []
        if (inds.length==0) {return;}
        for (var i = 0; i < inds.length; i++) {
        ym += d1['y'][inds[i]]
        d1['color'][inds[i]] = "red"
        if (d1['x'][inds[i]] < min) {
          min = d1['x'][inds[i]]}
        if (d1['x'][inds[i]] > max) {
          max = d1['x'][inds[i]]}
        }
        ym /= inds.length
        ts = max - min
        d2['a'].push(Math.round(ts*1000.0)/1000.0)
        d2['b'].push(Math.round(ym*100.0)/100.0)
        d2['c'].push(Math.round(ym*4.2*100.0)/100.0)
        d2['d'].push(Math.round(ym*4.2*ts*100.0)/100.0)
        d2['e'].push(Math.round(ym*ts*100.0)/100.0)
        source.change.emit();
        mytable.change.emit();
    """))

    # Layout the plot and the datatable bar
    save(layout([[dt], [plot]]))
    return plot, dt
    def monsoon_data_plot_power(self, mon_info, monsoon_results, tag=''):
        """Plot the monsoon power data using bokeh interactive plotting tool.

        Args:
            mon_info: Dictionary with the monsoon packet config.
            monsoon_results: a MonsoonResult or list of MonsoonResult objects to
                             to plot.
            tag: an extra tag to append to the resulting filename.

        """

        if not isinstance(monsoon_results, list):
            monsoon_results = [monsoon_results]
        logging.info('Plotting the power measurement data.')

        voltage = monsoon_results[0].voltage

        total_current = 0
        total_samples = 0
        for result in monsoon_results:
            total_current += result.average_current * result.num_samples
            total_samples += result.num_samples
        avg_current = total_current / total_samples

        time_relative = [
            data_point.time
            for monsoon_result in monsoon_results
            for data_point in monsoon_result.get_data_points()
        ]

        power_data = [
            data_point.current * voltage
            for monsoon_result in monsoon_results
            for data_point in monsoon_result.get_data_points()
        ]

        total_data_points = sum(
            result.num_samples for result in monsoon_results)
        color = ['navy'] * total_data_points

        # Preparing the data and source link for bokehn java callback
        source = ColumnDataSource(
            data=dict(x0=time_relative, y0=power_data, color=color))
        s2 = ColumnDataSource(
            data=dict(
                z0=[mon_info.duration],
                y0=[round(avg_current, 2)],
                x0=[round(avg_current * voltage, 2)],
                z1=[round(avg_current * voltage * mon_info.duration, 2)],
                z2=[round(avg_current * mon_info.duration, 2)]))
        # Setting up data table for the output
        columns = [
            TableColumn(field='z0', title='Total Duration (s)'),
            TableColumn(field='y0', title='Average Current (mA)'),
            TableColumn(field='x0', title='Average Power (4.2v) (mW)'),
            TableColumn(field='z1', title='Average Energy (mW*s)'),
            TableColumn(field='z2', title='Normalized Average Energy (mA*s)')
        ]
        dt = DataTable(
            source=s2, columns=columns, width=1300, height=60, editable=True)

        plot_title = (os.path.basename(
            os.path.splitext(monsoon_results[0].tag)[0])
                      + tag)
        output_file(os.path.join(mon_info.data_path, plot_title + '.html'))
        tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
        # Create a new plot with the datatable above
        plot = figure(
            plot_width=1300,
            plot_height=700,
            title=plot_title,
            tools=tools,
            output_backend='webgl')
        plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='width'))
        plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='height'))
        plot.line('x0', 'y0', source=source, line_width=2)
        plot.circle('x0', 'y0', source=source, size=0.5, fill_color='color')
        plot.xaxis.axis_label = 'Time (s)'
        plot.yaxis.axis_label = 'Power (mW)'
        plot.title.text_font_size = {'value': '15pt'}
        jsscript = open(self.customjsfile, 'r')
        customjsscript = jsscript.read()
        # Callback Java scripting
        source.callback = CustomJS(
            args=dict(mytable=dt),
            code=customjsscript)

        # Layout the plot and the datatable bar
        save(layout([[dt], [plot]]))
예제 #4
0
def bokeh_chart_plot(bt_attenuation_range,
               data_sets,
               legends,
               fig_property,
               shaded_region=None,
               output_file_path=None):
    """Plot bokeh figs.

    Args:
        bt_attenuation_range: range of BT attenuation.
        data_sets: data sets including lists of x_data and lists of y_data
            ex: [[[x_data1], [x_data2]], [[y_data1],[y_data2]]]
        legends: list of legend for each curve
        fig_property: dict containing the plot property, including title,
                      labels, linewidth, circle size, etc.
        shaded_region: optional dict containing data for plot shading
        output_file_path: optional path at which to save figure

    Returns:
        plot: bokeh plot figure object
    """
    TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
    colors = [
        'red', 'green', 'blue', 'olive', 'orange', 'salmon', 'black', 'navy',
        'yellow', 'darkred', 'goldenrod'
    ]
    plot = []
    data = [[], []]
    legend = []
    for i in bt_attenuation_range:
        if "Packet drop" in legends[i][0]:
            plot_info = {0: "A2dp_packet_drop_plot", 1: "throughput_plot"}
        else:
            plot_info = {0: "throughput_plot"}
        for j in plot_info:
            if "Packet drops" in legends[i][j]:
                if data_sets[i]["a2dp_packet_drops"]:
                    plot_i_j = figure(
                        plot_width=1000,
                        plot_height=500,
                        title=fig_property['title'],
                        tools=TOOLS)

                    plot_i_j.add_tools(
                        bokeh_tools.WheelZoomTool(dimensions="width"))
                    plot_i_j.add_tools(
                        bokeh_tools.WheelZoomTool(dimensions="height"))
                    plot_i_j.xaxis.axis_label = fig_property['x_label']
                    plot_i_j.yaxis.axis_label = fig_property['y_label'][j]
                    plot_i_j.legend.location = "top_right"
                    plot_i_j.legend.click_policy = "hide"
                    plot_i_j.title.text_font_size = {'value': '15pt'}

                    plot_i_j.line(
                        data_sets[i]["a2dp_attenuation"],
                        data_sets[i]["a2dp_packet_drops"],
                        legend=legends[i][j],
                        line_width=3,
                        color=colors[j])
                    plot_i_j.circle(
                        data_sets[i]["a2dp_attenuation"],
                        data_sets[i]["a2dp_packet_drops"],
                        legend=str(legends[i][j]),
                        fill_color=colors[j])
                    plot.append(plot_i_j)
            elif "Performance Results" in legends[i][j]:
                plot_i_j = figure(
                    plot_width=1000,
                    plot_height=500,
                    title=fig_property['title'],
                    tools=TOOLS)
                plot_i_j.add_tools(
                    bokeh_tools.WheelZoomTool(dimensions="width"))
                plot_i_j.add_tools(
                    bokeh_tools.WheelZoomTool(dimensions="height"))
                plot_i_j.xaxis.axis_label = fig_property['x_label']
                plot_i_j.yaxis.axis_label = fig_property['y_label'][j]
                plot_i_j.legend.location = "top_right"
                plot_i_j.legend.click_policy = "hide"
                plot_i_j.title.text_font_size = {'value': '15pt'}
                data[0].insert(0, data_sets[i]["attenuation"])
                data[1].insert(0, data_sets[i]["throughput_received"])
                legend.insert(0, legends[i][j + 1])
                plot_i_j.line(
                    data_sets[i]["user_attenuation"],
                    data_sets[i]["user_throughput"],
                    legend=legends[i][j],
                    line_width=3,
                    color=colors[j])
                plot_i_j.circle(
                    data_sets[i]["user_attenuation"],
                    data_sets[i]["user_throughput"],
                    legend=str(legends[i][j]),
                    fill_color=colors[j])
                plot_i_j.line(
                    data_sets[i]["attenuation"],
                    data_sets[i]["throughput_received"],
                    legend=legends[i][j + 1],
                    line_width=3,
                    color=colors[j])
                plot_i_j.circle(
                    data_sets[i]["attenuation"],
                    data_sets[i]["throughput_received"],
                    legend=str(legends[i][j + 1]),
                    fill_color=colors[j])
                if shaded_region:
                    band_x = shaded_region[i]["x_vector"]
                    band_x.extend(shaded_region[i]["x_vector"][::-1])
                    band_y = shaded_region[i]["lower_limit"]
                    band_y.extend(shaded_region[i]["upper_limit"][::-1])
                    plot_i_j.patch(
                        band_x,
                        band_y,
                        color='#7570B3',
                        line_alpha=0.1,
                        fill_alpha=0.1)
                plot.append(plot_i_j)
            else:
                plot_i_j = figure(
                    plot_width=1000,
                    plot_height=500,
                    title=fig_property['title'],
                    tools=TOOLS)
                plot_i_j.add_tools(
                    bokeh_tools.WheelZoomTool(dimensions="width"))
                plot_i_j.add_tools(
                    bokeh_tools.WheelZoomTool(dimensions="height"))
                plot_i_j.xaxis.axis_label = fig_property['x_label']
                plot_i_j.yaxis.axis_label = fig_property['y_label'][j]
                plot_i_j.legend.location = "top_right"
                plot_i_j.legend.click_policy = "hide"
                plot_i_j.title.text_font_size = {'value': '15pt'}
                data[0].insert(0, data_sets[i]["attenuation"])
                data[1].insert(0, data_sets[i]["throughput_received"])
                legend.insert(0, legends[i][j])
                plot_i_j.line(
                    data_sets[i]["attenuation"],
                    data_sets[i]["throughput_received"],
                    legend=legends[i][j],
                    line_width=3,
                    color=colors[j])
                plot_i_j.circle(
                    data_sets[i]["attenuation"],
                    data_sets[i]["throughput_received"],
                    legend=str(legends[i][j]),
                    fill_color=colors[j])
                plot.append(plot_i_j)
    fig_property['y_label'] = "Throughput (Mbps)"
    all_plot = bokeh_plot(data, legend, fig_property, shaded_region=None,
            output_file_path=None)
    plot.insert(0, all_plot)
    if output_file_path is not None:
        output_file(output_file_path)
        save(column(plot))
    return plot
예제 #5
0
def bokeh_plot(data_sets,
               legends,
               fig_property,
               shaded_region=None,
               output_file_path=None):
    """Plot bokeh figs.
        Args:
            data_sets: data sets including lists of x_data and lists of y_data
                       ex: [[[x_data1], [x_data2]], [[y_data1],[y_data2]]]
            legends: list of legend for each curve
            fig_property: dict containing the plot property, including title,
                      labels, linewidth, circle size, etc.
            shaded_region: optional dict containing data for plot shading
            output_file_path: optional path at which to save figure
        Returns:
            plot: bokeh plot figure object
    """
    tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
    plot = figure(plot_width=1300,
                  plot_height=700,
                  title=fig_property['title'],
                  tools=tools,
                  output_backend="webgl")
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="width"))
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="height"))
    colors = [
        'red', 'green', 'blue', 'olive', 'orange', 'salmon', 'black', 'navy',
        'yellow', 'darkred', 'goldenrod'
    ]
    if shaded_region:
        band_x = shaded_region["x_vector"]
        band_x.extend(shaded_region["x_vector"][::-1])
        band_y = shaded_region["lower_limit"]
        band_y.extend(shaded_region["upper_limit"][::-1])
        plot.patch(band_x,
                   band_y,
                   color='#7570B3',
                   line_alpha=0.1,
                   fill_alpha=0.1)

    for x_data, y_data, legend in zip(data_sets[0], data_sets[1], legends):
        index_now = legends.index(legend)
        color = colors[index_now % len(colors)]
        plot.line(x_data,
                  y_data,
                  legend=str(legend),
                  line_width=fig_property['linewidth'],
                  color=color)
        plot.circle(x_data,
                    y_data,
                    size=fig_property['markersize'],
                    legend=str(legend),
                    fill_color=color)

    # Plot properties
    plot.xaxis.axis_label = fig_property['x_label']
    plot.yaxis.axis_label = fig_property['y_label']
    plot.legend.location = "top_right"
    plot.legend.click_policy = "hide"
    plot.title.text_font_size = {'value': '15pt'}
    if output_file_path is not None:
        output_file(output_file_path)
        save(plot)
    return plot
예제 #6
0
def current_waveform_plot(samples, voltage, dest_path, plot_title):
    """Plot the current data using bokeh interactive plotting tool.

    Plotting power measurement data with bokeh to generate interactive plots.
    You can do interactive data analysis on the plot after generating with the
    provided widgets, which make the debugging much easier. To realize that,
    bokeh callback java scripting is used. View a sample html output file:
    https://drive.google.com/open?id=0Bwp8Cq841VnpT2dGUUxLYWZvVjA

    Args:
        samples: a list of tuples in which the first element is a timestamp and
          the second element is the sampled current in milli amps at that time.
        voltage: the voltage that was used during the measurement.
        dest_path: destination path.
        plot_title: a filename and title for the plot.
    Returns:
        plot: the plotting object of bokeh, optional, will be needed if multiple
           plots will be combined to one html file.
        dt: the datatable object of bokeh, optional, will be needed if multiple
           datatables will be combined to one html file.
    """
    logging.info('Plotting the power measurement data.')

    time_relative = [sample[0] for sample in samples]
    duration = time_relative[-1] - time_relative[0]
    current_data = [sample[1] * 1000 for sample in samples]
    avg_current = sum(current_data) / len(current_data)

    color = ['navy'] * len(samples)

    # Preparing the data and source link for bokehn java callback
    source = ColumnDataSource(
        data=dict(x=time_relative, y=current_data, color=color))
    s2 = ColumnDataSource(
        data=dict(a=[duration],
                  b=[round(avg_current, 2)],
                  c=[round(avg_current * voltage, 2)],
                  d=[round(avg_current * voltage * duration, 2)],
                  e=[round(avg_current * duration, 2)]))
    # Setting up data table for the output
    columns = [
        TableColumn(field='a', title='Total Duration (s)'),
        TableColumn(field='b', title='Average Current (mA)'),
        TableColumn(field='c', title='Average Power (4.2v) (mW)'),
        TableColumn(field='d', title='Average Energy (mW*s)'),
        TableColumn(field='e', title='Normalized Average Energy (mA*s)')
    ]
    dt = DataTable(source=s2,
                   columns=columns,
                   width=1300,
                   height=60,
                   editable=True)

    output_file(os.path.join(dest_path, plot_title + '.html'))
    tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
    # Create a new plot with the datatable above
    plot = figure(plot_width=1300,
                  plot_height=700,
                  title=plot_title,
                  tools=tools)
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='width'))
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions='height'))
    plot.line('x', 'y', source=source, line_width=2)
    plot.circle('x', 'y', source=source, size=0.5, fill_color='color')
    plot.xaxis.axis_label = 'Time (s)'
    plot.yaxis.axis_label = 'Current (mA)'
    plot.title.text_font_size = {'value': '15pt'}

    # Callback JavaScript
    source.selected.js_on_change(
        "indices",
        CustomJS(args=dict(source=source, mytable=dt),
                 code="""
        const inds = source.selected.indices;
        const d1 = source.data;
        const d2 = mytable.source.data;
        var ym = 0
        var ts = 0
        var min=d1['x'][inds[0]]
        var max=d1['x'][inds[0]]
        d2['a'] = []
        d2['b'] = []
        d2['c'] = []
        d2['d'] = []
        d2['e'] = []
        if (inds.length==0) {return;}
        for (var i = 0; i < inds.length; i++) {
        ym += d1['y'][inds[i]]
        d1['color'][inds[i]] = "red"
        if (d1['x'][inds[i]] < min) {
          min = d1['x'][inds[i]]}
        if (d1['x'][inds[i]] > max) {
          max = d1['x'][inds[i]]}
        }
        ym /= inds.length
        ts = max - min
        d2['a'].push(Math.round(ts*1000.0)/1000.0)
        d2['b'].push(Math.round(ym*100.0)/100.0)
        d2['c'].push(Math.round(ym*4.2*100.0)/100.0)
        d2['d'].push(Math.round(ym*4.2*ts*100.0)/100.0)
        d2['e'].push(Math.round(ym*ts*100.0)/100.0)
        source.change.emit();
        mytable.change.emit();
    """))

    # Layout the plot and the datatable bar
    save(layout([[dt], [plot]]))
    return plot, dt
예제 #7
0
def monsoon_data_plot(mon_info, file_path, tag=""):
    """Plot the monsoon current data using bokeh interactive plotting tool.

    Plotting power measurement data with bokeh to generate interactive plots.
    You can do interactive data analysis on the plot after generating with the
    provided widgets, which make the debugging much easier. To realize that,
    bokeh callback java scripting is used. View a sample html output file:
    https://drive.google.com/open?id=0Bwp8Cq841VnpT2dGUUxLYWZvVjA

    Args:
        mon_info: obj with information of monsoon measurement, including
                  monsoon device object, measurement frequency, duration and
                  offset etc.
        file_path: the path to the monsoon log file with current data

    Returns:
        plot: the plotting object of bokeh, optional, will be needed if multiple
           plots will be combined to one html file.
        dt: the datatable object of bokeh, optional, will be needed if multiple
           datatables will be combined to one html file.
    """

    log = logging.getLogger()
    log.info("Plot the power measurement data")
    #Get results as monsoon data object from the input file
    results = monsoon.MonsoonData.from_text_file(file_path)
    #Decouple current and timestamp data from the monsoon object
    current_data = []
    timestamps = []
    voltage = results[0].voltage
    [current_data.extend(x.data_points) for x in results]
    [timestamps.extend(x.timestamps) for x in results]
    period = 1 / float(mon_info.freq)
    time_relative = [x * period for x in range(len(current_data))]
    #Calculate the average current for the test
    current_data = [x * 1000 for x in current_data]
    avg_current = sum(current_data) / len(current_data)
    color = ['navy'] * len(current_data)

    #Preparing the data and source link for bokehn java callback
    source = ColumnDataSource(
        data=dict(x0=time_relative, y0=current_data, color=color))
    s2 = ColumnDataSource(
        data=dict(z0=[mon_info.duration],
                  y0=[round(avg_current, 2)],
                  x0=[round(avg_current * voltage, 2)],
                  z1=[round(avg_current * voltage * mon_info.duration, 2)],
                  z2=[round(avg_current * mon_info.duration, 2)]))
    #Setting up data table for the output
    columns = [
        TableColumn(field='z0', title='Total Duration (s)'),
        TableColumn(field='y0', title='Average Current (mA)'),
        TableColumn(field='x0', title='Average Power (4.2v) (mW)'),
        TableColumn(field='z1', title='Average Energy (mW*s)'),
        TableColumn(field='z2', title='Normalized Average Energy (mA*s)')
    ]
    dt = DataTable(source=s2,
                   columns=columns,
                   width=1300,
                   height=60,
                   editable=True)

    plot_title = file_path[file_path.rfind('/') + 1:-4] + tag
    output_file("%s/%s.html" % (mon_info.data_path, plot_title))
    TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
    # Create a new plot with the datatable above
    plot = figure(plot_width=1300,
                  plot_height=700,
                  title=plot_title,
                  tools=TOOLS,
                  output_backend="webgl")
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="width"))
    plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="height"))
    plot.line('x0', 'y0', source=source, line_width=2)
    plot.circle('x0', 'y0', source=source, size=0.5, fill_color='color')
    plot.xaxis.axis_label = 'Time (s)'
    plot.yaxis.axis_label = 'Current (mA)'
    plot.title.text_font_size = {'value': '15pt'}

    #Callback Java scripting
    source.callback = CustomJS(args=dict(mytable=dt),
                               code="""
    var inds = cb_obj.get('selected')['1d'].indices;
    var d1 = cb_obj.get('data');
    var d2 = mytable.get('source').get('data');
    ym = 0
    ts = 0
    d2['x0'] = []
    d2['y0'] = []
    d2['z1'] = []
    d2['z2'] = []
    d2['z0'] = []
    min=max=d1['x0'][inds[0]]
    if (inds.length==0) {return;}
    for (i = 0; i < inds.length; i++) {
    ym += d1['y0'][inds[i]]
    d1['color'][inds[i]] = "red"
    if (d1['x0'][inds[i]] < min) {
      min = d1['x0'][inds[i]]}
    if (d1['x0'][inds[i]] > max) {
      max = d1['x0'][inds[i]]}
    }
    ym /= inds.length
    ts = max - min
    dx0 = Math.round(ym*4.2*100.0)/100.0
    dy0 = Math.round(ym*100.0)/100.0
    dz1 = Math.round(ym*4.2*ts*100.0)/100.0
    dz2 = Math.round(ym*ts*100.0)/100.0
    dz0 = Math.round(ts*1000.0)/1000.0
    d2['z0'].push(dz0)
    d2['x0'].push(dx0)
    d2['y0'].push(dy0)
    d2['z1'].push(dz1)
    d2['z2'].push(dz2)
    mytable.trigger('change');
    """)

    #Layout the plot and the datatable bar
    l = layout([[dt], [plot]])
    save(l)
    return [plot, dt]