Added derivative option and scale option to histogram, reorganized histogram config

This commit is contained in:
Rashid Khan 2013-10-23 15:24:50 -07:00
parent e00d327c5d
commit 40e55f0d0d
9 changed files with 187 additions and 97 deletions

View File

@ -1,74 +1,45 @@
<div class="row-fluid">
<div class="span2">
<label class="small">Mode</label>
<div class="editor-row">
<div class="section">
<h5>Values</h5>
<div class="editor-option">
<label class="small">Chart value</label>
<select ng-change="set_refresh(true)" class="input-small" ng-model="panel.mode" ng-options="f for f in ['count','min','mean','max','total']"></select>
</div>
<div class="span2">
<label class="small">Time Field</label>
<input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.time_field">
</div>
<div class="span2" ng-show="panel.mode != 'count'">
<label class="small">Value Field</label>
<input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.value_field">
</div>
<div class="span3" ng-show="panel.mode != 'count'">
<label class="small">Note</label><small> In <strong>{{panel.mode}}</strong> mode the configured field <strong>must</strong> be a numeric type</small>
<div class="editor-option" ng-show="panel.mode != 'count'">
<label class="small">Value Field <tip>This field must contain a numeric value</tip></label>
<input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-large" ng-model="panel.value_field">
</div>
</div>
<h5>Chart Settings</h5>
<div class="row-fluid" style="text-align:center;margin-bottom:10px;">
<div class="span1"> <label class="small">Bars</label><input type="checkbox" ng-model="panel.bars" ng-checked="panel.bars"></div>
<div class="span1"> <label class="small">Lines</label><input type="checkbox" ng-model="panel.lines" ng-checked="panel.lines"></div>
<div class="span1"> <label class="small">Points</label><input type="checkbox" ng-model="panel.points" ng-checked="panel.points"></div>
<div class="span1"> <label class="small">Stack</label><input type="checkbox" ng-model="panel.stack" ng-checked="panel.stack"></div>
<div class="span1" ng-show="panel.stack">
<label style="white-space:nowrap" class="small">Percent <tip>Stack as a percentage of total</tip></label>
<input type="checkbox" ng-model="panel.percentage" ng-checked="panel.percentage">
<div class="section">
<h5>Transform Series</h5>
<div class="editor-option" ng-show="panel.mode != 'count'">
<label class="small">Scale</label>
<input type="text" class="input-mini" ng-model="panel.scale">
</div>
<div class="span1"> <label class="small">Legend</label><input type="checkbox" ng-model="panel.legend" ng-checked="panel.legend"></div>
<div class="span1"> <label class="small">xAxis</label><input type="checkbox" ng-model="panel['x-axis']" ng-checked="panel['x-axis']"></div>
<div class="span1"> <label class="small">yAxis</label><input type="checkbox" ng-model="panel['y-axis']" ng-checked="panel['y-axis']"></div>
<div class="span2" ng-show="panel.lines">
<label class="small">Line Fill</label>
<select class="input-mini" ng-model="panel.fill" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
</div>
<div class="span2" ng-show="panel.lines">
<label class="small">Line Width</label>
<select class="input-mini" ng-model="panel.linewidth" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
<div class="editor-option">
<label class="small">Derivative <tip>Plot the change per interval in the series</tip></label><input type="checkbox" ng-model="panel.derivative" ng-checked="panel.derivative" ng-change="set_refresh(true)">
</div>
</div>
<div class="row-fluid">
<div class="span2">
<label class="small">Time correction</label>
<select ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select>
</div>
<div class="span1"> <label class="small">Selectable</label><input type="checkbox" ng-model="panel.interactive" ng-checked="panel.interactive"></div>
<div class="span2">
<label class="small">Zoom Links</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks" />
</div>
<div class="span2">
<label class="small">View Options</label><input type="checkbox" ng-model="panel.options" ng-checked="panel.options" />
</div>
<div class="span2">
<label class="small">Auto-interval</label><input type="checkbox" ng-model="panel.auto_int" ng-checked="panel.auto_int" />
</div>
<div class="span2" ng-show='panel.auto_int'>
<label class="small">Resolution <tip>Shoot for this many data points, rounding to sane intervals</tip></label>
<input type="number" class='input-mini' ng-model="panel.resolution" ng-change='set_refresh(true)'/>
</div>
<div class="span2" ng-hide='panel.auto_int'>
<label class="small">Interval <tip>Use Elasticsearch date math format (eg 1m, 5m, 1d, 2w, 1y)</tip></label>
<input type="text" class='input-mini' ng-model="panel.interval" ng-change='set_refresh(true)'/>
</div>
</div>
<h5>Time Options</h5>
<div class="editor-row">
<div class="editor-option">
<label class="small">Time Field</label>
<input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.time_field">
</div>
<h5>Tooltip Settings</h5>
<div class="row-fluid" style="margin-bottom:10px;">
<div class="span3">
<label class="small">Stacked Values <tip>How should the values in stacked charts to be calculated?</tip></label>
<select class="input-medium" ng-model="panel.tooltip.value_type" ng-options="f for f in ['cumulative','individual']"></select>
</div>
<div class="span3">
<label class="small">Display Query <tip>If an alias is set, it will be shown in the tooltip. If not, should it show the query?</tip></label>
<input type="checkbox" ng-model="panel.tooltip.query_as_alias" />
</div>
<div class="editor-option">
<label class="small">Time correction</label>
<select ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select>
</div>
<div class="editor-option">
<label class="small">Auto-interval</label><input type="checkbox" ng-model="panel.auto_int" ng-checked="panel.auto_int" />
</div>
<div class="editor-option" ng-show='panel.auto_int'>
<label class="small">Resolution <tip>Shoot for this many data points, rounding to sane intervals</tip></label>
<input type="number" class='input-mini' ng-model="panel.resolution" ng-change='set_refresh(true)'/>
</div>
<div class="editor-option" ng-hide='panel.auto_int'>
<label class="small">Interval <tip>Use Elasticsearch date math format (eg 1m, 5m, 1d, 2w, 1y)</tip></label>
<input type="text" class='input-mini' ng-model="panel.interval" ng-change='set_refresh(true)'/>
</div>
</div>

