From patchwork Tue Jun 19 04:01:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Doan X-Patchwork-Id: 9423 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 9D0D323E1B for ; Tue, 19 Jun 2012 04:01:14 +0000 (UTC) Received: from mail-yw0-f52.google.com (mail-yw0-f52.google.com [209.85.213.52]) by fiordland.canonical.com (Postfix) with ESMTP id 42C87A187B2 for ; Tue, 19 Jun 2012 04:01:14 +0000 (UTC) Received: by yhpp61 with SMTP id p61so4831158yhp.11 for ; Mon, 18 Jun 2012 21:01:13 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :content-type:mime-version:x-launchpad-project:x-launchpad-branch :x-launchpad-message-rationale:x-launchpad-branch-revision-number :x-launchpad-notification-type:to:from:subject:message-id:date :reply-to:sender:errors-to:precedence:x-generated-by :x-launchpad-hash:x-gm-message-state; bh=DFssLRdeDY/LntUHDDukNhChc1vqtcM4xmsvz2IkSLI=; b=oZAAHHsCHXS9Z3cBZPkGUE/zTiHzYp1MPFrqu1f61GRqasWVKsbpQcNqZ14B6xolzp 1nW+Dr6z06x8u2B2PeygosV3v8SrXOUPgKDNs+5n0iTacT45U4npeM+EWG9B7IsPQQNz 3/UchvEitsA57ilbTJBExqkUXsL/UaKlgrDm12YBhlltno/x+OI8az+3ZytmGfkZKkG+ HBd3KqxOhuqaLZYlmErVvQMBSY9o84JuPuHu/7I/Vo0jJ9gqxXoSuwqqumVfIK3Z9Ssp WLd6QirKYRPy/hNH3VaDBN0eZrIt1/vkPMRjLCTMFE8Yrk62DrDh7vqvsbDwjUAiSeag cvXA== Received: by 10.50.87.227 with SMTP id bb3mr2420368igb.57.1340078473232; Mon, 18 Jun 2012 21:01:13 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp104406ibb; Mon, 18 Jun 2012 21:01:11 -0700 (PDT) Received: by 10.216.218.216 with SMTP id k66mr8776718wep.191.1340078471093; Mon, 18 Jun 2012 21:01:11 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id p3si24647212wia.6.2012.06.18.21.01.10 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 18 Jun 2012 21:01:11 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1Sgpcs-0000AF-GK for ; Tue, 19 Jun 2012 04:01:10 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id 6F499E00AD for ; Tue, 19 Jun 2012 04:01:10 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-scheduler X-Launchpad-Branch: ~linaro-validation/lava-scheduler/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 186 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-scheduler/trunk] Rev 186: fix the stacked graphing in reports Message-Id: <20120619040110.9507.51195.launchpad@ackee.canonical.com> Date: Tue, 19 Jun 2012 04:01:10 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="15435"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: d90580277da39ee80e1808e26a3ad9c1f314becb X-Gm-Message-State: ALoCoQmiY4sPWKnP4Qbj4DTMb8U6zasQxwWZYCQCsCj4PCoqin/rJ83kiE9VJoZb3oW43/K3yb3Y ------------------------------------------------------------ revno: 186 committer: Andy Doan branch nick: lava-scheduler timestamp: Mon 2012-06-18 18:34:04 -0500 message: fix the stacked graphing in reports I omitted this plugin when I converted to using own copy of flot. Not using this skews the way the graph looks added: lava_scheduler_app/static/lava_scheduler_app/js/jquery.flot.stack.js modified: lava_scheduler_app/templates/lava_scheduler_app/_content.html --- lp:lava-scheduler https://code.launchpad.net/~linaro-validation/lava-scheduler/trunk You are subscribed to branch lp:lava-scheduler. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-scheduler/trunk/+edit-subscription === added file 'lava_scheduler_app/static/lava_scheduler_app/js/jquery.flot.stack.js' --- lava_scheduler_app/static/lava_scheduler_app/js/jquery.flot.stack.js 1970-01-01 00:00:00 +0000 +++ lava_scheduler_app/static/lava_scheduler_app/js/jquery.flot.stack.js 2012-06-18 23:34:04 +0000 @@ -0,0 +1,184 @@ +/* +Flot plugin for stacking data sets, i.e. putting them on top of each +other, for accumulative graphs. + +The plugin assumes the data is sorted on x (or y if stacking +horizontally). For line charts, it is assumed that if a line has an +undefined gap (from a null point), then the line above it should have +the same gap - insert zeros instead of "null" if you want another +behaviour. This also holds for the start and end of the chart. Note +that stacking a mix of positive and negative values in most instances +doesn't make sense (so it looks weird). + +Two or more series are stacked when their "stack" attribute is set to +the same key (which can be any number or string or just "true"). To +specify the default stack, you can set + + series: { + stack: null or true or key (number/string) + } + +or specify it for a specific series + + $.plot($("#placeholder"), [{ data: [ ... ], stack: true }]) + +The stacking order is determined by the order of the data series in +the array (later series end up on top of the previous). + +Internally, the plugin modifies the datapoints in each series, adding +an offset to the y value. For line series, extra data points are +inserted through interpolation. If there's a second y value, it's also +adjusted (e.g for bar charts or filled areas). +*/ + +(function ($) { + var options = { + series: { stack: null } // or number/string + }; + + function init(plot) { + function findMatchingSeries(s, allseries) { + var res = null + for (var i = 0; i < allseries.length; ++i) { + if (s == allseries[i]) + break; + + if (allseries[i].stack == s.stack) + res = allseries[i]; + } + + return res; + } + + function stackData(plot, s, datapoints) { + if (s.stack == null) + return; + + var other = findMatchingSeries(s, plot.getData()); + if (!other) + return; + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + horizontal = s.bars.horizontal, + withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y), + withsteps = withlines && s.lines.steps, + fromgap = true, + keyOffset = horizontal ? 1 : 0, + accumulateOffset = horizontal ? 0 : 1, + i = 0, j = 0, l; + + while (true) { + if (i >= points.length) + break; + + l = newpoints.length; + + if (points[i] == null) { + // copy gaps + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + i += ps; + } + else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + } + i += ps; + } + else if (otherpoints[j] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) + newpoints.push(null); + fromgap = true; + j += otherps; + } + else { + // cases where we actually got two points + px = points[i + keyOffset]; + py = points[i + accumulateOffset]; + qx = otherpoints[j + keyOffset]; + qy = otherpoints[j + accumulateOffset]; + bottom = 0; + + if (px == qx) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + newpoints[l + accumulateOffset] += qy; + bottom = qy; + + i += ps; + j += otherps; + } + else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + if (withlines && i > 0 && points[i - ps] != null) { + intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); + newpoints.push(qx); + newpoints.push(intery + qy); + for (m = 2; m < ps; ++m) + newpoints.push(points[i + m]); + bottom = qy; + } + + j += otherps; + } + else { // px < qx + if (fromgap && withlines) { + // if we come from a gap, we just skip this point + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + // we might be able to interpolate a point below, + // this can give us a better y + if (withlines && j > 0 && otherpoints[j - otherps] != null) + bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); + + newpoints[l + accumulateOffset] += bottom; + + i += ps; + } + + fromgap = false; + + if (l != newpoints.length && withbottom) + newpoints[l + 2] += bottom; + } + + // maintain the line steps invariant + if (withsteps && l != newpoints.length && l > 0 + && newpoints[l] != null + && newpoints[l] != newpoints[l - ps] + && newpoints[l + 1] != newpoints[l - ps + 1]) { + for (m = 0; m < ps; ++m) + newpoints[l + ps + m] = newpoints[l + m]; + newpoints[l + 1] = newpoints[l - ps + 1]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push(stackData); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'stack', + version: '1.2' + }); +})(jQuery); === modified file 'lava_scheduler_app/templates/lava_scheduler_app/_content.html' --- lava_scheduler_app/templates/lava_scheduler_app/_content.html 2012-06-18 18:49:51 +0000 +++ lava_scheduler_app/templates/lava_scheduler_app/_content.html 2012-06-18 23:34:04 +0000 @@ -6,4 +6,5 @@ + {% endblock %}