I'm trying to make an all positive bubble chart have quadrants by drawing the quadrants using the baseline property like so:
var dataT = google.visualization.arrayToDataTable(.....);
var options = {
hAxis: {title: 'h axis',baseline:100},
vAxis: {title: 'v axis',baseline:20},
...}
var chart = new google.visualization.BubbleChart(...);
chart.draw(dataT,options);
Except the graph will keep changing depending on the query so the baselines will not be the same for all the graphs. I would like to be able to get the max axis value and divide it by 2 to set the baselines right in the middle of each axis.
Example:
var options = {
hAxis: {title: 'h axis',baseline:max_h_axis/2},
vAxis: {title: 'v axis',baseline:max_v_axis/2},
...
Is there any way of knowing the max axis values of the graph before drawing the graph?
the getColumnRange method works for this...
Returns the minimal and maximal values of values in a specified column. The returned object has properties min and max. If the range has no values, min and max will contain null.
you can also use this information to produce your own axis tick marks.
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['X', 'Y'],
[8, 120],
[4, 155],
[11, 140],
[4, 205],
[3, 35],
[6, 78]
]);
var ticksX = [];
var ticksY = [];
var numberOfTicks = 10;
var rangeX = data.getColumnRange(0);
var rangeY = data.getColumnRange(1);
var stepX = Math.ceil((rangeX.max - rangeX.min) / numberOfTicks);
for (var i = rangeX.min - stepX; i <= rangeX.max + stepX; i = i + stepX) {
ticksX.push(i);
}
var stepY = Math.ceil((rangeY.max - rangeY.min) / numberOfTicks);
for (var i = rangeY.min - stepY; i <= rangeY.max + stepY; i = i + stepY) {
ticksY.push(i);
}
var baseX = Math.ceil((rangeX.max - rangeX.min) / 2) + rangeX.min;
var baseY = Math.ceil((rangeY.max - rangeY.min) / 2) + rangeY.min;
var options = {
hAxis: {
title: 'h axis',
baseline: baseX,
ticks: ticksX
},
vAxis: {
title: 'v axis',
baseline: baseY,
ticks: ticksY
},
legend: 'none',
height: 600,
width: 600
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
chart.draw(data, options);
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Related
I am trying to add some annotations to a Google Candlestick chart. I noticed someone had already asked this same question (Adding annotations to Google Candlestick chart). The user Aperçu replied with a detailed solution to extend the chart and add annotations since the chart doesn't have any such feature built in. However, when I try this solution I get an error "TypeError: document.querySelectorAll(...)[0] is undefined"
Here is my code:
chartPoints = [
['Budget', 0, 0, 9999, 9999, 'foo1'],
['Sales', 0, 0, 123, 123, 'foo2'],
['Backlog', 123, 123, 456, 456, 'foo3'],
['Hard Forecast', 456, 456, 789, 789, 'foo4'],
['Sales to Budget', 789, 789, 1000, 1000, 'foo5']
];
var data = google.visualization.arrayToDataTable(chartPoints, true);
data.setColumnProperty(5, 'role', 'annotation');
var options = {
legend: 'none',
bar: { groupWidth: '40%', width: '100%' },
candlestick: {
fallingColor: { strokeWidth: 0, fill: '#a52714' },
risingColor: { strokeWidth: 0, fill: '#0f9d58' }
}
};
var chart = new google.visualization.CandlestickChart(document.getElementById('chart_div'));
chart.draw(data, options);
// attempt to use Aperçu's solution
const bars = document.querySelectorAll('#chart_div svg > g:nth-child(5) > g')[0].lastChild.children // this triggers a TypeError
for (var i = 0 ; i < bars.length ; i++) {
const bar = bars[i]
const { top, left, width } = bar.getBoundingClientRect()
const hint = document.createElement('div')
hint.style.top = top + 'px'
hint.style.left = left + width + 5 + 'px'
hint.classList.add('hint')
hint.innerText = rawData.filter(t => t[1])[i][0]
document.getElementById('chart_div').append(hint)
}
I want the chart to show the last piece of data next to the bars (i.e. "foo1", "foo2", etc)
each candle or bar will be represented by a <rect> element
we can use the rise and fall colors to separate the bars from other <rect> elements in the chart
there will be the same number of bars as rows in the data table
once we find the first bar, we can use rowIndex of zero to pull values from the data
we need to find the value of the rise / fall, to know where to place the annotation
then use chart methods to find the location for the annotation
getChartLayoutInterface() - Returns an object containing information about the onscreen placement of the chart and its elements.
getYLocation(position, optional_axis_index) - Returns the screen y-coordinate of position relative to the chart's container.
see following working snippet
two annotations are added
one for the difference in rise and fall
and the other for the value in the column with annotation role
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var chartPoints = [
['Budget', 0, 0, 9999, 9999, 'foo1'],
['Sales', 0, 0, 123, 123, 'foo2'],
['Backlog', 123, 123, 456, 456, 'foo3'],
['Hard Forecast', 456, 456, 789, 789, 'foo4'],
['Sales to Budget', 789, 789, 1000, 1000, 'foo5']
];
var data = google.visualization.arrayToDataTable(chartPoints, true);
data.setColumnProperty(5, 'role', 'annotation');
var options = {
legend: 'none',
bar: { groupWidth: '40%', width: '100%' },
candlestick: {
fallingColor: { strokeWidth: 0, fill: '#a52714' },
risingColor: { strokeWidth: 0, fill: '#0f9d58' }
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.CandlestickChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
var annotation;
var bars;
var chartLayout;
var formatNumber;
var positionY;
var positionX;
var rowBalance;
var rowBottom;
var rowIndex;
var rowTop;
var rowValue;
var rowWidth;
chartLayout = chart.getChartLayoutInterface();
rowIndex = 0;
formatNumber = new google.visualization.NumberFormat({
pattern: '#,##0'
});
bars = container.getElementsByTagName('rect');
for (var i = 0; i < bars.length; i++) {
switch (bars[i].getAttribute('fill')) {
case '#a52714':
case '#0f9d58':
rowWidth = parseFloat(bars[i].getAttribute('width'));
if (rowWidth > 2) {
rowBottom = data.getValue(rowIndex, 1);
rowTop = data.getValue(rowIndex, 3);
rowValue = rowTop - rowBottom;
rowBalance = Math.max(rowBottom, rowTop);
positionY = chartLayout.getYLocation(rowBalance) - 6;
positionX = parseFloat(bars[i].getAttribute('x'));
// row value
annotation = container.getElementsByTagName('svg')[0].appendChild(container.getElementsByTagName('text')[0].cloneNode(true));
annotation.textContent = formatNumber.formatValue(rowValue);
annotation.setAttribute('x', (positionX + (rowWidth / 2)));
annotation.setAttribute('y', positionY);
annotation.setAttribute('font-weight', 'bold');
// annotation column
annotation = container.getElementsByTagName('svg')[0].appendChild(container.getElementsByTagName('text')[0].cloneNode(true));
annotation.textContent = data.getValue(rowIndex, 5);
annotation.setAttribute('x', (positionX + (rowWidth / 2)));
annotation.setAttribute('y', positionY - 18);
annotation.setAttribute('font-weight', 'bold');
rowIndex++;
}
break;
}
}
});
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I want to add percentage marks to number labels and found a option for it.
{hAxis: {format: 'percent'}}
But it also multiple the number by 100.
For instance, {hAxis: { format:'#,###%'} } displays the values "1,000%", "750%", and "50%" for values 10, 7.5, and 0.5.
https://developers.google.com/chart/interactive/docs/customizing_axes#number-formats
How can I just add % to the labels?
you could try adding custom axis labels, or ticks...
using object notation, you can provide both a...
value (v:) and a formatted value (f:)
then using google's NumberFormat class, build each tick manually...
var formatPercent = new google.visualization.NumberFormat({
suffix: '%'
});
...
ticks.push({
v: data.getValue(i, 0),
f: formatPercent.formatValue(data.getValue(i, 0))
});
...
hAxis: {
ticks: ticks
}
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages:['corechart']
});
function drawChart() {
var data = google.visualization.arrayToDataTable([
['X', 'Y'],
[1, 1],
[10, 2],
[20, 3],
[30, 4]
]);
var formatPercent = new google.visualization.NumberFormat({
pattern: '#,##0',
suffix: '%'
});
var ticks = [];
for (var i = 0; i < data.getNumberOfRows(); i++) {
ticks.push({
v: data.getValue(i, 0),
f: formatPercent.formatValue(data.getValue(i, 0))
});
}
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, {
hAxis: {
ticks: ticks
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I have an line/area chart, I want to set a minimum range on the y-axis.
Let's say my points are [0,300],[1,270],[2,230],[3,260] (those are retrieved through ajax, so they're not static).
I want the y-axis range to be at least 100, but by default google will set maximum as maximum value (300 in this case), and minimum at minimum value (230 in this case), so range in this case would be (and it is actually) 70, I want it to be at least 100, so the chart maximum should be (300+230)/2+50 and minimum (300+230)/2-50, so that I have a 100 range and the chart i vertically center aligned.
I want the range to have a minimum but not a maximum, if my points are [0,100],[1,240],[5,160] then range should match the data range (140 in this case) also if the optimum is smaller (100).
Basically I don't want the chart to show a big difference when the actual difference in data is small. I know how to set fixed maximum and minimum on axis, but that doesn't solve my problem.
This is my actual code:
$.fn.createChart = function(url,options){
var obj = $(this);
console.log('CREATING CHART: '+url);
// Load the Visualization API and the linechart package.
if(!$.canAccessGoogleVisualization()){
google.charts.load('current', {packages: ['corechart', 'line']});
}
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var jsonData = $.ajax({
url: url ,
dataType: "json",
async: false
}).responseText;
// Create our data table out of JSON data loaded from server.
var data = new google.visualization.DataTable(jsonData);
//Default options
var def = {
width: obj.width(),
height: obj.height(),
curveType: 'function',
legend: { position: 'bottom' },
hAxis: {
format: 'dd/MM'
},
animation:{
"startup": true,
duration: 1000,
easing: 'out',
}
};
//Overwrite default options with passed options
var options = typeof options !== 'undefined' ? $.mergeObjects(def,options) : def;
// Instantiate and draw our chart, passing in some options.
var chart = new google.visualization.AreaChart(obj.get(0));
chart.draw(data, options);
}
}
$.mergeObjects = function(obj1,obj2){
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
return obj1;
}
$.canAccessGoogleVisualization = function()
{
if ((typeof google === 'undefined') || (typeof google.visualization === 'undefined')) {
return false;
}
else{
return true;
}
}
you can use the getColumnRange method on the DataTable to find the min and max
then apply you're logic to set the viewWindow on the vAxis
see following working snippet...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['X', 'Y'],
[0, 300],
[1, 270],
[2, 230],
[3, 260]
]);
var yMin;
var yMax;
var columnRange = data.getColumnRange(1);
if ((columnRange.max - columnRange.min) < 100) {
yMin = ((columnRange.max + columnRange.min) / 2) - 50;
yMax = ((columnRange.max + columnRange.min) / 2) + 50;
} else {
yMin = columnRange.min;
yMax = columnRange.max;
}
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
chart.draw(data, {
vAxis: {
viewWindow: {
min: yMin,
max: yMax
}
}
});
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
How to show the sum of bars of a tick in jqplot. I want to show the values of each month as sum in top of that bar in line as shown to below image.
Starting fiddler http://jsfiddle.net/bywfc5xx/1/
`var s1 = [200, 600, 700, 1000];
var s2 = [460, 210, 690, 820];
var s3 = [260, 440, 320, 200];
// Can specify a custom tick Array.
// Ticks should match up one for each y value (category) in the series.
var ticks = ['May', 'June', 'July', 'August'];`
Any help please.
I don't understand what are u trying to do, to have the total there use:
var total = [s1[0] + s2[0] + s3[0], s1[1] + s2[1] + s3[1], s1[2] + s2[2] + s3[2], s1[3] + s2[3] + s3[3]];
var plot1 = $.jqplot('chart1', [s1, s2, s3, total], {..
The implementation:
http://jsfiddle.net/e4zasp6L/
Ok, got it,here is the updated answer: http://jsfiddle.net/282tkr12/
series:[
{
label:'Total',
color: 'blue' ,
renderer: $.jqplot.BarRenderer,
rendererOptions: {
barWidth:80,
shadowAlpha: 0,
barPadding: -86,
}
},
{label:'Hotel'},
{label:'Event Registration'},
{label:'Airfare'}
]
I am having some problem with Google chart. Here is the codes for my pie chart:
EDITED PORTION
function displayExistHospital(){
queryTask = new esri.tasks.QueryTask(overlayURLs["moh_hospital_WSA2"] + "/10");
query = new esri.tasks.Query();
query.returnGeometry = false;
query.where = "1=1";
query.outFields = ["*"];
queryTask.execute(query, getExistHospitalData);
document.getElementById("tabsLabel").style.display = "block";
document.getElementById("tabsLabel3").innerHTML = "Age > 60";
document.getElementById("tabsLabel2").innerHTML = "SCPR";
document.getElementById("tabsLabel1").innerHTML = "Total Pop";
}
google.load("visualization", "1", {packages:["corechart"], callback: displayExistHospital});
var arrList = [];
function getExistHospitalData(results){
arrList = [];
var features = results.features;
dojo.forEach(features, function(feature){
var tempArr = [];
var total_SCPR = feature.attributes.SUM_SUM_TOTAL_SCPR;
var total_NR = feature.attributes.SUM_SUM_TOTAL_NR;
var time = feature.attributes.FIRST_E_BREAK;
tempArr.push(time,total_SCPR,total_NR);
arrList.push(tempArr);
});
displayExistHospitalGraph(arrList);
}
function displayExistHospitalGraph(arrListData){
var total_ten = parseInt(arrListData[0][1]) + parseInt(arrListData[0][2]);
var total_tentoFifteen = arrListData[1][1] + arrListData[1][2];
var total_fifteenTwenty = arrListData[2][1] + arrListData[2][2];
var total_greaterTwenty = arrListData[3][1] + arrListData[3][2];
var ppl_num = total_ten + total_tentoFifteen;
var total_pop = total_ten + total_tentoFifteen + total_fifteenTwenty + total_greaterTwenty;
var dataOne = google.visualization.arrayToDataTable([
['Population', 'Percentage'],
['<10 mins' +getPercentageInString(total_ten,total_pop) , total_ten],
['10 - 15 mins' +getPercentageInString(total_tentoFifteen,total_pop), total_tentoFifteen],
['15 - 20 mins' +getPercentageInString(total_fifteenTwenty,total_pop), total_fifteenTwenty],
['>20 mins' +getPercentageInString(total_greaterTwenty,total_pop) , total_greaterTwenty],
]);
var percentage = (((total_ten / total_pop) + (total_tentoFifteen / total_pop)) * 100).toFixed(1);
var title = "Total Population ("+total_pop.toLocaleString()+") Catchment By Drive-Time(Existing)";
var optionsOne = {
chartArea: {
width: 350,
height: 200,
top: 20,
left: 10
},
fontName: 'Arial',
fontSize: getFontSize(),
isStacked:false,
title: title,
width: 400,
height: 200,
sliceVisibilityThreshold: 0,
colors:['#004CA8','#437DC4','#96B8E0','#FFFFFF']
};
document.getElementById('hospitalBoxContent').innerHTML= "</br><p ><span style='font-size:2em; color:#00297A; font-family:ArialVerdana; font-weight:bold;'>"+percentage+"% ("+ppl_num.toLocaleString()+")</span > of residents stay within <span style='font-size:2em; color:#00297A; font-family:ArialVerdana; font-weight:bold;'>15-min</span> drive-time to a public hospital </p><br/>";
var chart = new google.visualization.PieChart(document.getElementById('displayHospitalGraph'));
chart.draw(dataOne, optionsOne);
}
The chart works but somehow the percentage on the pie chart was cut off as the picture shown below:
I wonder is there any way to adjust the percentage for example, shift it nearer to the centre so that it won't cut off? I know the reason is because the chart was trying to draw before the API finish loading because this will only occur for the first load. After switching a few charts, the percentage label will be placed nicely inside the chart.
Credits to #asgallant and #Yoann as they helped me to spot the error but after added the codes, it still does not solve.
Thanks in advance.
Please change the last color #FFFFFF to any other color #FFFFFF this color is same as background
Some elements are cut off in you screenshot.
for the title, you need to increase top in optionsOne.chartArea (and height)
for the legend, increase width or reduce left in optionsOne.chartArea
the last pie item is set up on white colors:['#004CA8','#437DC4','#96B8E0','#FFFFFF'], change the font-colour or the last colour to avoid white on white
EDIT :
I created a http://jsfiddle.net/X24Sy/3/ with your code, I cannot reproduce your issue. Do you have any CSS for your container?
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart(){
var total_ten=15,total_tentoFifteen=35,total_fifteenTwenty=50,total_greaterTwenty=10;
var ppl_num = total_ten + total_tentoFifteen;
var total_pop = total_ten + total_tentoFifteen + total_fifteenTwenty + total_greaterTwenty;
var dataOne = google.visualization.arrayToDataTable([
['Population', 'Percentage'],
['<10 mins' +getPercentageInString(total_ten,total_pop) , total_ten],
['10 - 15 mins' +getPercentageInString(total_tentoFifteen,total_pop), total_tentoFifteen],
['15 - 20 mins' +getPercentageInString(total_fifteenTwenty,total_pop), total_fifteenTwenty],
['>20 mins' +getPercentageInString(total_greaterTwenty,total_pop) , total_greaterTwenty],
]);
var percentage = (((total_ten / total_pop) + (total_tentoFifteen / total_pop)) * 100).toFixed(1);
var title = "Total Population ("+total_pop.toLocaleString()+") Catchment By Drive-Time(Existing)";
var optionsOne = {
chartArea: {
width: 350,
height: 200,
top: 20,
left: 10
},
fontName: 'Arial',
fontSize: 12,
legend: { alignment: 'center', textStyle: { fontSize: 12} },
// pieSliceText: 'none', //label - > show the name on the pie
tooltip: {
trigger: 'focus'// focus -> tooltip will be displayed when the user hovers over an element.
// none -> tooltip is not displayed
},
isStacked:false,
title: title,
width: 350,
height: 200,
sliceVisibilityThreshold: 0,
colors:['#004CA8','#437DC4','#96B8E0','#FFFFFF']
};
var chart = new google.visualization.PieChart($('#displayHospitalGraph')[0]);
chart.draw(dataOne, optionsOne);
}
The problem is in this:
function getExistHospitalData(results){
arrList = [];
var features = results.features;
dojo.forEach(features, function(feature){
var tempArr = [];
var total_SCPR = feature.attributes.SUM_SUM_TOTAL_SCPR;
var total_NR = feature.attributes.SUM_SUM_TOTAL_NR;
var time = feature.attributes.FIRST_E_BREAK;
tempArr.push(time,total_SCPR,total_NR);
arrList.push(tempArr);
});
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(displayExistHospitalGraph(arrList));
}
First, you want to call google.load outside of any other functions. Second, this line:
google.setOnLoadCallback(displayExistHospitalGraph(arrList));
calls your displayExistHospitalGraph function with arrList as an argument, and passes it's return value (null) to google.setOnLoadCallback. This means that your drawing function is being executed immediately, not in the callback. Try this approach instead:
function getExistHospitalData(results){
arrList = [];
var features = results.features;
dojo.forEach(features, function(feature){
var tempArr = [];
var total_SCPR = feature.attributes.SUM_SUM_TOTAL_SCPR;
var total_NR = feature.attributes.SUM_SUM_TOTAL_NR;
var time = feature.attributes.FIRST_E_BREAK;
tempArr.push(time,total_SCPR,total_NR);
arrList.push(tempArr);
});
displayExistHospitalGraph(arrList);
}
function init () {
// get "results" and feed them to getExistHospitalData
getExistHospitalData(results);
}
google.load("visualization", "1", {packages:["corechart"], callback: init});