View File

@ -47,7 +47,7 @@
<i class='icon-circle' ng-style="{color: series.info.color}"></i>
<span class='small histogram-legend-item'>{{series.info.alias}} ({{series.hits}})</span>
</span>
<span ng-show="panel.legend" class="small"><span ng-show="panel.value_field && panel.mode != 'count'">{{panel.value_field}}</span> {{panel.mode}} per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> hits)</span>
<span ng-show="panel.legend" class="small"><span ng-show="panel.derivative">change in </span><span class="strong" ng-show="panel.value_field && panel.mode != 'count'">{{panel.value_field}}</span> {{panel.mode}} per <strong>{{panel.interval}}</strong> | (<strong>{{hits}}</strong> hits)</span>
</div>
<form class="form-inline bordered histogram-options" ng-show="options">
<span>

View File

@ -61,10 +61,14 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}
],
editorTabs : [
{
title:'Style',
src:'app/panels/histogram/styleEditor.html'
},
{
title:'Queries',
src:'app/partials/querySelect.html'
}
},
],
status : "Stable",
description : "A bucketed time series chart of the current query or queries. Uses the "+
@ -98,11 +102,14 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
'x-axis' : true,
'y-axis' : true,
percentage : false,
zerofill : true,
interactive : true,
options : true,
derivative : false,
scale : 1,
tooltip : {
value_type: 'cumulative',
query_as_alias: false
query_as_alias: true
}
};
@ -115,6 +122,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
$scope.get_data();
});
// Always show the query if an alias isn't set. Users can set an alias if the query is too
// long
$scope.panel.tooltip.query_as_alias = true;
$scope.get_data();
};
@ -249,12 +260,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
// we need to initialize the data variable on the first run,
// and when we are working on the first segment of the data.
if(_.isUndefined($scope.data[i]) || segment === 0) {
time_series = new timeSeries.ZeroFilled({
var tsOpts = {
interval: _interval,
start_date: _range && _range.from,
end_date: _range && _range.to,
fill_style: 'minimal'
});
fill_style: $scope.panel.derivative ? 'null' : 'minimal'
};
time_series = new timeSeries.ZeroFilled(tsOpts);
hits = 0;
} else {
time_series = $scope.data[i].time_series;
@ -354,6 +366,24 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
render_panel();
});
var scale = function(series,factor) {
return _.map(series,function(p) {
return [p[0],p[1]*factor];
});
};
var derivative = function(series) {
return _.map(series, function(p,i) {
var _v;
if(i === 0 || p[1] === null) {
_v = [p[0],null];
} else {
_v = series[i-1][1] === null ? [p[0],null] : [p[0],p[1]-(series[i-1][1])];
}
return _v;
});
};
// Function for rendering panel
function render_panel() {
// IE doesn't work without this
@ -441,8 +471,16 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}), true);
}
for (var i = 0; i < scope.data.length; i++) {
scope.data[i].data = scope.data[i].time_series.getFlotPairs(required_times);
var _d = scope.data[i].time_series.getFlotPairs(required_times);
if(scope.panel.derivative) {
_d = derivative(_d);
}
if(scope.panel.scale !== 1) {
_d = scale(_d,scope.panel.scale);
}
scope.data[i].data = _d;
}
scope.plot = $.plot(elem, scope.data, options);

View File

