I'm having an issue with flot multibar chart (using orderBars plugin) -- the bars are too far from each other, when having many (=24) columns. I started up from this example, directly from http://en.benjaminbuffet.com/labs/flot/
<script type='text/javascript' src='jquery.flot.min.js'></script>
<script type='text/javascript' src='jquery.flot.orderBars.js'></script>
...
var d1 = [];
for (var i = 0; i <= 5; i += 1)
d1.push([i, parseInt(Math.random() * 30)]);
var d2 = [];
for (var i = 0; i <= 5; i += 1)
d2.push([i, parseInt(Math.random() * 30)]);
ds.push({
data:d1,
bars: {
show: true,
barWidth: 0.3,
order: 1,
lineWidth : 2
}
});
ds.push({
data:d2,
bars: {
show: true,
barWidth: 0.3,
order: 2
}
});
$.plot($("#placeholder"), ds, {
grid:{
hoverable:true
}
});
The bars are nicely next to each other, pairs separated by a space.
But, if I put there 24 columns (yes, I want to create chart for values on 24 hours), i.e. change the beginning of the code:
var d1 = [];
for (var i = 0; i <= 23; i += 1)
d1.push([i, parseInt(Math.random() * 30)]);
var d2 = [];
for (var i = 0; i <= 23; i += 1)
d2.push([i, parseInt(Math.random() * 30)]);
There is a space between the bars that belong to the one x-value; and no space between the two pairs. This is very confusing, user is mismatching the pairs. I need no space (or very little space) between the corresponding bars, and reasonable space between the pairs.
Here is a picture of both graphs, so you can see the problem:
Any help on this? Thx.
You have 24 bars in a confined space. You want more space between the groups of bars. Your options are:
1.) you increase width of your plot.
2.) you decrease the size of each bar.
You can't adjust the space between the bars directly. From the comments to the plugin:
The plugin adjust the point by adding a value depanding of the barwidth
* Exemple for 3 series (barwidth : 0.1) :
*
* first bar décalage : -0.15
* second bar décalage : -0.05
* third bar décalage : 0.05
Here's some code snips with possible fixes:
var d1 = [];
for (var i = 0; i <= 23; i += 1)
d1.push([i, parseInt(Math.random() * 30)]);
var d2 = [];
for (var i = 0; i <= 23; i += 1)
d2.push([i, parseInt(Math.random() * 30)]);
ds = [];
ds.push({
data: d1,
bars: {
show: true,
barWidth: 0.3,
order: 1,
lineWidth: 2
}
});
ds.push({
data: d2,
bars: {
show: true,
barWidth: 0.3,
order: 2
}
});
$.plot($("#placeholder"), ds, {
grid: {
hoverable: true
}
});
ds1 = [];
ds1.push({
data: d1,
bars: {
show: true,
barWidth: 0.005,
order: 1,
lineWidth: 2
}
});
ds1.push({
data: d2,
bars: {
show: true,
barWidth: 0.005,
order: 2
}
});
$.plot($("#placeholder1"), ds1, {
grid: {
hoverable: true
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://www.flotcharts.org/flot/jquery.flot.js"></script>
<script src="http://rawgit.com/emmerich/flot-orderBars/master/js/jquery.flot.orderBars.js"></script>
<div id="placeholder" style="width:3000px; height:300px"></div>
<div id="placeholder1" style="width:600px; height:300px"></div>
EDITS - UPDATED ANSWER
Another idea if you could drop the plugin and jitter the values yourself. This would allow better control on the spacing.
See this snip:
var barWidth = 0.2;
var jitterVal = barWidth / 1.5;
var d1 = [];
for (var i = 0; i <= 23; i += 1)
d1.push([i - jitterVal, parseInt(Math.random() * 30)]);
var d2 = [];
for (var i = 0; i <= 23; i += 1)
d2.push([i + jitterVal, parseInt(Math.random() * 30)]);
ds = [];
ds.push({
data: d1,
bars: {
show: true,
barWidth: barWidth
}
});
ds.push({
data: d2,
bars: {
show: true,
barWidth: barWidth
}
});
$.plot($("#placeholder"), ds, {
grid: {
hoverable: true
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://www.flotcharts.org/flot/jquery.flot.js"></script>
<div id="placeholder" style="width:400px; height:300px"></div>
Related
I am using highcharts.js for multiple series column chart and I want to show the shared tooltip on the top of group of column(It should take the highest column length)
So far I have tried this https:JSFiddle.
$(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'column',
plotBorderColor: '#CDCDCD',
plotBorderWidth: 1,
},
xAxis: {
type: "category"
},
yAxis: {
endOnTick: true,
startOnTick: true,
tickInterval: null,
},
tooltip: {
useHTML: true,
borderRadius: 0,
borderWidth: 0,
shadow: false,
followPointer: false,
hideDelay: 0,
shared: true,
enabled: true,
backgroundColor: "none",
positioner: function(labelWidth, labelHeight, point) {
var tooltipX, tooltipY;
var chart = this.chart;
tooltipX = point.plotX + chart.plotLeft - 20;
if (point.negative)
tooltipY = point.plotY + chart.plotTop + 20;
else
tooltipY = point.plotY + chart.plotTop - 30;
return {
x: tooltipX,
y: tooltipY
};
},
formatter: function() {
var templateHtmlString = "";
templateHtmlString += '<div class ="ttContainer">';
$.each(this.points, function(index, item) {
templateHtmlString += '<div class = "ttItem">';
templateHtmlString += item.y;
templateHtmlString += '</div>';
});
templateHtmlString += '</div>';
return templateHtmlString;
}
},
series: [{
"color": "red",
"data": [5,-1,17,9,8,19,-2,8,10],
"name": "ABCD"
}, {
"color": "Green",
"data": [8, -7,2,11,28,14,-3,8,-1],
"name": "XYZ"
}]
});
});
.ttItem {
display: inline-block;
padding: 5px;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div id="container" style="height: 400px"></div>
but it doesn't work when height of second column is greater than the first column. Please suggest how to fix this issue.
Finally, I figured out the solution myself.I have updated the JSFiddle.
I have modified the tooltip.positioner function to set the tooltip position.
positioner: function(labelWidth, labelHeight, point) {
var tooltipX, tooltipY;
var chart = this.chart;
var hoverPoints = this.chart.hoverPoints;
var y = 0;
var x = 0;
var totalColumnWidth = 0;
var deltaX = 0;
this.charts.hoverPoints contains the array of point object being hovered in case of multiple series chart.I loop through each point object in hoverpoints array.
plotY- y coordinate value of each column/point
barX - Starting x coordinate of each column/point
pointWidth - Width of each column/point
I have set the x as start of first point and y as the lowest plotY value among all points(lowest plotY means highest column)
$.each(hoverPoints, function(index, hPoint) {
var plotY = Math.ceil(hPoint.plotY);
if (index === 0) {
x = Math.ceil(hPoint.barX);
y = plotY;
}
totalColumnWidth += Math.ceil(hPoint.pointWidth);
if ((plotY > y && point.negative) || (plotY < y && !point.negative)) {
y = plotY;
}
});
delta = (totalColumnWidth - labelWidth) / 2
delta variable used to center align the tooltip.
tooltipX = x + chart.plotLeft + delta;
If column is on positive axis then add labelHeight so that tooltip wont overlap on column.
if (point.negative)
tooltipY = y + chart.plotTop;
else
tooltipY = y + chart.plotTop - labelHeight;
return {
x: tooltipX,
y: tooltipY
};
}
}
Alternatively, you could find the total height of y-axis and compare that with the points in the tooltipPos in hoverPoints.
$('#div_id').find('.highcharts-container').find('.highcharts-root').find('.highcharts-plot-background').attr('height'));
This way you could position each tooltip accordingly.
I have a line graph with lot of points to plot
I want x axis to be scrollable
I have already looked few solutions but they are providing solution with old versions of chart js.
Is there any option to get scrollable x axis in chart.js version 2?
And
How can i get width of content in y axis in chart.js version 2?
if there is no direct option to get scrollable x axis, I can copy content in Y-axis region and draw image in other canvas.
My answer on a related question will help you. In my example I have made the Y axis scrollable, but this could easily be applied to the X axis too.
https://stackoverflow.com/a/51282003/10060003
JS fiddle - https://jsfiddle.net/EmmaLouise/eb1aqpx8/3/
I am using the animation onComplete and onProgress options to redraw the axis that I want to scroll with the chart. (See https://www.chartjs.org/docs/latest/configuration/animations.html).
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'bar',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: false
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
},
animation: {
onComplete: function () {
if (!rectangleSet) {
var scale = window.devicePixelRatio;
var sourceCanvas = chartTest.chart.canvas;
var copyWidth = chartTest.scales['y-axis-0'].width - 10;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var targetCtx = document.getElementById("axis-Test").getContext("2d");
targetCtx.scale(scale, scale);
targetCtx.canvas.width = copyWidth * scale;
targetCtx.canvas.height = copyHeight * scale;
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth * scale, copyHeight * scale, 0, 0, copyWidth * scale, copyHeight * scale);
var sourceCtx = sourceCanvas.getContext('2d');
// Normalize coordinate system to use css pixels.
sourceCtx.clearRect(0, 0, copyWidth * scale, copyHeight * scale);
rectangleSet = true;
}
},
onProgress: function () {
if (rectangleSet === true) {
var copyWidth = chartTest.scales['y-axis-0'].width;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var sourceCtx = chartTest.chart.canvas.getContext('2d');
sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
}
}
}
}
});
i need to highlight y value example 20 to -10 and -30 to -45 in y axis. permanently with some color with opacity 50%, how to do.,
in this example how to add external csv file to this following code. Pls Guide me
var orig_range;
window.onload = function(){ var r = [];
var arr = ["7/13/2015 0:15:45",45,"7/13/2015 0:30",5,"7/13/2015 0:45",100,"7/13/2015 1:00",95,"7/13/2015 1:15",88,"7/13/2015 1:30",78];
for (var i = 0; i < arr.length; i++) {
r.push([ new Date(arr[i]),arr[i+1]
]);
i++;
}
orig_range = [ r[0][0].valueOf(), r[r.length - 1][0].valueOf() ];
g2 = new Dygraph(
document.getElementById("div_g"),
r, {
rollPeriod: 7,
animatedZooms: true,
// errorBars: true,
width: 1000,
height: 500,
xlabel: 'date',
ylabel: 'Pressure',
}
);
var desired_range = null;};
function approach_range() {
if (!desired_range) return;
// go halfway there
var range = g2.xAxisRange();
if (Math.abs(desired_range[0] - range[0]) < 60 &&
Math.abs(desired_range[1] - range[1]) < 60) {
g2.updateOptions({dateWindow: desired_range});
// (do not set another timeout.)
} else {
var new_range;
new_range = [0.5 * (desired_range[0] + range[0]),
0.5 * (desired_range[1] + range[1])];
g2.updateOptions({dateWindow: new_range});
animate();
}
}
function animate() {
setTimeout(approach_range, 50);
}
function zoom(res) {
var w = g2.xAxisRange();
desired_range = [ w[0], w[0] + res * 1000 ];
animate();
}
function reset() {
desired_range = orig_range;
animate();
}
function pan(dir) {
var w = g2.xAxisRange();
var scale = w[1] - w[0];
var amount = scale * 0.25 * dir;
desired_range = [ w[0] + amount, w[1] + amount ];
animate();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/1.1.0/dygraph-combined-dev.js"></script>
<div id="div_g"></div>
<div id="output"></div>
<b>Zoom:</b>
hour
day
week
month
full
<b>Pan:</b>
left
right
i'm trying to convert graph to dynamic graph data from csv file
var data = ["te1.csv"];
g2 = new Dygraph(document.getElementById("div_g"), data,
{
drawPoints: true,
showRoller: true,
labels:['date','depth'],
});
setInterval(function() {
data.push([data]);
g2.updateOptions( { 'file': data } );
}, 1000);
i have seen example but i dont know how to link my csv file with dynamic dygraph pls guide me
This example does something extremely similar to what you want: it highlights a specific range on the x-axis. To adapt it, you'd do something like this:
new Dygraph(data, div, {
underlayCallback: function (canvas, area, g) {
var bottom = g.toDomYCoord(highlight_start);
var top = g.toDomYCoord(highlight_end);
canvas.fillStyle = "rgba(255, 255, 102, 1.0)";
canvas.fillRect(area.x, top, area.w, bottom - top);
}
})
The problem is when I have a lot of bars to show. I plot the graph and doesn't show the background or the descriptions but when I scroll down they appear (you can see in the images). It doesn't happen in IE or Firefox.
I detect that when I reduce the size of the graph it doesn't happen, but when I have more data to plot I have to reduce more and for that reason this solution doesn't scale.
It seems to be a chrome bug because i don't have any JavaScript error in console more than
"event.returnValue is deprecated. Please use the standard event.preventDefault() instead. "
This is before scroll down: https://www.dropbox.com/s/0c295g64okupxnc/error%20.jpg
And this, after: https://www.dropbox.com/s/1gj9iyuvzrshs9p/error%202.jpg
That's the function who draws the chart:
/**
* Creates a bar chart
*
* #param title
* #param data
* #param labelX
* #param labelY
*/
_draw_bars: function (title, data, labelX, labelY) {
var values = [];
var min = 0;
var max = 0;
var items = [];
$(data).each(function(){
var n = values.length+1;
if (this[1] > max) {
max = this[1];
}
values.push([[n, this[1]]]);
items.push('<li >' + n + ': ' + this[0] + ' (' + this[1] + ')</li>');
});
if(values.length < 15){
this._show_modal(this._get_html(title, items,800,400),950,450);
}else{
this._show_modal(this._get_html(title, items,800,300),1350,650);
}
var barSize = this._get_bar_size(values.length);
$.jqplot.config.defaultHeight = $(window).height()*0.5;
$.jqplot('chart_div', values, {
legend:{show:false},
title: {show:false},
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {
barDirection:'vertical',
barPadding: barSize[0],
barMargin: barSize[1]
}
},
series: [],
axes:{
xaxis:{
renderer:$.jqplot.CategoryAxisRenderer,
label: labelY,
min:0,
max:values.length,
autoscale: true,
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
labelOptions: {enableFontSupport: true,
fontFamily: 'Arial',
fontSize: '12pt'
}
},
yaxis:{
min:0,
max:max,
ticks:this._get_ticks(min, max),
tickOptions:{formatString:'%d'},
label: labelX,
autoscale: true,
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
labelOptions: {enableFontSupport: true, fontFamily: 'Arial',fontSize: '12pt'}
}
},
highlighter: {
show: false
}
});
},
First time ever working with JS and HighCharts... But I'll try to formulate a question so it'll make sense!
At the moment I'm working with only 4 sources of data, which is incredibly easy to throw right in to highcharts.
The problem is, the 4 aggregated numbers is... well, not very consistent.
The numbers I have atm is: 349531093, 156777100, 572480, 7 and 0.
The first number and the second covers the whole funnel, which makes the plot very unattractive and hard to visually see the values.
(Yeah, yeah - the labels are brilliant, but I want to be able to visually see each section).
I've been reading through the documentation of the funnel plot, but I cannot find a way to limit the section size in any way.
So I tried to play around a bit with the different kind of limits, like:
minSize - The minimum size for a pie in response to auto margins. The pie will try to shrink to make room for data labels in side the
plot area, but only to this size. (which does exactly what it says,
so I'm not sure why I even tried it...)
size - that ofc just changed the size of the whole chart....
series: {
dataLabels: {
enabled: true,
format: '<b>{point.name}</b> ({point.y:,.0f})',
minSize: '10%',
color: 'black',
softConnector: true
},
neckWidth: '50%',
neckHeight: '50%',
minSize: '20%',
//-- Other available options
height: '200'
// width: pixels or percent
}
You can see my horrible attempt here at it here: JSFiddle thingy
So to the actual question: Is it possible to set an minimum limit for the section in the funnel?
Any suggestions or just a simple: "dude, not possible" is appreciated!
Cheers!
Unfortunately this is not supported (good idea to post this on userVoice!)
However I have created simple example that you can preprocess data and still display proper values: https://jsfiddle.net/69eey/2/
$(function () {
var dataEx = [
['Raw Events', 349531093],
['Filtered/Aggregated Events', 156777100],
['Correlated Events', 2792294],
['Use Case Events', 572480],
['Finalized', 0]
],
len = dataEx.length,
sum = 0,
minHeight = 0.05,
data = [],
i;
for(i = 0; i < len; i++){
sum += dataEx[i][1];
}
for(i = 0; i < len; i++){
var t = dataEx[i],
r = t[1] / sum;
data[i] = {
name: t[0],
y: ( r > minHeight ? t[1] : sum * minHeight ),
label: t[1]
}
}
It is only workaround of course. You also need to use formatter for a tooltip to make sure you will display proper values (like for dataLabels).
I took Paweł Fus's great example and extended it to include the tooltip correction. Just add the snippet below:
tooltip: {
formatter: function() {
return '<b>'+ this.key +
'</b> = <b>'+ Highcharts.numberFormat(this.point.label, 0) +'</b>';
}
},
JSFiddle with a working example:
HTML
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/funnel.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="width: 600px; height: 400px; margin: 0 auto"></div>
JavaScript
$(function () {
var dataEx = [
['Raw Events', 349531093],
['Filtered/Aggregated Events', 156777100],
['Correlated Events', 2792294],
['Use Case Events', 572480],
['Finalized', 0]
],
len = dataEx.length,
sum = 0,
minHeight = 0.05,
data = [];
for(var i = 0; i < len; i++){
sum += dataEx[i][1];
}
for(var i = 0; i < len; i++){
var t = dataEx[i],
r = t[1] / sum;
data[i] = {
name: t[0],
y: ( r > minHeight ? t[1] : sum * minHeight ),
label: t[1]
}
}
$('#container').highcharts({
chart: {
type: 'funnel',
marginRight: 100
},
title: {
text: 'SEIM Metrics',
x: -50
},
tooltip: {
//enabled: false
formatter: function() {
return '<b>'+ this.key +
'</b> = <b>'+ Highcharts.numberFormat(this.point.label, 0) +'</b>';
}
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
formatter: function(){
var point = this.point;
console.log(point);
return '<b>' + point.name + '</b> (' + Highcharts.numberFormat(point.label, 0) + ')';
},
minSize: '10%',
color: 'black',
softConnector: true
},
neckWidth: '50%',
neckHeight: '50%',
//-- Other available options
height: '200'
// width: pixels or percent
}
},
legend: {
enabled: false
},
series: [{
name: 'Unique users',
data: data
}]
});
});
You can try normalizing the values first by taking log.
log(349531093)=8.5
log(572480)=5.75