Commit 865688a1 authored by olau@iola.dk's avatar olau@iola.dk

Some further tweaks to time series handling, implemented support for tickSize...

Some further tweaks to time series handling, implemented support for tickSize and minTickSize, automatic detection of no. ticks

git-svn-id: https://flot.googlecode.com/svn/trunk@45 1e0a6537-2640-0410-bfb7-f154510ff394
parent dfba9f38
...@@ -148,6 +148,8 @@ Customizing the axes ...@@ -148,6 +148,8 @@ Customizing the axes
max: null or number max: null or number
autoscaleMargin: null or number autoscaleMargin: null or number
ticks: null or number or ticks array or (fn: range -> ticks array) ticks: null or number or ticks array or (fn: range -> ticks array)
tickSize: number or array
minTickSize: number or array
tickFormatter: (fn: number, object -> string) or string tickFormatter: (fn: number, object -> string) or string
tickDecimals: null or number tickDecimals: null or number
} }
...@@ -171,41 +173,25 @@ nearest whole tick. The default value is "null" for the x axis and ...@@ -171,41 +173,25 @@ nearest whole tick. The default value is "null" for the x axis and
The rest of the options deal with the ticks. The rest of the options deal with the ticks.
If you don't specify any ticks, a tick generator algorithm will make If you don't specify any ticks, a tick generator algorithm will make
some for you. You can tweak how many it tries to generate by setting some for you. The algorithm has two passes. It first estimates how
"ticks" to a number. The algorithm always tries to generate reasonably many ticks would be reasonable and uses this number to compute a nice
round tick values so even if you ask for 3 ticks, you might get 5 if round tick interval size. Then it generates the ticks.
that fits better with the rounding. If you don't want ticks, set
"ticks" to 0 or an empty array.
You can control how the ticks look like with "tickDecimals", the
number of decimals to display (default is auto-detected), or by
providing a function as "tickFormatter". The tick formatter function
gets two argument, the tick value and an optional "axis" object with
information, and should return a string. The default formatter looks
like this:
function formatter(val, axis) {
return val.toFixed(axis.tickDecimals);
}
The axis object has "min" and "max" with the range of the axis, You can specify how many ticks the algorithm aims for by setting
"tickDecimals" with the number of decimals to round the value to and "ticks" to a number. The algorithm always tries to generate reasonably
"tickSize" with the size of the interval between ticks as calculated round tick values so even if you ask for three ticks, you might get
by the automatic axis scaling algorithm. Here's an example of a five if that fits better with the rounding. If you don't want ticks,
custom formatter: set "ticks" to 0 or an empty array.
function suffixFormatter(val, axis) {
if (val > 1000000)
return (val / 1000000).toFixed(axis.tickDecimals) + " MB";
else if (val > 1000)
return (val / 1000).toFixed(axis.tickDecimals) + " kB";
else
return val.toFixed(axis.tickDecimals) + " B";
}
Another option is to skip the rounding part and directly set the tick
interval size with "tickSize". If you set it to 2, you'll get ticks at
2, 4, 6, etc. Alternatively, you can specify that you just don't want
ticks at a size less than a specific tick size with "minTickSize".
Note that for time series, the format is an array like [2, "month"],
see the next section.
If you want to override the tick algorithm, you can specify an array If you want to completely override the tick algorithm, you can specify
to "ticks", either like this: an array for "ticks", either like this:
ticks: [0, 1.2, 2.4] ticks: [0, 1.2, 2.4]
...@@ -220,24 +206,50 @@ generator that spits out intervals of pi, suitable for use on the x ...@@ -220,24 +206,50 @@ generator that spits out intervals of pi, suitable for use on the x
axis for trigonometric functions: axis for trigonometric functions:
function piTickGenerator(axis) { function piTickGenerator(axis) {
var res = [], i = Math.ceil(axis.min / Math.PI); var res = [], i = Math.floor(axis.min / Math.PI);
while (true) { do {
var v = i * Math.PI; var v = i * Math.PI;
if (v > axis.max)
break;
res.push([v, i + "\u03c0"]); res.push([v, i + "\u03c0"]);
++i; ++i;
} } while (v < axis.max);
return res; return res;
} }
You can control how the ticks look like with "tickDecimals", the
number of decimals to display (default is auto-detected).
Alternatively, for ultimate control you can provide a function to
"tickFormatter". The function is passed two parameters, the tick value
and an "axis" object with information, and should return a string. The
default formatter looks like this:
function formatter(val, axis) {
return val.toFixed(axis.tickDecimals);
}
The axis object has "min" and "max" with the range of the axis,
"tickDecimals" with the number of decimals to round the value to and
"tickSize" with the size of the interval between ticks as calculated
by the automatic axis scaling algorithm (or specified by you). Here's
an example of a custom formatter:
function suffixFormatter(val, axis) {
if (val > 1000000)
return (val / 1000000).toFixed(axis.tickDecimals) + " MB";
else if (val > 1000)
return (val / 1000).toFixed(axis.tickDecimals) + " kB";
else
return val.toFixed(axis.tickDecimals) + " B";
}
Time series data Time series data
================ ================
The time series support in Flot is based on Javascript timestamps, The time series support in Flot is based on Javascript timestamps,
i.e. everywhere a time value is expected or passed over, a Javascript i.e. everywhere a time value is expected or handed over, a Javascript
timestamp number is used. This is not the same as a Date object. A timestamp number is used. This is not the same as a Date object. A
Javascript timestamp is the number of milliseconds since January 1, Javascript timestamp is the number of milliseconds since January 1,
1970 00:00:00. This is almost the same as Unix timestamps, except it's 1970 00:00:00. This is almost the same as Unix timestamps, except it's
...@@ -264,10 +276,11 @@ the axis mode, Flot will automatically generate relevant ticks and ...@@ -264,10 +276,11 @@ the axis mode, Flot will automatically generate relevant ticks and
format them. As always, you can tweak the ticks via the "ticks" format them. As always, you can tweak the ticks via the "ticks"
option. Again the values should be timestamps, not Date objects! option. Again the values should be timestamps, not Date objects!
Formatting is controlled separately through the following axis Tick generation and formatting is controlled separately through the
options: following axis options:
xaxis, yaxis: { xaxis, yaxis: {
minTickSize
timeformat: null or format string timeformat: null or format string
monthNames: null or array of size 12 of strings monthNames: null or array of size 12 of strings
} }
...@@ -306,10 +319,17 @@ which will format December 24 as 24/12: ...@@ -306,10 +319,17 @@ which will format December 24 as 24/12:
return d.getDate() + "/" + (d.getMonth() + 1); return d.getDate() + "/" + (d.getMonth() + 1);
} }
For the time mode the axis object contains an additional Note that for the time mode "tickSize" and "minTickSize" are a bit
"tickSizeUnit" which is one of "second", "minute", "hour", "day", special in that they are arrays on the form "[value, unit]" where unit
"month" and "year". So if axis.tickSize is 2 and axis.tickSizeUnit is is one of "second", "minute", "hour", "day", "month" and "year". So
"day", the ticks have been produced with two days in-between. you can specify
minTickSize: [1, "month"]
to get a tick interval size of at least 1 month and correspondingly,
if axis.tickSize is [2, "day"] in the tick formatter, the ticks have
been produced with two days in-between.
Customizing the data series Customizing the data series
...@@ -370,10 +390,12 @@ Customizing the grid ...@@ -370,10 +390,12 @@ Customizing the grid
==================== ====================
grid: { grid: {
color: color, color: color
backgroundColor: color or null, backgroundColor: color or null
tickColor: color, tickColor: color
labelMargin: number, labelMargin: number
coloredAreas: array of areas or (fn: plot area -> array of areas)
coloredAreasColor: color
clickable: boolean clickable: boolean
} }
...@@ -389,8 +411,33 @@ of the page with CSS. ...@@ -389,8 +411,33 @@ of the page with CSS.
between tick labels and the grid. between tick labels and the grid.
"coloredAreas" is an array of areas that will be drawn on top of the
background. You can either specify an array of objects with { x1, y1,
x2, y2 } or a function that returns such an array given the plot area
as { xmin, xmax, ymin, ymax }. The default color of the areas are
"coloredAreasColor". You can override the color of individual areas by
specifying "color" in the area object.
Here's an example array:
coloredAreas: [ { x1: 0, y1: 10, x2: 2, y2: 15, color: "#bb0000" }, ... ]
If you leave out one of the values, that value is assumed to go to the
border of the plot. So for example { x1: 0, x2: 2 } means an area that
extends from the top to the bottom of the plot in the x range 0-2.
An example function might look like this:
coloredAreas: function (plotarea) {
var areas = [];
for (var x = Math.floor(plotarea.xmin); x < plotarea.xmax; x += 2)
areas.push({ x1: x, x2: x + 1 });
return areas;
}
If you set "clickable" to true, the plot will listen for click events If you set "clickable" to true, the plot will listen for click events
on the plot are and fire a "plotclick" event on the placeholder with on the plot area and fire a "plotclick" event on the placeholder with
an object { x: number, y: number } as parameter when one occurs. The an object { x: number, y: number } as parameter when one occurs. The
returned coordinates will be in the unit of the plot (not in pixels). returned coordinates will be in the unit of the plot (not in pixels).
You can use it like this: You can use it like this:
......
Flot x.x Flot x.x
-------- --------
Time series support. Specify axis.mode: "time", put in Javascript
timestamps as data, and Flot will automatically spit out sensible
ticks. Take a look at the two new examples. The format can be
customized with axis.timeformat and axis.monthNames, or if that fails
with axis.tickFormatter.
Support for colored background areas via grid.coloredAreas. Specify an
array of { x1, y1, x2, y2 } objects or a function that returns these
given { xmin, xmax, ymin, ymax }.
The default number of ticks to aim for is now dependent on the size of
the plot in pixels. Support for customizing tick interval sizes
directly with axis.minTickSize and axis.tickSize.
Cleaned up the automatic axis scaling algorithm and fixed how it Cleaned up the automatic axis scaling algorithm and fixed how it
interacts with ticks. Also fixed a couple of tick-related corner case interacts with ticks. Also fixed a couple of tick-related corner case
bugs. bugs.
"tickFormatter" now takes a function with two parameters, the second The option axis.tickFormatter now takes a function with two
parameter is an optional object with information about the axis. It parameters, the second parameter is an optional object with
has min, max, tickDecimals, tickSize. information about the axis. It has min, max, tickDecimals, tickSize.
API changes: deprecated axis.noTicks in favor of just specifying the
number as axis.ticks.
Flot 0.3 Flot 0.3
......
...@@ -4,10 +4,10 @@ say why or come up with a patch. :-) ...@@ -4,10 +4,10 @@ say why or come up with a patch. :-)
pending pending
- split out autoscaleMargin into a snapToTicks - split out autoscaleMargin into a snapToTicks
- autodetect a sensible ticks setting
grid configuration grid configuration
- how ticks look like - how ticks look like
- consider setting default grid colors from each other?
selection selection
- user should be able to cancel selection with escape - user should be able to cancel selection with escape
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
<button id="nineties">1990-2000</button> <button id="nineties">1990-2000</button>
<button id="ninetynine">1999</button></p> <button id="ninetynine">1999</button></p>
<p>The timestamps <em>must</em> be specified as Javascript <p>The timestamps must be specified as Javascript
timestamps, as milliseconds since January 1, 1970 00:00. This is timestamps, as milliseconds since January 1, 1970 00:00. This is
like Unix timestamps, but in milliseconds instead of seconds like Unix timestamps, but in milliseconds instead of seconds
(remember to multiply with 1000!).</p> (remember to multiply with 1000!).</p>
...@@ -49,6 +49,7 @@ $(function () { ...@@ -49,6 +49,7 @@ $(function () {
$("#ninetynine").click(function () { $("#ninetynine").click(function () {
$.plot($("#placeholder"), [d], { xaxis: { $.plot($("#placeholder"), [d], { xaxis: {
mode: "time", mode: "time",
minTickSize: [1, "month"],
min: (new Date("1999/01/01")).getTime(), min: (new Date("1999/01/01")).getTime(),
max: (new Date("2000/01/01")).getTime() max: (new Date("2000/01/01")).getTime()
} }); } });
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
$(function () { $(function () {
var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], [1196722800000, 77], [1196809200000, 3636], [1196895600000, 3575], [1196982000000, 2736], [1197068400000, 1086], [1197154800000, 676], [1197241200000, 1205], [1197327600000, 906], [1197414000000, 710], [1197500400000, 639], [1197586800000, 540], [1197673200000, 435], [1197759600000, 301], [1197846000000, 575], [1197932400000, 481], [1198018800000, 591], [1198105200000, 608], [1198191600000, 459], [1198278000000, 234], [1198364400000, 1352], [1198450800000, 686], [1198537200000, 279], [1198623600000, 449], [1198710000000, 468], [1198796400000, 392], [1198882800000, 282], [1198969200000, 208], [1199055600000, 229], [1199142000000, 177], [1199228400000, 374], [1199314800000, 436], [1199401200000, 404], [1199487600000, 253], [1199574000000, 218], [1199660400000, 476], [1199746800000, 462], [1199833200000, 448], [1199919600000, 442], [1200006000000, 403], [1200092400000, 204], [1200178800000, 194], [1200265200000, 327], [1200351600000, 374], [1200438000000, 507], [1200524400000, 546], [1200610800000, 482], [1200697200000, 283], [1200783600000, 221], [1200870000000, 483], [1200956400000, 523], [1201042800000, 528], [1201129200000, 483], [1201215600000, 452], [1201302000000, 270], [1201388400000, 222], [1201474800000, 439], [1201561200000, 559], [1201647600000, 521], [1201734000000, 477], [1201820400000, 442], [1201906800000, 252], [1201993200000, 236], [1202079600000, 525], [1202166000000, 477], [1202252400000, 386], [1202338800000, 409], [1202425200000, 408], [1202511600000, 237], [1202598000000, 193], [1202684400000, 357], [1202770800000, 414], [1202857200000, 393], [1202943600000, 353], [1203030000000, 364], [1203116400000, 215], [1203202800000, 214], [1203289200000, 356], [1203375600000, 399], [1203462000000, 334], [1203548400000, 348], [1203634800000, 243], [1203721200000, 126], [1203807600000, 157], [1203894000000, 288]]; var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], [1196722800000, 77], [1196809200000, 3636], [1196895600000, 3575], [1196982000000, 2736], [1197068400000, 1086], [1197154800000, 676], [1197241200000, 1205], [1197327600000, 906], [1197414000000, 710], [1197500400000, 639], [1197586800000, 540], [1197673200000, 435], [1197759600000, 301], [1197846000000, 575], [1197932400000, 481], [1198018800000, 591], [1198105200000, 608], [1198191600000, 459], [1198278000000, 234], [1198364400000, 1352], [1198450800000, 686], [1198537200000, 279], [1198623600000, 449], [1198710000000, 468], [1198796400000, 392], [1198882800000, 282], [1198969200000, 208], [1199055600000, 229], [1199142000000, 177], [1199228400000, 374], [1199314800000, 436], [1199401200000, 404], [1199487600000, 253], [1199574000000, 218], [1199660400000, 476], [1199746800000, 462], [1199833200000, 448], [1199919600000, 442], [1200006000000, 403], [1200092400000, 204], [1200178800000, 194], [1200265200000, 327], [1200351600000, 374], [1200438000000, 507], [1200524400000, 546], [1200610800000, 482], [1200697200000, 283], [1200783600000, 221], [1200870000000, 483], [1200956400000, 523], [1201042800000, 528], [1201129200000, 483], [1201215600000, 452], [1201302000000, 270], [1201388400000, 222], [1201474800000, 439], [1201561200000, 559], [1201647600000, 521], [1201734000000, 477], [1201820400000, 442], [1201906800000, 252], [1201993200000, 236], [1202079600000, 525], [1202166000000, 477], [1202252400000, 386], [1202338800000, 409], [1202425200000, 408], [1202511600000, 237], [1202598000000, 193], [1202684400000, 357], [1202770800000, 414], [1202857200000, 393], [1202943600000, 353], [1203030000000, 364], [1203116400000, 215], [1203202800000, 214], [1203289200000, 356], [1203375600000, 399], [1203462000000, 334], [1203548400000, 348], [1203634800000, 243], [1203721200000, 126], [1203807600000, 157], [1203894000000, 288]];
// helper for returning the week-ends in a period // helper for returning the weekends in a period
function weekendAreas(plotarea) { function weekendAreas(plotarea) {
var areas = []; var areas = [];
var d = new Date(plotarea.xmin); var d = new Date(plotarea.xmin);
......
This diff is collapsed.
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