Commit f6b08328 authored by olau@iola.dk's avatar olau@iola.dk

Added support for coloring the data points below a certain threshold


git-svn-id: https://flot.googlecode.com/svn/trunk@139 1e0a6537-2640-0410-bfb7-f154510ff394
parent 89ce1ca9
......@@ -53,14 +53,15 @@ not connected.
The format of a single series object is as follows:
{
color: color or number,
data: rawdata,
label: string,
lines: specific lines options,
bars: specific bars options,
points: specific points options,
xaxis: 1 or 2,
yaxis: 1 or 2,
color: color or number
data: rawdata
label: string
lines: specific lines options
bars: specific bars options
points: specific points options
threshold: specific threshold options
xaxis: 1 or 2
yaxis: 1 or 2
clickable: boolean
hoverable: boolean
shadowSize: number
......@@ -429,6 +430,11 @@ Customizing the data series
shadowSize: number
threshold: {
below: number
color: color
}
The most important options are "lines", "points" and "bars" that
specifies whether and how lines, points and bars should be shown for
each data series. In case you don't specify anything at all, Flot will
......@@ -477,6 +483,10 @@ extra colors by lightening and darkening colors in the theme.
"shadowSize" is the default size of shadows in pixels. Set it to 0 to
remove shadows.
"threshold" specifies that the data points below "below" should be
drawn with the specified color. This makes it easy to mark points
below 0, e.g. for budget data.
Customizing the grid
====================
......
......@@ -46,7 +46,12 @@ Changes:
data (and fixes issue 112).
- Step-wise charting: line charts have a new option "steps" that when
set to true connects the points with steps instead of diagonal lines.
set to true connects the points with horizontal/vertical steps
instead of diagonal lines.
- Thresholding: you can set a threshold and a color, and the data
points below that threshold will then get the color. Useful for
marking data below 0, for instance.
Bug fixes:
......
......@@ -16,7 +16,7 @@
<ul>
<li><a href="basic.html">Basic example</a></li>
<li><a href="graph-types.html">Different graph types</a> and <a href="setting-options.html">setting various options</a></li>
<li><a href="turning-series.html">Turning series on/off</a></li>
<li><a href="turning-series.html">Turning series on/off</a> and <a href="thresholding.html">thresholding the data</a></li>
<li><a href="selection.html">Selection support and zooming</a> and <a href="zooming.html">zooming with overview</a></li>
<li><a href="time.html">Plotting time series</a> and <a href="visitors.html">visitors per day with zooming and weekends</a></li>
<li><a href="dual-axis.html">Dual axis support</a></li>
......
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Flot Examples</title>
<link href="layout.css" rel="stylesheet" type="text/css"></link>
<!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../jquery.js"></script>
<script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
</head>
<body>
<h1>Flot Examples</h1>
<div id="placeholder" style="width:600px;height:300px;"></div>
<p>You can apply a specific color to the part of a data series
below a threshold. This is can be useful for highlighting negative
values, e.g. when displaying net results or what's in stock.</p>
<p class="controls">
<input type="button" value="Threshold at 5">
<input type="button" value="Threshold at 0">
<input type="button" value="Threshold at -2.5">
</p>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var d1 = [];
for (var i = 0; i <= 60; i += 1)
d1.push([i, parseInt(Math.random() * 30 - 10)]);
function doPlot(t) {
$.plot($("#placeholder"), [ {
data: d1,
color: "rgb(30, 180, 20)",
threshold: { below: t, color: "rgb(200, 20, 30)" },
lines: { steps: true }
} ]);
}
doPlot(0);
$(".controls input").click(function (e) {
e.preventDefault();
var t = parseFloat($(this).val().replace('Threshold at ', ''));
doPlot(t);
});
});
</script>
</body>
</html>
......@@ -75,6 +75,7 @@
fillColor: null,
align: "left" // or "center"
},
threshold: null, // or { below: number, color: color spec}
grid: {
color: "#545454", // primary color used for outline and labels
backgroundColor: null, // null for transparent, else color
......@@ -264,6 +265,10 @@
s.yaxis = axes.yaxis;
else if (s.yaxis == 2)
s.yaxis = axes.y2axis;
if (!s.threshold)
s.threshold = options.threshold;
s.subseries = null;
}
}
......@@ -290,12 +295,13 @@
incr = s.datapoints.incr,
axisx = s.xaxis, axisy = s.yaxis,
xmin = topSentry, xmax = bottomSentry,
ymin = topSentry, ymax = bottomSentry;
ymin = topSentry, ymax = bottomSentry,
x, y, p;
/*
// determine the increment
// examine data to find out how to copy
/*
for (j = 0; j < data.length; ++j) {
}*/
......@@ -303,7 +309,8 @@
axisx.used = axisy.used = true;
for (j = k = 0; j < data.length; ++j, k += incr) {
var x = null, y = null;
x = null;
y = null;
if (data[j] != null) {
x = data[j][0];
......@@ -336,26 +343,6 @@
points[k] = x;
}
s.bars.datapoints = s.lines.datapoints = s.points.datapoints = s.datapoints;
if (s.lines.show && s.lines.steps) {
var p = [];
// copy, inserting extra points to make steps
for (j = k = 0; j < points.length; j += incr, k += incr) {
if (j > 0
&& points[j - incr] != null
&& points[j] != null
&& points[j - incr + 1] != points[j + 1]) {
p[k] = points[j];
p[k + 1] = points[j - incr + 1];
k += incr;
}
p[k] = points[j];
p[k + 1] = points[j + 1];
}
s.lines.datapoints.points = p;
}
if (s.bars.show) {
// make sure we got room for the bar
var delta = s.bars.align == "left" ? 0 : -s.bars.barWidth/2;
......@@ -368,6 +355,96 @@
axisy.datamin = Math.min(axisy.datamin, ymin);
axisy.datamax = Math.max(axisy.datamax, ymax);
// step charts
if (s.lines.show && s.lines.steps) {
p = [];
// copy, inserting extra points to make steps
for (j = k = 0; j < points.length; j += incr, k += incr) {
x = points[j];
y = points[j + 1];
if (j > 0
&& points[j - incr] != null
&& x != null
&& points[j - incr + 1] != y) {
p[k] = x;
p[k + 1] = points[j - incr + 1];
k += incr;
}
p[k] = x;
p[k + 1] = y;
}
s.datapoints.linespoints = p;
}
// possibly split data points because of threshold
if (s.threshold) {
var orig = $.extend({}, s), thresholded = $.extend({}, s);
orig.datapoints = { points: [], incr: incr };
thresholded.datapoints = { points: [], incr: incr };
thresholded.color = s.threshold.color;
var below = s.threshold.below,
origpoints = orig.datapoints.points,
threspoints = thresholded.datapoints.points;
// ordinary points
for (j = 0; j < points.length; j += incr) {
x = points[j];
y = points[j + 1];
if (y < below)
p = threspoints;
else
p = origpoints;
p.push(x);
p.push(y);
}
// possibly split lines
if (s.lines.show) {
var lp = s.datapoints.linespoints || points;
origpoints = [];
threspoints = [];
p = origpoints;
for (j = 0; j < lp.length; j += incr) {
x = lp[j];
y = lp[j + 1];
var prevp = p;
if (y != null) {
if (y < below)
p = threspoints;
else
p = origpoints;
}
if (p != prevp && x != null && j > 0 && lp[j - incr] != null) {
// find intersection and add it to both
k = (x - lp[j - incr]) / (y - lp[j - incr + 1]) * (below - y) + x;
prevp.push(k);
prevp.push(below);
p.push(null); // start new segment
p.push(null);
p.push(k);
p.push(below);
}
p.push(x);
p.push(y);
}
orig.datapoints.linespoints = origpoints
thresholded.datapoints.linespoints = threspoints;
}
s.subseries = [orig, thresholded];
}
}
}
......@@ -870,8 +947,13 @@
function draw() {
drawGrid();
for (var i = 0; i < series.length; i++) {
drawSeries(series[i]);
for (var i = 0; i < series.length; ++i) {
var s = series[i];
if (s.subseries)
for (var j = 0; j < s.subseries.length; ++j)
drawSeries(s.subseries[j]);
else
drawSeries(s);
}
}
......@@ -1085,7 +1167,8 @@
function drawSeriesLines(series) {
function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
var points = datapoints.points, incr = datapoints.incr,
var points = datapoints.linespoints || datapoints.points,
incr = datapoints.incr,
prevx = null, prevy = null;
ctx.beginPath();
......@@ -1164,7 +1247,8 @@
}
function plotLineArea(datapoints, axisx, axisy) {
var points = datapoints.points, incr = datapoints.incr,
var points = datapoints.linespoints || datapoints.points,
incr = datapoints.incr,
bottom = Math.min(Math.max(0, axisy.min), axisy.max),
top, lastX = 0, areaOpen = false;
......@@ -1310,9 +1394,9 @@
ctx.lineWidth = sw;
ctx.strokeStyle = "rgba(0,0,0,0.1)";
var xoffset = 1;
plotLine(series.lines.datapoints, xoffset, Math.sqrt((lw/2 + sw/2)*(lw/2 + sw/2) - xoffset*xoffset), series.xaxis, series.yaxis);
plotLine(series.datapoints, xoffset, Math.sqrt((lw/2 + sw/2)*(lw/2 + sw/2) - xoffset*xoffset), series.xaxis, series.yaxis);
ctx.lineWidth = sw/2;
plotLine(series.lines.datapoints, xoffset, Math.sqrt((lw/2 + sw/4)*(lw/2 + sw/4) - xoffset*xoffset), series.xaxis, series.yaxis);
plotLine(series.datapoints, xoffset, Math.sqrt((lw/2 + sw/4)*(lw/2 + sw/4) - xoffset*xoffset), series.xaxis, series.yaxis);
}
ctx.lineWidth = lw;
......@@ -1320,11 +1404,11 @@
var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
if (fillStyle) {
ctx.fillStyle = fillStyle;
plotLineArea(series.lines.datapoints, series.xaxis, series.yaxis);
plotLineArea(series.datapoints, series.xaxis, series.yaxis);
}
if (lw > 0)
plotLine(series.lines.datapoints, 0, 0, series.xaxis, series.yaxis);
plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
ctx.restore();
}
......@@ -1358,17 +1442,17 @@
var w = sw / 2;
ctx.lineWidth = w;
ctx.strokeStyle = "rgba(0,0,0,0.1)";
plotPoints(series.points.datapoints, radius, null, w + w/2, 2 * Math.PI,
plotPoints(series.datapoints, radius, null, w + w/2, 2 * Math.PI,
series.xaxis, series.yaxis);
ctx.strokeStyle = "rgba(0,0,0,0.2)";
plotPoints(series.points.datapoints, radius, null, w/2, 2 * Math.PI,
plotPoints(series.datapoints, radius, null, w/2, 2 * Math.PI,
series.xaxis, series.yaxis);
}
ctx.lineWidth = lw;
ctx.strokeStyle = series.color;
plotPoints(series.points.datapoints, radius,
plotPoints(series.datapoints, radius,
getFillStyle(series.points, series.color), 0, 2 * Math.PI,
series.xaxis, series.yaxis);
ctx.restore();
......@@ -1475,7 +1559,7 @@
ctx.strokeStyle = series.color;
var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
plotBars(series.points.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
ctx.restore();
}
......@@ -1589,8 +1673,8 @@
var s = series[i],
axisx = s.xaxis,
axisy = s.yaxis,
points = s.points.datapoints.points,
incr = s.points.datapoints.incr,
points = s.datapoints.points,
incr = s.datapoints.incr,
mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
my = axisy.c2p(mouseY),
maxx = maxDistance / axisx.scale,
......@@ -1621,9 +1705,6 @@
}
if (s.bars.show && !item) { // no other point can be nearby
points = s.bars.datapoints.points;
incr = s.bars.datapoints.incr;
var barLeft = s.bars.align == "left" ? 0 : -s.bars.barWidth/2,
barRight = barLeft + s.bars.barWidth;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment