Skip to content

Commit

Permalink
[TSVB] Adding log scale mode to y-axis (elastic#17761)
Browse files Browse the repository at this point in the history
* [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
  • Loading branch information
simianhacker committed May 3, 2018
1 parent a537fae commit a26ddaf
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 0 deletions.
20 changes: 20 additions & 0 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ THE SOFTWARE.
This product uses Noto fonts that are licensed under the SIL Open
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
"MIT" license.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class TimeseriesPanelConfig extends Component {
{ label: 'Right', value: 'right' },
{ label: 'Left', value: 'left' }
];
const scaleOptions = [
{ label: 'Normal', value: 'normal' },
{ label: 'Log', value: 'log' }
];
const legendPositionOptions = [
{ label: 'Right', value: 'right' },
{ label: 'Left', value: 'left' },
Expand Down Expand Up @@ -98,6 +102,17 @@ class TimeseriesPanelConfig extends Component {
onChange={handleSelectChange('axis_position')}
/>
</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 className="vis_editor__vis_config-row">
<div className="vis_editor__label">Background Color</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ class TimeseriesVisualization extends Component {

if (model.axis_min) mainAxis.min = model.axis_min;
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];

Expand Down
1 change: 1 addition & 0 deletions src/core_plugins/metrics/public/kbn_vis_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default function MetricsVisProvider(Private) {
interval: 'auto',
axis_position: 'left',
axis_formatter: 'number',
axis_scale: 'normal',
show_legend: 1,
show_grid: 1
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class FlotChart extends Component {
axis.max !== this.props.yaxes[i].max ||
axis.min !== this.props.yaxes[i].min ||
axis.axisFormatter !== this.props.yaxes[i].axisFormatter ||
axis.mode !== this.props.yaxes[i].mode ||
axis.axisFormatterTemplate !== this.props.yaxes[i].axisFormatterTemplate
);
}
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/flot-charts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ require('ui/flot-charts/jquery.flot.pie');
require('ui/flot-charts/jquery.flot.stack');
require('ui/flot-charts/jquery.flot.threshold');
require('ui/flot-charts/jquery.flot.fillbetween');
require('ui/flot-charts/jquery.flot.log');
module.exports = $;
162 changes: 162 additions & 0 deletions src/ui/public/flot-charts/jquery.flot.log.js
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit a26ddaf

Please sign in to comment.