@ -0,0 +1,58 @@
<div class="editor-row">
<div class="section">
<h5>Chart Options</h5>
<div class="editor-option">
<label class="small">Bars</label><input type="checkbox" ng-model="panel.bars" ng-checked="panel.bars">
</div>
<div class="editor-option">
<label class="small">Lines</label><input type="checkbox" ng-model="panel.lines" ng-checked="panel.lines">
</div>
<div class="editor-option">
<label class="small">Points</label><input type="checkbox" ng-model="panel.points" ng-checked="panel.points">
</div>
<div class="editor-option">
<label class="small">Selectable</label><input type="checkbox" ng-model="panel.interactive" ng-checked="panel.interactive">
</div>
<div class="editor-option">
<label class="small">xAxis</label><input type="checkbox" ng-model="panel['x-axis']" ng-checked="panel['x-axis']"></div>
<div class="editor-option">
<label class="small">yAxis</label><input type="checkbox" ng-model="panel['y-axis']" ng-checked="panel['y-axis']"></div>
<div class="editor-option" ng-show="panel.lines">
<label class="small">Line Fill</label>
<select class="input-mini" ng-model="panel.fill" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
</div>
<div class="editor-option" ng-show="panel.lines">
<label class="small">Line Width</label>
<select class="input-mini" ng-model="panel.linewidth" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10]"></select>
</div>
</div>
<div class="section">
<h5>Multiple Series</h5>
<div class="editor-option">
<label class="small">Stack</label><input type="checkbox" ng-model="panel.stack" ng-checked="panel.stack">
</div>
<div class="editor-option" ng-show="panel.stack">
<label style="white-space:nowrap" class="small">Percent <tip>Stack as a percentage of total</tip></label>
<input type="checkbox" ng-model="panel.percentage" ng-checked="panel.percentage">
</div>
<div class="editor-option" ng-show="panel.stack">
<label class="small">Stacked Values <tip>How should the values in stacked charts to be calculated?</tip></label>
<select class="input-small" ng-model="panel.tooltip.value_type" ng-options="f for f in ['cumulative','individual']"></select>
</div>
</div>
</div>
<div class="editor-row">
<div class="section">
<h5>Header<h5>
<div class="editor-option">
<label class="small">Legend</label><input type="checkbox" ng-model="panel.legend" ng-checked="panel.legend">
</div>
<div class="editor-option">
<label class="small">Zoom</label><input type="checkbox" ng-model="panel.zoomlinks" ng-checked="panel.zoomlinks" />
</div>
<div class="editor-option">
<label class="small">View</label><input type="checkbox" ng-model="panel.options" ng-checked="panel.options" />
</div>
</div>
</div>

View File

@ -88,7 +88,7 @@ function (_, Interval) {
* return the rows in the format:
* [ [time, value], [time, value], ... ]
*
* Heavy lifting is done by _get(Min|All)FlotPairs()
* Heavy lifting is done by _get(Min|Default|All)FlotPairs()
* @param {array} required_times An array of timestamps that must be in the resulting pairs
* @return {array}
*/
@ -99,8 +99,8 @@ function (_, Interval) {
if(this.opts.fill_style === 'all') {
strategy = this._getAllFlotPairs;
} else if(this.opts.fill_style = 'default') {
strategy = this._getDefaultFlotPairs;
} else if(this.opts.fill_style === 'null') {
strategy = this._getNullFlotPairs;
} else {
strategy = this._getMinFlotPairs;
}
@ -114,13 +114,15 @@ function (_, Interval) {
// if the first or last pair is inside either the start or end time,
// add those times to the series with null values so the graph will stretch to contain them.
// Not sure this is required with flot 0.8.1's min/max params. Might be harmful?
// Removing, flot 0.8.1's max/min params satisfy this
/*
if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) {
pairs.unshift([this.start_time, null]);
}
if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) {
pairs.push([this.end_time, null]);
}
*/
return pairs;
};
@ -144,7 +146,7 @@ function (_, Interval) {
}
// add the current time
result.push([ time, this._data[time] || 0 ]);
result.push([ time, this._data[time] || 0]);
// check for next measurement
if (times.length > i) {
@ -179,17 +181,31 @@ function (_, Interval) {
/**
* ** called as a reduce stragegy in getFlotPairs() **
* Does no zero filling
* Same as min, but fills with nulls
* @return {array} An array of points to plot with flot
*/
ts.ZeroFilled.prototype._getDefaultFlotPairs = function (result, time, i, times) {
var next, expected_next;
ts.ZeroFilled.prototype._getNullFlotPairs = function (result, time, i, times) {
var next, expected_next, prev, expected_prev;
result.push([ times[i], this._data[times[i]] || 0 ]);
next = times[i + 1];
expected_next = this.interval.after(time);
for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) {
result.push([expected_next, 0]);
// check for previous measurement
if (i > 0) {
prev = times[i - 1];
expected_prev = this.interval.before(time);
if (prev < expected_prev) {
result.push([expected_prev, null]);
}
}
// add the current time
result.push([ time, this._data[time] || null]);
// check for next measurement
if (times.length > i) {
next = times[i + 1];
expected_next = this.interval.after(time);
if (next > expected_next) {
result.push([expected_next, null]);
}
}
return result;

View File

@ -114,14 +114,4 @@ define([
});
module.directive('queryConfig', function() {
return {
restrict: 'A',
template: '<div></div>',
link: function(scope, elem) {
console.log(elem);
}
};
});
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,20 @@
div.editor-row {
vertical-align: top;
}
div.editor-row div.section {
margin-right: 20px;
vertical-align: top;
display: inline-block;
}
div.editor-option {
vertical-align: top;
display: inline-block;
margin-right: 10px;
}
div.editor-option label {
display: block;
}
#events {
font-size: 12px;
}