mirror of
https://github.com/getredash/redash.git
synced 2026-03-22 10:00:17 -04:00
174 lines
5.3 KiB
JavaScript
174 lines
5.3 KiB
JavaScript
(function() {
|
|
var module = angular.module('redash.visualization');
|
|
|
|
module.config(['VisualizationProvider', function(VisualizationProvider) {
|
|
var renderTemplate =
|
|
'<boxplot-renderer ' +
|
|
'options="visualization.options" query-result="queryResult">' +
|
|
'</boxplot-renderer>';
|
|
|
|
var editTemplate = '<boxplot-editor></boxplot-editor>';
|
|
|
|
VisualizationProvider.registerVisualization({
|
|
type: 'BOXPLOT',
|
|
name: 'Boxplot',
|
|
renderTemplate: renderTemplate,
|
|
editorTemplate: editTemplate
|
|
});
|
|
}
|
|
]);
|
|
module.directive('boxplotRenderer', function() {
|
|
return {
|
|
restrict: 'E',
|
|
templateUrl: '/views/visualizations/boxplot.html',
|
|
link: function($scope, elm, attrs) {
|
|
|
|
function iqr(k) {
|
|
return function(d, i) {
|
|
var q1 = d.quartiles[0],
|
|
q3 = d.quartiles[2],
|
|
iqr = (q3 - q1) * k,
|
|
i = -1,
|
|
j = d.length;
|
|
while (d[++i] < q1 - iqr);
|
|
while (d[--j] > q3 + iqr);
|
|
return [i, j];
|
|
};
|
|
};
|
|
|
|
$scope.$watch('[queryResult && queryResult.getData(), visualization.options]', function () {
|
|
|
|
var data = $scope.queryResult.getData();
|
|
var parentWidth = d3.select(elm[0].parentNode).node().getBoundingClientRect().width;
|
|
var margin = {top: 10, right: 50, bottom: 40, left: 50, inner: 25},
|
|
width = parentWidth - margin.right - margin.left
|
|
height = 500 - margin.top - margin.bottom;
|
|
|
|
var min = Infinity,
|
|
max = -Infinity;
|
|
var mydata = [];
|
|
var value = 0;
|
|
var d = [];
|
|
var xAxisLabel = $scope.visualization.options.xAxisLabel;
|
|
var yAxisLabel = $scope.visualization.options.yAxisLabel;
|
|
|
|
var columns = $scope.queryResult.columnNames;
|
|
var xscale = d3.scale.ordinal()
|
|
.domain(columns)
|
|
.rangeBands([0, parentWidth-margin.left-margin.right]);
|
|
|
|
if (columns.length > 1){
|
|
boxWidth = Math.min(xscale(columns[1]),120.0);
|
|
} else {
|
|
boxWidth=120.0;
|
|
};
|
|
margin.inner = boxWidth/3.0;
|
|
|
|
_.each(columns, function(column, i){
|
|
d = mydata[i] = [];
|
|
_.each(data, function (row) {
|
|
value = row[column];
|
|
d.push(value);
|
|
if (value > max) max = Math.ceil(value);
|
|
if (value < min) min = Math.floor(value);
|
|
});
|
|
});
|
|
|
|
var yscale = d3.scale.linear()
|
|
.domain([min*0.99,max*1.01])
|
|
.range([height, 0]);
|
|
|
|
var chart = d3.box()
|
|
.whiskers(iqr(1.5))
|
|
.width(boxWidth-2*margin.inner)
|
|
.height(height)
|
|
.domain([min*0.99,max*1.01]);
|
|
var xAxis = d3.svg.axis()
|
|
.scale(xscale)
|
|
.orient("bottom");
|
|
|
|
|
|
var yAxis = d3.svg.axis()
|
|
.scale(yscale)
|
|
.orient("left");
|
|
|
|
var xLines = d3.svg.axis()
|
|
.scale(xscale)
|
|
.tickSize(height)
|
|
.orient("bottom");
|
|
|
|
var yLines = d3.svg.axis()
|
|
.scale(yscale)
|
|
.tickSize(width)
|
|
.orient("right");
|
|
|
|
var barOffset = function(i){
|
|
return xscale(columns[i]) + (xscale(columns[1]) - margin.inner)/2.0;
|
|
};
|
|
|
|
d3.select(elm[0]).selectAll("svg").remove();
|
|
|
|
var plot = d3.select(elm[0])
|
|
.append("svg")
|
|
.attr("width",parentWidth)
|
|
.attr("height",height + margin.bottom + margin.top)
|
|
.append("g")
|
|
.attr("width",parentWidth-margin.left-margin.right)
|
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
|
|
|
|
d3.select("svg").append("text")
|
|
.attr("class", "box")
|
|
.attr("x", parentWidth/2.0)
|
|
.attr("text-anchor", "middle")
|
|
.attr("y", height+margin.bottom)
|
|
.text(xAxisLabel)
|
|
|
|
d3.select("svg").append("text")
|
|
.attr("class", "box")
|
|
.attr("transform","translate(10,"+(height+margin.top+margin.bottom)/2.0+")rotate(-90)")
|
|
.attr("text-anchor", "middle")
|
|
.text(yAxisLabel)
|
|
|
|
plot.append("rect")
|
|
.attr("class", "grid-background")
|
|
.attr("width", width)
|
|
.attr("height", height);
|
|
|
|
plot.append("g")
|
|
.attr("class","grid")
|
|
.call(yLines)
|
|
|
|
plot.append("g")
|
|
.attr("class","grid")
|
|
.call(xLines)
|
|
|
|
plot.append("g")
|
|
.attr("class", "x axis")
|
|
.attr("transform", "translate(0," + height + ")")
|
|
.call(xAxis);
|
|
|
|
plot.append("g")
|
|
.attr("class", "y axis")
|
|
.call(yAxis);
|
|
|
|
plot.selectAll(".box").data(mydata)
|
|
.enter().append("g")
|
|
.attr("class", "box")
|
|
.attr("width", boxWidth)
|
|
.attr("height", height)
|
|
.attr("transform", function(d,i) { return "translate(" + barOffset(i) + "," + 0 + ")"; } )
|
|
.call(chart);
|
|
}, true);
|
|
}
|
|
}
|
|
});
|
|
|
|
module.directive('boxplotEditor', function() {
|
|
return {
|
|
restrict: 'E',
|
|
templateUrl: '/views/visualizations/boxplot_editor.html'
|
|
};
|
|
});
|
|
|
|
})();
|