Skip to content

Commit

Permalink
Implement error bars using standard deviation on timeline plots
Browse files Browse the repository at this point in the history
jqplot.ohlcRendererWithErrorBars.min.js is the standard OHLC Renderer plugin
from jqPlot 1.0.9 (revision d96a669) with the error-bar addition given here:

https://bitbucket.org/cleonello/jqplot/issues/35/add-error-bar-capability#comment-141580
  • Loading branch information
daniloaf authored and str4d committed Jun 9, 2016
1 parent a85b782 commit 848adf3
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 9 deletions.
2 changes: 2 additions & 0 deletions codespeed/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@
# COMP_EXECUTABLES = [
# ('myexe', '21df2423ra'),
# ('myexe', 'L'),]

USE_ERROR_BARS = True # True to enable error bars on Timeline view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 53 additions & 7 deletions codespeed/static/js/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,19 @@ function shouldPlotEquidistant() {
return $("#equidistant").is(':checked');
}

function shouldPlotErrorBars() {
return $("#show_error_bars").is(':checked');
}

function getConfiguration() {
var config = {
exe: readCheckbox("input[name='executable']:checked"),
base: $("#baseline option:selected").val(),
ben: $("input[name='benchmark']:checked").val(),
env: $("input[name='environments']:checked").val(),
revs: $("#revisions option:selected").val(),
equid: $("#equidistant").is(':checked') ? "on" : "off"
equid: $("#equidistant").is(':checked') ? "on" : "off",
error: $("#show_error_bars").is(':checked') ? "on" : "off"
};

var branch = readCheckbox("input[name='branch']:checked");
Expand Down Expand Up @@ -64,17 +69,41 @@ function OnMarkerClickHandler(ev, gridpos, datapos, neighbor, plot) {
function renderPlot(data) {
var plotdata = [],
series = [],
firstdates = [],
lastdates = [],
lastvalues = [];//hopefully the smallest values for determining significant digits.
seriesindex = [];
var errorSeries = 0;
for (var branch in data.branches) {
// NOTE: Currently, only the "default" branch is shown in the timeline
for (var exe_id in data.branches[branch]) {
if (shouldPlotErrorBars()) {
marker = false;
var error = new Array();
for (res in data["branches"][branch][exe_id]) {
var date = data["branches"][branch][exe_id][res][0];
var value = data["branches"][branch][exe_id][res][1];
var std_dev = data["branches"][branch][exe_id][res][2];
error.push([date, value - std_dev, value + std_dev, data["branches"][branch][exe_id][res][3]]);
}
plotdata.push(error);
series.push({renderer:$.jqplot.OHLCRenderer, rendererOptions:{errorBar:true}, showLabel: false, showMarker: true,
"label": $("label[for*='executable" + getColor(exe_id) + "']").html() + " error", color: "#C0C0C0"});
errorSeries++;
}
// FIXME if (branch !== "default") { label += " - " + branch; }
var label = $("label[for*='executable" + exe_id + "']").html();
series.push({"label": label, "color": getColor(exe_id)});
seriesindex.push(exe_id);
plotdata.push(data.branches[branch][exe_id]);
lastvalues.push(data.branches[branch][exe_id][0][1]);
var exeData = data.branches[branch][exe_id];
plotdata.push(exeData);
var startDate = new Date(exeData[exeData.length - 1][0])
var endDate = new Date(exeData[0][0]);
startDate.setDate(startDate.getDate() - 1);
endDate.setDate(endDate.getDate() + 1);
firstdates.push(startDate);
lastdates.push(endDate);
lastvalues.push(exeData[0][1]);
}
//determine significant digits
var digits = 2;
Expand Down Expand Up @@ -115,7 +144,8 @@ function renderPlot(data) {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickOptions:{formatString:'%b %d'},
pad: 1.01,
autoscale:true,
min: Math.min.apply(Math, firstdates),
max: Math.max.apply(Math, lastdates),
rendererOptions:{sortMergedLabels:true} /* only relevant when
$.jqplot.CategoryAxisRenderer is used */
}
Expand All @@ -129,7 +159,7 @@ function renderPlot(data) {
},
cursor:{show:true, zoom:true, showTooltip:false, clickReset:true}
};
if (series.length > 4) {
if (series.length > 4 + errorSeries) {
// Move legend outside plot area to unclutter
var labels = [];
for (var l in series) {
Expand All @@ -149,14 +179,23 @@ function renderPlot(data) {

function renderMiniplot(plotid, data) {
var plotdata = [],
series = [];
series = [],
firstdates = [],
lastdates = [];

for (var branch in data.branches) {
for (var id in data.branches[branch]) {
series.push({
"label": $("label[for*='executable" + id + "']").html(),
"color": getColor(id)
});
var exeData = data.branches[branch][id];
var startDate = new Date(exeData[exeData.length - 1][0])
var endDate = new Date(exeData[0][0]);
startDate.setDate(startDate.getDate() - 1);
endDate.setDate(endDate.getDate() + 1);
firstdates.push(startDate);
lastdates.push(endDate);
plotdata.push(data.branches[branch][id]);
}
}
Expand All @@ -181,7 +220,10 @@ function renderMiniplot(plotid, data) {
renderer:$.jqplot.DateAxisRenderer,
pad: 1.01,
autoscale:true,
showTicks: false
showTicks: false,
min: Math.min.apply(Math, firstdates),
max: Math.max.apply(Math, lastdates),
rendererOptions:{sortMergedLabels:true}
}
},
highlighter: {show:false},
Expand All @@ -193,6 +235,7 @@ function renderMiniplot(plotid, data) {
function render(data) {
$("#revisions").attr("disabled", false);
$("#equidistant").attr("disabled", false);
$("#show_error_bars").attr("disabled", false);
$("#plotgrid").html("");
if(data.error !== "None") {
var h = $("#content").height();//get height for error message
Expand All @@ -208,6 +251,7 @@ function render(data) {
//Render Grid of plots
$("#revisions").attr("disabled",true);
$("#equidistant").attr("disabled", true);
$("#show_error_bars").attr("disabled",true);
for (var bench in data.timelines) {
var plotid = "plot_" + data.timelines[bench].benchmark_id;
$("#plotgrid").append('<div id="' + plotid + '" class="miniplot"></div>');
Expand Down Expand Up @@ -254,6 +298,7 @@ function initializeSite(event) {
$("input[name='benchmark']" ).change(updateUrl);
$("input[name='environments']").change(updateUrl);
$("#equidistant" ).change(updateUrl);
$("#show_error_bars" ).change(updateUrl);
}

function refreshSite(event) {
Expand Down Expand Up @@ -307,6 +352,7 @@ function setValuesOfInputFields(event) {

$("#baselinecolor").css("background-color", baselineColor);
$("#equidistant").prop('checked', valueOrDefault(event.parameters.equid, defaults.equidistant) === "on");
$("#show_error_bars").prop('checked', valueOrDefault(event.parameters.error, defaults.error) === "on");
}

function init(def) {
Expand Down
10 changes: 9 additions & 1 deletion codespeed/templates/codespeed/timeline.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@
<input id="equidistant" name="equidistant" type="checkbox" />
<label for="equidistant">Equidistant</label>
</span>
{% if use_error_bars %}
<span class="options" title="Shows error bars in the plots">
<input id="show_error_bars" type="checkbox" name="show_error_bars" checked="checked"/>
<label for="show_error_bars">Show error bars</label>
</span>
{% endif %}
<a id="permalink" href="#">Permalink</a>
</div>
<div id="content" class="clearfix">
Expand All @@ -102,6 +108,7 @@
<script type="text/javascript" src="{{ STATIC_URL }}js/jqplot/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/jqplot/jqplot.canvasTextRenderer.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/jqplot/jqplot.canvasAxisLabelRenderer.min.js"></script>
<script type="text/javascript" src="{{ STATIC_URL }}js/jqplot/jqplot.ohlcRendererWithErrorBars.min.js"></script>
<script type="text/javascript">
var CHANGES_URL = "{% url "changes" %}";
</script>
Expand All @@ -115,7 +122,8 @@
branches: [{% for b in branch_list %}"{{ branch }}", {% endfor %}],
benchmark: "{{ defaultbenchmark }}",
environment: {{ defaultenvironment.id }},
equidistant: "{{ defaultequid }}"
equidistant: "{{ defaultequid }}",
error: "on"
});
});
</script>
Expand Down
4 changes: 3 additions & 1 deletion codespeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ def timeline(request):
executables = {}
for proj in Project.objects.filter(track=True):
executables[proj] = Executable.objects.filter(project=proj)
use_error_bars = hasattr(settings, 'USE_ERROR_BARS') and settings.USE_ERROR_BARS
return render_to_response('codespeed/timeline.html', {
'checkedexecutables': checkedexecutables,
'defaultbaseline': defaultbaseline,
Expand All @@ -442,7 +443,8 @@ def timeline(request):
'environments': enviros,
'branch_list': branch_list,
'defaultbranch': defaultbranch,
'defaultequid': defaultequid
'defaultequid': defaultequid,
'use_error_bars': use_error_bars
}, context_instance=RequestContext(request))


Expand Down

0 comments on commit 848adf3

Please sign in to comment.