I am using google datavisualization charts. I have a datatable with 2 columns and 4 rows. I need to display this data into a single stacked bar chart as shown below
Sample of my data :
var data = new google.visualization.DataTable();
data.addColumn('string', 'name');
data.addColumn('number', 'count');
data.addRows([
['abc', 321],
['def', 163],
['ghi', 125],
['jkl', 197]
]);
I have tried using column chart and bar chart by enabling isStacked:true , but no luck.
Is there a way to display the data in a single stacked chart as shown in the image. I don't mind whether it is a bar chart or column chart.
I would appreciate if someone can help me.
Thanks.
The issue is that right now there is nothing linking the different columns together, so that there is no reason for them to be stacked on top of each other.
You need to have each of the elements share a common element, like the date. Next, you need to add a separate column for each of the different 'name' fields. Finally, when adding your values, add them only to the column index that matches the (name, value) pair.
data.addColumn('number', 'irrelevant');
data.addColumn('number', 'abc');
data.addColumn('number', 'def');
data.addColumn('number', 'ghi');
data.addColumn('number', 'jkl');
data.addColumn('number', 'mno');
data.addRows([
[0, 321, 0, 0, 0, 0],
[0, 0, 163, 0, 0, 0],
[0, 0, 0, 125, 0, 0],
[0, 0, 0, 0, 452, 0],
[0, 0, 0, 0, 0, 825]
]);
This sort of thing is annoying to do by hand, so in my chart system I iterate through a list of all the different groupings (or 'name's in your case) and keep track of each index so I know which element of the individual row to specify.
Here's a small sample from my code so you can get the right idea:
GoogleDataTable.addColumn('number', 'Age');
var GroupIndex = 0;
var DateIndex = 0;
for (var i = 0; i < RawJSON.length; i++) {
//If the groupkey is not in the group array yet.
if (GroupArray.indexOf(RawJSON[i][GroupKey]) == -1) {
GroupArray[GroupIndex] = RawJSON[i][GroupKey];
GroupIndex++;
GoogleDataTable.addColumn('number', RawJSON[i][GroupKey]);
}
//If the timeslice is not yet in the Date array.
if (DateArray.indexOf(RawJSON[i]["Age"]) == -1) {
DateArray[DateIndex] = RawJSON[i]['Age'];
DateIndex++;
}
}
then later
var groupIndex = GroupArray.indexOf(RawJSON[i][GroupKey]) + 1;
for (var j = 1; j <= GroupIndex; j++) {
if (j == groupIndex) {
RowArray[insertIndex][groupIndex] = RawJSON[i]['Value'];
}
}
Related
How to format vAxis in google charts that would display vertical scale with points instead of commas.
Example(now): 100,000
Example(then): 100.000
I know that the trick is with 'format' function, but I can't get it to work like i want.
I am trying to format it like with this:
vAxis: {minValue:0, format:'##.##'}
if the format option does not meet your needs,
you can use the ticks option to provide custom labels
using object notation, you can provide both the...
v: - value for the axis
f: - formatted value for the label
{v: 100000, f: '100.000'}
see following working snippet
the NumberFormat class is used, in an attempt to create the format
(not sure exactly what is needed)
data table method getColumnRange is used to find the range of the y-axis
a loop builds each tick for the axis labels...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'x');
data.addColumn('number', 'y0');
data.addRows([
[0, 500000],
[1, 500000],
[2, 200000],
[3, 700000],
[4, 400000]
]);
var formatNumber = new google.visualization.NumberFormat({
groupingSymbol: '.',
fractionDigits: 0
});
var ticksY = [];
var yRange = data.getColumnRange(1);
for (var i = 0; i <= yRange.max; i=i+100000) {
ticksY.push({
v: i,
f: formatNumber.formatValue(i)
});
}
var options = {
vAxis: {
ticks: ticksY
}
};
var chart = new google.visualization.LineChart(
document.getElementById('chart_div')
);
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Try this :
vAxis.format:{format:'##.##'}
I am trying to draw multiple Google charts in a for loop, but can't seem to make it work. I have seen some similar questions being asked, but only with PHP. Anyone who can help? This is what I have tried so far https://jsfiddle.net/8nfbz1v1/
<ul id="draw-charts"></ul>
google.charts.load('current', {'packages':['corechart']});
for(var i = 0; i>6; i+){
var charts = "";
google.charts.setOnLoadCallback(drawChart);
function drawCharts() {
charts += '<td><div id="chart_div' + i +'" style="border: 1px solid #ccc"></div></td>';
$("#draw-charts").html(charts);
var data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 1],
['Onions', 1],
['Olives', 2],
['Zucchini', 2],
['Pepperoni', 1]
]);
var options = {title:'How Much Pizza Sarah Ate Last Night',
width:400,
height:300};
// Instantiate and draw the chart for Sarah's pizza.
var chart = new google.visualization.PieChart(document.getElementById('chart_div' + i));
chart.draw(data, options);
}
}
setOnLoadCallback should only be called once per page load
once it fires, you can draw as many charts as needed
you can also include the callback in the load statement
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 1],
['Onions', 1],
['Olives', 2],
['Zucchini', 2],
['Pepperoni', 1]
]);
var options = {
title:'How Much Pizza Sarah Ate Last Night',
width:400,
height:300
};
for (var i = 0; i < 6; i++) {
var container = document.getElementById('draw-charts').appendChild(document.createElement('div'));
var chart = new google.visualization.PieChart(container);
chart.draw(data, options);
}
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<ul id="draw-charts"></ul>
I am working on my first full program with two weeks of programming under my belt, and have run into a road block I can't seem to figure out. I am making a connect 4 game, and have started by building the logic in JavaScript before pushing to the DOM. I have started to make it with cell objects made by a constructor, that are then pushed into a game object in the form of a 2D array. I have managed to create a function that makes the play each time, and changes the value of the cell at the lowest point of that column with a 2 day array. However, I am not sure how to get my check for wins function to operate.
So far my logic is that, for each point in the 2D array, you can check by row, by column, and by diagonals. I understand the logic of how to check for win, but I don't understand how to traverse through the arrays by row and column. In the example below, this.cellsArray is an array of cell objects in the Board Constructor. The array has 7 column arrays, with 6 rows each, as I flipped the typical row column logic to account for Connect Four's column based nature. However I can't access the array like this.cellsArray[col][row], as col and row aren't defined, and I'm not sure how to define an index value? Any help would be appreciated!
Connect 4
Example:
//array location is equal to an instance of this.cellsArray[col][row]
Board.prototype.checkRowRight = function (arrayLocation) {
if ((arrayLocation[i+1][i].value === arrayLocation.value) && (arrayLocation[i+2][i]=== arrayLocation.value) && (arrayLocation[i+3][i].value === arraylocation.value)){
this.winner = this.currentPlayer;
this.winnerFound = true;
console.log('Winner has been found!')
}
};
Referencing back to my logic found here and refactoring out the winning line detection code, this can easily be converted into Javascript as follows:
function chkLine(a,b,c,d) {
// Check first cell non-zero and all cells match
return ((a != 0) && (a ==b) && (a == c) && (a == d));
}
function chkWinner(bd) {
// Check down
for (r = 0; r < 3; r++)
for (c = 0; c < 7; c++)
if (chkLine(bd[r][c], bd[r+1][c], bd[r+2][c], bd[r+3][c]))
return bd[r][c];
// Check right
for (r = 0; r < 6; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r][c+1], bd[r][c+2], bd[r][c+3]))
return bd[r][c];
// Check down-right
for (r = 0; r < 3; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r+1][c+1], bd[r+2][c+2], bd[r+3][c+3]))
return bd[r][c];
// Check down-left
for (r = 3; r < 6; r++)
for (c = 0; c < 4; c++)
if (chkLine(bd[r][c], bd[r-1][c+1], bd[r-2][c+2], bd[r-3][c+3]))
return bd[r][c];
return 0;
}
And a test call:
x =[ [0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 0, 0],
[0, 0, 1, 2, 2, 2, 0],
[0, 1, 2, 2, 1, 2, 0] ];
alert(chkWinner(x));
The chkWinner function will, when called with the board, return the first (and only, assuming each move changes only one cell and you're checking after every move) winning player.
The idea is to basically limit the checks to those that make sense. For example, when checking cells to the right (see the second loop), you only need to check each row 0-6 starting in each of the leftmost four columns 0-3.
That's because starting anywhere else would run off the right hand side of the board before finding a possible win. In other words, column sets {0,1,2,3}, {1,2,3,4}, {2,3,4,5} and {3,4,5,6} would be valid but {4,5,6,7} would not (the seven valid columns are 0-6).
This is an old thread but i'll throw my solution into the mix since this shows up as a top search result for "how to calculate connect4 win javascript"
I tackled this problem by using matrix addition.
Assume your game board is stored in memory as a 2D array like this:
[ [0, 0, 0, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, R, 0, 0, 0, 0],
[0, 0, Y, 0, 0, 0, 0],
[0, 0, R, R, R, 0, 0] ];
On each "Coin Drop" you should call a function passing the x/y position of the coin.
THIS is where you calculate weather the user has won the game
let directionsMatrix = {
vertical: { south: [1, 0], north: [-1, 0] },
horizontal: { east: [0, 1], west: [0, -1] },
backward: { southEast: [1, 1], northWest: [-1, -1] },
forward: { southWest: [1, -1], northEast: [-1, 1] },
};
NOTE: "South" in matrix notation is [1,0], meaning "Down 1 cell, Right 0 cells"
Now we can loop through each Axis/Direction to check if there is 4 in a row.
const playerHasWon = (colnum, rowNum, playerColor, newGrid) => {
//For each [North/South, East/West, NorthEast/Northwest, SouthEast/Southwest]
for (let axis in directionsMatrix) {
// We difine this variable here so that "East" and "West" share the same count,
// This allows a coin to be dropped in a middle cell
let numMatches = 1;
// For each [North, South]
for (let direction in directionsMatrix[axis]) {
// Get X/Y co-ordinates of our dropped coin
let cellReference = [rowNum, colnum];
// Add co-ordinates of 1 cell in test direction (eg "North")
let testCell = newGrid[cellReference[0]][cellReference[1]];
// Count how many matching color cells are in that direction
while (testCell == playerColor) {
try {
// Add co-ordinates of 1 cell in test direction (eg "North")
cellReference[0] += directionsMatrix[axis][direction][0];
cellReference[1] += directionsMatrix[axis][direction][1];
testCell = newGrid[cellReference[0]][cellReference[1]];
// Test if cell is matching color
if (testCell == playerColor) {
numMatches += 1;
// If our count reaches 4, the player has won the game
if (numMatches >= 4) {
return true;
}
}
} catch (error) {
// Exceptions are to be expected here.
// We wrap this in a try/catch to ignore the array overflow exceptions
// console.error(error);
break;
}
}
// console.log(`direction: ${direction}, numMatches: ${numMatches}`);
// If our count reaches 4, the player has won the game
if (numMatches >= 4) {
return true;
}
}
}
// If we reach this statement: they have NOT won the game
return false;
};
Here's a link to the github repo if you wish to see the full code.
Here's a link to a live demo
When trying to plot a Line Chart using the Google Charts code I get this error
Error: Type mismatch. Value 0.8 does not match type number in column index 0
The '0.8' is referring to the value p1 in the code.
function drawChart() {
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('number', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
[p1,1.89],
[ch_period[17],5],
[3,2],
[5,2],
[5,2],
[6,7]
]);
// Set chart options
var options = {'title':'How Much Pizza I Ate Last Night',
'width':400,
'height':300};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
I've made a jsfiddle with your code that works: http://jsfiddle.net/kychan/Dfx4V/1/
var p1 = parseInt('4'),
ch_period = {'17':4};
function drawChart() {
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('number', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
[p1, 1.89],
[ch_period[17], 5],
[3, 2],
[5, 2],
[5, 2],
[6, 7]
]);
// Set chart options
var options = {
'title': 'How Much Pizza I Ate Last Night',
'width': 400,
'height': 300
};
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
drawChart();
The problem was that p1 (and maybe ch_period) isn't the type number. Thus you must make it a number using parseInt(p1) / parseInt(ch_period) or manually assign it to a number.
I've created a ColumnChart and it has two bars. How can I set different colours on these two bars?
I'm currently only able to set one color for both bars,
This is part of the code I use:
var d = [['', ''], ['Bar 1', 100], ['Bar 2', 300]];
data = new google.visualization.arrayToDataTable(d);
var option = {
title: 'Betalingsoppfølging',
width: '300',
height: '250',
min: '0',
legend: 'none',
colors: ['#b2cedc', '#7b7b7b','#e2e2e2', '#747c1f']
}
wrap.setOptions(option);
wrap.draw(data);
The intention with colors: ['#b2cedc', '#7b7b7b','#b2cedc', '#7b7b7b'] is to set start-end colour for bar1 and bar 2. But all i does, is to use the first color defined.
And is there a way to chagne the background color through options?
Test code for Visualization tool
Cut and paste this into Code Playground.
function drawVisualization() {
// Create and populate the data table.
var data = new google.visualization.DataTable();
var raw_data = [['Austria', 150000, 225000]];
var years = [2003, 2004];
data.addColumn('string', 'Year');
for (var i = 0; i < raw_data.length; ++i) {
data.addColumn('number', raw_data[i][0]);
}
data.addRows(years.length);
for (var j = 0; j < years.length; ++j) {
data.setValue(j, 0, years[j].toString());
}
for (var i = 0; i < raw_data.length; ++i) {
for (var j = 1; j < raw_data[i].length; ++j) {
data.setValue(j-1, i+1, raw_data[i][j]);
}
}
// Create and draw the visualization.
new google.visualization.ColumnChart(document.getElementById('visualization')).
draw(data,
{title:"Color testing",
width:600, height:400,
hAxis: {title: "Year"},
colors: ['#dedb70', '#747c1f','yellow', 'red'],
min: '0',
legend: 'none'
}
);
}
The problem seems to be that you are only entering one entry, Austria, with multiple data points. colors sets the color for each entry, not each entry's data point. The chart does not have an option I can find for multiple data point colors.
To see what I mean change:
var raw_data = [['Austria', 150000, 225000]];
to
var raw_data = [['Austria', 150000, 225000],['Japan',100000,200000]];
You don't need to repeat the color codes, it will repeat the set you give it.
colors: ['#b2cedc', '#7b7b7b']
You can also just let it use the default, which will give a distinct color set, if you're not picky about the colors.
Background color is changed through backgroundColor. It takes a string like 'red' or '#b2cedc'
There's a nice tool you can play with to test your code on the fly. The above color code inserted in after width:600, height:400, colors in every other line like it should.
This documentation might also be helpful.
Very useful code: i found it here.
https://groups.google.com/forum/?fromgroups=#!topic/google-visualization-api/jCVmevbBT4Q
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Year');
data.addColumn('number', 'Sales');
data.addColumn('number', 'Expenses');
data.addRows(4);
data.setValue(0, 0, '2004');
data.setValue(0, 1, 1000);
data.setValue(0, 2, 400);
data.setValue(1, 0, '2005');
data.setValue(1, 1, 1170);
data.setValue(1, 2, 460);
data.setValue(2, 0, '2006');
data.setValue(2, 1, 660);
data.setValue(2, 2, 1120);
data.setValue(3, 0, '2007');
data.setValue(3, 1, 1030);
data.setValue(3, 2, 540);
var chart = new google.visualization.ColumnChart(document.getElementById('visualization'));
chart.draw(data, { width: 640, height: 480, title: 'Company Performance',
vAxis: { title: 'Year', titleTextStyle: { color: 'red'} },
legend: 'none', colors: ['#cc00cc', '#ccffcc']
});
changeColors();
}
function changeColors() {
var chartArea = document.getElementsByTagName('iframe') [0].contentDocument.getElementById('chartArea');
var nodes = chartArea.getElementsByTagName('rect');
// finding all <rect> elements with #cc00cc fill color and replacing them with 'blue','red','green','blue'
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.getAttribute('fill') && node.getAttribute('fill') == '#cc00cc') {
switch (i % 4) {
case 0:
node.setAttribute('fill', 'blue');
break;
case 1:
node.setAttribute('fill', 'red');
break;
case 2:
node.setAttribute('fill', 'green');
break;
case 3:
node.setAttribute('fill', 'red');
break;
}
}
}
// finding all <rect> elements with #ccffcc fill color and replacing them with 'blue','red','green','blue'
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.getAttribute('fill') && node.getAttribute('fill') == '#ccffcc') {
switch (i % 4) {
case 0:
node.setAttribute('fill', 'blue');
break;
case 1:
node.setAttribute('fill', 'red');
break;
case 2:
node.setAttribute('fill', 'green');
break;
case 3:
node.setAttribute('fill', 'red');
break;
}
}
}
}