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 Aug 25, 2017
1 parent a577496 commit 6f65c38
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 6 deletions.
1 change: 1 addition & 0 deletions codespeed/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
# ('myexe', '21df2423ra'),
# ('myexe', 'L'),]

USE_ERROR_BARS = True # True to enable error bars on Timeline view
USE_MEDIAN_BANDS = True # True to enable median bands on Timeline view


Expand Down

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

61 changes: 55 additions & 6 deletions codespeed/static/js/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ function shouldPlotEquidistant() {
return $("#equidistant").is(':checked');
}

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

function shouldPlotQuartiles() {
return $("#show_quartile_bands").is(':checked');
}
Expand All @@ -50,6 +54,7 @@ function getConfiguration() {
env: $("input[name='environments']:checked").val(),
revs: $("#revisions option:selected").val(),
equid: $("#equidistant").is(':checked') ? "on" : "off",
error: $("#show_error_bars").is(':checked') ? "on" : "off",
quarts: $("#show_quartile_bands").is(':checked') ? "on" : "off",
extr: $("#show_extrema_bands").is(':checked') ? "on" : "off"
};
Expand Down Expand Up @@ -98,13 +103,34 @@ function getHighlighterConfig(median) {
function renderPlot(data) {
var plotdata = [],
series = [],
firstdates = [],
lastdates = [],
lastvalues = [];//hopefully the smallest values for determining significant digits.
seriesindex = [];
var errorSeries = 0;
var hiddenSeries = 0;
var mean = data['data_type'] === 'U';
var median = data['data_type'] === 'M';
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 (mean) {
$("span.options.mean").css("display", "inline");
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();
var seriesConfig = {
Expand Down Expand Up @@ -153,8 +179,15 @@ function renderPlot(data) {
}
series.push(seriesConfig);
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 @@ -202,7 +235,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 @@ -211,7 +245,7 @@ function renderPlot(data) {
highlighter: getHighlighterConfig(median),
cursor: {show:true, zoom:true, showTooltip:false, clickReset:true}
};
if (series.length > 4 + hiddenSeries) {
if (series.length > 4 + errorSeries + hiddenSeries) {
// Move legend outside plot area to unclutter
var labels = [];
for (var l in series) {
Expand All @@ -231,14 +265,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 Down Expand Up @@ -268,7 +311,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 @@ -280,6 +326,7 @@ function renderMiniplot(plotid, data) {
function render(data) {
$("#revisions").attr("disabled", false);
$("#equidistant").attr("disabled", false);
$("span.options.mean").css("display", "none");
$("span.options.median").css("display", "none");
$("#plotgrid").html("");
if(data.error !== "None") {
Expand Down Expand Up @@ -342,6 +389,7 @@ function initializeSite(event) {
$("input[name='benchmark']" ).change(updateUrl);
$("input[name='environments']").change(updateUrl);
$("#equidistant" ).change(updateUrl);
$("#show_error_bars" ).change(updateUrl);
$("#show_quartile_bands" ).change(updateUrl);
$("#show_extrema_bands" ).change(updateUrl);
}
Expand Down Expand Up @@ -397,6 +445,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");
$("#show_quartile_bands").prop('checked', valueOrDefault(event.parameters.quarts, defaults.quartiles) === "on");
$("#show_extrema_bands").prop('checked', valueOrDefault(event.parameters.extr, defaults.extrema) === "on");
}
Expand Down
8 changes: 8 additions & 0 deletions codespeed/templates/codespeed/timeline.html
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@
<input id="equidistant" name="equidistant" type="checkbox" />
<label for="equidistant">Equidistant</label>
</span>
{% if use_error_bars %}
<span class="options mean" title="Shows error bars in the plots" style="display: none">
<input id="show_error_bars" type="checkbox" name="show_error_bars" checked="checked"/>
<label for="show_error_bars">Show error bars</label>
</span>
{% endif %}
{% if use_median_bands %}
<span class="options median" title="Shows quartile bands in the plots" style="display: none">
<input id="show_quartile_bands" type="checkbox" name="show_quartile_bands" checked="checked"/>
Expand Down Expand Up @@ -114,6 +120,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 @@ -128,6 +135,7 @@
benchmark: "{{ defaultbenchmark }}",
environment: {{ defaultenvironment.id }},
equidistant: "{{ defaultequid }}",
error: "{{ defaulterr }}",
quartiles: "{{ defaultquarts }}",
extrema: "{{ defaultextr }}"
});
Expand Down
7 changes: 7 additions & 0 deletions codespeed/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,10 @@ def timeline(request):
defaultequid = data['equid']
else:
defaultequid = "off"
if 'error' in data:
defaulterr = data['error']
else:
defaulterr = "on"
if 'quarts' in data:
defaultquarts = data['quarts']
else:
Expand All @@ -479,6 +483,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
use_median_bands = hasattr(settings, 'USE_MEDIAN_BANDS') and settings.USE_MEDIAN_BANDS
return render_to_response('codespeed/timeline.html', {
'checkedexecutables': checkedexecutables,
Expand All @@ -494,8 +499,10 @@ def timeline(request):
'branch_list': branch_list,
'defaultbranch': defaultbranch,
'defaultequid': defaultequid,
'defaulterr': defaulterr,
'defaultquarts': defaultquarts,
'defaultextr': defaultextr,
'use_error_bars': use_error_bars,
'use_median_bands': use_median_bands,
}, context_instance=RequestContext(request))

Expand Down

0 comments on commit 6f65c38

Please sign in to comment.