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

Generalized the data normalization step so it can be parameterized

with a format spec (this should also fix the problem of bar bottoms
not affecting the axis scaling), made the heuristic for determing the
number of axis ticks to aim for smarter, added a new image plugin for
plotting images


git-svn-id: https://flot.googlecode.com/svn/trunk@177 1e0a6537-2640-0410-bfb7-f154510ff394
parent 0dd400db
......@@ -915,6 +915,26 @@ Currently available hooks (when in doubt, check the Flot source):
points and sets datapoints.pointsize to the size of the points,
Flot will skip the copying/normalization step for this series.
In any case, you might be interested in setting datapoints.format,
an array of objects for specifying how a point is normalized and
how it interferes with axis scaling.
The default format array for points is something along the lines of:
[
{ x: true, number: true, required: true },
{ y: true, number: true, required: true }
]
The first object means that for the first coordinate it should be
taken into account when scaling the x axis, that it must be a
number, and that it is required - so if it is null or cannot be
converted to a number, the whole point will be zeroed out with
nulls. Beyond these you can also specify "default". If the
coordinate is null and default is set, then default is used for the
value. This is for instance handy for bars where we can omit the
third coordinate (the bottom of the bar) which then defaults to 0.
- processDatapoints [phase 3]
......
......@@ -89,8 +89,8 @@ Changes:
- Hooks: you can register functions that are called while Flot is
crunching the data and doing the plot. This can be used to modify
Flot without changing the source, useful for writing plugins. At
this point only some hooks are defined.
Flot without changing the source, useful for writing plugins. Some
hooks are defined, more are likely to come.
- Threshold plugin: you can set a threshold and a color, and the data
points below that threshold will then get the color. Useful for
......@@ -103,6 +103,8 @@ Changes:
- Crosshairs plugin: trace the mouse position on the axes, enable with
crosshair: { mode: "x"} (see the new tracking example for a use).
- Image plugin: plot prerendered images.
Bug fixes:
......@@ -140,6 +142,8 @@ Bug fixes:
with vertical lines.
- Round tick positions to avoid possible problems with fractions
(suggestion by Fred, issue 130).
- Made the heuristic for determining how many ticks to aim for a bit
smarter.
Flot 0.5
......
<!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>
<script language="javascript" type="text/javascript" src="../jquery.flot.image.js"></script>
</head>
<body>
<h1>Flot Examples</h1>
<div id="placeholder" style="width:400px;height:400px;"></div>
<p>The Cat's Eye Nebula (picture taken with <a href="http://hubblesite.org/gallery/album/nebula/pr2004027a/">Hubble</a>).</p>
<p>With the image plugin, you can plot images. This is for example
useful for getting ticks on complex prerendered visualizations.
Instead of inputting data points, you put in the images and where
their two opposite corners are supposed to be in plot space.</p>
<p>Images represent a little further complication because you need
to make sure they are loaded before you can use them (Flot skips
incomplete images). The plugin comes with a couple of helpers
for doing that.</p>
<script id="source" language="javascript" type="text/javascript">
$(function () {
var data = [ [ ["hs-2004-27-a-large_web.jpg", -10, -10, 10, 10] ] ];
var options = {
series: { images: { show: true } },
xaxis: { min: -8, max: 4 },
yaxis: { min: -8, max: 4 }
};
$.plot.image.loadDataImages(data, options, function () {
$.plot($("#placeholder"), data, options);
});
});
</script>
</body>
</html>
......@@ -35,7 +35,8 @@
<li><a href="dual-axis.html">Dual axis support</a></li>
<li><a href="thresholding.html">Thresholding the data</a> (with plugin)</li>
<li><a href="stacking.html">Stacked charts</a> (with plugin)</li>
<li><a href="tracking.html">Tracking curves with crosshair</a></li>
<li><a href="tracking.html">Tracking curves with crosshair</a> (with plugin)</li>
<li><a href="image.html">Plotting prerendered images</a> (with plugin)</li>
</ul>
</body>
</html>
......@@ -303,8 +303,16 @@
s.color = colors[s.color].toString();
// turn on lines automatically in case nothing is set
if (s.lines.show == null && !s.bars.show && !s.points.show)
if (s.lines.show == null) {
var v, show = true;
for (var v in s)
if (s[v].show) {
show = false;
break;
}
if (show)
s.lines.show = true;
}
// setup axes
s.xaxis = axisSpecToRealAxis(s, "xaxis");
......@@ -316,7 +324,7 @@
var topSentry = Number.POSITIVE_INFINITY,
bottomSentry = Number.NEGATIVE_INFINITY,
i, j, k, m, length,
s, points, ps, x, y, axis;
s, points, ps, x, y, axis, val, f, p;
for (axis in axes) {
axes[axis].datamin = topSentry;
......@@ -344,23 +352,25 @@
for (i = 0; i < series.length; ++i) {
s = series[i];
if (s.datapoints.pointsize != null)
continue; // already filled in
var data = s.data, format = s.datapoints.format;
var data = s.data, format = [], p;
if (!format) {
format = []
// find out how to copy
format.push({ x: true, number: true, required: true })
format.push({ y: true, number: true, required: true })
// determine the point size
if (s.bars.show) {
s.datapoints.pointsize = 3;
format.push({ d: 0 });
if (s.bars.show)
format.push({ y: true, number: true, required: false, default: 0 });
s.datapoints.format = format;
}
else
s.datapoints.pointsize = 2;
/*
// examine data to find out how to copy
for (j = 0; j < data.length; ++j) {
}*/
if (s.datapoints.pointsize != null)
continue; // already filled in
if (s.datapoints.pointsize == null)
s.datapoints.pointsize = format.length;
ps = s.datapoints.pointsize;
points = s.datapoints.points;
......@@ -371,54 +381,62 @@
for (j = k = 0; j < data.length; ++j, k += ps) {
p = data[j];
if (p != null) {
x = p[0];
y = p[1];
}
else
y = x = null;
var nullify = p == null;
if (!nullify) {
for (m = 0; m < ps; ++m) {
val = p[m];
f = format[m];
if (x != null) {
x = +x; // convert to number
if (isNaN(x))
x = null;
if (f) {
if (f.number && val != null) {
val = +val; // convert to number
if (isNaN(val))
val = null;
}
if (y != null) {
y = +y; // convert to number
if (isNaN(y))
y = null;
if (val == null) {
if (f.required) {
// extract min/max info before we whack it
if (f.x)
updateAxis(s.xaxis, val, val)
if (f.y)
updateAxis(s.yaxis, val, val)
val = null;
nullify = true;
}
// check validity of point, making sure both are cleared
if (x == null && y != null) {
// extract min/max info before we whack
updateAxis(s.yaxis, y, y);
y = null;
if (f.default != null)
val = f.default;
}
}
if (y == null && x != null) {
updateAxis(s.xaxis, x, x);
x = null;
points[k + m] = val;
}
}
if (insertSteps && x != null && k > 0
if (nullify) {
for (m = 0; m < ps; ++m)
points[k + m] = null;
}
else {
// a little bit of line specific stuff that
// perhaps shouldn't be here, but lacking
// better means...
if (insertSteps && k > 0
&& points[k - ps] != null
&& points[k - ps] != x && points[k - ps + 1] != y) {
&& points[k - ps] != points[k]
&& points[k - ps + 1] != points[k + 1]) {
// copy the point to make room for a middle point
for (m = 0; m < ps; ++m)
points[k + ps + m] = points[k + m];
// middle point has same y
points[k + 1] = points[k - ps + 1];
points[k] = x;
// copy the remainding from real point
for (m = 2; m < ps; ++m)
points[k + m] = p[m] == null ? format[m-2].d : p[m];
// we've added a point, better reflect that
k += ps;
}
for (m = 2; m < ps; ++m)
points[k + m] = p == null || p[m] == null ? format[m-2].d : p[m];
points[k] = x;
points[k + 1] = y;
}
}
}
......@@ -438,22 +456,28 @@
xmax = bottomSentry, ymax = bottomSentry;
for (j = 0; j < points.length; j += ps) {
x = points[j];
if (x == null)
if (points[j] == null)
continue;
if (x < xmin)
xmin = x;
if (x > xmax)
xmax = x;
y = points[j + 1];
for (m = 0; m < ps; ++m) {
val = points[j + m];
f = format[m];
if (!f)
continue
if (y < ymin)
ymin = y;
if (y > ymax)
ymax = y;
if (f.x) {
if (val < xmin)
xmin = val;
if (val > xmax)
xmax = val;
}
if (f.y) {
if (val < ymin)
ymin = val;
if (val > ymax)
ymax = val;
}
}
}
if (s.bars.show) {
......@@ -627,12 +651,14 @@
if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0)
noTicks = axisOptions.ticks;
else if (axis == axes.xaxis || axis == axes.x2axis)
noTicks = canvasWidth / 100;
// heuristic based on the model a*sqrt(x) fitted to
// some reasonable data points
noTicks = 0.3 * Math.sqrt(canvasWidth);
else
noTicks = canvasHeight / 60;
noTicks = 0.3 * Math.sqrt(canvasHeight);
var delta = (axis.max - axis.min) / noTicks;
var size, generator, unit, formatter, i, magn, norm;
var delta = (axis.max - axis.min) / noTicks,
size, generator, unit, formatter, i, magn, norm;
if (axisOptions.mode == "time") {
// pretty handling of time
......@@ -2276,10 +2302,6 @@
return new Color(this.r, this.b, this.g, this.a);
};
var limit = function(val,minVal,maxVal) {
return Math.max(Math.min(val, maxVal), minVal);
};
this.normalize = function() {
this.r = clamp(0, parseInt(this.r), 255);
this.g = clamp(0, parseInt(this.g), 255);
......
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