Bar overlapping issue in google chart - Combo chart - javascript

I am having a little problem with google chart implementation. As per requirement, I should have dual y-axis and the bars for y-axis should be overlapping. I achieved following output with my code:
Notice the two blue arrows for last two bars. The blue bar is hidden behind red bar as its smaller. It should actually look something like this:
This is my code for js file:
var chart, data;
google.load('visualization', '1.0', {'packages':['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart()
{
// Create the data table.
data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addColumn('number', 'pieces');
data.addColumn('number', 'ratio');
data.addColumn('number', 'ratio2');
data.addRows([
['Mushrooms', 300, 200, 50, 1],
['Onions', 100, 244, 4, 3],
['Olives', 100, 400, 56, 10]
]);
// Set chart options
options = {
chartType:"ComboChart",
containerId:"visualization",
stackSeries: true,
isStacked : true,
seriesDefaults: {
rendererOptions: {
barPadding: 0,
barMargin: 10
},
pointLabels: {
show: true,
stackedValue: true
}
},
grid: {
background: '#272424',
drawGridlines: false
},
seriesType: "bars",
series: {
0: {
targetAxisIndex: 0
},
1: {
targetAxisIndex: 1
},
2: {
targetAxisIndex: 1,
type: "line"
},
3: {
type: "line"
}
},
hAxis:{
},
vAxes: {
0: {
title: "Slices",
label:'Slices',
type:'bars'
},
1: {
title: "pieces",
label:'pieces',
type:'bars'
},
2: {
title: "ratio,",
label:'ratio',
type:'line'
},
3: {
title: "ratio2,",
label:'ratio2',
type:'line'
}
}
};
// Instantiate and draw our chart, passing in some options.
chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, options);
google.visualization.events.addListener(chart, 'select', selectionHandler);
}
function selectionHandler() {
var selectedData = chart.getSelection(), row, item;
if(selectedData != '')
{
row = selectedData[0].row;
item = data.getValue(row,3);
alert("You selected :" + item);
}
}
Can anyone suggest me how could I go about this? Any help would be appreciated.

You are displaying your bars on separate axes:
0: {
targetAxisIndex: 0
},
1: {
targetAxisIndex: 1
},
2: {
targetAxisIndex: 1,
type: "line"
},
3: {
type: "line"
}
So the first bar is on the left axis, the second is on the right axis. The first bar only shows because it is taller than the red bar in front of it. This is by design. If you want them to display stacked, change your code to this:
0: {
targetAxisIndex: 0
},
1: {
targetAxisIndex: 0
},
2: {
targetAxisIndex: 1,
type: "line"
},
3: {
targetAxisIndex: 1,
type: "line"
}
This will end up with this:
Note that your two axes no longer have equivalent size. Adjust other parameters as needed. If you want them side by side, you can put them on the same axis and remove isStacked: true which will make them stand next to each other.
Note: This sort of chart is incredibly busy and is likely not good visualization practice. Regardless, if you need to create a chart, the above solution should work. If you actually mean that you want the smaller bar in front, then good luck with SVG editing.

There actually is a way to get what you want, using a DataView to split your blue data series into two. Make one series where the data is greater than red series, and one where it is less than or equal to the red series, and position them (in order) greater than, red, less than. In the series option, set this new series to be the same color as the first, and hide it from the index.
Here's the DataView you would use:
var view = new google.visualization.DataView(data);
view.setColumns([0, {
type: 'number',
label: data.getColumnLabel(1),
calc: function (dt, row) {
var val = dt.getValue(row, 1);
return (val > dt.getValue(row, 2)) ? val : null;
}
}, 2, {
type: 'number',
label: data.getColumnLabel(1),
calc: function (dt, row) {
var val = dt.getValue(row, 1);
return (val <= dt.getValue(row, 2)) ? val : null;
}
}, 3, 4]);
and here's the series option:
series: {
0: {
targetAxisIndex: 0
},
1: {
targetAxisIndex: 1
},
2: {
targetAxisIndex: 0,
visibleInLegend: false,
color: '#3366cc' // matches series 0
},
3: {
targetAxisIndex: 1,
type: "line"
},
4: {
type: "line"
}
}
Draw the chart with the view instead of the DataTable:
chart.draw(view, options);
See it working here: http://jsfiddle.net/asgallant/4jhC5/

Related

Google visualization dual Y axis chart align line with specific bar

I have attached snippet for a dual Y axis chart.
The orange dot for Ontime% Goal corresponds with the blue bar for Ontime %. Both have been assigned to targetAxisIndex: 0
Can I shift/move the dot to align above the blue bar? (see attached picture for desired position).
Thank you as always to the experts out there!
google.charts.load('current', {'packages':['corechart', 'bar']});
google.charts.setOnLoadCallback(drawStuff);
function drawStuff() {
var button = document.getElementById('change-chart');
var chartDiv = document.getElementById('chart_div');
var data = google.visualization.arrayToDataTable([
['Type', 'Ontime%', 'Count', 'Ontime% Goal'],
['AE', 90, 500, 100]
]);
var classicOptions = {
width: 900,
series: {
0: {targetAxisIndex: 0, type: 'bars'},
1: {targetAxisIndex: 1, type: 'bars'},
2: {targetAxisIndex: 0, type: 'line', pointSize: 8, pointShape: { type: 'circle' } },
},
title: 'Ontime % on the left, Count on the right',
bar:{
width: "60%"
},
vAxis: {
minValue: 0
},
vAxes: {
// Adds titles to each axis.
0: {title: 'Ontime %'},
1: {title: 'Count'}
}
};
function drawClassicChart() {
var classicChart = new google.visualization.ColumnChart(chartDiv);
classicChart.draw(data, classicOptions);
button.innerText = 'Change to Material';
button.onclick = drawMaterialChart;
}
drawClassicChart();
};
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<br><br>
<div id="chart_div" style="width: 800px; height: 500px;"></div>
nothing out of the box will allow you to adjust the position of the point.
you can move it manually, on the chart's ready event.
but the chart will move it back when the user hovers the point.
you can use a MutationObserver to move the point when the chart moves it back,
but this will just cause it to blink from one spot to the other while it is being hovered.
not much you can do, unless you disable tooltips.
see following working snippet,
hover the point to see it move...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
//var button = document.getElementById('change-chart');
var chartDiv = document.getElementById('chart_div');
var data = google.visualization.arrayToDataTable([
['Type', 'Ontime%', 'Count', 'Ontime% Goal'],
['AE', 90, 500, 100]
]);
var classicOptions = {
width: 900,
series: {
0: {targetAxisIndex: 0, type: 'bars'},
1: {targetAxisIndex: 1, type: 'bars'},
2: {
targetAxisIndex: 0,
type: 'line',
pointSize: 8,
pointShape: {type: 'circle'},
},
},
title: 'Ontime % on the left, Count on the right',
bar:{
width: "60%"
},
vAxis: {
minValue: 0
},
vAxes: {
0: {title: 'Ontime %'},
1: {title: 'Count'}
}
};
function drawClassicChart() {
var classicChart = new google.visualization.ColumnChart(chartDiv);
google.visualization.events.addListener(classicChart, 'ready', function () {
var chartLayout = classicChart.getChartLayoutInterface();
var bounds = chartLayout.getBoundingBox('bar#0#0');
var observer = new MutationObserver(function () {
var circles = chartDiv.getElementsByTagName('circle');
if (circles.length > 1) {
circles[1].setAttribute('cx', (bounds.left + (bounds.width / 2)));
}
});
observer.observe(chartDiv, {
childList: true,
subtree: true
});
});
classicChart.draw(data, classicOptions);
//button.innerText = 'Change to Material';
//button.onclick = drawMaterialChart;
}
drawClassicChart();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
best case, you could disable the chart's tooltips,
then add your own custom tooltips,
for both the point and columns, etc...
the chart does provide mouseover and mouseout events,
not sure its worth the effort...

Change chart y-axis text orientation

I want to change my Google Chart's y-axis title to horizontal orientation. Currently, it is drawn with vertical writing, as shown in this image:
My chart drawing code
function drawVisualization() {
// Some raw data (not necessarily accurate)
var data = google.visualization.arrayToDataTable(temp);
var options = {
title: 'Report',
// vAxis: {title: 'Cups'},
hAxis: {
title: 'Date'
},
seriesType: 'bars',
series: {
0: {
targetAxisIndex: 0
},
1: {
targetAxisIndex: 1,
type: 'line'
}
},
vAxes: {
0: {
title: '報酬額',
titleTextStyle: {
italic: false,
}
},
1: {
title: '再生',
titleTextStyle: {
italic: false,
}
},
},
'chartArea' : {'width': '70%', left: '15%'}
};
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
You can see in the Axis Overview:
Direction - You can customize the direction using the
hAxis/vAxis.direction option.
hAxis.direction The direction in which the values along the
horizontal axis grow. Specify -1 to reverse the order of the values.
Type: 1 or -1 Default: 1
If this didn't answer the question, try the workarounds from this SO post.
I did like this. And works well. I don't think this is pretty way.
If anyone find better way Please say to me thanks.
var textTags = document.getElementsByTagName("text");
var searchPlay = "Play";
var searchProfit = "Profit"
$.each(textTags, function(index,value){
if (value.textContent == searchPlay) {
$(this).css('transform','rotate(1turn)');
console.log(value);
}
if (value.textContent == searchProfit) {
console.log(value);
$(this).css('transform', 'rotate(1turn)');
}
});

Google chart, average line removes my other line

I have a Google combo chart that has one value as bars and one value for a line, I also wanted a line to show the average of the value of the bars, so I found code that would do that, however, when implemented my other line disappeared.
This is what my chart looked like prior.
And this is after I implemented the average line, my other line disappeared.
I don't know how to do to make them both show?
This line seems to have things to do with all of it, changing dv back to data will show how my chart looked like on the first picture, but I guess there is something more I need to change to make it all work?
chart.draw(dv, options);
Here is the code.
<script>
google.charts.load('current', {
'packages': ['corechart']
});
google.charts.setOnLoadCallback(drawVisualization);
function drawVisualization() {
var data = google.visualization.arrayToDataTable([
['Day', 'Repetitions', 'Sets'],
#foreach (var c in db.Query(Query, inputDate, endDate, baselift))
{
var totAvg = c.avg;
var allReps = c.reps;
var realAvg = (totAvg / allReps) * 100;
//Writes out the data that will be shown in the chart.
<text>['#c.date', #c.reps, #c.sets],</text>
}
]);
// Create a DataView that adds another column which is all the same (empty-string) to be able to aggregate on.
var viewWithKey = new google.visualization.DataView(data);
viewWithKey.setColumns([0, 1, {
type: 'string',
label: '',
calc: function (d, r) {
return ''
}
}])
// Aggregate the previous view to calculate the average. This table should be a single table that looks like:
// [['', AVERAGE]], so you can get the Average with .getValue(0,1)
var group = google.visualization.data.group(viewWithKey, [2], [{
column: 1,
id: 'avg',
label: 'Average',
aggregation: google.visualization.data.avg,
'type': 'number'
}]);
// Create a DataView where the third column is the average.
var dv = new google.visualization.DataView(data);
dv.setColumns([0, 1, {
type: 'number',
label: 'Average',
calc: function (dt, row) {
return group.getValue(0, 1);
}
}]);
var options = {
title: 'Daily Repetition Statistics',
backgroundColor: { fill: 'transparent' },
explorer: { axis: 'horizontal' },
vAxes: {
0: { logScale: false, viewWindow: { min: 0 } },
1: { logScale: false, maxValue: 2 }
},
hAxis: { title: 'Day' },
seriesType: 'bars',
curveType: 'function',
series: {
0: {
targetAxisIndex: 0,
color: 'orange'
},
1: { targetAxisIndex: 1 },
1: { targetAxisIndex: 1, type: "line" },
2: { targetAxisIndex: 1, type: "line" }
}
};
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(dv, options);
}
</script>
the column index for 'sets' is not provided to setColumns
change this...
var dv = new google.visualization.DataView(data);
dv.setColumns([0, 1, {
type: 'number',
label: 'Average',
calc: function (dt, row) {
return group.getValue(0, 1);
}
}]);
to..
var dv = new google.visualization.DataView(data);
dv.setColumns([0, 1, 2, { // <-- add 'sets' column index 2
type: 'number',
label: 'Average',
calc: function (dt, row) {
return group.getValue(0, 1);
}
}]);

Change color of Multibar chart in Django

I am using Highcharts to represent some data and I've got stuck at this point:
I have the following chart:
How can I change the colors of each point of a bar ? ( e.g: instead of orange to set up 'red' ). Also, can I modify the color depending on the value of the point? (e.g: if the value is > 2.5k to transform that into another color).
My class looks like this:
class _TimeSeriesChart(_Chart):
def get_options(self, series):
return {
'title': {
'text': self.title,
},
'xAxis': {
'type': 'datetime',
},
'yAxis': {
'min': 0,
},
'plotOptions': {
'series': {
'animation': True,
},
'column': {
'stacking': 'normal',
#'colorByPoint': True,
},
},
'credits': {
'enabled': False
},
'series': series,
}
If colorByPoint is uncommented, I'll have each bar transformed in only one color.
Colors can be set per point.
series: [{
data: [{y: 1, color: '#ff0072'},
...
Example: http://jsfiddle.net/sbphxhfs/
Other option is to set negativeColor and threshold
series: [{
negativeColor: 'red',
threshold: 3,
...
Example: http://jsfiddle.net/sbphxhfs/1/
Colors can be also set for series (using color setting), or whole chart (using colors array).
Example: http://jsfiddle.net/sbphxhfs/2/

How to create combo chart with Highcharts

Need to create a chart similar to the one you see here: http://imgbin.org/index.php?page=image&id=20802. So far managed to put together a jsfiddle that displays both charts but its far from complete.
How would you correctly place the bottom chart (column) over the first to achieve the effect you see in example? http://jsfiddle.net/e106L47h/6/
$(function () {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=aapl-ohlcv.json&callback=?', function (data) {
// split the data set into ohlc and volume
var ohlc = [],
volume = [],
dataLength = data.length,
// set the allowed units for data grouping
groupingUnits = [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]],
i = 0;
for (i; i < dataLength; i += 1) {
ohlc.push([
data[i][0], // the date
data[i][1], // open
data[i][2], // high
data[i][3], // low
data[i][4] // close
]);
volume.push([
data[i][0], // the date
data[i][5] // the volume
]);
}
// create the chart
$('#container').highcharts('StockChart', {
navigator: {
enabled: false
},
rangeSelector: {
selected: 1,
inputEnabled: false
},
credits: {
enabled: false
},
yAxis: [{
height: '60%',
lineWidth: 0
}, {
top: '65%',
height: '35%',
offset: 0,
lineWidth: 0,
// gridLineWidth: 0,
labels:
{
//enabled: false
}
}],
series: [{
type: 'candlestick',
name: 'AAPL',
data: ohlc,
dataGrouping: {
units: groupingUnits
}
}, {
type: 'column',
name: 'Volume',
data: volume,
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}]
});
});
});
I would remove the height 35%/65% split and show both series with the same baseline.
Then I would hide the volume axis to reduce clutter.
You can modify the height of the volume bars by setting the max of the second hidden axis rather than the height (I have used maxValue*3 to approximate your 35% height value).
Find the maximum value in the volume series like this:
var maxVolume = Math.max.apply(Math, volume.map(function(v) { return v[1]}))
Example: http://jsfiddle.net/cvezpup7/

Categories