mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[TSVB] Adding log scale mode to y-axis (#17761)
* [TSVB] Adding log scale mode to y-axis * adding license for jquery.flot.log.js to NOTICE * Adding transforms to log * updating notices * Fixing transform to ingore zero
This commit is contained in:
parent
a537fae358
commit
a26ddafb19
7 changed files with 205 additions and 0 deletions
20
NOTICE.txt
20
NOTICE.txt
|
@ -31,6 +31,26 @@ THE SOFTWARE.
|
||||||
This product uses Noto fonts that are licensed under the SIL Open
|
This product uses Noto fonts that are licensed under the SIL Open
|
||||||
Font License, Version 1.1.
|
Font License, Version 1.1.
|
||||||
|
|
||||||
|
---
|
||||||
|
Pretty handling of logarithmic axes.
|
||||||
|
Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||||
|
Licensed under the MIT license.
|
||||||
|
Created by Arne de Laat
|
||||||
|
Set axis.mode to "log" and make the axis logarithmic using transform:
|
||||||
|
axis: {
|
||||||
|
mode: 'log',
|
||||||
|
transform: function(v) {v <= 0 ? Math.log(v) / Math.LN10 : null},
|
||||||
|
inverseTransform: function(v) {Math.pow(10, v)}
|
||||||
|
}
|
||||||
|
The transform filters negative and zero values, because those are
|
||||||
|
invalid on logarithmic scales.
|
||||||
|
This plugin tries to create good looking logarithmic ticks, using
|
||||||
|
unicode superscript characters. If all data to be plotted is between two
|
||||||
|
powers of ten then the default flot tick generator and renderer are
|
||||||
|
used. Logarithmic ticks are places at powers of ten and at half those
|
||||||
|
values if there are not to many ticks already (e.g. [1, 5, 10, 50, 100]).
|
||||||
|
For details, see https://github.com/flot/flot/pull/1328
|
||||||
|
|
||||||
---
|
---
|
||||||
This product bundles angular-ui-bootstrap@0.12.1 which is available under a
|
This product bundles angular-ui-bootstrap@0.12.1 which is available under a
|
||||||
"MIT" license.
|
"MIT" license.
|
||||||
|
|
|
@ -38,6 +38,10 @@ class TimeseriesPanelConfig extends Component {
|
||||||
{ label: 'Right', value: 'right' },
|
{ label: 'Right', value: 'right' },
|
||||||
{ label: 'Left', value: 'left' }
|
{ label: 'Left', value: 'left' }
|
||||||
];
|
];
|
||||||
|
const scaleOptions = [
|
||||||
|
{ label: 'Normal', value: 'normal' },
|
||||||
|
{ label: 'Log', value: 'log' }
|
||||||
|
];
|
||||||
const legendPositionOptions = [
|
const legendPositionOptions = [
|
||||||
{ label: 'Right', value: 'right' },
|
{ label: 'Right', value: 'right' },
|
||||||
{ label: 'Left', value: 'left' },
|
{ label: 'Left', value: 'left' },
|
||||||
|
@ -98,6 +102,17 @@ class TimeseriesPanelConfig extends Component {
|
||||||
onChange={handleSelectChange('axis_position')}
|
onChange={handleSelectChange('axis_position')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<label className="vis_editor__label" htmlFor={htmlId('axisPos')}>Axis Scale</label>
|
||||||
|
<div className="vis_editor__row_item">
|
||||||
|
<Select
|
||||||
|
inputProps={{ id: htmlId('axisScale') }}
|
||||||
|
autosize={false}
|
||||||
|
clearable={false}
|
||||||
|
options={scaleOptions}
|
||||||
|
value={model.axis_scale}
|
||||||
|
onChange={handleSelectChange('axis_scale')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="vis_editor__vis_config-row">
|
<div className="vis_editor__vis_config-row">
|
||||||
<div className="vis_editor__label">Background Color</div>
|
<div className="vis_editor__label">Background Color</div>
|
||||||
|
|
|
@ -71,6 +71,11 @@ class TimeseriesVisualization extends Component {
|
||||||
|
|
||||||
if (model.axis_min) mainAxis.min = model.axis_min;
|
if (model.axis_min) mainAxis.min = model.axis_min;
|
||||||
if (model.axis_max) mainAxis.max = model.axis_max;
|
if (model.axis_max) mainAxis.max = model.axis_max;
|
||||||
|
if (model.axis_scale === 'log') {
|
||||||
|
mainAxis.mode = 'log';
|
||||||
|
mainAxis.transform = value => value > 0 ? Math.log(value) / Math.LN10 : null;
|
||||||
|
mainAxis.inverseTransform = value => Math.pow(10, value);
|
||||||
|
}
|
||||||
|
|
||||||
const yaxes = [mainAxis];
|
const yaxes = [mainAxis];
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ export default function MetricsVisProvider(Private) {
|
||||||
interval: 'auto',
|
interval: 'auto',
|
||||||
axis_position: 'left',
|
axis_position: 'left',
|
||||||
axis_formatter: 'number',
|
axis_formatter: 'number',
|
||||||
|
axis_scale: 'normal',
|
||||||
show_legend: 1,
|
show_legend: 1,
|
||||||
show_grid: 1
|
show_grid: 1
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,6 +32,7 @@ class FlotChart extends Component {
|
||||||
axis.max !== this.props.yaxes[i].max ||
|
axis.max !== this.props.yaxes[i].max ||
|
||||||
axis.min !== this.props.yaxes[i].min ||
|
axis.min !== this.props.yaxes[i].min ||
|
||||||
axis.axisFormatter !== this.props.yaxes[i].axisFormatter ||
|
axis.axisFormatter !== this.props.yaxes[i].axisFormatter ||
|
||||||
|
axis.mode !== this.props.yaxes[i].mode ||
|
||||||
axis.axisFormatterTemplate !== this.props.yaxes[i].axisFormatterTemplate
|
axis.axisFormatterTemplate !== this.props.yaxes[i].axisFormatterTemplate
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,4 +37,5 @@ require('ui/flot-charts/jquery.flot.pie');
|
||||||
require('ui/flot-charts/jquery.flot.stack');
|
require('ui/flot-charts/jquery.flot.stack');
|
||||||
require('ui/flot-charts/jquery.flot.threshold');
|
require('ui/flot-charts/jquery.flot.threshold');
|
||||||
require('ui/flot-charts/jquery.flot.fillbetween');
|
require('ui/flot-charts/jquery.flot.fillbetween');
|
||||||
|
require('ui/flot-charts/jquery.flot.log');
|
||||||
module.exports = $;
|
module.exports = $;
|
||||||
|
|
162
src/ui/public/flot-charts/jquery.flot.log.js
Normal file
162
src/ui/public/flot-charts/jquery.flot.log.js
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/*@notice
|
||||||
|
* Pretty handling of logarithmic axes.
|
||||||
|
* Copyright (c) 2007-2014 IOLA and Ole Laursen.
|
||||||
|
* Licensed under the MIT license.
|
||||||
|
* Created by Arne de Laat
|
||||||
|
* Set axis.mode to "log" and make the axis logarithmic using transform:
|
||||||
|
* axis: {
|
||||||
|
* mode: 'log',
|
||||||
|
* transform: function(v) {v <= 0 ? Math.log(v) / Math.LN10 : null},
|
||||||
|
* inverseTransform: function(v) {Math.pow(10, v)}
|
||||||
|
* }
|
||||||
|
* The transform filters negative and zero values, because those are
|
||||||
|
* invalid on logarithmic scales.
|
||||||
|
* This plugin tries to create good looking logarithmic ticks, using
|
||||||
|
* unicode superscript characters. If all data to be plotted is between two
|
||||||
|
* powers of ten then the default flot tick generator and renderer are
|
||||||
|
* used. Logarithmic ticks are places at powers of ten and at half those
|
||||||
|
* values if there are not to many ticks already (e.g. [1, 5, 10, 50, 100]).
|
||||||
|
* For details, see https://github.com/flot/flot/pull/1328
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
function log10(value) {
|
||||||
|
/* Get the Log10 of the value
|
||||||
|
*/
|
||||||
|
return Math.log(value) / Math.LN10;
|
||||||
|
}
|
||||||
|
|
||||||
|
function floorAsLog10(value) {
|
||||||
|
/* Get power of the first power of 10 below the value
|
||||||
|
*/
|
||||||
|
return Math.floor(log10(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function ceilAsLog10(value) {
|
||||||
|
/* Get power of the first power of 10 above the value
|
||||||
|
*/
|
||||||
|
return Math.ceil(log10(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// round to nearby lower multiple of base
|
||||||
|
function floorInBase(n, base) {
|
||||||
|
return base * Math.floor(n / base);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUnicodePower(power) {
|
||||||
|
var superscripts = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"],
|
||||||
|
result = "",
|
||||||
|
str_power = "" + power;
|
||||||
|
for (var i = 0; i < str_power.length; i++) {
|
||||||
|
if (str_power[i] === "+") {
|
||||||
|
}
|
||||||
|
else if (str_power[i] === "-") {
|
||||||
|
result += "⁻";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += superscripts[str_power[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(plot) {
|
||||||
|
plot.hooks.processOptions.push(function (plot) {
|
||||||
|
$.each(plot.getAxes(), function(axisName, axis) {
|
||||||
|
|
||||||
|
var opts = axis.options;
|
||||||
|
|
||||||
|
if (opts.mode === "log") {
|
||||||
|
|
||||||
|
axis.tickGenerator = function (axis) {
|
||||||
|
|
||||||
|
var ticks = [],
|
||||||
|
end = ceilAsLog10(axis.max),
|
||||||
|
start = floorAsLog10(axis.datamin),
|
||||||
|
tick = Number.NaN,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
if (axis.datamin === null || axis.datamin <= 0) {
|
||||||
|
// Bad minimum, make ticks from 1 (10**0) to max
|
||||||
|
start = 0;
|
||||||
|
axis.min = 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end <= start) {
|
||||||
|
// Start less than end?!
|
||||||
|
ticks = [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
|
||||||
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6,
|
||||||
|
1e7, 1e8, 1e9];
|
||||||
|
}
|
||||||
|
else if (log10(axis.max) - log10(axis.datamin) < 1) {
|
||||||
|
// Default flot generator incase no powers of 10
|
||||||
|
// are between start and end
|
||||||
|
var prev;
|
||||||
|
start = floorInBase(axis.min, axis.tickSize);
|
||||||
|
do {
|
||||||
|
prev = tick;
|
||||||
|
tick = start + i * axis.tickSize;
|
||||||
|
ticks.push(tick);
|
||||||
|
++i;
|
||||||
|
} while (tick < axis.max && tick !== prev);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Make ticks at each power of ten
|
||||||
|
for (; i <= (end - start); i++) {
|
||||||
|
tick = Math.pow(10, start + i);
|
||||||
|
ticks.push(tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
var length = ticks.length;
|
||||||
|
|
||||||
|
// If not to many ticks also put a tick between
|
||||||
|
// the powers of ten
|
||||||
|
if (end - start < 6) {
|
||||||
|
for (var j = 1; j < length * 2 - 1; j += 2) {
|
||||||
|
tick = ticks[j - 1] * 5;
|
||||||
|
ticks.splice(j, 0, tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ticks;
|
||||||
|
};
|
||||||
|
|
||||||
|
axis.tickFormatter = function (value, axis) {
|
||||||
|
var formatted;
|
||||||
|
if (log10(axis.max) - log10(axis.datamin) < 1) {
|
||||||
|
// Default flot formatter
|
||||||
|
var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
|
||||||
|
formatted = "" + Math.round(value * factor) / factor;
|
||||||
|
if (axis.tickDecimals !== null) {
|
||||||
|
var decimal = formatted.indexOf(".");
|
||||||
|
var precision = decimal === -1 ? 0 : formatted.length - decimal - 1;
|
||||||
|
if (precision < axis.tickDecimals) {
|
||||||
|
return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var multiplier = "",
|
||||||
|
exponential = parseFloat(value).toExponential(0),
|
||||||
|
power = getUnicodePower(exponential.slice(2));
|
||||||
|
if (exponential[0] !== "1") {
|
||||||
|
multiplier = exponential[0] + "x";
|
||||||
|
}
|
||||||
|
formatted = multiplier + "10" + power;
|
||||||
|
}
|
||||||
|
return formatted;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$.plot.plugins.push({
|
||||||
|
init: init,
|
||||||
|
name: "log",
|
||||||
|
version: "0.9"
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
Loading…
Add table
Add a link
Reference in a new issue