Commit 40e55f0d by Rashid Khan

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

parent e00d327c
<div class="row-fluid"> <div class="editor-row">
<div class="span2"> <div class="section">
<label class="small">Mode</label> <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> <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>
<div class="span2"> <div class="editor-option" ng-show="panel.mode != 'count'">
<label class="small">Time Field</label> <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-small" ng-model="panel.time_field"> <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 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> </div>
</div> </div>
<h5>Chart Settings</h5> <div class="section">
<div class="row-fluid" style="text-align:center;margin-bottom:10px;"> <h5>Transform Series</h5>
<div class="span1"> <label class="small">Bars</label><input type="checkbox" ng-model="panel.bars" ng-checked="panel.bars"></div> <div class="editor-option" ng-show="panel.mode != 'count'">
<div class="span1"> <label class="small">Lines</label><input type="checkbox" ng-model="panel.lines" ng-checked="panel.lines"></div> <label class="small">Scale</label>
<div class="span1"> <label class="small">Points</label><input type="checkbox" ng-model="panel.points" ng-checked="panel.points"></div> <input type="text" class="input-mini" ng-model="panel.scale">
<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> </div>
<div class="span1"> <label class="small">Legend</label><input type="checkbox" ng-model="panel.legend" ng-checked="panel.legend"></div> <div class="editor-option">
<div class="span1"> <label class="small">xAxis</label><input type="checkbox" ng-model="panel['x-axis']" ng-checked="panel['x-axis']"></div> <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 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> </div>
</div> </div>
<div class="row-fluid"> </div>
<div class="span2"> <h5>Time Options</h5>
<label class="small">Time correction</label> <div class="editor-row">
<select ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select> <div class="editor-option">
</div> <label class="small">Time Field</label>
<div class="span1"> <label class="small">Selectable</label><input type="checkbox" ng-model="panel.interactive" ng-checked="panel.interactive"></div> <input ng-change="set_refresh(true)" placeholder="Start typing" bs-typeahead="fields.list" type="text" class="input-small" ng-model="panel.time_field">
<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> </div>
<h5>Tooltip Settings</h5> <div class="editor-option">
<div class="row-fluid" style="margin-bottom:10px;"> <label class="small">Time correction</label>
<div class="span3"> <select ng-model="panel.timezone" class='input-small' ng-options="f for f in ['browser','utc']"></select>
<label class="small">Stacked Values <tip>How should the values in stacked charts to be calculated?</tip></label> </div>
<select class="input-medium" ng-model="panel.tooltip.value_type" ng-options="f for f in ['cumulative','individual']"></select> <div class="editor-option">
</div> <label class="small">Auto-interval</label><input type="checkbox" ng-model="panel.auto_int" ng-checked="panel.auto_int" />
<div class="span3"> </div>
<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> <div class="editor-option" ng-show='panel.auto_int'>
<input type="checkbox" ng-model="panel.tooltip.query_as_alias" /> <label class="small">Resolution <tip>Shoot for this many data points, rounding to sane intervals</tip></label>
</div> <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>
</div>
\ No newline at end of file
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<i class='icon-circle' ng-style="{color: series.info.color}"></i> <i class='icon-circle' ng-style="{color: series.info.color}"></i>
<span class='small histogram-legend-item'>{{series.info.alias}} ({{series.hits}})</span> <span class='small histogram-legend-item'>{{series.info.alias}} ({{series.hits}})</span>
</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> </div>
<form class="form-inline bordered histogram-options" ng-show="options"> <form class="form-inline bordered histogram-options" ng-show="options">
<span> <span>
......
...@@ -62,9 +62,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -62,9 +62,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
], ],
editorTabs : [ editorTabs : [
{ {
title:'Style',
src:'app/panels/histogram/styleEditor.html'
},
{
title:'Queries', title:'Queries',
src:'app/partials/querySelect.html' src:'app/partials/querySelect.html'
} },
], ],
status : "Stable", status : "Stable",
description : "A bucketed time series chart of the current query or queries. Uses the "+ description : "A bucketed time series chart of the current query or queries. Uses the "+
...@@ -98,11 +102,14 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -98,11 +102,14 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
'x-axis' : true, 'x-axis' : true,
'y-axis' : true, 'y-axis' : true,
percentage : false, percentage : false,
zerofill : true,
interactive : true, interactive : true,
options : true, options : true,
derivative : false,
scale : 1,
tooltip : { tooltip : {
value_type: 'cumulative', value_type: 'cumulative',
query_as_alias: false query_as_alias: true
} }
}; };
...@@ -115,6 +122,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -115,6 +122,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
$scope.get_data(); $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(); $scope.get_data();
}; };
...@@ -249,12 +260,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -249,12 +260,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
// we need to initialize the data variable on the first run, // we need to initialize the data variable on the first run,
// and when we are working on the first segment of the data. // and when we are working on the first segment of the data.
if(_.isUndefined($scope.data[i]) || segment === 0) { if(_.isUndefined($scope.data[i]) || segment === 0) {
time_series = new timeSeries.ZeroFilled({ var tsOpts = {
interval: _interval, interval: _interval,
start_date: _range && _range.from, start_date: _range && _range.from,
end_date: _range && _range.to, end_date: _range && _range.to,
fill_style: 'minimal' fill_style: $scope.panel.derivative ? 'null' : 'minimal'
}); };
time_series = new timeSeries.ZeroFilled(tsOpts);
hits = 0; hits = 0;
} else { } else {
time_series = $scope.data[i].time_series; time_series = $scope.data[i].time_series;
...@@ -354,6 +366,24 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -354,6 +366,24 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
render_panel(); 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 for rendering panel
function render_panel() { function render_panel() {
// IE doesn't work without this // IE doesn't work without this
...@@ -441,8 +471,16 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -441,8 +471,16 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}), true); }), true);
} }
for (var i = 0; i < scope.data.length; i++) { 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); scope.plot = $.plot(elem, scope.data, options);
......
<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>
...@@ -88,7 +88,7 @@ function (_, Interval) { ...@@ -88,7 +88,7 @@ function (_, Interval) {
* return the rows in the format: * return the rows in the format:
* [ [time, value], [time, value], ... ] * [ [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 * @param {array} required_times An array of timestamps that must be in the resulting pairs
* @return {array} * @return {array}
*/ */
...@@ -99,8 +99,8 @@ function (_, Interval) { ...@@ -99,8 +99,8 @@ function (_, Interval) {
if(this.opts.fill_style === 'all') { if(this.opts.fill_style === 'all') {
strategy = this._getAllFlotPairs; strategy = this._getAllFlotPairs;
} else if(this.opts.fill_style = 'default') { } else if(this.opts.fill_style === 'null') {
strategy = this._getDefaultFlotPairs; strategy = this._getNullFlotPairs;
} else { } else {
strategy = this._getMinFlotPairs; strategy = this._getMinFlotPairs;
} }
...@@ -114,13 +114,15 @@ function (_, Interval) { ...@@ -114,13 +114,15 @@ function (_, Interval) {
// if the first or last pair is inside either the start or end time, // 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. // 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)) { if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) {
pairs.unshift([this.start_time, null]); pairs.unshift([this.start_time, null]);
} }
if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) {
pairs.push([this.end_time, null]); pairs.push([this.end_time, null]);
} }
*/
return pairs; return pairs;
}; };
...@@ -144,7 +146,7 @@ function (_, Interval) { ...@@ -144,7 +146,7 @@ function (_, Interval) {
} }
// add the current time // add the current time
result.push([ time, this._data[time] || 0 ]); result.push([ time, this._data[time] || 0]);
// check for next measurement // check for next measurement
if (times.length > i) { if (times.length > i) {
...@@ -179,17 +181,31 @@ function (_, Interval) { ...@@ -179,17 +181,31 @@ function (_, Interval) {
/** /**
* ** called as a reduce stragegy in getFlotPairs() ** * ** 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 * @return {array} An array of points to plot with flot
*/ */
ts.ZeroFilled.prototype._getDefaultFlotPairs = function (result, time, i, times) { ts.ZeroFilled.prototype._getNullFlotPairs = function (result, time, i, times) {
var next, expected_next; var next, expected_next, prev, expected_prev;
result.push([ times[i], this._data[times[i]] || 0 ]); // check for previous measurement
next = times[i + 1]; if (i > 0) {
expected_next = this.interval.after(time); prev = times[i - 1];
for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { expected_prev = this.interval.before(time);
result.push([expected_next, 0]); 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; return result;
......
...@@ -114,14 +114,4 @@ define([ ...@@ -114,14 +114,4 @@ define([
}); });
module.directive('queryConfig', function() {
return {
restrict: 'A',
template: '<div></div>',
link: function(scope, elem) {
console.log(elem);
}
};
});
}); });
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
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 { #events {
font-size: 12px; font-size: 12px;
} }
......
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