1 /* Flot plugin for plotting textual data or categories.
3 Copyright (c) 2007-2012 IOLA and Ole Laursen.
4 Licensed under the MIT license.
6 Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin
7 allows you to plot such a dataset directly.
9 To enable it, you must specify mode: "categories" on the axis with the textual
12 $.plot("#placeholder", data, { xaxis: { mode: "categories" } });
14 By default, the labels are ordered as they are met in the data series. If you
15 need a different ordering, you can specify "categories" on the axis options
16 and list the categories there:
20 categories: ["February", "March", "April"]
23 If you need to customize the distances between the categories, you can specify
24 "categories" as an object mapping labels to values
28 categories: { "February": 1, "March": 3, "April": 4 }
31 If you don't specify all categories, the remaining categories will be numbered
32 from the max value plus 1 (with a spacing of 1 between each).
34 Internally, the plugin works by transforming the input data through an auto-
35 generated mapping where the first category becomes 0, the second 1, etc.
36 Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this
37 is visible in hover and click events that return numbers rather than the
38 category labels). The plugin also overrides the tick generator to spit out the
39 categories as ticks instead of the values.
41 If you need to map a value back to its label, the mapping is always accessible
42 as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories.
56 function processRawData(plot, series, data, datapoints) {
57 // if categories are enabled, we need to disable
58 // auto-transformation to numbers so the strings are intact
59 // for later processing
61 var xCategories = series.xaxis.options.mode == "categories",
62 yCategories = series.yaxis.options.mode == "categories";
64 if (!(xCategories || yCategories))
67 var format = datapoints.format;
70 // FIXME: auto-detection should really not be defined here
73 format.push({ x: true, number: true, required: true });
74 format.push({ y: true, number: true, required: true });
76 if (s.bars.show || (s.lines.show && s.lines.fill)) {
77 var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
78 format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
79 if (s.bars.horizontal) {
80 delete format[format.length - 1].y;
81 format[format.length - 1].x = true;
85 datapoints.format = format;
88 for (var m = 0; m < format.length; ++m) {
89 if (format[m].x && xCategories)
90 format[m].number = false;
92 if (format[m].y && yCategories)
93 format[m].number = false;
97 function getNextIndex(categories) {
100 for (var v in categories)
101 if (categories[v] > index)
102 index = categories[v];
107 function categoriesTickGenerator(axis) {
109 for (var label in axis.categories) {
110 var v = axis.categories[label];
111 if (v >= axis.min && v <= axis.max)
112 res.push([v, label]);
115 res.sort(function (a, b) { return a[0] - b[0]; });
120 function setupCategoriesForAxis(series, axis, datapoints) {
121 if (series[axis].options.mode != "categories")
124 if (!series[axis].categories) {
126 var c = {}, o = series[axis].options.categories || {};
128 for (var i = 0; i < o.length; ++i)
136 series[axis].categories = c;
140 if (!series[axis].options.ticks)
141 series[axis].options.ticks = categoriesTickGenerator;
143 transformPointsOnAxis(datapoints, axis, series[axis].categories);
146 function transformPointsOnAxis(datapoints, axis, categories) {
147 // go through the points, transforming them
148 var points = datapoints.points,
149 ps = datapoints.pointsize,
150 format = datapoints.format,
151 formatColumn = axis.charAt(0),
152 index = getNextIndex(categories);
154 for (var i = 0; i < points.length; i += ps) {
155 if (points[i] == null)
158 for (var m = 0; m < ps; ++m) {
159 var val = points[i + m];
161 if (val == null || !format[m][formatColumn])
164 if (!(val in categories)) {
165 categories[val] = index;
169 points[i + m] = categories[val];
174 function processDatapoints(plot, series, datapoints) {
175 setupCategoriesForAxis(series, "xaxis", datapoints);
176 setupCategoriesForAxis(series, "yaxis", datapoints);
179 function init(plot) {
180 plot.hooks.processRawData.push(processRawData);
181 plot.hooks.processDatapoints.push(processDatapoints);
184 $.plot.plugins.push({