Commit 93c7c941 authored by Ole Laursen's avatar Ole Laursen

New categories plugin with support for plotting categories/textual

data directly; also tick generators now get the whole axis rather than
just min/max
parent b52f74e5
...@@ -187,7 +187,7 @@ Customizing the axes ...@@ -187,7 +187,7 @@ Customizing the axes
transform: null or fn: number -> number transform: null or fn: number -> number
inverseTransform: null or fn: number -> number inverseTransform: null or fn: number -> number
ticks: null or number or ticks array or (fn: range -> ticks array) ticks: null or number or ticks array or (fn: axis -> ticks array)
tickSize: number or array tickSize: number or array
minTickSize: number or array minTickSize: number or array
tickFormatter: (fn: number, object -> string) or string tickFormatter: (fn: number, object -> string) or string
......
...@@ -25,6 +25,11 @@ Changes: ...@@ -25,6 +25,11 @@ Changes:
- Support for multiple thresholds in thresholds plugin (patch by - Support for multiple thresholds in thresholds plugin (patch by
Arnaud Bellec, issue 523). Arnaud Bellec, issue 523).
- Support for plotting categories/textual data directly with new
categories plugin.
- Tick generators now get the whole axis rather than just min/max.
Bug fixes Bug fixes
- Fix problem with null values and pie plugin (patch by gcruxifix, - Fix problem with null values and pie plugin (patch by gcruxifix,
......
<!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">
<!--[if lte IE 8]><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.categories.js"></script>
</head>
<body>
<h1>Flot Examples</h1>
<div id="placeholder" style="width:600px;height:300px;"></div>
<p>With the categories plugin you can plot categories/textual data
easily.</p>
<script type="text/javascript">
$(function () {
var data = [ ["January", 10], ["February", 8], ["March", 4], ["April", 13], ["May", 17], ["June", 9] ];
$.plot($("#placeholder"), [ data ], {
series: {
bars: {
show: true,
barWidth: 0.6,
align: "center" }
},
xaxis: {
mode: "categories",
tickLength: 0
}
});
});
</script>
</body>
</html>
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<ul> <ul>
<li><a href="basic.html">Basic example</a></li> <li><a href="basic.html">Basic example</a></li>
<li><a href="graph-types.html">Different graph types</a></li> <li><a href="graph-types.html">Different graph types</a> and <a href="categories.html">simple categories/textual data</a></li>
<li><a href="setting-options.html">Setting various options</a> and <a href="annotating.html">annotating a chart</a></li> <li><a href="setting-options.html">Setting various options</a> and <a href="annotating.html">annotating a chart</a></li>
<li><a href="ajax.html">Updating graphs with AJAX</a> and <a href="realtime.html">real-time updates</a></li> <li><a href="ajax.html">Updating graphs with AJAX</a> and <a href="realtime.html">real-time updates</a></li>
</ul> </ul>
......
/*
Flot plugin for plotting textual data or categories. Consider a
dataset like [["February", 34], ["March", 20], ...]. This plugin
allows you to plot such a dataset directly.
To enable it, you must specify mode: "categories" on the axis with the
textual labels, e.g.
$.plot("#placeholder", data, { xaxis: { mode: "categories" } });
By default, the labels are ordered as they are met in the data series.
If you need a different ordering, you can specify "categories" on the
axis options and list the categories there:
xaxis: {
mode: "categories",
categories: ["February", "March", "April"]
}
If you need to customize the distances between the categories, you can
specify "categories" as an object mapping labels to values
xaxis: {
mode: "categories",
categories: { "February": 1, "March": 3, "April": 4 }
}
If you don't specify all categories, the remaining encountered
categories will be numbered from the max value plus 1 (with a spacing
of 1 between each).
Internally, the plugin works by transforming the input data through an
auto-generated mapping where the first category becomes 0, the second
1, etc. Hence, a point like ["February", 34] becomes [0, 34]
internally in Flot (this is visible in hover and click events that
return numbers rather than the category labels). The plugin also
overrides the tick generator to spit out the categories as ticks
instead of the values.
If you need to map a value back to its label, the mapping is always
accessible as "categories" on the axis object, e.g.
plot.getAxes().xaxis.categories.
*/
(function ($) {
var options = {
xaxis: {
categories: null
},
yaxis: {
categories: null
}
};
function processRawData(plot, series, data, datapoints) {
// if categories are enabled, we need to disable
// auto-transformation to numbers so the strings are intact
// for later processing
var xCategories = series.xaxis.options.mode == "categories",
yCategories = series.yaxis.options.mode == "categories";
if (!(xCategories || yCategories))
return;
var format = datapoints.format;
if (!format) {
// FIXME: auto-detection should really not be defined here
var s = series;
format = [];
format.push({ x: true, number: true, required: true });
format.push({ y: true, number: true, required: true });
if (s.bars.show || (s.lines.show && s.lines.fill)) {
format.push({ y: true, number: true, required: false, defaultValue: 0 });
if (s.bars.horizontal) {
delete format[format.length - 1].y;
format[format.length - 1].x = true;
}
}
datapoints.format = format;
}
for (var m = 0; m < format.length; ++m) {
if (format[m].x && xCategories)
format[m].number = false;
if (format[m].y && yCategories)
format[m].number = false;
}
}
function getNextIndex(categories) {
var index = -1;
for (var v in categories)
if (categories[v] > index)
index = categories[v];
return index + 1;
}
function categoriesTickGenerator(axis) {
var res = [];
for (var label in axis.categories) {
var v = axis.categories[label];
if (v >= axis.min && v <= axis.max)
res.push([v, label]);
}
res.sort(function (a, b) { return a[0] - b[0]; });
return res;
}
function setupCategoriesForAxis(series, axis, datapoints) {
if (series[axis].options.mode != "categories")
return;
if (!series[axis].categories) {
// parse options
var c = {}, o = series[axis].options.categories || {};
if ($.isArray(o)) {
for (var i = 0; i < o.length; ++i)
c[o[i]] = i;
}
else {
for (var v in o)
c[v] = o[v];
}
series[axis].categories = c;
}
// fix ticks
if (!series[axis].options.ticks)
series[axis].options.ticks = categoriesTickGenerator;
transformPointsOnAxis(datapoints, axis, series[axis].categories);
}
function transformPointsOnAxis(datapoints, axis, categories) {
// go through the points, transforming them
var points = datapoints.points,
ps = datapoints.pointsize,
format = datapoints.format,
formatColumn = axis.charAt(0),
index = getNextIndex(categories);
for (var i = 0; i < points.length; i += ps) {
if (points[i] == null)
continue;
for (var m = 0; m < ps; ++m) {
var val = points[i + m];
if (val == null || !format[m][formatColumn])
continue;
if (!(val in categories)) {
categories[val] = index;
++index;
}
points[i + m] = categories[val];
}
}
}
function processDatapoints(plot, series, datapoints) {
setupCategoriesForAxis(series, "xaxis", datapoints);
setupCategoriesForAxis(series, "yaxis", datapoints);
}
function init(plot) {
plot.hooks.processRawData.push(processRawData);
plot.hooks.processDatapoints.push(processDatapoints);
}
$.plot.plugins.push({
init: init,
options: options,
name: 'categories',
version: '1.0'
});
})(jQuery);
...@@ -1376,7 +1376,7 @@ ...@@ -1376,7 +1376,7 @@
// we might need an extra decimal since forced // we might need an extra decimal since forced
// ticks don't necessarily fit naturally // ticks don't necessarily fit naturally
if (axis.mode != "time" && opts.tickDecimals == null) { if (!axis.mode && opts.tickDecimals == null) {
var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1), var extraDec = Math.max(0, -Math.floor(Math.log(delta) / Math.LN10) + 1),
ts = generator(axis); ts = generator(axis);
...@@ -1403,7 +1403,7 @@ ...@@ -1403,7 +1403,7 @@
else if (oticks) { else if (oticks) {
if ($.isFunction(oticks)) if ($.isFunction(oticks))
// generate the ticks // generate the ticks
ticks = oticks({ min: axis.min, max: axis.max }); ticks = oticks(axis);
else else
ticks = oticks; ticks = oticks;
} }
......
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